Merge remote-tracking branch 'upstream/master' into gm-new-gears

pull/24764/head
Jason Shuler 3 years ago
commit 1c22cb9c11
  1. 3
      .github/workflows/prebuilt.yaml
  2. 3
      .github/workflows/release.yaml
  3. 10
      .github/workflows/selfdrive_tests.yaml
  4. 40
      .github/workflows/tools_tests.yaml
  5. 9
      .pylintrc
  6. 7
      Dockerfile.openpilot
  7. 52
      Jenkinsfile
  8. 8
      Pipfile
  9. 561
      Pipfile.lock
  10. 12
      README.md
  11. 9
      RELEASES.md
  12. 2
      SConstruct
  13. 2
      cereal
  14. 2
      common/api/__init__.py
  15. 2
      common/basedir.py
  16. 2
      common/modeldata.h
  17. 3
      common/params.cc
  18. 2
      common/realtime.py
  19. 2
      common/swaglog.cc
  20. 2
      common/tests/test_swaglog.cc
  21. 128
      docs/CARS.md
  22. 6
      docs/conf.py
  23. 2
      laika_repo
  24. 6
      launch_chffrplus.sh
  25. 2
      opendbc
  26. 2
      panda
  27. 40
      release/files_common
  28. 2
      release/files_tici
  29. 2
      scripts/disable-powersave.py
  30. 6
      selfdrive/athena/athenad.py
  31. 4
      selfdrive/athena/manage_athenad.py
  32. 4
      selfdrive/athena/registration.py
  33. 9
      selfdrive/athena/tests/test_athenad.py
  34. 2
      selfdrive/boardd/boardd.cc
  35. 2
      selfdrive/boardd/main.cc
  36. 4
      selfdrive/boardd/pandad.py
  37. 2
      selfdrive/boardd/tests/boardd_old.py
  38. 2
      selfdrive/boardd/tests/test_boardd_loopback.py
  39. 2
      selfdrive/camerad/cameras/camera_common.cc
  40. 2
      selfdrive/camerad/cameras/camera_common.h
  41. 7
      selfdrive/camerad/cameras/camera_qcom2.cc
  42. 1
      selfdrive/camerad/cameras/camera_qcom2.h
  43. 2
      selfdrive/camerad/main.cc
  44. 2
      selfdrive/camerad/snapshot/snapshot.py
  45. 1
      selfdrive/camerad/test/camera_test.h
  46. 2
      selfdrive/camerad/test/test_camerad.py
  47. 2
      selfdrive/camerad/test/test_exposure.py
  48. 30
      selfdrive/car/CARS_template.md
  49. 1
      selfdrive/car/body/interface.py
  50. 4
      selfdrive/car/car_helpers.py
  51. 9
      selfdrive/car/chrysler/interface.py
  52. 2
      selfdrive/car/disable_ecu.py
  53. 4
      selfdrive/car/docs.py
  54. 65
      selfdrive/car/docs_definitions.py
  55. 1
      selfdrive/car/ford/interface.py
  56. 6
      selfdrive/car/ford/radar_interface.py
  57. 4
      selfdrive/car/ford/values.py
  58. 2
      selfdrive/car/fw_versions.py
  59. 6
      selfdrive/car/gm/carstate.py
  60. 37
      selfdrive/car/gm/interface.py
  61. 27
      selfdrive/car/honda/carcontroller.py
  62. 47
      selfdrive/car/honda/carstate.py
  63. 39
      selfdrive/car/honda/hondacan.py
  64. 12
      selfdrive/car/honda/interface.py
  65. 40
      selfdrive/car/hyundai/interface.py
  66. 27
      selfdrive/car/hyundai/values.py
  67. 10
      selfdrive/car/interfaces.py
  68. 24
      selfdrive/car/isotp_parallel_query.py
  69. 1
      selfdrive/car/mazda/interface.py
  70. 2
      selfdrive/car/mock/interface.py
  71. 1
      selfdrive/car/nissan/interface.py
  72. 3
      selfdrive/car/subaru/interface.py
  73. 4
      selfdrive/car/subaru/values.py
  74. 1
      selfdrive/car/tesla/interface.py
  75. 3
      selfdrive/car/tests/routes.py
  76. 6
      selfdrive/car/tests/test_car_interfaces.py
  77. 6
      selfdrive/car/tests/test_docs.py
  78. 1
      selfdrive/car/tests/test_models.py
  79. 1
      selfdrive/car/torque_data.json
  80. 45
      selfdrive/car/toyota/interface.py
  81. 4
      selfdrive/car/toyota/tunes.py
  82. 40
      selfdrive/car/toyota/values.py
  83. 2
      selfdrive/car/vin.py
  84. 7
      selfdrive/car/volkswagen/interface.py
  85. 5
      selfdrive/car/volkswagen/values.py
  86. 4
      selfdrive/controls/controlsd.py
  87. 27
      selfdrive/controls/lib/drive_helpers.py
  88. 2
      selfdrive/controls/lib/events.py
  89. 2
      selfdrive/controls/lib/lane_planner.py
  90. 1
      selfdrive/controls/lib/latcontrol_indi.py
  91. 29
      selfdrive/controls/lib/latcontrol_torque.py
  92. 12
      selfdrive/controls/lib/lateral_planner.py
  93. 12
      selfdrive/controls/lib/longcontrol.py
  94. 2
      selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py
  95. 2
      selfdrive/controls/lib/longitudinal_planner.py
  96. 4
      selfdrive/controls/plannerd.py
  97. 2
      selfdrive/controls/radard.py
  98. 15
      selfdrive/debug/count_events.py
  99. 2
      selfdrive/debug/disable_ecu.py
  100. 1
      selfdrive/hardware
  101. Some files were not shown because too many files have changed in this diff Show More

@ -25,11 +25,12 @@ jobs:
IMAGE_NAME: openpilot-prebuilt IMAGE_NAME: openpilot-prebuilt
steps: steps:
- name: Wait for green check mark - name: Wait for green check mark
uses: lewagon/wait-on-check-action@v0.2 uses: commaai/wait-on-check-action@f16fc3bb6cd4886520b4e9328db1d42104d5cadc
with: with:
ref: master ref: master
wait-interval: 30 wait-interval: 30
running-workflow-name: 'build prebuilt' running-workflow-name: 'build prebuilt'
check-regexp: ^((?!.*(build master-ci).*).)*$
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true

@ -12,11 +12,12 @@ jobs:
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
steps: steps:
- name: Wait for green check mark - name: Wait for green check mark
uses: lewagon/wait-on-check-action@v0.2 uses: commaai/wait-on-check-action@f16fc3bb6cd4886520b4e9328db1d42104d5cadc
with: with:
ref: master ref: master
wait-interval: 30 wait-interval: 30
running-workflow-name: 'build master-ci' running-workflow-name: 'build master-ci'
check-regexp: ^((?!.*(build prebuilt).*).)*$
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true

@ -20,8 +20,7 @@ env:
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache $BASE_IMAGE /bin/sh -c RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache $BASE_IMAGE /bin/sh -c
BUILD_CL: | BUILD_CL: |
docker pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base_cl) || true docker pull $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest || true
docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true
docker build --cache-from $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $CL_BASE_IMAGE:latest -f Dockerfile.openpilot_base_cl . docker build --cache-from $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $CL_BASE_IMAGE:latest -f Dockerfile.openpilot_base_cl .
RUN_CL: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache $CL_BASE_IMAGE /bin/sh -c RUN_CL: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache $CL_BASE_IMAGE /bin/sh -c
@ -95,7 +94,7 @@ jobs:
run: | run: |
${{ env.RUN }} "scons -j$(nproc) --extras --test && \ ${{ env.RUN }} "scons -j$(nproc) --extras --test && \
rm -rf /tmp/scons_cache/* && \ rm -rf /tmp/scons_cache/* && \
scons -j$(nproc) --cache-populate" scons -j$(nproc) --extras --test --cache-populate"
#build_mac: #build_mac:
# name: build macos # name: build macos
@ -201,12 +200,15 @@ jobs:
submodules: true submodules: true
- name: Build Docker image - name: Build Docker image
run: eval "$BUILD" run: eval "$BUILD"
- name: Push to container registry
run: |
$DOCKER_LOGIN
docker push $DOCKER_REGISTRY/$BASE_IMAGE:latest
- name: Build CL Docker image - name: Build CL Docker image
run: eval "$BUILD_CL" run: eval "$BUILD_CL"
- name: Push to container registry - name: Push to container registry
run: | run: |
$DOCKER_LOGIN $DOCKER_LOGIN
docker push $DOCKER_REGISTRY/$BASE_IMAGE:latest
docker push $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest docker push $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest
static_analysis: static_analysis:

@ -21,6 +21,46 @@ env:
GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/comma_download_cache:/tmp/comma_download_cache $BASE_IMAGE /bin/sh -c GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/comma_download_cache:/tmp/comma_download_cache $BASE_IMAGE /bin/sh -c
jobs: jobs:
build_latest_ubuntu:
name: build latest ubuntu
runs-on: ubuntu-20.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Cache pyenv
id: ubuntu-latest-pyenv
uses: actions/cache@v3
with:
path: |
~/.pyenv
~/.local/share/virtualenvs/
key: ubuntu-latest-python-${{ hashFiles('tools/ubuntu_setup.sh') }}-
- name: Cache scons
id: ubuntu-latest-scons
uses: actions/cache@v3
with:
path: /tmp/scons_cache
key: ubuntu-latest-scons-${{ hashFiles('.github/workflows/tools_test.yaml') }}-
restore-keys: |
ubuntu-latest-scons-${{ hashFiles('.github/workflows/tools_test.yaml') }}-
ubuntu-latest-scons-
- name: tools/ubuntu_setup.sh
run: |
source tools/openpilot_env.sh
tools/ubuntu_setup.sh
- name: Build openpilot
run: |
source tools/openpilot_env.sh
pipenv run scons -j$(nproc) --extras --test
- name: Cleanup scons cache
run: |
source tools/openpilot_env.sh
rm -rf /tmp/scons_cache/*
pipenv run scons -j$(nproc) --extras --test --cache-populate
plotjuggler: plotjuggler:
name: plotjuggler name: plotjuggler
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04

@ -3,7 +3,7 @@
# A comma-separated list of package or module names from where C extensions may # A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may # be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code # run arbitrary code
extension-pkg-whitelist=scipy cereal.messaging.messaging_pyx extension-pkg-whitelist=scipy,cereal.messaging.messaging_pyx,PyQt5,av
# Add files or directories to the blacklist. They should be base names, not # Add files or directories to the blacklist. They should be base names, not
# paths. # paths.
@ -250,13 +250,6 @@ max-line-length=100
# Maximum number of lines in a module # Maximum number of lines in a module
max-module-lines=1000 max-module-lines=1000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,
dict-separator
# Allow the body of a class to be on the same line as the declaration if body # Allow the body of a class to be on the same line as the declaration if body
# contains single statement. # contains single statement.
single-line-class-stmt=no single-line-class-stmt=no

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

52
Jenkinsfile vendored

@ -42,6 +42,7 @@ def phone_steps(String device_type, steps) {
pipeline { pipeline {
agent none agent none
environment { environment {
CI = "1"
TEST_DIR = "/data/openpilot" TEST_DIR = "/data/openpilot"
SOURCE_DIR = "/data/openpilot_source/" SOURCE_DIR = "/data/openpilot_source/"
} }
@ -74,13 +75,37 @@ pipeline {
} }
} }
stages {
stage('On-device Tests') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
stages {
stage('parallel tests') {
parallel { parallel {
stage('simulator') {
agent {
dockerfile {
filename 'Dockerfile.sim_nvidia'
dir 'tools/sim'
args '--user=root'
}
}
steps {
sh "git config --global --add safe.directory ${WORKSPACE}"
sh "git lfs pull"
sh "${WORKSPACE}/tools/sim/build_container.sh"
lock(resource: "", label: "simulator", inversePrecedence: true, quantity: 1) {
sh "DETACH=1 ${WORKSPACE}/tools/sim/start_carla.sh"
sh "${WORKSPACE}/tools/sim/start_openpilot_docker.sh"
}
}
post {
always {
sh "docker kill carla_sim || true"
sh "rm -rf ${WORKSPACE}/* || true"
sh "rm -rf .* || true"
}
}
}
stage('build') { stage('build') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
environment { environment {
R3_PUSH = "${env.BRANCH_NAME == 'master' ? '1' : ' '}" R3_PUSH = "${env.BRANCH_NAME == 'master' ? '1' : ' '}"
} }
@ -96,10 +121,11 @@ pipeline {
} }
stage('HW + Unit Tests') { stage('HW + Unit Tests') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps { steps {
phone_steps("tici2", [ phone_steps("tici2", [
["build", "cd selfdrive/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["test power draw", "python selfdrive/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"],
@ -109,6 +135,7 @@ pipeline {
} }
stage('camerad') { stage('camerad') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps { steps {
phone_steps("tici-party", [ phone_steps("tici-party", [
["build", "cd selfdrive/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
@ -119,6 +146,7 @@ pipeline {
} }
stage('replay') { stage('replay') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps { steps {
phone_steps("tici3", [ phone_steps("tici3", [
["build", "cd selfdrive/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
@ -126,20 +154,8 @@ pipeline {
]) ])
} }
} }
}
}
} }
post {
always {
cleanWs()
}
}
}
}
} }
} }
} }

@ -11,7 +11,7 @@ coverage = "*"
dictdiffer = "*" dictdiffer = "*"
fastcluster = "*" fastcluster = "*"
hexdump = "*" hexdump = "*"
hypothesis = "*" hypothesis = "==6.46.7"
inputs = "*" inputs = "*"
lru-dict = "*" lru-dict = "*"
markdown-it-py = "*" markdown-it-py = "*"
@ -39,7 +39,8 @@ breathe = "*"
subprocess32 = "*" subprocess32 = "*"
tenacity = "*" tenacity = "*"
mpld3 = "*" mpld3 = "*"
carla = {version = "==0.9.12", markers="platform_system != 'Darwin'"} carla = {version = "==0.9.13", markers="platform_system != 'Darwin'"}
ft4222 = "*"
[packages] [packages]
atomicwrites = "*" atomicwrites = "*"
@ -58,6 +59,7 @@ json-rpc = "*"
libusb1 = "*" libusb1 = "*"
nose = "*" nose = "*"
numpy = "*" numpy = "*"
protobuf = "==3.20.1"
onnx = "*" onnx = "*"
onnxruntime-gpu = {version = "*", markers="platform_system != 'Darwin'"} onnxruntime-gpu = {version = "*", markers="platform_system != 'Darwin'"}
pillow = "*" pillow = "*"
@ -84,6 +86,8 @@ urllib3 = "*"
utm = "*" utm = "*"
websocket_client = "*" websocket_client = "*"
hatanaka = "==2.4" hatanaka = "==2.4"
PyQt5 = "==5.15.4"
PyQt5-sip = "==12.9.0"
[requires] [requires]
python_version = "3.8" python_version = "3.8"

561
Pipfile.lock generated

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "50d3486820d05997c1e084e70362fa080e0a294faa01c7f1d43219e44f94a80b" "sha256": "d2629168f477b3a14f68f26e3b63ea9797b20599c066b2aa23a027bcee2ca40a"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -18,11 +18,11 @@
"default": { "default": {
"astroid": { "astroid": {
"hashes": [ "hashes": [
"sha256:14ffbb4f6aa2cf474a0834014005487f7ecd8924996083ab411e7fa0b508ce0b", "sha256:4f933d0bf5e408b03a6feb5d23793740c27e07340605f236496cd6ce552043d6",
"sha256:f4e4ec5294c4b07ac38bab9ca5ddd3914d4bf46f9006eb5c0ae755755061044e" "sha256:ba33a82a9a9c06a5ceed98180c5aab16e29c285b828d94696bf32d6015ea82a9"
], ],
"markers": "python_full_version >= '3.6.2'", "markers": "python_full_version >= '3.6.2'",
"version": "==2.11.5" "version": "==2.11.6"
}, },
"atomicwrites": { "atomicwrites": {
"hashes": [ "hashes": [
@ -146,7 +146,7 @@
"sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
"sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
], ],
"markers": "python_version >= '3'", "markers": "python_full_version >= '3.5.0'",
"version": "==2.0.12" "version": "==2.0.12"
}, },
"click": { "click": {
@ -347,7 +347,7 @@
"sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
"sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
], ],
"markers": "python_version >= '3'", "markers": "python_full_version >= '3.5.0'",
"version": "==3.3" "version": "==3.3"
}, },
"importlib-metadata": { "importlib-metadata": {
@ -689,21 +689,35 @@
"hashes": [ "hashes": [
"sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf", "sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf",
"sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f", "sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f",
"sha256:0d4719e724472e296062ba8e82a36d64693fcfdb550d9dff98af70ca79eafe3d",
"sha256:284f86a6207c897542d7e956eb243a36bb8f9564c1742b253462386e96c6b78f", "sha256:284f86a6207c897542d7e956eb243a36bb8f9564c1742b253462386e96c6b78f",
"sha256:2b35602cb65d53c168c104469e714bf68670335044c38eee3c899d6a8af03ffc",
"sha256:32ca378605b41fd180dfe4e14d3226386d8d1b002ab31c969c366549e66a2bb7", "sha256:32ca378605b41fd180dfe4e14d3226386d8d1b002ab31c969c366549e66a2bb7",
"sha256:32fff501b6df3050936d1839b80ea5899bf34db24792d223d7640611f67de15a",
"sha256:34400fd76f85bdae9a2e9c1444ea4699c0280962423eff4418765deceebd81b5",
"sha256:3767c64593a49c7ac0accd08ed39ce42744405f0989d468f0097a17496fdbe84",
"sha256:3cc797c9d15d7689ed507b165cd05913acb992d78b379f6014e013f9ecb20996", "sha256:3cc797c9d15d7689ed507b165cd05913acb992d78b379f6014e013f9ecb20996",
"sha256:3f2ed842e8ca43b790cb4a101bcf577226e0ded98a6a6ba2d5e12095a08dc4da",
"sha256:52c1e44e25f2949be7ffa7c66acbfea940b0945dd416920231f7cb30ea5ac6db",
"sha256:5d9b5c8270461706973c3871c6fbdd236b51dfe9dab652f1fb6a36aa88287e47",
"sha256:62f1b5c4cd6c5402b4e2d63804ba49a327e0c386c99b1675c8a0fefda23b2067", "sha256:62f1b5c4cd6c5402b4e2d63804ba49a327e0c386c99b1675c8a0fefda23b2067",
"sha256:69ccfdf3657ba59569c64295b7d51325f91af586f8d5793b734260dfe2e94e2c", "sha256:69ccfdf3657ba59569c64295b7d51325f91af586f8d5793b734260dfe2e94e2c",
"sha256:6f50601512a3d23625d8a85b1638d914a0970f17920ff39cec63aaef80a93fb7", "sha256:6f50601512a3d23625d8a85b1638d914a0970f17920ff39cec63aaef80a93fb7",
"sha256:72d357cc4d834cc85bd957e8b8e1f4b64c2eac9ca1a942efeb8eb2e723fca852",
"sha256:7403941f6d0992d40161aa8bb23e12575637008a5a02283a930addc0508982f9", "sha256:7403941f6d0992d40161aa8bb23e12575637008a5a02283a930addc0508982f9",
"sha256:755f3aee41354ae395e104d62119cb223339a8f3276a0cd009ffabfcdd46bb0c", "sha256:755f3aee41354ae395e104d62119cb223339a8f3276a0cd009ffabfcdd46bb0c",
"sha256:77053d28427a29987ca9caf7b72ccafee011257561259faba8dd308fda9a8739", "sha256:77053d28427a29987ca9caf7b72ccafee011257561259faba8dd308fda9a8739",
"sha256:79cd8d0a269b714f6b32641f86928c718e8d234466919b3f552bfb069dbb159b",
"sha256:7e371f10abe57cee5021797126c93479f59fccc9693dafd6bd5633ab67808a91", "sha256:7e371f10abe57cee5021797126c93479f59fccc9693dafd6bd5633ab67808a91",
"sha256:9016d01c91e8e625141d24ec1b20fed584703e527d28512aa8c8707f105a683c", "sha256:9016d01c91e8e625141d24ec1b20fed584703e527d28512aa8c8707f105a683c",
"sha256:9be73ad47579abc26c12024239d3540e6b765182a91dbc88e23658ab71767153", "sha256:9be73ad47579abc26c12024239d3540e6b765182a91dbc88e23658ab71767153",
"sha256:a4c0c6f2f95a559e59a0258d3e4b186f340cbdc5adec5ce1bc06d01972527c88",
"sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9", "sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9",
"sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388", "sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388",
"sha256:af0ebadc74e281a517141daad9d0f2c5d93ab78e9d455113719a45a49da9db4e", "sha256:af0ebadc74e281a517141daad9d0f2c5d93ab78e9d455113719a45a49da9db4e",
"sha256:b309fda192850ac4184ca1777aab9655564bc8d10a9cc98f10e1c8bf11295c22",
"sha256:b3d7d4b4945fe3c001403b6c24442901a5e58c0a3059290f5a63523ed4435f82",
"sha256:c8829092c5aeb61619161269b2f8a2e36fd7cb26abbd9282d3bc453f02769146",
"sha256:cb29edb9eab15742d791e1025dd7b6a8f6fcb53802ad2f6e3adcb102051063ab", "sha256:cb29edb9eab15742d791e1025dd7b6a8f6fcb53802ad2f6e3adcb102051063ab",
"sha256:cd68be2559e2a3b84f517fb029ee611546f7812b1fdd0aa2ecc9bc6ec0e4fdde", "sha256:cd68be2559e2a3b84f517fb029ee611546f7812b1fdd0aa2ecc9bc6ec0e4fdde",
"sha256:cdee09140e1cd184ba9324ec1df410e7147242b94b5f8b0c64fc89e38a8ba531", "sha256:cdee09140e1cd184ba9324ec1df410e7147242b94b5f8b0c64fc89e38a8ba531",
@ -712,7 +726,7 @@
"sha256:e250a42f15bf9d5b09fe1b293bdba2801cd520a9f5ea2d7fb7536d4441811d20", "sha256:e250a42f15bf9d5b09fe1b293bdba2801cd520a9f5ea2d7fb7536d4441811d20",
"sha256:ff8d8fa42675249bb456f5db06c00de6c2f4c27a065955917b28c4f15978b9c3" "sha256:ff8d8fa42675249bb456f5db06c00de6c2f4c27a065955917b28c4f15978b9c3"
], ],
"markers": "python_version >= '3.7'", "index": "pypi",
"version": "==3.20.1" "version": "==3.20.1"
}, },
"psutil": { "psutil": {
@ -841,11 +855,11 @@
}, },
"pylint": { "pylint": {
"hashes": [ "hashes": [
"sha256:095567c96e19e6f57b5b907e67d265ff535e588fe26b12b5ebe1fc5645b2c731", "sha256:549261e0762c3466cc001024c4419c08252cb8c8d40f5c2c6966fea690e7fe2a",
"sha256:705c620d388035bdd9ff8b44c5bcdd235bfb49d276d488dd2c8ff1736aa42526" "sha256:bb71e6d169506de585edea997e48d9ff20c0dc0e2fbc1d166bad6b640120326b"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.13.9" "version": "==2.14.1"
}, },
"pyopencl": { "pyopencl": {
"hashes": [ "hashes": [
@ -890,6 +904,53 @@
"index": "pypi", "index": "pypi",
"version": "==2022.1.5" "version": "==2022.1.5"
}, },
"pyqt5": {
"hashes": [
"sha256:213bebd51821ed89b4d5b35bb10dbe67564228b3568f463a351a08e8b1677025",
"sha256:2a69597e0dd11caabe75fae133feca66387819fc9bc050f547e5551bce97e5be",
"sha256:883a549382fc22d29a0568f3ef20b38c8e7ab633a59498ac4eb63a3bf36d3fd3",
"sha256:8c0848ba790a895801d5bfd171da31cad3e551dbcc4e59677a3b622de2ceca98",
"sha256:a88526a271e846e44779bb9ad7a738c6d3c4a9d01e15a128ecfc6dd4696393b7"
],
"index": "pypi",
"version": "==5.15.4"
},
"pyqt5-qt5": {
"hashes": [
"sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a",
"sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962",
"sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154",
"sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327"
],
"version": "==5.15.2"
},
"pyqt5-sip": {
"hashes": [
"sha256:055581c6fed44ba4302b70eeb82e979ff70400037358908f251cd85cbb3dbd93",
"sha256:0fc9aefacf502696710b36cdc9fa2a61487f55ee883dbcf2c2a6477e261546f7",
"sha256:42274a501ab4806d2c31659170db14c282b8313d2255458064666d9e70d96206",
"sha256:4347bd81d30c8e3181e553b3734f91658cfbdd8f1a19f254777f906870974e6d",
"sha256:485972daff2fb0311013f471998f8ec8262ea381bded244f9d14edaad5f54271",
"sha256:4f8e05fe01d54275877c59018d8e82dcdd0bc5696053a8b830eecea3ce806121",
"sha256:69a3ad4259172e2b1aa9060de211efac39ddd734a517b1924d9c6c0cc4f55f96",
"sha256:6a8701892a01a5a2a4720872361197cc80fdd5f49c8482d488ddf38c9c84f055",
"sha256:6d5bca2fc222d58e8093ee8a81a6e3437067bb22bc3f86d06ec8be721e15e90a",
"sha256:83c3220b1ca36eb8623ba2eb3766637b19eb0ce9f42336ad8253656d32750c0a",
"sha256:a25b9843c7da6a1608f310879c38e6434331aab1dc2fe6cb65c14f1ecf33780e",
"sha256:ac57d796c78117eb39edd1d1d1aea90354651efac9d3590aac67fa4983f99f1f",
"sha256:b09f4cd36a4831229fb77c424d89635fa937d97765ec90685e2f257e56a2685a",
"sha256:c446971c360a0a1030282a69375a08c78e8a61d568bfd6dab3dcc5cf8817f644",
"sha256:c5216403d4d8d857ec4a61f631d3945e44fa248aa2415e9ee9369ab7c8a4d0c7",
"sha256:d3e4489d7c2b0ece9d203ae66e573939f7f60d4d29e089c9f11daa17cfeaae32",
"sha256:d59af63120d1475b2bf94fe8062610720a9be1e8940ea146c7f42bb449d49067",
"sha256:d85002238b5180bce4b245c13d6face848faa1a7a9e5c6e292025004f2fd619a",
"sha256:d8b2bdff7bbf45bc975c113a03b14fd669dc0c73e1327f02706666a7dd51a197",
"sha256:dd05c768c2b55ffe56a9d49ce6cc77cdf3d53dbfad935258a9e347cbfd9a5850",
"sha256:fc43f2d7c438517ee33e929e8ae77132749c15909afab6aeece5fcf4147ffdb5"
],
"index": "pypi",
"version": "==12.9.0"
},
"pyserial": { "pyserial": {
"hashes": [ "hashes": [
"sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb",
@ -954,74 +1015,74 @@
}, },
"pyzmq": { "pyzmq": {
"hashes": [ "hashes": [
"sha256:011a45c846ec69a3671ed15893b74b6ad608800c89ac6d0f0411e2137c6b313d", "sha256:057176dd3f5ccf5aad4abd662d76b6a39bbf799baaf2f39cd4fdaf2eab326e43",
"sha256:011f26841dd56ed87e464c98023dbbd4c0b3ab8802a045de3ea83e0187eb8145", "sha256:05ec90a8da618f2398f9d1aa20b18a9ef332992c6ac23e8c866099faad6ef0d6",
"sha256:0258563bf69f6ca305204354f171e0627a9bf8fe78c9d4f63a5e2447035cbb4b", "sha256:154de02b15422af28b53d29a02de72121ba503634955017255573fc1f995143d",
"sha256:07d2008e51718fba60641e5d1a0646b222b7929f16f6e7cf0834b8439f42c9e8", "sha256:16b832adb5d8716f46051da5533c480250bf126984ce86804db6137a3a7f931b",
"sha256:0a787f7870cba38d655c68ea7ae14bb6c3e9e19bb618d0c2412513321eeaeb80", "sha256:1df26aa854bdd3a8341bf199064dd6aa6e240f2eaa3c9fa8d217e5d8b868c73e",
"sha256:0a89b9860d2171bcf674648dc8186db9cf3b773ad3c0610a2c7bf189cf3560b6", "sha256:28f9164fb2658b7b414fa0894c75b1a9c61375774cdc1bdb7298beb042a2cd87",
"sha256:0de8a7e13ffacfe33c89acc0d7bfa2f5bde94e3f74b7f1e4d43c97ce17864d77", "sha256:2951c29b8649f3672af9dca8ff61d86310d3664d9629788b1c66422fb13b1239",
"sha256:12a53f5c13edf12547ce495afebdd5ab11c1b67ea078a941b21e13161783741a", "sha256:2b08774057ae7ce8a2eb4e7d54db05358234440706ce43a85814500c5d7bd22e",
"sha256:12eac2294d48ee27d1eaef7e214acedb394e4c95e3a1f6e4467099b82d58ef73", "sha256:2e2ac40f7a91c740ec68d6db07ae19ea9259c959333c68bee56ab2c799a67d66",
"sha256:176be6c348dbec04e8e0d41e810743b7084b73e50954a6fedeeafc65d7fa9290", "sha256:312e56799410c34797417a4060a8bd37d4db1f06d1ec0c54f7c8fd81e0d90376",
"sha256:1d480d48253f61ff90115b8069ed32f51a0907eb19101c4a5ae0b9a5973e40ad", "sha256:38f778a74e3889392e949326cfd0e9b2eb37dcbb2980d98fad2c51703d523db2",
"sha256:21792f4d0fcc5040978ee211c033e915d8b6608ea8a5b33fe197a04f0d43e991", "sha256:3955dd5bbbe02f454655296ee36a66c334c7102a29b8458223d168c0380edfd5",
"sha256:277b3ebc684b369a57a186a9acf629c1b01247eb04d1105536ef2dae5f61168a", "sha256:425ba851a6f9892bde1da2024d82e2fe6796bd77e3391fb96665c50fe9d4c6a5",
"sha256:2f227150148e7c3db7ecd8a58500439979f556e15455841a30b6d121755b14bc", "sha256:48bbc2db041ab28eeee4a3e8ada0ed336640946dd5a8e53dbd3805f9dbdcf0dc",
"sha256:34b143751e9b2b89cf9b656081f1b2842a563c4c9ffc8465531875daf546e772", "sha256:4fbcd657cda75574fd1315a4c44bd322bc2e219039fb09f146bbe6f8aef039e9",
"sha256:3f3807e81bf51d4c63eb12a21920614e0e840645418e9f2e3b5ffdd5991b3415", "sha256:523ba7fd4d8fe75ad09c1e574a648892b75a97d0cfc8005727681053ac19555b",
"sha256:3fa7126d532effee452c0ab395ab3cbef1c06fd6870ab7e681f812ba9e685cfa", "sha256:53b2c1326c2e484d450932d2be739f064b7cb572faabec38386098a28516a529",
"sha256:434044eec7f9df08fc5ca5c9bdd1a4bb08663679d43ebe7b9849713956f4d85f", "sha256:540d7146c3cdc9bbffab039ea067f494eba24d1abe5bd33eb9f963c01e3305d4",
"sha256:4d861ae20040afc17adef33053c328667da78d4d3676b2936788fd031665e3a8", "sha256:563d4281c4dbdf647d93114420151d33f895afc4c46b7115a67a0aa5347e6624",
"sha256:536491ad640448f14d8aa2dc497c354a348f216eb23513bf5aa0ac40e2b02577", "sha256:67a049bcf967a39993858beed873ed3405536019820922d4efacfe35ab3da51a",
"sha256:5619f6598d6fd30778053ae2daa48a7c54029816648b908270b751411fd52e74", "sha256:67ec63ae3c9c1fa2e077fcb42e77035e2121a04f987464bdf9945a28535d30ad",
"sha256:591b455546d34bb96aa453dd9666bddb8c81314e23dbf2606f9614acf7e73d9f", "sha256:68e22c5d3be451e87d47f956b397a7823bfbde2176341bc902fba30f96831d7e",
"sha256:5a13171268f05d127e31b4c369b753733f67dbb0d765901ef625a115feb5c7de", "sha256:6ab4b6108e69f63c917cd7ef7217c5727955b1ac90600e44a13ed5312019a014",
"sha256:5eaf7e0841d3d8d1d92838c8b56f98cb9bf35b14bcbe4efa281e4812ef4be728", "sha256:6bd7f18bd4cf51ea8d7e54825902cf36f9d2f35cc51ef618373988d5398b8dd0",
"sha256:6c09e6e5c4baf0959287943dc8170624d739ae555d334e896a94d9de01c7bb21", "sha256:6cd53e861bccc0bdc4620f68fb4a91d5bcfe9f4213cf8e200fa498044d33a6dc",
"sha256:6e2093a97bf3f6008a4be6b5bae8ae3fc409f18373593bef19dd7b381ab8030c", "sha256:6d346e551fa64b89d57a4ac74b9bc66703413f02f50093e089e861999ec5cccc",
"sha256:7b518ad9cdbaaeb1a9da3444797698871ae2eeae34ff9a656d5150d37e1e42a1", "sha256:6ff8708fabc9f9bc2949f457d39b4088c9656c4c9ac15fbbbbaafce8f6d07833",
"sha256:7ca7d77f24644298cbe53bc279eb7ca05f3b8637473d392f0c9f34b37f08b49a", "sha256:7626e8384275a7dea6f3d1f749fb5e00299042e9c895fc3dbe24cb154909c242",
"sha256:7eca5902ff41575d9a26f91fc750018b7eb129600ea600fe69ce852fbdfab4e2", "sha256:7e7346b2b33dcd4a2171dd8a9870ae283eec8f6231dcbcf237a0f41e74751a50",
"sha256:8951830d6a00636b3af478091f9668ecc486f1dad01b975527957fd1d8c31bfd", "sha256:81623c67cb71b93b5f7e06c9107f3781738ae86866db830c950223d87af2a235",
"sha256:8c234aefeef034c5d6de452e2af5173a95ea06315b685db703091e6f937a6e60", "sha256:83f1c76068faf62c32a36dd62dc4db642c2027bbbd960f8f6345b59e9d4dc472",
"sha256:9273f6d1da1018822f41630fb0f3fe208e8e70e5d5e780795326900cfa22d8b6", "sha256:8679bb1dd723ecbea03b1f96c98972815775fd8ec756c440a14f289c436c472e",
"sha256:9622d9560a6fd8d589816cdcec6946642cb4e070b3f68be1d3779b52cf240f73", "sha256:86fb683cb9a9c0bb7476988b7957393ecdd22777d87d804442c66e62c99197f9",
"sha256:9ef2d1476cea927ba33a29f59aa128ce3b174e81083cbd091dd3149af741c85d", "sha256:8757c62f7960cd26122f7aaaf86eda1e016fa85734c3777b8054dd334d7dea4d",
"sha256:9feb7ccd426ff2158ce79f4c87a8a1600ed4f77e65e2fffda2b42638b2bc73e4", "sha256:894be7d17228e7328cc188096c0162697211ec91761f6812fff12790cbe11c66",
"sha256:a0b8528aefceb787f41ad429f3210a3c6b52e99f85413416e3d0c9e6d035f8ac", "sha256:8a0f240bf43c29be1bd82d77e602a61c798e9de02e5f8bb7bb414cb814f43236",
"sha256:a2e4d70d34112997a32c8193fae2579aec854745f8730031e5d84cc579fd98ff", "sha256:8c3abf7eab5b76ae162c4fbb16d514a947fc57fd995b64e5ea8ef8ba3b888a69",
"sha256:a37f0ec88e220326803084208d80229218b309d728954ab747ab21cca33424aa", "sha256:93332c6972e4c91522c4810e907f3aea067424338071161b39cacded022559df",
"sha256:a45f5c0477d12df05ef2e2922b49b7c0ae9d0f4ff9b6bb0d666558df0ef37122", "sha256:97d6c676dc97d593625d9fc48154f2ffeabb619a1e6fe8d2a5b53f97e3e9bdee",
"sha256:a64b9cce166396df5f33894074d6515778d48c63aae5ee1abd86d8bbc5a711d8", "sha256:99dd85f0ca1db8d17a01a25c2bbb7784d25a2d39497c6beddbe96bff74194e04",
"sha256:a89285fedbeca483a855a77285453e21e4fc86ef0944bc018ef4b3033aa04ad2", "sha256:9c7fb691fb07ec7ab99fd173bb0e7e0248d31bf83d484a87b917a342f63812c9",
"sha256:a8f40604437ec8010f77f7053fd135ccb202d6ca18329903831087cab8dbdab1", "sha256:b3bc3cf200aab74f3d758586ac50295214eda496ac6a6636e0c881c5958d9123",
"sha256:b2a4af5e6fa85ee1743c725b46579f8de0b97024eb5ae1a0b5c5711adc436665", "sha256:bba54f97578943f48f621b4a7afb8eb022370da26a88b88ccc9fee9f3ef7ce45",
"sha256:b97dc1273f16f85a38cff6668a07b636ef14e30591039efbfd21f5f91efae964", "sha256:bd2a13a0f8367e50347cbac87ae230ae1953935443240238f956bf10668bead6",
"sha256:bdd008629293a0d4f00b516841ac0df89f17a64bc2d83bcfa48212d3f3b3ca1a", "sha256:cbc1184349ca6e5112898aa7fc3efa1b1bbae24ab1edc774cfd09cbfd3b091d7",
"sha256:be3425dfdb9c46dc62d490fc1a6142a5f3dc6605ebb9048ae675056ef621413c", "sha256:cd82cca9c489e441574804dbda2dd8e114cf3be7935b03de11dade2c9478aea6",
"sha256:c2394bb857607494c3750b5040f852a1ad7831d7a7907b6106f0af2c70860cef", "sha256:ce8ba5ed8b0a7a203922d61cff45ee6001a41a9359f04f00d055a4e988755569",
"sha256:cb45b7ea577283b547b907a3389d62ca2eaddaf725fbb79cd360802440fa9c91", "sha256:cfee22e072a382b92ee0709dbb8203dabd52d54258051e770d9d2a81b162530b",
"sha256:cd3f563b98e2a8730c93bdc550f119ae766b2d3da1f0d6a3c7735b59adfa1642", "sha256:d977df6f7c4109ed1d96ffb6795f6af77114be606ae4556efbfc9cac725db65d",
"sha256:cda55ff0a7566405fb29ca38db1829fecb4c041b8dc3f91754f337bb7b27cbd8", "sha256:da72a384a1d7e87490ca71182f3ab469ed21d847adc16b70c34faac5a3b12801",
"sha256:df0b05fa4321b090abe5601dea9b1c8933c06f496588ccb397a0b1f9dfe32ebe", "sha256:ddf4ad1d651e6c9234945061e1a31fe27a4be0dea21c498b87b186fadf8f5919",
"sha256:e464e7b1be2216eba54b47256c15bf307ae4a656aa0f73becea7b3e7283c5ac2", "sha256:eb0ae5dfda83bbce660179d7b41c1c38fd833a54d2e6d9b258c644f3b75ef94d",
"sha256:e730d490b1421e52b43b1b9f5e1f8c3973499206e188f29b582577531e11033b", "sha256:f4c7d370badc60ac94a554bc571a46d03e39d8aacfba8006b334512e184aed59",
"sha256:e7ae3e520bd182a0cbfff3cc69dda3a2c26f69847e81bd3f090ed04471fc1282", "sha256:f6c378b435a26fda8996579c0e324b108d2ca0d01b4661503a75634e5155559f",
"sha256:e9631c6a339843e4f95efb80ff9a1bfaaf3d611ba9677a7a5cc61ffb923b4e06", "sha256:f6c9d30888503f2f5f87d6d41f016301352dd98da4a861bd10663c3a2d99d3b5",
"sha256:f3daabbe42ca31712e29d906dfa4bf1890341d2fd5178de118bc9977a8d2b23b", "sha256:fab8a7877275060f7b303e1f91c218069a2814a616b6a5ee2d8a3737deb15915",
"sha256:fe8807d67456e7cf0e9a33b85e0d05bb9d2977dbdb23977e4cc2b843633618fd" "sha256:fc32e7d7f98cac3d8d5153ed2cb583158ae3d446a6efb8e28ccb1c54a09f4169"
], ],
"index": "pypi", "index": "pypi",
"version": "==23.0.0" "version": "==23.1.0"
}, },
"requests": { "requests": {
"hashes": [ "hashes": [
"sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", "sha256:bc7861137fbce630f17b03d3ad02ad0bf978c844f3536d0edda6499dafce2b6f",
"sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" "sha256:d568723a7ebd25875d8d1eaf5dfa068cd2fc8194b2e483d7b1f7c81918dbec6b"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.27.1" "version": "==2.28.0"
}, },
"scons": { "scons": {
"hashes": [ "hashes": [
@ -1118,11 +1179,11 @@
}, },
"setuptools": { "setuptools": {
"hashes": [ "hashes": [
"sha256:68e45d17c9281ba25dc0104eadd2647172b3472d9e01f911efa57965e8d51a36", "sha256:5a844ad6e190dccc67d6d7411d119c5152ce01f7c76be4d8a1eaa314501bba77",
"sha256:a43bdedf853c670e5fed28e5623403bad2f73cf02f9a2774e91def6bda8265a7" "sha256:bf8a748ac98b09d32c9a64a995a6b25921c96cc5743c1efa82763ba80ff54e91"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==62.3.2" "version": "==62.4.0"
}, },
"six": { "six": {
"hashes": [ "hashes": [
@ -1134,11 +1195,11 @@
}, },
"smbus2": { "smbus2": {
"hashes": [ "hashes": [
"sha256:6276eb599b76c4e74372f2582d2282f03b4398f0da16bc996608e4f21557ca9b", "sha256:50f3c78e436b42a9583948be06961a8104cf020ebad5edfaaf2657528bef0818",
"sha256:8b1e70cda011b6fb3caf8377a1084f73a5aa99392b78529f140b0a3f06468f6c" "sha256:634541ed794068a822fe7499f1577468b9d4641b68dd9bfb6d0eb7270f4d2a32"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.4.1" "version": "==0.4.2"
}, },
"sympy": { "sympy": {
"hashes": [ "hashes": [
@ -1150,11 +1211,11 @@
}, },
"timezonefinder": { "timezonefinder": {
"hashes": [ "hashes": [
"sha256:90228f7bcf60388868ac95d3d6a8c9f710c766990909cb89dc39a893da7132ad", "sha256:0471463083b5fef7a656c7e31a7376fa1941bf6a41a0750c6e0ca151e43646e7",
"sha256:ce16831bc6349a82ca25ffc0e4c89df5bc5df29b286e5201701bce852f8e49f2" "sha256:2e8e958814f21fa809b16e98bd2f99082b69a0f88b864a4a1f2944d5a7e61827"
], ],
"index": "pypi", "index": "pypi",
"version": "==6.0.0" "version": "==6.0.1"
}, },
"tomli": { "tomli": {
"hashes": [ "hashes": [
@ -1164,6 +1225,14 @@
"markers": "python_version < '3.11'", "markers": "python_version < '3.11'",
"version": "==2.0.1" "version": "==2.0.1"
}, },
"tomlkit": {
"hashes": [
"sha256:0f4050db66fd445b885778900ce4dd9aea8c90c4721141fde0d6ade893820ef1",
"sha256:71ceb10c0eefd8b8f11fe34e8a51ad07812cb1dc3de23247425fbc9ddc47b9dd"
],
"markers": "python_version >= '3.6' and python_version < '4.0'",
"version": "==0.11.0"
},
"tqdm": { "tqdm": {
"hashes": [ "hashes": [
"sha256:40be55d30e200777a307a7585aee69e4eabb46b4ec6a4b4a5f2d9f11e7d5408d", "sha256:40be55d30e200777a307a7585aee69e4eabb46b4ec6a4b4a5f2d9f11e7d5408d",
@ -1374,11 +1443,11 @@
}, },
"babel": { "babel": {
"hashes": [ "hashes": [
"sha256:3f349e85ad3154559ac4930c3918247d319f21910d5ce4b25d439ed8693b98d2", "sha256:7aed055f0c04c9e7f51a2f75261e41e1c804efa724cb65b60a970dd4448d469d",
"sha256:98aeaca086133efb3e1e2aad0396987490c8425929ddbcfe0550184fdc54cd13" "sha256:81a3beca4d0cd40a9cfb9e2adb2cf39261c2f959b92e7a74750befe5d79afd7b"
], ],
"markers": "python_version >= '3.6'", "markers": "python_version >= '3.6'",
"version": "==2.10.1" "version": "==2.10.2"
}, },
"bcrypt": { "bcrypt": {
"hashes": [ "hashes": [
@ -1407,17 +1476,17 @@
}, },
"carla": { "carla": {
"hashes": [ "hashes": [
"sha256:1ed11b56c781cd15cbd540cacfb59ad348e0a021d898cfd0ff89a585f144da0b", "sha256:1210cce213e968a644effd4e2e48458a072481459d073424b05725056ba3d77d",
"sha256:20c1e1b72034175824d89b2d86b09ae72b4aca09ea25874dc6251f239297251d", "sha256:339fcb1e392f3ade1be82b7258de19c533e2efae111e954a6eb174efb296903d",
"sha256:6d1122c24af4f6375dc6858fbb0309b61c219b101d8c5a540def4c36c4563fe1", "sha256:5f065825ce812343bf27a80a19d647b3200b31b44a9e80cea0340e3bd20cdf81",
"sha256:9c19ebf6cbbc535bde4baf9e18c72ab349657b34c4202b9751541e4c0d20b3cc", "sha256:954ca34d5bdd4516ceca353db907fee8cec6630d6b31a732b17dd1554e0f0f94",
"sha256:a69f6d84b59e2f805b2a417de98f977fe9efe0cfa733da8d75e20d28892da915", "sha256:a64ee78fe91137fa7d4828c7fc06d5824bd7312e29e4ea4f31a5d74dd28bff40",
"sha256:c3ae0dce3f1354b6311fee21a365947b0ff169249993a913904f676046d2d69f", "sha256:a95d2d4218ea388c863c66b7c2ab3fe49ffefe53999305cfcb6a8107042f79af",
"sha256:dd392a267e14b785a8f65dafef86e05a92201253e9fb4a01e1e262834f20bed2" "sha256:d2bfaea2d6824a2d758cbe813856c69420494f5c97d2a2dfb45653ccf976f1ce"
], ],
"index": "pypi", "index": "pypi",
"markers": "platform_system != 'Darwin'", "markers": "platform_system != 'Darwin'",
"version": "==0.9.12" "version": "==0.9.13"
}, },
"certifi": { "certifi": {
"hashes": [ "hashes": [
@ -1496,62 +1565,62 @@
"sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
"sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
], ],
"markers": "python_version >= '3'", "markers": "python_full_version >= '3.5.0'",
"version": "==2.0.12" "version": "==2.0.12"
}, },
"control": { "control": {
"hashes": [ "hashes": [
"sha256:8c9084bf386eafcf5d74008f780fae6dec68d243d18a380c866ac10a3549f8d3" "sha256:0891d2d32d6006ac1faa4e238ed8223ca342a4721d202dfeccae24fb02563183"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.9.1" "version": "==0.9.2"
}, },
"coverage": { "coverage": {
"hashes": [ "hashes": [
"sha256:00c8544510f3c98476bbd58201ac2b150ffbcce46a8c3e4fb89ebf01998f806a", "sha256:01c5615d13f3dd3aa8543afc069e5319cfa0c7d712f6e04b920431e5c564a749",
"sha256:016d7f5cf1c8c84f533a3c1f8f36126fbe00b2ec0ccca47cc5731c3723d327c6", "sha256:106c16dfe494de3193ec55cac9640dd039b66e196e4641fa8ac396181578b982",
"sha256:03014a74023abaf5a591eeeaf1ac66a73d54eba178ff4cb1fa0c0a44aae70383", "sha256:129cd05ba6f0d08a766d942a9ed4b29283aff7b2cccf5b7ce279d50796860bb3",
"sha256:033ebec282793bd9eb988d0271c211e58442c31077976c19c442e24d827d356f", "sha256:145f296d00441ca703a659e8f3eb48ae39fb083baba2d7ce4482fb2723e050d9",
"sha256:21e6686a95025927775ac501e74f5940cdf6fe052292f3a3f7349b0abae6d00f", "sha256:1480ff858b4113db2718848d7b2d1b75bc79895a9c22e76a221b9d8d62496428",
"sha256:26f8f92699756cb7af2b30720de0c5bb8d028e923a95b6d0c891088025a1ac8f", "sha256:269eaa2c20a13a5bf17558d4dc91a8d078c4fa1872f25303dddcbba3a813085e",
"sha256:2e76bd16f0e31bc2b07e0fb1379551fcd40daf8cdf7e24f31a29e442878a827c", "sha256:26dff09fb0d82693ba9e6231248641d60ba606150d02ed45110f9ec26404ed1c",
"sha256:341e9c2008c481c5c72d0e0dbf64980a4b2238631a7f9780b0fe2e95755fb018", "sha256:2bd9a6fc18aab8d2e18f89b7ff91c0f34ff4d5e0ba0b33e989b3cd4194c81fd9",
"sha256:3cfd07c5889ddb96a401449109a8b97a165be9d67077df6802f59708bfb07720", "sha256:309ce4a522ed5fca432af4ebe0f32b21d6d7ccbb0f5fcc99290e71feba67c264",
"sha256:4002f9e8c1f286e986fe96ec58742b93484195defc01d5cc7809b8f7acb5ece3", "sha256:3384f2a3652cef289e38100f2d037956194a837221edd520a7ee5b42d00cc605",
"sha256:50ed480b798febce113709846b11f5d5ed1e529c88d8ae92f707806c50297abf", "sha256:342d4aefd1c3e7f620a13f4fe563154d808b69cccef415415aece4c786665397",
"sha256:543e172ce4c0de533fa892034cce260467b213c0ea8e39da2f65f9a477425211", "sha256:39ee53946bf009788108b4dd2894bf1349b4e0ca18c2016ffa7d26ce46b8f10d",
"sha256:5a78cf2c43b13aa6b56003707c5203f28585944c277c1f3f109c7b041b16bd39", "sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c",
"sha256:5cd698341626f3c77784858427bad0cdd54a713115b423d22ac83a28303d1d95", "sha256:4803e7ccf93230accb928f3a68f00ffa80a88213af98ed338a57ad021ef06815",
"sha256:60c2147921da7f4d2d04f570e1838db32b95c5509d248f3fe6417e91437eaf41", "sha256:4ce1b258493cbf8aec43e9b50d89982346b98e9ffdfaae8ae5793bc112fb0068",
"sha256:62d382f7d77eeeaff14b30516b17bcbe80f645f5cf02bb755baac376591c653c", "sha256:664a47ce62fe4bef9e2d2c430306e1428ecea207ffd68649e3b942fa8ea83b0b",
"sha256:69432946f154c6add0e9ede03cc43b96e2ef2733110a77444823c053b1ff5166", "sha256:75ab269400706fab15981fd4bd5080c56bd5cc07c3bccb86aab5e1d5a88dc8f4",
"sha256:727dafd7f67a6e1cad808dc884bd9c5a2f6ef1f8f6d2f22b37b96cb0080d4f49", "sha256:83c4e737f60c6936460c5be330d296dd5b48b3963f48634c53b3f7deb0f34ec4",
"sha256:742fb8b43835078dd7496c3c25a1ec8d15351df49fb0037bffb4754291ef30ce", "sha256:84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3",
"sha256:750e13834b597eeb8ae6e72aa58d1d831b96beec5ad1d04479ae3772373a8088", "sha256:84e65ef149028516c6d64461b95a8dbcfce95cfd5b9eb634320596173332ea84",
"sha256:7b546cf2b1974ddc2cb222a109b37c6ed1778b9be7e6b0c0bc0cf0438d9e45a6", "sha256:865d69ae811a392f4d06bde506d531f6a28a00af36f5c8649684a9e5e4a85c83",
"sha256:83bd142cdec5e4a5c4ca1d4ff6fa807d28460f9db919f9f6a31babaaa8b88426", "sha256:87f4f3df85aa39da00fd3ec4b5abeb7407e82b68c7c5ad181308b0e2526da5d4",
"sha256:8d2e80dd3438e93b19e1223a9850fa65425e77f2607a364b6fd134fcd52dc9df", "sha256:8c08da0bd238f2970230c2a0d28ff0e99961598cb2e810245d7fc5afcf1254e8",
"sha256:9229d074e097f21dfe0643d9d0140ee7433814b3f0fc3706b4abffd1e3038632", "sha256:961e2fb0680b4f5ad63234e0bf55dfb90d302740ae9c7ed0120677a94a1590cb",
"sha256:968ed5407f9460bd5a591cefd1388cc00a8f5099de9e76234655ae48cfdbe2c3", "sha256:9b3e07152b4563722be523e8cd0b209e0d1a373022cfbde395ebb6575bf6790d",
"sha256:9c82f2cd69c71698152e943f4a5a6b83a3ab1db73b88f6e769fabc86074c3b08", "sha256:a7f3049243783df2e6cc6deafc49ea123522b59f464831476d3d1448e30d72df",
"sha256:a00441f5ea4504f5abbc047589d09e0dc33eb447dc45a1a527c8b74bfdd32c65", "sha256:bf5601c33213d3cb19d17a796f8a14a9eaa5e87629a53979a5981e3e3ae166f6",
"sha256:a022394996419142b33a0cf7274cb444c01d2bb123727c4bb0b9acabcb515dea", "sha256:cec3a0f75c8f1031825e19cd86ee787e87cf03e4fd2865c79c057092e69e3a3b",
"sha256:af5b9ee0fc146e907aa0f5fb858c3b3da9199d78b7bb2c9973d95550bd40f701", "sha256:d42c549a8f41dc103a8004b9f0c433e2086add8a719da00e246e17cbe4056f72",
"sha256:b5578efe4038be02d76c344007b13119b2b20acd009a88dde8adec2de4f630b5", "sha256:d67d44996140af8b84284e5e7d398e589574b376fb4de8ccd28d82ad8e3bea13",
"sha256:b84ab65444dcc68d761e95d4d70f3cfd347ceca5a029f2ffec37d4f124f61311", "sha256:d9c80df769f5ec05ad21ea34be7458d1dc51ff1fb4b2219e77fe24edf462d6df",
"sha256:c53ad261dfc8695062fc8811ac7c162bd6096a05a19f26097f411bdf5747aee7", "sha256:e57816f8ffe46b1df8f12e1b348f06d164fd5219beba7d9433ba79608ef011cc",
"sha256:cc173f1ce9ffb16b299f51c9ce53f66a62f4d975abe5640e976904066f3c835d", "sha256:ee2ddcac99b2d2aec413e36d7a429ae9ebcadf912946b13ffa88e7d4c9b712d6",
"sha256:d548edacbf16a8276af13063a2b0669d58bbcfca7c55a255f84aac2870786a61", "sha256:f02cbbf8119db68455b9d763f2f8737bb7db7e43720afa07d8eb1604e5c5ae28",
"sha256:d55fae115ef9f67934e9f1103c9ba826b4c690e4c5bcf94482b8b2398311bf9c", "sha256:f1d5aa2703e1dab4ae6cf416eb0095304f49d004c39e9db1d86f57924f43006b",
"sha256:d8099ea680201c2221f8468c372198ceba9338a5fec0e940111962b03b3f716a", "sha256:f5b66caa62922531059bc5ac04f836860412f7f88d38a476eda0a6f11d4724f4",
"sha256:e35217031e4b534b09f9b9a5841b9344a30a6357627761d4218818b865d45055", "sha256:f69718750eaae75efe506406c490d6fc5a6161d047206cc63ce25527e8a3adad",
"sha256:e4f52c272fdc82e7c65ff3f17a7179bc5f710ebc8ce8a5cadac81215e8326740", "sha256:fb73e0011b8793c053bfa85e53129ba5f0250fdc0392c1591fd35d915ec75c46",
"sha256:e637ae0b7b481905358624ef2e81d7fb0b1af55f5ff99f9ba05442a444b11e45", "sha256:fd180ed867e289964404051a958f7cccabdeed423f91a899829264bb7974d3d3",
"sha256:eef5292b60b6de753d6e7f2d128d5841c7915fb1e3321c3a1fe6acfe76c38052", "sha256:fdb6f7bd51c2d1714cea40718f6149ad9be6a2ee7d93b19e9f00934c0f2a74d9",
"sha256:fb45fe08e1abc64eb836d187b20a59172053999823f7f6ef4f18a819c44ba16f" "sha256:ffa9297c3a453fba4717d06df579af42ab9a28022444cae7fa605af4df612d54"
], ],
"index": "pypi", "index": "pypi",
"version": "==6.4" "version": "==6.4.1"
}, },
"cryptography": { "cryptography": {
"hashes": [ "hashes": [
@ -1665,11 +1734,11 @@
}, },
"filelock": { "filelock": {
"hashes": [ "hashes": [
"sha256:b795f1b42a61bbf8ec7113c341dad679d772567b936fbd1bf43c9a238e673e20", "sha256:37def7b658813cda163b56fc564cdc75e86d338246458c4c28ae84cabefa2404",
"sha256:c7b5fdb219b398a5b28c8e4c1893ef5f98ece6a38c6ab2c22e26ec161556fed6" "sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==3.7.0" "version": "==3.7.1"
}, },
"fonttools": { "fonttools": {
"hashes": [ "hashes": [
@ -1679,6 +1748,33 @@
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==4.33.3" "version": "==4.33.3"
}, },
"ft4222": {
"hashes": [
"sha256:1489b08e4042cb2b24894495c1c8514fa115122e9f8a739f665f0e4d8c53d3f4",
"sha256:1c71913f9fb862634fb77eb6efeea38b2b839e09f739aee5864b9549bcf1c4a9",
"sha256:1f9be0961bd7f3e0c1729c9692f602244e93898610611602ce1fa16059ac5bfa",
"sha256:208cde748fc2bf4a753e217ee2844e75d7d1b6d370a8937a2055f9de8906f933",
"sha256:372be3d7d04c0f6dfa62ff66b3d4be5c39d57c258ab562d9eb0d7cdd3a90ed0f",
"sha256:3ebf9380315c6af8f9f3bc5c5c7a5ae06498349c14a7b2e65d5067b20462d21b",
"sha256:422740efac86f3fdd971bb9a94d9974e56cfe062284a2be1a85db96dd0e77e5e",
"sha256:4414ef82a6321c5205ab0e3dab2bf072f14b4dd3262e5f392560adf107210d41",
"sha256:459894dcca7db71a0d58e6f3abb4c9dd67654c92ad9d934f1e32dc08bed87645",
"sha256:4b7e4c8b5e4a8fe769127d3db99b7b410468ffe2718a07f7b317e7dc1ad9ca4f",
"sha256:68e6b357ea2287fe0e8dac287efbac2f0ce9632d65e828d422d3a0604555c174",
"sha256:800a26a4a8fc854f41e4de41e45b6deafdeb78ae5eff48818f710bb2d94a8c11",
"sha256:8790e96b4c3f8d1fb768f689f1c437a59b20889e4726ed7457ff3d188f0a3274",
"sha256:9369b55393b2e1f58f8b8516bcf9cd6fd34c05e77377c4cc48be39a49cad7be5",
"sha256:a6236f05b8948cd9c113c7159e3fdde202a0f73dce6440da078fd2fc9e411123",
"sha256:b7f58cd16213a5c92503c530b301f071d67283c80c1e8cb43d6f3ec5c186df35",
"sha256:cc368b06b92529a11add37d14196d2e2aaae19c6ffc51b9457513a0d05ceae1a",
"sha256:d479c037b417ff289727112f1d4725563b78448d3765f457c8bf6884e4d83abd",
"sha256:dce00d513be811f738954c5593c52b533a02331e8a26983280dea3f4d864962f",
"sha256:eadcbc1dd20ed6d7d07dc53354ea137bcea30fb0889d74bedcd189cdb4f61c84",
"sha256:ec984bd7e9300e5f2e50823dcd5874d54aa3e7503e69afe7eb3b4cea77071084"
],
"index": "pypi",
"version": "==1.4.1"
},
"hexdump": { "hexdump": {
"hashes": [ "hashes": [
"sha256:d781a43b0c16ace3f9366aade73e8ad3a7bd5137d58f0b45ab2d3f54876f20db" "sha256:d781a43b0c16ace3f9366aade73e8ad3a7bd5137d58f0b45ab2d3f54876f20db"
@ -1689,6 +1785,8 @@
"hypothesis": { "hypothesis": {
"hashes": [ "hashes": [
"sha256:2696cdb9005946bf1d2b215cc91d3fc01625e3342eb8743ddd04b667b2f1882b", "sha256:2696cdb9005946bf1d2b215cc91d3fc01625e3342eb8743ddd04b667b2f1882b",
"sha256:4ad26c5d434171ffc02aba569dd52255573d615554c062bc30734dbe6f318c61",
"sha256:69978811f1d9c19710c7d2bf8233dc43c80efa964251b72efbe8274044e073b4",
"sha256:967009fa561b3a3f8363a73d71923357271c37dc7fa27b30c2d21a1b6092b240" "sha256:967009fa561b3a3f8363a73d71923357271c37dc7fa27b30c2d21a1b6092b240"
], ],
"index": "pypi", "index": "pypi",
@ -1707,7 +1805,7 @@
"sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
"sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
], ],
"markers": "python_version >= '3'", "markers": "python_full_version >= '3.5.0'",
"version": "==3.3" "version": "==3.3"
}, },
"imagesize": { "imagesize": {
@ -1751,52 +1849,52 @@
}, },
"kiwisolver": { "kiwisolver": {
"hashes": [ "hashes": [
"sha256:0b7f50a1a25361da3440f07c58cd1d79957c2244209e4f166990e770256b6b0b", "sha256:007799c7fa934646318fc128b033bb6e6baabe7fbad521bfb2279aac26225cd7",
"sha256:0c380bb5ae20d829c1a5473cfcae64267b73aaa4060adc091f6df1743784aae0", "sha256:130c6c35eded399d3967cf8a542c20b671f5ba85bd6f210f8b939f868360e9eb",
"sha256:0d98dca86f77b851350c250f0149aa5852b36572514d20feeadd3c6b1efe38d0", "sha256:1858ad3cb686eccc7c6b7c5eac846a1cfd45aacb5811b2cf575e80b208f5622a",
"sha256:0e45e780a74416ef2f173189ef4387e44b5494f45e290bcb1f03735faa6779bf", "sha256:1ae7aa0784aeadfbd693c27993727792fbe1455b84d49970bad5886b42976b18",
"sha256:0e8afdf533b613122e4bbaf3c1e42c2a5e9e2d1dd3a0a017749a7658757cb377", "sha256:1d2c744aeedce22c122bb42d176b4aa6d063202a05a4abdacb3e413c214b3694",
"sha256:1008346a7741620ab9cc6c96e8ad9b46f7a74ce839dbb8805ddf6b119d5fc6c2", "sha256:21a3a98f0a21fc602663ca9bce2b12a4114891bdeba2dea1e9ad84db59892fca",
"sha256:1d1078ba770d6165abed3d9a1be1f9e79b61515de1dd00d942fa53bba79f01ae", "sha256:22ccba48abae827a0f952a78a7b1a7ff01866131e5bbe1f826ce9bda406bf051",
"sha256:1dcade8f6fe12a2bb4efe2cbe22116556e3b6899728d3b2a0d3b367db323eacc", "sha256:26b5a70bdab09e6a2f40babc4f8f992e3771751e144bda1938084c70d3001c09",
"sha256:240009fdf4fa87844f805e23f48995537a8cb8f8c361e35fda6b5ac97fcb906f", "sha256:2d76780d9c65c7529cedd49fa4802d713e60798d8dc3b0d5b12a0a8f38cca51c",
"sha256:240c2d51d098395c012ddbcb9bd7b3ba5de412a1d11840698859f51d0e643c4f", "sha256:325fa1b15098e44fe4590a6c5c09a212ca10c6ebb5d96f7447d675f6c8340e4e",
"sha256:262c248c60f22c2b547683ad521e8a3db5909c71f679b93876921549107a0c24", "sha256:3a297d77b3d6979693f5948df02b89431ae3645ec95865e351fb45578031bdae",
"sha256:2e6cda72db409eefad6b021e8a4f964965a629f577812afc7860c69df7bdb84a", "sha256:3b1dcbc49923ac3c973184a82832e1f018dec643b1e054867d04a3a22255ec6a",
"sha256:3c032c41ae4c3a321b43a3650e6ecc7406b99ff3e5279f24c9b310f41bc98479", "sha256:40240da438c0ebfe2aa76dd04b844effac6679423df61adbe3437d32f23468d9",
"sha256:42f6ef9b640deb6f7d438e0a371aedd8bef6ddfde30683491b2e6f568b4e884e", "sha256:46c6e5018ba31d5ee7582f323d8661498a154dea1117486a571db4c244531f24",
"sha256:484f2a5f0307bc944bc79db235f41048bae4106ffa764168a068d88b644b305d", "sha256:46fb56fde006b7ef5f8eaa3698299b0ea47444238b869ff3ced1426aa9fedcb5",
"sha256:69b2d6c12f2ad5f55104a36a356192cfb680c049fe5e7c1f6620fc37f119cdc2", "sha256:4dc350cb65fe4e3f737d50f0465fa6ea0dcae0e5722b7edf5d5b0a0e3cd2c3c7",
"sha256:6e395ece147f0692ca7cdb05a028d31b83b72c369f7b4a2c1798f4b96af1e3d8", "sha256:51078855a16b7a4984ed2067b54e35803d18bca9861cb60c60f6234b50869a56",
"sha256:6ece2e12e4b57bc5646b354f436416cd2a6f090c1dadcd92b0ca4542190d7190", "sha256:547111ef7cf13d73546c2de97ce434935626c897bdec96a578ca100b5fcd694b",
"sha256:71469b5845b9876b8d3d252e201bef6f47bf7456804d2fbe9a1d6e19e78a1e65", "sha256:5fb73cc8a34baba1dfa546ae83b9c248ef6150c238b06fc53d2773685b67ec67",
"sha256:7f606d91b8a8816be476513a77fd30abe66227039bd6f8b406c348cb0247dcc9", "sha256:654280c5f41831ddcc5a331c0e3ce2e480bbc3d7c93c18ecf6236313aae2d61a",
"sha256:7f88c4b8e449908eeddb3bbd4242bd4dc2c7a15a7aa44bb33df893203f02dc2d", "sha256:6b3136eecf7e1b4a4d23e4b19d6c4e7a8e0b42d55f30444e3c529700cdacaa0d",
"sha256:81237957b15469ea9151ec8ca08ce05656090ffabc476a752ef5ad7e2644c526", "sha256:7118ca592d25b2957ff7b662bc0fe4f4c2b5d5b27814b9b1bc9f2fb249a970e7",
"sha256:89b57c2984f4464840e4b768affeff6b6809c6150d1166938ade3e22fbe22db8", "sha256:71af5b43e4fa286a35110fc5bb740fdeae2b36ca79fbcf0a54237485baeee8be",
"sha256:8a830a03970c462d1a2311c90e05679da56d3bd8e78a4ba9985cb78ef7836c9f", "sha256:747190fcdadc377263223f8f72b038381b3b549a8a3df5baf4d067da4749b046",
"sha256:8ae5a071185f1a93777c79a9a1e67ac46544d4607f18d07131eece08d415083a", "sha256:8395064d63b26947fa2c9faeea9c3eee35e52148c5339c37987e1d96fbf009b3",
"sha256:8b6086aa6936865962b2cee0e7aaecf01ab6778ce099288354a7229b4d9f1408", "sha256:84f85adfebd7d3c3db649efdf73659e1677a2cf3fa6e2556a3f373578af14bf7",
"sha256:8ec2e55bf31b43aabe32089125dca3b46fdfe9f50afbf0756ae11e14c97b80ca", "sha256:86bcf0009f2012847a688f2f4f9b16203ca4c835979a02549aa0595d9f457cc8",
"sha256:8ff3033e43e7ca1389ee59fb7ecb8303abb8713c008a1da49b00869e92e3dd7c", "sha256:ab8a15c2750ae8d53e31f77a94f846d0a00772240f1c12817411fa2344351f86",
"sha256:91eb4916271655dfe3a952249cb37a5c00b6ba68b4417ee15af9ba549b5ba61d", "sha256:af24b21c2283ca69c416a8a42cde9764dc36c63d3389645d28c69b0e93db3cd7",
"sha256:9d2bb56309fb75a811d81ed55fbe2208aa77a3a09ff5f546ca95e7bb5fac6eff", "sha256:afe173ac2646c2636305ab820cc0380b22a00a7bca4290452e7166b4f4fa49d0",
"sha256:a4e8f072db1d6fb7a7cc05a6dbef8442c93001f4bb604f1081d8c2db3ca97159", "sha256:b9eb88593159a53a5ee0b0159daee531ff7dd9c87fa78f5d807ca059c7eb1b2b",
"sha256:b1605c7c38cc6a85212dfd6a641f3905a33412e49f7c003f35f9ac6d71f67720", "sha256:c16635f8dddbeb1b827977d0b00d07b644b040aeb9ff8607a9fc0997afa3e567",
"sha256:b3e251e5c38ac623c5d786adb21477f018712f8c6fa54781bd38aa1c60b60fc2", "sha256:ca3eefb02ef17257fae8b8555c85e7c1efdfd777f671384b0e4ef27409b02720",
"sha256:b978afdb913ca953cf128d57181da2e8798e8b6153be866ae2a9c446c6162f40", "sha256:caa59e2cae0e23b1e225447d7a9ddb0f982f42a6a22d497a484dfe62a06f7c0e",
"sha256:be9a650890fb60393e60aacb65878c4a38bb334720aa5ecb1c13d0dac54dd73b", "sha256:cb55258931448d61e2d50187de4ee66fc9d9f34908b524949b8b2b93d0c57136",
"sha256:c222f91a45da9e01a9bc4f760727ae49050f8e8345c4ff6525495f7a164c8973", "sha256:d248c46c0aa406695bda2abf99632db991f8b3a6d46018721a2892312a99f069",
"sha256:c839bf28e45d7ddad4ae8f986928dbf5a6d42ff79760d54ec8ada8fb263e097c", "sha256:d2578e5149ff49878934debfacf5c743fab49eca5ecdb983d0b218e1e554c498",
"sha256:cbb5eb4a2ea1ffec26268d49766cafa8f957fe5c1b41ad00733763fae77f9436", "sha256:dd22085446f3eca990d12a0878eeb5199dc9553b2e71716bfe7bed9915a472ab",
"sha256:e348f1904a4fab4153407f7ccc27e43b2a139752e8acf12e6640ba683093dd96", "sha256:e7cf940af5fee00a92e281eb157abe8770227a5255207818ea9a34e54a29f5b2",
"sha256:e677cc3626287f343de751e11b1e8a5b915a6ac897e8aecdbc996cd34de753a0", "sha256:f70f3d028794e31cf9d1a822914efc935aadb2438ec4e8d4871d95eb1ce032d6",
"sha256:f74f2a13af201559e3d32b9ddfc303c94ae63d63d7f4326d06ce6fe67e7a8255", "sha256:fd2842a0faed9ab9aba0922c951906132d9384be89690570f0ed18cd4f20e658",
"sha256:fa4d97d7d2b2c082e67907c0b8d9f31b85aa5d3ba0d33096b7116f03f8061261", "sha256:fd628e63ffdba0112e3ddf1b1e9f3db29dd8262345138e08f4938acbc6d0805a",
"sha256:ffbdb9a96c536f0405895b5e21ee39ec579cb0ed97bdbd169ae2b55f41d73219" "sha256:ffd7cf165ff71afb202b3f36daafbf298932bee325aac9f58e1c9cd55838bef0"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==1.4.2" "version": "==1.4.3"
}, },
"lru-dict": { "lru-dict": {
"hashes": [ "hashes": [
@ -1918,41 +2016,40 @@
}, },
"mpld3": { "mpld3": {
"hashes": [ "hashes": [
"sha256:3626d37da7ac11d0fce4dd5ceb37d04ba618bf951129bf6ca3f94bf48da87d6f", "sha256:1a167dbef836dd7c66d8aa71c06a32d50bffa18725f304d93cb74fdb3545043b",
"sha256:b1290f6cca2d9515e32ee21a8b0c18b2ea361cefce58ba0f4df881e9eeb3f64c", "sha256:41938e65de4ba41a1b53d92e7c8609e7172e09b33ef5db42bb6f73701106c8b7"
"sha256:c589db8b661aee25c93e198e2e18ed47b9a96951de41d96241345acec5f819ab"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.5.7" "version": "==0.5.8"
}, },
"mypy": { "mypy": {
"hashes": [ "hashes": [
"sha256:0112752a6ff07230f9ec2f71b0d3d4e088a910fdce454fdb6553e83ed0eced7d", "sha256:006be38474216b833eca29ff6b73e143386f352e10e9c2fbe76aa8549e5554f5",
"sha256:0384d9f3af49837baa92f559d3fa673e6d2652a16550a9ee07fc08c736f5e6f8", "sha256:03c6cc893e7563e7b2949b969e63f02c000b32502a1b4d1314cabe391aa87d66",
"sha256:1b333cfbca1762ff15808a0ef4f71b5d3eed8528b23ea1c3fb50543c867d68de", "sha256:0e9f70df36405c25cc530a86eeda1e0867863d9471fe76d1273c783df3d35c2e",
"sha256:1fdeb0a0f64f2a874a4c1f5271f06e40e1e9779bf55f9567f149466fc7a55038", "sha256:1ece702f29270ec6af25db8cf6185c04c02311c6bb21a69f423d40e527b75c56",
"sha256:4c653e4846f287051599ed8f4b3c044b80e540e88feec76b11044ddc5612ffed", "sha256:3e09f1f983a71d0672bbc97ae33ee3709d10c779beb613febc36805a6e28bb4e",
"sha256:563514c7dc504698fb66bb1cf897657a173a496406f1866afae73ab5b3cdb334", "sha256:439c726a3b3da7ca84a0199a8ab444cd8896d95012c4a6c4a0d808e3147abf5d",
"sha256:5b231afd6a6e951381b9ef09a1223b1feabe13625388db48a8690f8daa9b71ff", "sha256:5a0b53747f713f490affdceef835d8f0cb7285187a6a44c33821b6d1f46ed813",
"sha256:5ce6a09042b6da16d773d2110e44f169683d8cc8687e79ec6d1181a72cb028d2", "sha256:5f1332964963d4832a94bebc10f13d3279be3ce8f6c64da563d6ee6e2eeda932",
"sha256:5e7647df0f8fc947388e6251d728189cfadb3b1e558407f93254e35abc026e22", "sha256:63e85a03770ebf403291ec50097954cc5caf2a9205c888ce3a61bd3f82e17569",
"sha256:6003de687c13196e8a1243a5e4bcce617d79b88f83ee6625437e335d89dfebe2", "sha256:64759a273d590040a592e0f4186539858c948302c653c2eac840c7a3cd29e51b",
"sha256:61504b9a5ae166ba5ecfed9e93357fd51aa693d3d434b582a925338a2ff57fd2", "sha256:697540876638ce349b01b6786bc6094ccdaba88af446a9abb967293ce6eaa2b0",
"sha256:77423570c04aca807508a492037abbd72b12a1fb25a385847d191cd50b2c9605", "sha256:9940e6916ed9371809b35b2154baf1f684acba935cd09928952310fbddaba648",
"sha256:a4d9898f46446bfb6405383b57b96737dcfd0a7f25b748e78ef3e8c576bba3cb", "sha256:9f5f5a74085d9a81a1f9c78081d60a0040c3efb3f28e5c9912b900adf59a16e6",
"sha256:a952b8bc0ae278fc6316e6384f67bb9a396eb30aced6ad034d3a76120ebcc519", "sha256:a5ea0875a049de1b63b972456542f04643daf320d27dc592d7c3d9cd5d9bf950",
"sha256:b5b5bd0ffb11b4aba2bb6d31b8643902c48f990cc92fda4e21afac658044f0c0", "sha256:b117650592e1782819829605a193360a08aa99f1fc23d1d71e1a75a142dc7e15",
"sha256:ca75ecf2783395ca3016a5e455cb322ba26b6d33b4b413fcdedfc632e67941dc", "sha256:b24be97351084b11582fef18d79004b3e4db572219deee0212078f7cf6352723",
"sha256:cf9c261958a769a3bd38c3e133801ebcd284ffb734ea12d01457cb09eacf7d7b", "sha256:b88f784e9e35dcaa075519096dc947a388319cb86811b6af621e3523980f1c8a",
"sha256:dd4d670eee9610bf61c25c940e9ade2d0ed05eb44227275cce88701fee014b1f", "sha256:bdd5ca340beffb8c44cb9dc26697628d1b88c6bddf5c2f6eb308c46f269bb6f3",
"sha256:e19736af56947addedce4674c0971e5dceef1b5ec7d667fe86bcd2b07f8f9075", "sha256:d5aaf1edaa7692490f72bdb9fbd941fbf2e201713523bdb3f4038be0af8846c6",
"sha256:eaea21d150fb26d7b4856766e7addcf929119dd19fc832b22e71d942835201ef", "sha256:e999229b9f3198c0c880d5e269f9f8129c8862451ce53a011326cad38b9ccd24",
"sha256:eaff8156016487c1af5ffa5304c3e3fd183edcb412f3e9c72db349faf3f6e0eb", "sha256:f4a21d01fc0ba4e31d82f0fff195682e29f9401a8bdb7173891070eb260aeb3b",
"sha256:ee0a36edd332ed2c5208565ae6e3a7afc0eabb53f5327e281f2ef03a6bc7687a", "sha256:f4b794db44168a4fc886e3450201365c9526a522c46ba089b55e1f11c163750d",
"sha256:ef7beb2a3582eb7a9f37beaf38a28acfd801988cde688760aea9e6cc4832b10b" "sha256:f730d56cb924d371c26b8eaddeea3cc07d78ff51c521c6d04899ac6904b75492"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.950" "version": "==0.961"
}, },
"mypy-extensions": { "mypy-extensions": {
"hashes": [ "hashes": [
@ -1963,11 +2060,11 @@
}, },
"myst-parser": { "myst-parser": {
"hashes": [ "hashes": [
"sha256:1635ce3c18965a528d6de980f989ff64d6a1effb482e1f611b1bfb79e38f3d98", "sha256:4965e51918837c13bf1c6f6fe2c6bddddf193148360fbdaefe743a4981358f6a",
"sha256:4c076d649e066f9f5c7c661bae2658be1ca06e76b002bb97f02a09398707686c" "sha256:739a4d96773a8e55a2cacd3941ce46a446ee23dcd6b37e06f73f551ad7821d86"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.17.2" "version": "==0.18.0"
}, },
"natsort": { "natsort": {
"hashes": [ "hashes": [
@ -2014,16 +2111,16 @@
}, },
"opencv-python-headless": { "opencv-python-headless": {
"hashes": [ "hashes": [
"sha256:3f330468c29882dbbec5af25695c5e575572c6b855cb0f9fe53e14116fd46bfc", "sha256:21e70f8b0c04098cdf466d27184fe6c3820aaef944a22548db95099959c95889",
"sha256:4bdf982574bf2fefc5f82c86df7cb42e56ad627874c7c0f4d94ecf4ae8885304", "sha256:2c032c373e447c3fc2a670bca20e2918a1205a6e72854df60425fd3f82c78c32",
"sha256:567a54c1919bcf5b3d20a9830e3c511e57134de8def286ce137c3544a892f98c", "sha256:3bacd806cce1f1988e58f3d6f761538e0215d6621d316de94c009dc0acbd6ad3",
"sha256:62e31878641a8f96e773118d1eea9f34bdda87c9990a0faab04ebaafb5ae015c", "sha256:d5291d7e10aa2c19cab6fd86f0d61af8617290ecd2d7ffcb051e446868d04cc5",
"sha256:a60e9ff48854ec37be391e19dd634883cc26c2f0f814e5325b3deca33420912c", "sha256:e6c069bc963d7e8fcec21b3e33e594d35948badd63eccb2e80f88b0a12102c03",
"sha256:c3c2dda44d601757a508b07d628537c49f31223ad4edd0f747a70d4c852a7b98", "sha256:eec6281054346103d6af93f173b7c6a206beb2663d3adc04aa3ddc66e85093df",
"sha256:ca4f013fa958f60fb2327fe87e6127c1ac0ab536890b1d4b00847f417b7af1ba" "sha256:ffbf26fcd697af996408440a93bc69c49c05a36845771f984156dfbeaa95d497"
], ],
"index": "pypi", "index": "pypi",
"version": "==4.5.5.64" "version": "==4.6.0.66"
}, },
"packaging": { "packaging": {
"hashes": [ "hashes": [
@ -2329,11 +2426,11 @@
}, },
"requests": { "requests": {
"hashes": [ "hashes": [
"sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", "sha256:bc7861137fbce630f17b03d3ad02ad0bf978c844f3536d0edda6499dafce2b6f",
"sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" "sha256:d568723a7ebd25875d8d1eaf5dfa068cd2fc8194b2e483d7b1f7c81918dbec6b"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.27.1" "version": "==2.28.0"
}, },
"reverse-geocoder": { "reverse-geocoder": {
"hashes": [ "hashes": [

@ -35,16 +35,17 @@ What is openpilot?
</table> </table>
Running in a car Running on a dedicated device in a car
------ ------
To use openpilot in a car, you need four things To use openpilot in a car, you need four things
* This software. It's free and available right here. * A supported device to run this software: a [comma three](https://comma.ai/shop/products/three).
* This software. The setup procedure of the comma three allows the user to enter a url for custom software.
The url, openpilot.comma.ai will install the release version of openpilot. To install openpilot master, you can use installer.comma.ai/commaai/master, and replacing commaai with another github username can install a fork.
* One of [the 150+ supported cars](docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, and more. If your car is not supported, but has adaptive cruise control and lane keeping assist, it's likely able to run openpilot. * One of [the 150+ supported cars](docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, and more. If your car is not supported, but has adaptive cruise control and lane keeping assist, it's likely able to run openpilot.
* A supported device to run this software: a [comma three](https://comma.ai/shop/products/three), or if you like to experiment, a [Ubuntu computer with webcams](https://github.com/commaai/openpilot/tree/master/tools/webcam). * A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car.
* A way to connect to your car. With a comma three, you need only a [car harness](https://comma.ai/shop/products/car-harness). With a PC, you also need a [black panda](https://comma.ai/shop/products/panda).
We have detailed instructions for [how to install the device in a car](https://comma.ai/setup). We have detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
Running on PC Running on PC
------ ------
@ -55,6 +56,7 @@ With openpilot's tools you can plot logs, replay drives and watch the full-res c
You can also run openpilot in simulation [with the CARLA simulator](tools/sim/README.md). This allows openpilot to drive around a virtual car on your Ubuntu machine. The whole setup should only take a few minutes, but does require a decent GPU. You can also run openpilot in simulation [with the CARLA simulator](tools/sim/README.md). This allows openpilot to drive around a virtual car on your Ubuntu machine. The whole setup should only take a few minutes, but does require a decent GPU.
A PC running openpilot can also control your vehicle if it is connected to a [a webcam](https://github.com/commaai/openpilot/tree/master/tools/webcam), a [black panda](https://comma.ai/shop/products/panda), and [a harness](https://comma.ai/shop/products/car-harness).
Community and Contributing Community and Contributing
------ ------

@ -5,7 +5,16 @@ Version 0.8.15 (2022-XX-XX)
* Much smoother control, consistent across the speed range * Much smoother control, consistent across the speed range
* Effective feedforward that uses road roll * Effective feedforward that uses road roll
* Simplified tuning, all car-specific parameters can be derived from data * Simplified tuning, all car-specific parameters can be derived from data
* Significantly improved control on TSS-P Prius
* New driver monitoring model
* takes a larger input frame
* outputs a driver state for both driver and passenger
* automatically determines which side the driver is on (soon)
* Display speed limit while navigating
* Reduced power usage: device runs cooler and fan spins less
* AGNOS 5 * AGNOS 5
* Hyundai Tucson 2021 support thanks to bluesforte!
* Lexus NX Hybrid 2020 support thanks to AlexandreSato!
Version 0.8.14 (2022-06-01) Version 0.8.14 (2022-06-01)
======================== ========================

@ -359,6 +359,7 @@ Export('cereal', 'messaging', 'visionipc')
rednose_config = { rednose_config = {
'generated_folder': '#selfdrive/locationd/models/generated', 'generated_folder': '#selfdrive/locationd/models/generated',
'to_build': { 'to_build': {
'gnss': ('#selfdrive/locationd/models/gnss_kf.py', True, []),
'live': ('#selfdrive/locationd/models/live_kf.py', True, ['live_kf_constants.h']), 'live': ('#selfdrive/locationd/models/live_kf.py', True, ['live_kf_constants.h']),
'car': ('#selfdrive/locationd/models/car_kf.py', True, []), 'car': ('#selfdrive/locationd/models/car_kf.py', True, []),
}, },
@ -366,7 +367,6 @@ rednose_config = {
if arch != "larch64": if arch != "larch64":
rednose_config['to_build'].update({ rednose_config['to_build'].update({
'gnss': ('#selfdrive/locationd/models/gnss_kf.py', True, []),
'loc_4': ('#selfdrive/locationd/models/loc_kf.py', True, []), 'loc_4': ('#selfdrive/locationd/models/loc_kf.py', True, []),
'pos_computer_4': ('#rednose/helpers/lst_sq_computer.py', False, []), 'pos_computer_4': ('#rednose/helpers/lst_sq_computer.py', False, []),
'pos_computer_5': ('#rednose/helpers/lst_sq_computer.py', False, []), 'pos_computer_5': ('#rednose/helpers/lst_sq_computer.py', False, []),

@ -1 +1 @@
Subproject commit 7cbb4f1c8cb7cfc798a058c611801442b40feb52 Subproject commit 4b4d9aab03937f5a45677ff15efb275abf9c958b

@ -3,7 +3,7 @@ import os
import requests import requests
from datetime import datetime, timedelta from datetime import datetime, timedelta
from common.basedir import PERSIST from common.basedir import PERSIST
from selfdrive.version import get_version from system.version import get_version
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com') API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')

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

@ -2,7 +2,7 @@
#include <array> #include <array>
#include "common/mat.h" #include "common/mat.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
const int TRAJECTORY_SIZE = 33; const int TRAJECTORY_SIZE = 33;
const int LAT_MPC_N = 16; const int LAT_MPC_N = 16;

@ -8,7 +8,7 @@
#include "common/swaglog.h" #include "common/swaglog.h"
#include "common/util.h" #include "common/util.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
namespace { namespace {
@ -127,6 +127,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START}, {"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
{"IsUpdateAvailable", CLEAR_ON_MANAGER_START}, {"IsUpdateAvailable", CLEAR_ON_MANAGER_START},
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"LaikadEphemeris", PERSISTENT},
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START}, {"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
{"LastGPSPosition", PERSISTENT}, {"LastGPSPosition", PERSISTENT},
{"LastManagerExitReason", CLEAR_ON_MANAGER_START}, {"LastManagerExitReason", CLEAR_ON_MANAGER_START},

@ -8,7 +8,7 @@ from typing import Optional, List, Union
from setproctitle import getproctitle # pylint: disable=no-name-in-module from setproctitle import getproctitle # pylint: disable=no-name-in-module
from common.clock import sec_since_boot # pylint: disable=no-name-in-module, import-error from common.clock import sec_since_boot # pylint: disable=no-name-in-module, import-error
from selfdrive.hardware import PC from system.hardware import PC
# time step for each process # time step for each process

@ -15,7 +15,7 @@
#include "common/util.h" #include "common/util.h"
#include "common/version.h" #include "common/version.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
class SwaglogState : public LogState { class SwaglogState : public LogState {
public: public:

@ -7,7 +7,7 @@
#include "common/swaglog.h" #include "common/swaglog.h"
#include "common/util.h" #include "common/util.h"
#include "common/version.h" #include "common/version.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
const char *SWAGLOG_ADDR = "ipc:///tmp/logmessage"; const char *SWAGLOG_ADDR = "ipc:///tmp/logmessage";
std::string daemon_name = "testy"; std::string daemon_name = "testy";

@ -25,7 +25,8 @@ How We Rate The Cars
- <a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a> - No steering control below certain speeds. - <a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a> - No steering control below certain speeds.
### Steering Torque ### Steering Torque
- <a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a> - Car has enough steering torque for comfortable highway driving. - <a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a> - Car has enough steering torque to take tighter turns.
- <a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a> - Car has enough steering torque for comfortable highway driving.
- <a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a> - Limited ability to make turns. - <a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a> - Limited ability to make turns.
### Actively Maintained ### Actively Maintained
@ -34,7 +35,7 @@ How We Rate The Cars
**All supported cars can move between the tiers as support changes.** **All supported cars can move between the tiers as support changes.**
## Gold Cars # Gold - 28 cars
|Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque|Actively Maintained| |Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque|Actively Maintained|
|---|---|---|:---:|:---:|:---:|:---:|:---:| |---|---|---|:---:|:---:|:---:|:---:|:---:|
@ -51,7 +52,9 @@ How We Rate The Cars
|Lexus|ES 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|ES 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|ES Hybrid 2019-22|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|ES Hybrid 2019-22|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|NX 2020|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|NX 2020|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|RX 2020-22|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|UX Hybrid 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|UX Hybrid 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Avalon 2022|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Camry 2021-22|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>[<sup>4</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Camry 2021-22|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>[<sup>4</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Camry Hybrid 2021-22|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Camry Hybrid 2021-22|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Corolla 2020-22|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Corolla 2020-22|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
@ -65,11 +68,16 @@ How We Rate The Cars
|Toyota|RAV4 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|RAV4 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|RAV4 Hybrid 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|RAV4 Hybrid 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
## Silver Cars # Silver - 76 cars
|Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque|Actively Maintained| |Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque|Actively Maintained|
|---|---|---|:---:|:---:|:---:|:---:|:---:| |---|---|---|:---:|:---:|:---:|:---:|:---:|
|Audi|A3 2014-19|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Audi|A3 Sportback e-tron 2017-18|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Audi|Q2 2018|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Audi|Q2 2018|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Audi|RS3 2018|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Audi|S3 2015-17|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Chevrolet|Volt 2017-18[<sup>1</sup>](#footnotes)|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Genesis|G70 2018|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Genesis|G70 2018|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Genesis|G80 2018|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Genesis|G80 2018|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Hyundai|Elantra 2021-22|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Hyundai|Elantra 2021-22|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
@ -87,7 +95,7 @@ How We Rate The Cars
|Kia|Ceed 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Ceed 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Kia|Forte 2018|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Forte 2018|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Kia|Forte 2019-21|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Forte 2019-21|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Kia|K5 2021-22|SCC + LFA|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|K5 2021-22|SCC|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Kia|Niro Hybrid 2021|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Niro Hybrid 2021|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Kia|Niro Hybrid 2022|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Niro Hybrid 2022|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Kia|Optima 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Optima 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
@ -95,16 +103,17 @@ How We Rate The Cars
|Kia|Sorento 2018|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Sorento 2018|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Kia|Sorento 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Sorento 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Kia|Stinger 2018|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Stinger 2018|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|ES Hybrid 2017-18|LSS|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|NX 2018-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|NX 2018-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|NX Hybrid 2018-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|NX Hybrid 2018-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|RX 2020-22|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|NX Hybrid 2020|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|RX Hybrid 2020-21|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|RX Hybrid 2020-21|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Mazda|CX-5 2022|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Mazda|CX-5 2022|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|SEAT|Ateca 2018|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |SEAT|Ateca 2018|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|SEAT|Leon 2014-20|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |SEAT|Leon 2014-20|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Subaru|Forester 2019-21|EyeSight|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Subaru|Crosstrek 2020-21|EyeSight|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Škoda|Kamiq 2021[<sup>6</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Subaru|Forester 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Subaru|Impreza 2020-21|EyeSight|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Škoda|Kamiq 2021[<sup>5</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Škoda|Karoq 2019|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Škoda|Karoq 2019|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Škoda|Kodiaq 2018-19|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Škoda|Kodiaq 2018-19|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Škoda|Octavia 2015, 2018-19|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Škoda|Octavia 2015, 2018-19|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
@ -113,40 +122,48 @@ How We Rate The Cars
|Škoda|Superb 2015-18|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Škoda|Superb 2015-18|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Alphard 2019-20|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Alphard 2019-20|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Alphard Hybrid 2021|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Alphard Hybrid 2021|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Avalon 2022|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Avalon 2019-21|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Avalon Hybrid 2022|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Avalon Hybrid 2022|All|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Camry 2018-20|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>[<sup>4</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Camry 2018-20|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>[<sup>4</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Camry Hybrid 2018-20|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>[<sup>4</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Camry Hybrid 2018-20|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>[<sup>4</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Highlander 2017-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Highlander Hybrid 2017-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Prius 2016-20|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Prius Prime 2017-20|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|RAV4 2022|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|RAV4 2022|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|RAV4 Hybrid 2016-18|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|RAV4 Hybrid 2022|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|RAV4 Hybrid 2022|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Arteon 2018, 2021[<sup>8</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Sienna 2018-20|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Passat 2015-19[<sup>7</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|Atlas 2018-19, 2022[<sup>7</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|e-Golf 2014, 2018-20|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf 2015-20|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf Alltrack 2017-18|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf GTE 2016|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf GTI 2018-21|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf R 2016-19|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf SportsVan 2016|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf SportWagen 2015|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Polo 2020|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|Polo 2020|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|T-Cross 2021[<sup>8</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|T-Cross 2021[<sup>7</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|T-Roc 2021[<sup>8</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|T-Roc 2021[<sup>7</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Taos 2022[<sup>8</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|Taos 2022[<sup>7</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Touran 2017|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|Touran 2017|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
## Bronze Cars # Bronze - 69 cars
|Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque|Actively Maintained| |Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque|Actively Maintained|
|---|---|---|:---:|:---:|:---:|:---:|:---:| |---|---|---|:---:|:---:|:---:|:---:|:---:|
|Acura|ILX 2016-19|AcuraWatch Plus|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Acura|ILX 2016-19|AcuraWatch Plus|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Acura|RDX 2016-18|AcuraWatch Plus|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Acura|RDX 2016-18|AcuraWatch Plus|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Acura|RDX 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Acura|RDX 2019-21|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Audi|A3 2014-19|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Audi|Q3 2020-21|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Audi|A3 Sportback e-tron 2017-18|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Audi|Q3 2020-21|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Audi|RS3 2018|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Audi|S3 2015-17|ACC + Lane Assist|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Cadillac|Escalade ESV 2016[<sup>1</sup>](#footnotes)|ACC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>| |Cadillac|Escalade ESV 2016[<sup>1</sup>](#footnotes)|ACC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|
|Chevrolet|Volt 2017-18[<sup>1</sup>](#footnotes)|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Chrysler|Pacifica 2017-18|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Chrysler|Pacifica 2017-18|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Chrysler|Pacifica 2020|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Chrysler|Pacifica 2020|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Chrysler|Pacifica Hybrid 2019-21|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Chrysler|Pacifica Hybrid 2019-21|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Genesis|G90 2018|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>| |Genesis|G90 2018|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|
|GMC|Acadia 2018[<sup>1</sup>](#footnotes)|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>| |GMC|Acadia 2018[<sup>1</sup>](#footnotes)|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|
|Honda|Accord 2018-21|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Honda|Accord 2018-21|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Honda|Accord Hybrid 2018-21|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Honda|Accord Hybrid 2018-21|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Honda|Civic 2016-18|Honda Sensing|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Honda|Civic 2016-18|Honda Sensing|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
@ -170,55 +187,41 @@ How We Rate The Cars
|Hyundai|Ioniq Electric 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Hyundai|Ioniq Electric 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Hyundai|Ioniq Hybrid 2017-19|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Hyundai|Ioniq Hybrid 2017-19|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Hyundai|Ioniq Plug-in Hybrid 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Hyundai|Ioniq Plug-in Hybrid 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Hyundai|Sonata 2018-19|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Hyundai|Sonata 2018-19|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Hyundai|Tucson 2021|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Hyundai|Veloster 2019-20|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Hyundai|Veloster 2019-20|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Jeep|Grand Cherokee 2016-18|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Jeep|Grand Cherokee 2019-20|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Jeep|Grand Cherokee 2019-20|Adaptive Cruise|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Kia|Niro Plug-in Hybrid 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Niro Plug-in Hybrid 2019|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Kia|Optima 2017|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Kia|Optima 2017|SCC + LKAS|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|CT Hybrid 2017-18|LSS|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|CT Hybrid 2017-18|LSS|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|ES Hybrid 2017-18|LSS|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|IS 2017-19|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|IS 2017-19|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|RC 2020|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|RC 2020|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|RX 2016-18|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|RX 2016-18|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Lexus|RX Hybrid 2016-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Lexus|RX Hybrid 2016-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Mazda|CX-9 2021|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Mazda|CX-9 2021|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Nissan|Altima 2019-20|ProPILOT|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Nissan|Altima 2019-20|ProPILOT|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Nissan|Leaf 2018-22|ProPILOT|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Nissan|Leaf 2018-22|ProPILOT|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Nissan|Rogue 2018-20|ProPILOT|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Nissan|Rogue 2018-20|ProPILOT|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Nissan|X-Trail 2017|ProPILOT|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Nissan|X-Trail 2017|ProPILOT|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Subaru|Ascent 2019-20|EyeSight|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Subaru|Ascent 2019-20|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Subaru|Crosstrek 2018-19|EyeSight|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Subaru|Crosstrek 2018-19|EyeSight|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Subaru|Crosstrek 2020-21|EyeSight|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Subaru|Impreza 2017-19|EyeSight|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Subaru|Impreza 2017-19|EyeSight|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Subaru|Impreza 2020-21|EyeSight|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Avalon 2016-18|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Avalon 2016-18|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Avalon 2019-21|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Avalon Hybrid 2019-21|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Avalon Hybrid 2019-21|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|C-HR 2017-21|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|C-HR 2017-21|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|C-HR Hybrid 2017-19|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|C-HR Hybrid 2017-19|All|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Corolla 2017-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Corolla 2017-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Highlander 2017-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|Prius v 2017|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Highlander Hybrid 2017-19|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Toyota|RAV4 2016-18|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Prius 2016-20|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>5</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|Arteon 2018, 2021[<sup>7</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Prius Prime 2017-20|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>5</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|California 2021[<sup>7</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Prius v 2017|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>5</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|Caravelle 2020[<sup>7</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|RAV4 2016-18|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|Jetta 2018-21|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|RAV4 Hybrid 2016-18|TSS-P|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|Jetta GLI 2021|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Toyota|Sienna 2018-20|All|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#footnotes)|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|Passat 2015-19[<sup>6</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Atlas 2018-19, 2022[<sup>8</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>| |Volkswagen|Tiguan 2019-22[<sup>7</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|California 2021[<sup>8</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Caravelle 2020[<sup>8</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|e-Golf 2014, 2018-20|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf 2015-20|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf Alltrack 2017-18|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf GTE 2016|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf GTI 2018-21|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf R 2016-19|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf SportsVan 2016|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Golf SportWagen 2015|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Jetta 2018-21|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Jetta GLI 2021|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|Volkswagen|Tiguan 2019-22[<sup>8</sup>](#footnotes)|Driver Assistance|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="##"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
<a id="footnotes"></a> <a id="footnotes"></a>
@ -226,10 +229,9 @@ How We Rate The Cars
<sup>2</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br /> <sup>2</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
<sup>3</sup>When disconnecting the Driver Support Unit (DSU), openpilot 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>3</sup>When disconnecting the Driver Support Unit (DSU), 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>4</sup>28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br /> <sup>4</sup>28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>5</sup>An inaccurate steering wheel angle sensor makes precise control difficult. <br /> <sup>5</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>6</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br /> <sup>6</sup>Not including the USA/China market Passat, which is based on the (currently) unsupported PQ35/NMS platform. <br />
<sup>7</sup>Not including the USA/China market Passat, which is based on the (currently) unsupported PQ35/NMS platform. <br /> <sup>7</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>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 />
## 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/).

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

@ -1 +1 @@
Subproject commit ba6ed3277cadfdc8697206784afbd7f9a223798b Subproject commit a3a80dc4f7977b2232946e56a16770e413190818

@ -22,12 +22,12 @@ function agnos_init {
# Check if AGNOS update is required # Check if AGNOS update is required
if [ $(< /VERSION) != "$AGNOS_VERSION" ]; then if [ $(< /VERSION) != "$AGNOS_VERSION" ]; then
AGNOS_PY="$DIR/selfdrive/hardware/tici/agnos.py" AGNOS_PY="$DIR/system/hardware/tici/agnos.py"
MANIFEST="$DIR/selfdrive/hardware/tici/agnos.json" MANIFEST="$DIR/system/hardware/tici/agnos.json"
if $AGNOS_PY --verify $MANIFEST; then if $AGNOS_PY --verify $MANIFEST; then
sudo reboot sudo reboot
fi fi
$DIR/selfdrive/hardware/tici/updater $AGNOS_PY $MANIFEST $DIR/system/hardware/tici/updater $AGNOS_PY $MANIFEST
fi fi
} }

@ -1 +1 @@
Subproject commit 7701277d2666119bc7fcaca9f8cfefd50cd5b071 Subproject commit a7b391cce88908824f1417f0c7abd35e3ae16f96

@ -1 +1 @@
Subproject commit 475a9a312410908abcaa32f2e48140fcbfc2362f Subproject commit 42772b49e313688f8f96114806a72784f978e990

@ -61,17 +61,17 @@ release/*
tools/lib/* tools/lib/*
tools/joystick/* tools/joystick/*
selfdrive/version.py
selfdrive/__init__.py selfdrive/__init__.py
selfdrive/sentry.py selfdrive/sentry.py
selfdrive/swaglog.py
selfdrive/logmessaged.py
selfdrive/tombstoned.py selfdrive/tombstoned.py
selfdrive/updated.py selfdrive/updated.py
selfdrive/rtshield.py selfdrive/rtshield.py
selfdrive/statsd.py selfdrive/statsd.py
system/logmessaged.py
system/swaglog.py
system/version.py
selfdrive/athena/__init__.py selfdrive/athena/__init__.py
selfdrive/athena/athenad.py selfdrive/athena/athenad.py
selfdrive/athena/manage_athenad.py selfdrive/athena/manage_athenad.py
@ -104,6 +104,7 @@ selfdrive/car/fw_versions.py
selfdrive/car/isotp_parallel_query.py selfdrive/car/isotp_parallel_query.py
selfdrive/car/tests/__init__.py selfdrive/car/tests/__init__.py
selfdrive/car/tests/test_car_interfaces.py selfdrive/car/tests/test_car_interfaces.py
selfdrive/car/torque_data.json
selfdrive/car/body/*.py selfdrive/car/body/*.py
selfdrive/car/chrysler/*.py selfdrive/car/chrysler/*.py
@ -181,21 +182,21 @@ selfdrive/controls/lib/longitudinal_mpc_lib/.gitignore
selfdrive/controls/lib/lateral_mpc_lib/* selfdrive/controls/lib/lateral_mpc_lib/*
selfdrive/controls/lib/longitudinal_mpc_lib/* selfdrive/controls/lib/longitudinal_mpc_lib/*
selfdrive/hardware/__init__.py system/hardware/__init__.py
selfdrive/hardware/base.h system/hardware/base.h
selfdrive/hardware/base.py system/hardware/base.py
selfdrive/hardware/hw.h system/hardware/hw.h
selfdrive/hardware/tici/__init__.py system/hardware/tici/__init__.py
selfdrive/hardware/tici/hardware.h system/hardware/tici/hardware.h
selfdrive/hardware/tici/hardware.py system/hardware/tici/hardware.py
selfdrive/hardware/tici/pins.py system/hardware/tici/pins.py
selfdrive/hardware/tici/agnos.py system/hardware/tici/agnos.py
selfdrive/hardware/tici/agnos.json system/hardware/tici/agnos.json
selfdrive/hardware/tici/amplifier.py system/hardware/tici/amplifier.py
selfdrive/hardware/tici/updater system/hardware/tici/updater
selfdrive/hardware/tici/iwlist.py system/hardware/tici/iwlist.py
selfdrive/hardware/pc/__init__.py system/hardware/pc/__init__.py
selfdrive/hardware/pc/hardware.py system/hardware/pc/hardware.py
selfdrive/locationd/__init__.py selfdrive/locationd/__init__.py
selfdrive/locationd/.gitignore selfdrive/locationd/.gitignore
@ -472,7 +473,6 @@ opendbc/gm_global_a_powertrain_generated.dbc
opendbc/gm_global_a_object.dbc opendbc/gm_global_a_object.dbc
opendbc/gm_global_a_chassis.dbc opendbc/gm_global_a_chassis.dbc
opendbc/ford_fusion_2018_adas.dbc
opendbc/ford_lincoln_base_pt.dbc opendbc/ford_lincoln_base_pt.dbc
opendbc/honda_accord_2018_can_generated.dbc opendbc/honda_accord_2018_can_generated.dbc

@ -2,7 +2,7 @@ third_party/snpe/larch64**
third_party/snpe/aarch64-ubuntu-gcc7.5/* third_party/snpe/aarch64-ubuntu-gcc7.5/*
third_party/mapbox-gl-native-qt/include/* third_party/mapbox-gl-native-qt/include/*
selfdrive/timezoned.py system/timezoned.py
selfdrive/assets/navigation/* selfdrive/assets/navigation/*
selfdrive/assets/training_wide/* selfdrive/assets/training_wide/*

@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from selfdrive.hardware import HARDWARE from system.hardware import HARDWARE
if __name__ == "__main__": if __name__ == "__main__":
HARDWARE.set_power_save(False) HARDWARE.set_power_save(False)

@ -32,12 +32,12 @@ from common.basedir import PERSIST
from common.file_helpers import CallbackReader from common.file_helpers import CallbackReader
from common.params import Params from common.params import Params
from common.realtime import sec_since_boot, set_core_affinity from common.realtime import sec_since_boot, set_core_affinity
from selfdrive.hardware import HARDWARE, PC, AGNOS from system.hardware import HARDWARE, PC, AGNOS
from selfdrive.loggerd.config import ROOT from selfdrive.loggerd.config import ROOT
from selfdrive.loggerd.xattr_cache import getxattr, setxattr from selfdrive.loggerd.xattr_cache import getxattr, setxattr
from selfdrive.statsd import STATS_DIR from selfdrive.statsd import STATS_DIR
from selfdrive.swaglog import SWAGLOG_DIR, cloudlog from system.swaglog import SWAGLOG_DIR, cloudlog
from selfdrive.version import get_commit, get_origin, get_short_branch, get_version from system.version import get_commit, get_origin, get_short_branch, get_version
ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai') ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai')
HANDLER_THREADS = int(os.getenv('HANDLER_THREADS', "4")) HANDLER_THREADS = int(os.getenv('HANDLER_THREADS', "4"))

@ -5,8 +5,8 @@ from multiprocessing import Process
from common.params import Params from common.params import Params
from selfdrive.manager.process import launcher from selfdrive.manager.process import launcher
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
from selfdrive.version import get_version, is_dirty from system.version import get_version, is_dirty
ATHENA_MGR_PID_PARAM = "AthenadPid" ATHENA_MGR_PID_PARAM = "AthenadPid"

@ -11,8 +11,8 @@ from common.params import Params
from common.spinner import Spinner from common.spinner import Spinner
from common.basedir import PERSIST from common.basedir import PERSIST
from selfdrive.controls.lib.alertmanager import set_offroad_alert from selfdrive.controls.lib.alertmanager import set_offroad_alert
from selfdrive.hardware import HARDWARE, PC from system.hardware import HARDWARE, PC
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
UNREGISTERED_DONGLE_ID = "UnregisteredDevice" UNREGISTERED_DONGLE_ID = "UnregisteredDevice"

@ -16,7 +16,7 @@ from unittest import mock
from websocket import ABNF from websocket import ABNF
from websocket._exceptions import WebSocketConnectionClosedException from websocket._exceptions import WebSocketConnectionClosedException
from selfdrive import swaglog from system import swaglog
from selfdrive.athena import athenad from selfdrive.athena import athenad
from selfdrive.athena.athenad import MAX_RETRY_COUNT, dispatcher from selfdrive.athena.athenad import MAX_RETRY_COUNT, dispatcher
from selfdrive.athena.tests.helpers import MockWebsocket, MockParams, MockApi, EchoSocket, with_http_server from selfdrive.athena.tests.helpers import MockWebsocket, MockParams, MockApi, EchoSocket, with_http_server
@ -120,6 +120,13 @@ class TestAthenadMethods(unittest.TestCase):
self.assertTrue(resp, 'list empty!') self.assertTrue(resp, 'list empty!')
self.assertCountEqual(resp, expected) self.assertCountEqual(resp, expected)
def test_strip_bz2_extension(self):
fn = os.path.join(athenad.ROOT, 'qlog.bz2')
Path(fn).touch()
if fn.endswith('.bz2'):
self.assertEqual(athenad.strip_bz2_extension(fn), fn[:-4])
@with_http_server @with_http_server
def test_do_upload(self, host): def test_do_upload(self, host):
fn = os.path.join(athenad.ROOT, 'qlog.bz2') fn = os.path.join(athenad.ROOT, 'qlog.bz2')

@ -27,7 +27,7 @@
#include "common/swaglog.h" #include "common/swaglog.h"
#include "common/timing.h" #include "common/timing.h"
#include "common/util.h" #include "common/util.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
#include "selfdrive/boardd/pigeon.h" #include "selfdrive/boardd/pigeon.h"

@ -3,7 +3,7 @@
#include "selfdrive/boardd/boardd.h" #include "selfdrive/boardd/boardd.h"
#include "common/swaglog.h" #include "common/swaglog.h"
#include "common/util.h" #include "common/util.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
LOGW("starting boardd"); LOGW("starting boardd");

@ -10,8 +10,8 @@ from functools import cmp_to_key
from panda import DEFAULT_FW_FN, DEFAULT_H7_FW_FN, MCU_TYPE_H7, Panda, PandaDFU from panda import DEFAULT_FW_FN, DEFAULT_H7_FW_FN, MCU_TYPE_H7, Panda, PandaDFU
from common.basedir import BASEDIR from common.basedir import BASEDIR
from common.params import Params from common.params import Params
from selfdrive.hardware import HARDWARE from system.hardware import HARDWARE
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
def get_expected_signature(panda: Panda) -> bytes: def get_expected_signature(panda: Panda) -> bytes:

@ -13,7 +13,7 @@ import time
import cereal.messaging as messaging import cereal.messaging as messaging
from common.realtime import Ratekeeper from common.realtime import Ratekeeper
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
from selfdrive.boardd.boardd import can_capnp_to_can_list from selfdrive.boardd.boardd import can_capnp_to_can_list
from cereal import car from cereal import car

@ -12,7 +12,7 @@ from common.spinner import Spinner
from common.timeout import Timeout from common.timeout import Timeout
from selfdrive.boardd.boardd import can_list_to_can_capnp from selfdrive.boardd.boardd import can_list_to_can_capnp
from selfdrive.car import make_can_msg from selfdrive.car import make_can_msg
from selfdrive.hardware import TICI from system.hardware import TICI
from selfdrive.test.helpers import phone_only, with_processes from selfdrive.test.helpers import phone_only, with_processes

@ -15,7 +15,7 @@
#include "common/modeldata.h" #include "common/modeldata.h"
#include "common/swaglog.h" #include "common/swaglog.h"
#include "common/util.h" #include "common/util.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
#include "msm_media_info.h" #include "msm_media_info.h"
#ifdef QCOM2 #ifdef QCOM2

@ -13,7 +13,7 @@
#include "common/mat.h" #include "common/mat.h"
#include "common/queue.h" #include "common/queue.h"
#include "common/swaglog.h" #include "common/swaglog.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
#define CAMERA_ID_IMX298 0 #define CAMERA_ID_IMX298 0
#define CAMERA_ID_IMX179 1 #define CAMERA_ID_IMX179 1

@ -837,7 +837,6 @@ void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_i
s->road_cam.camera_init(s, v, CAMERA_ID_AR0231, 1, 20, device_id, ctx, VISION_STREAM_RGB_ROAD, VISION_STREAM_ROAD, !env_disable_road); s->road_cam.camera_init(s, v, CAMERA_ID_AR0231, 1, 20, device_id, ctx, VISION_STREAM_RGB_ROAD, VISION_STREAM_ROAD, !env_disable_road);
s->wide_road_cam.camera_init(s, v, CAMERA_ID_AR0231, 0, 20, device_id, ctx, VISION_STREAM_RGB_WIDE_ROAD, VISION_STREAM_WIDE_ROAD, !env_disable_wide_road); s->wide_road_cam.camera_init(s, v, CAMERA_ID_AR0231, 0, 20, device_id, ctx, VISION_STREAM_RGB_WIDE_ROAD, VISION_STREAM_WIDE_ROAD, !env_disable_wide_road);
s->sm = new SubMaster({"driverState"});
s->pm = new PubMaster({"roadCameraState", "driverCameraState", "wideRoadCameraState", "thumbnail"}); s->pm = new PubMaster({"roadCameraState", "driverCameraState", "wideRoadCameraState", "thumbnail"});
} }
@ -948,7 +947,6 @@ void cameras_close(MultiCameraState *s) {
s->road_cam.camera_close(); s->road_cam.camera_close();
s->wide_road_cam.camera_close(); s->wide_road_cam.camera_close();
delete s->sm;
delete s->pm; delete s->pm;
} }
@ -1221,7 +1219,7 @@ static void ar0231_process_registers(MultiCameraState *s, CameraState *c, cereal
framed.setTemperaturesC({temp_0, temp_1}); framed.setTemperaturesC({temp_0, temp_1});
} }
static void driver_cam_auto_exposure(CameraState *c, SubMaster &sm) { static void driver_cam_auto_exposure(CameraState *c) {
struct ExpRect {int x1, x2, x_skip, y1, y2, y_skip;}; struct ExpRect {int x1, x2, x_skip, y1, y2, y_skip;};
const CameraBuf *b = &c->buf; const CameraBuf *b = &c->buf;
static ExpRect rect = {96, 1832, 2, 242, 1148, 4}; static ExpRect rect = {96, 1832, 2, 242, 1148, 4};
@ -1229,8 +1227,7 @@ static void driver_cam_auto_exposure(CameraState *c, SubMaster &sm) {
} }
static void process_driver_camera(MultiCameraState *s, CameraState *c, int cnt) { static void process_driver_camera(MultiCameraState *s, CameraState *c, int cnt) {
s->sm->update(0); driver_cam_auto_exposure(c);
driver_cam_auto_exposure(c, *(s->sm));
MessageBuilder msg; MessageBuilder msg;
auto framed = msg.initEvent().initDriverCameraState(); auto framed = msg.initEvent().initDriverCameraState();

@ -106,6 +106,5 @@ typedef struct MultiCameraState {
CameraState wide_road_cam; CameraState wide_road_cam;
CameraState driver_cam; CameraState driver_cam;
SubMaster *sm;
PubMaster *pm; PubMaster *pm;
} MultiCameraState; } MultiCameraState;

@ -4,7 +4,7 @@
#include "common/params.h" #include "common/params.h"
#include "common/util.h" #include "common/util.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (!Hardware::PC()) { if (!Hardware::PC()) {

@ -9,7 +9,7 @@ import cereal.messaging as messaging
from cereal.visionipc import VisionIpcClient, VisionStreamType from cereal.visionipc import VisionIpcClient, VisionStreamType
from common.params import Params from common.params import Params
from common.realtime import DT_MDL from common.realtime import DT_MDL
from selfdrive.hardware import PC from system.hardware import PC
from selfdrive.controls.lib.alertmanager import set_offroad_alert from selfdrive.controls.lib.alertmanager import set_offroad_alert
from selfdrive.manager.process_config import managed_processes from selfdrive.manager.process_config import managed_processes

@ -19,7 +19,6 @@ typedef struct MultiCameraState {
CameraState road_cam; CameraState road_cam;
CameraState driver_cam; CameraState driver_cam;
SubMaster *sm = nullptr;
PubMaster *pm = nullptr; PubMaster *pm = nullptr;
} MultiCameraState; } MultiCameraState;

@ -4,7 +4,7 @@ import time
import unittest import unittest
import cereal.messaging as messaging import cereal.messaging as messaging
from selfdrive.hardware import TICI from system.hardware import TICI
from selfdrive.test.helpers import with_processes from selfdrive.test.helpers import with_processes
TEST_TIMESPAN = 30 # random.randint(60, 180) # seconds TEST_TIMESPAN = 30 # random.randint(60, 180) # seconds

@ -6,7 +6,7 @@ import numpy as np
from selfdrive.test.helpers import with_processes from selfdrive.test.helpers import with_processes
from selfdrive.camerad.snapshot.snapshot import get_snapshots from selfdrive.camerad.snapshot.snapshot import get_snapshots
from selfdrive.hardware import TICI from system.hardware import TICI
TEST_TIME = 45 TEST_TIME = 45
REPEAT = 5 REPEAT = 5

@ -14,31 +14,19 @@ Cars are organized into three tiers:
How We Rate The Cars How We Rate The Cars
--- ---
### openpilot Adaptive Cruise Control (ACC) {% for star_row in star_descriptions.values() %}
- {{star_icon.format(Star.FULL.value)}} - openpilot is able to control the gas and brakes. {% for name, stars in star_row.items() %}
- {{star_icon.format(Star.HALF.value)}} - openpilot is able to control the gas and brakes with some restrictions. ### {{name}}
- {{star_icon.format(Star.EMPTY.value)}} - The gas and brakes are controlled by the car's stock Adaptive Cruise Control (ACC) system. {% for star, description in stars %}
- {{star_icon.format(star)}} - {{description}}
### Stop and Go {% endfor %}
- {{star_icon.format(Star.FULL.value)}} - Adaptive Cruise Control (ACC) operates down to 0 mph.
- {{star_icon.format(Star.EMPTY.value)}} - Adaptive Cruise Control (ACC) available only above certain speeds. See your car's manual for the minimum speed.
### Steer to 0
- {{star_icon.format(Star.FULL.value)}} - openpilot can control the steering wheel down to 0 mph.
- {{star_icon.format(Star.EMPTY.value)}} - No steering control below certain speeds.
### Steering Torque
- {{star_icon.format(Star.FULL.value)}} - Car has enough steering torque for comfortable highway driving.
- {{star_icon.format(Star.EMPTY.value)}} - Limited ability to make turns.
### Actively Maintained
- {{star_icon.format(Star.FULL.value)}} - Mainline software support, harness hardware sold by comma, lots of users, primary development target.
- {{star_icon.format(Star.EMPTY.value)}} - Low user count, community maintained, harness hardware not sold by comma.
{% endfor %}
{% endfor %}
**All supported cars can move between the tiers as support changes.** **All supported cars can move between the tiers as support changes.**
{% for tier, cars in tiers.items() %} {% for tier, cars in tiers.items() %}
## {{tier.name.title()}} Cars # {{tier.name.title()}} - {{cars | length}} cars
|{{Column | map(attribute='value') | join('|')}}| |{{Column | map(attribute='value') | join('|')}}|
|---|---|---|:---:|:---:|:---:|:---:|:---:| |---|---|---|:---:|:---:|:---:|:---:|:---:|

@ -19,7 +19,6 @@ class CarInterface(CarInterfaceBase):
ret.minSteerSpeed = -math.inf ret.minSteerSpeed = -math.inf
ret.maxLateralAccel = math.inf # TODO: set to a reasonable value ret.maxLateralAccel = math.inf # TODO: set to a reasonable value
ret.steerRatio = 0.5 ret.steerRatio = 0.5
ret.steerRateCost = 0.5
ret.steerLimitTimer = 1.0 ret.steerLimitTimer = 1.0
ret.steerActuatorDelay = 0. ret.steerActuatorDelay = 0.

@ -4,12 +4,12 @@ from typing import Dict, List
from cereal import car from cereal import car
from common.params import Params from common.params import Params
from common.basedir import BASEDIR from common.basedir import BASEDIR
from selfdrive.version import is_comma_remote, is_tested_branch from system.version import is_comma_remote, is_tested_branch
from selfdrive.car.interfaces import get_interface_attr from selfdrive.car.interfaces import get_interface_attr
from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars
from selfdrive.car.vin import get_vin, VIN_UNKNOWN from selfdrive.car.vin import get_vin, VIN_UNKNOWN
from selfdrive.car.fw_versions import get_fw_versions, match_fw_to_car from selfdrive.car.fw_versions import get_fw_versions, match_fw_to_car
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
import cereal.messaging as messaging import cereal.messaging as messaging
from selfdrive.car import gen_empty_fingerprint from selfdrive.car import gen_empty_fingerprint

@ -20,17 +20,8 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]]
ret.lateralTuning.pid.kf = 0.00006 # full torque for 10 deg at 80mph means 0.00007818594 ret.lateralTuning.pid.kf = 0.00006 # full torque for 10 deg at 80mph means 0.00007818594
ret.steerActuatorDelay = 0.1 ret.steerActuatorDelay = 0.1
ret.steerRateCost = 0.7
ret.steerLimitTimer = 0.4 ret.steerLimitTimer = 0.4
# set max lateral acceleration
if candidate in (CAR.PACIFICA_2018, CAR.PACIFICA_2019_HYBRID, CAR.JEEP_CHEROKEE, CAR.JEEP_CHEROKEE_2019):
ret.maxLateralAccel = 1.6
if candidate in (CAR.PACIFICA_2018_HYBRID,):
ret.maxLateralAccel = 1.4
if candidate in (CAR.PACIFICA_2017_HYBRID,):
ret.maxLateralAccel = 1.2
if candidate in (CAR.JEEP_CHEROKEE, CAR.JEEP_CHEROKEE_2019): if candidate in (CAR.JEEP_CHEROKEE, CAR.JEEP_CHEROKEE_2019):
ret.wheelbase = 2.91 # in meters ret.wheelbase = 2.91 # in meters
ret.steerRatio = 12.7 ret.steerRatio = 12.7

@ -1,5 +1,5 @@
from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
EXT_DIAG_REQUEST = b'\x10\x03' EXT_DIAG_REQUEST = b'\x10\x03'
EXT_DIAG_RESPONSE = b'\x50\x03' EXT_DIAG_RESPONSE = b'\x50\x03'

@ -7,7 +7,7 @@ from natsort import natsorted
from typing import Dict, List from typing import Dict, List
from common.basedir import BASEDIR from common.basedir import BASEDIR
from selfdrive.car.docs_definitions import CarInfo, Column, Star, Tier from selfdrive.car.docs_definitions import STAR_DESCRIPTIONS, CarInfo, Column, Star, Tier
from selfdrive.car.car_helpers import interfaces, get_interface_attr from selfdrive.car.car_helpers import interfaces, get_interface_attr
from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR as HKG_RADAR_START_ADDR from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR as HKG_RADAR_START_ADDR
from selfdrive.car.tests.routes import non_tested_cars from selfdrive.car.tests.routes import non_tested_cars
@ -65,7 +65,7 @@ def generate_cars_md(all_car_info: List[CarInfo], template_fn: str) -> str:
footnotes = [fn.value.text for fn in ALL_FOOTNOTES] footnotes = [fn.value.text for fn in ALL_FOOTNOTES]
cars_md: str = template.render(tiers=sort_by_tier(all_car_info), all_car_info=all_car_info, cars_md: str = template.render(tiers=sort_by_tier(all_car_info), all_car_info=all_car_info,
footnotes=footnotes, Star=Star, Column=Column) footnotes=footnotes, Star=Star, Column=Column, star_descriptions=STAR_DESCRIPTIONS)
return cars_md return cars_md

@ -6,7 +6,9 @@ from dataclasses import dataclass
from enum import Enum from enum import Enum
from typing import Dict, List, Optional, Union, no_type_check from typing import Dict, List, Optional, Union, no_type_check
STEERING_TORQUE_THRESHOLD = 2.0 # m/s^2 TACO_TORQUE_THRESHOLD = 2.5 # m/s^2
GREAT_TORQUE_THRESHOLD = 1.4 # m/s^2
GOOD_TORQUE_THRESHOLD = 1.0 # m/s^2
class Tier(Enum): class Tier(Enum):
@ -70,11 +72,6 @@ class CarInfo:
if self.min_enable_speed is not None: if self.min_enable_speed is not None:
min_enable_speed = self.min_enable_speed min_enable_speed = self.min_enable_speed
# TODO: remove hardcoded good torque and just use maxLateralAccel
good_torque = self.good_torque
if not math.isnan(CP.maxLateralAccel):
good_torque = CP.maxLateralAccel >= STEERING_TORQUE_THRESHOLD
self.car_name = CP.carName self.car_name = CP.carName
self.make, self.model = self.name.split(' ', 1) self.make, self.model = self.name.split(' ', 1)
self.row = { self.row = {
@ -82,21 +79,27 @@ class CarInfo:
Column.MODEL: self.model, Column.MODEL: self.model,
Column.PACKAGE: self.package, Column.PACKAGE: self.package,
# StarColumns # StarColumns
Column.LONGITUDINAL: CP.openpilotLongitudinalControl and not CP.radarOffCan, Column.LONGITUDINAL: Star.FULL if CP.openpilotLongitudinalControl and not CP.radarOffCan else Star.EMPTY,
Column.FSR_LONGITUDINAL: min_enable_speed <= 0., Column.FSR_LONGITUDINAL: Star.FULL if min_enable_speed <= 0. else Star.EMPTY,
Column.FSR_STEERING: min_steer_speed <= 0., Column.FSR_STEERING: Star.FULL if min_steer_speed <= 0. else Star.EMPTY,
Column.STEERING_TORQUE: good_torque, Column.STEERING_TORQUE: Star.FULL if self.good_torque else Star.EMPTY, # TODO: remove hardcoding and use maxLateralAccel
Column.MAINTAINED: CP.carFingerprint not in non_tested_cars and self.harness is not Harness.none, Column.MAINTAINED: Star.FULL if CP.carFingerprint not in non_tested_cars and self.harness is not Harness.none else Star.EMPTY,
} }
if not math.isnan(CP.maxLateralAccel):
if CP.maxLateralAccel >= GREAT_TORQUE_THRESHOLD:
self.row[Column.STEERING_TORQUE] = Star.FULL
elif CP.maxLateralAccel >= GOOD_TORQUE_THRESHOLD:
self.row[Column.STEERING_TORQUE] = Star.HALF
else:
self.row[Column.STEERING_TORQUE] = Star.EMPTY
if CP.notCar: if CP.notCar:
for col in StarColumns: for col in StarColumns:
self.row[col] = True self.row[col] = Star.FULL
self.all_footnotes = all_footnotes self.all_footnotes = all_footnotes
for column in StarColumns: for column in StarColumns:
self.row[column] = Star.FULL if self.row[column] else Star.EMPTY
# Demote if footnote specifies a star # Demote if footnote specifies a star
footnote = get_footnote(self.footnotes, column) footnote = get_footnote(self.footnotes, column)
if footnote is not None and footnote.value.star is not None: if footnote is not None and footnote.value.star is not None:
@ -120,7 +123,7 @@ class CarInfo:
class Harness(Enum): class Harness(Enum):
nidec = "Honda Nidec" nidec = "Honda Nidec"
bosch = "Honda Bosch" bosch = "Honda Bosch A"
toyota = "Toyota" toyota = "Toyota"
subaru = "Subaru" subaru = "Subaru"
fca = "FCA" fca = "FCA"
@ -147,3 +150,35 @@ class Harness(Enum):
nissan_b = "Nissan B" nissan_b = "Nissan B"
mazda = "Mazda" mazda = "Mazda"
none = "None" none = "None"
STAR_DESCRIPTIONS = {
"Gas & Brakes": { # icon and row name
"openpilot Adaptive Cruise Control (ACC)": [ # star column
[Star.FULL.value, "openpilot is able to control the gas and brakes."],
[Star.HALF.value, "openpilot is able to control the gas and brakes with some restrictions."],
[Star.EMPTY.value, "The gas and brakes are controlled by the car's stock Adaptive Cruise Control (ACC) system."],
],
Column.FSR_LONGITUDINAL.value: [
[Star.FULL.value, "Adaptive Cruise Control (ACC) operates down to 0 mph."],
[Star.EMPTY.value, "Adaptive Cruise Control (ACC) available only above certain speeds. See your car's manual for the minimum speed."],
],
},
"Steering": {
Column.FSR_STEERING.value: [
[Star.FULL.value, "openpilot can control the steering wheel down to 0 mph."],
[Star.EMPTY.value, "No steering control below certain speeds."],
],
Column.STEERING_TORQUE.value: [
[Star.FULL.value, "Car has enough steering torque to take tighter turns."],
[Star.HALF.value, "Car has enough steering torque for comfortable highway driving."],
[Star.EMPTY.value, "Limited ability to make turns."],
],
},
"Support": {
Column.MAINTAINED.value: [
[Star.FULL.value, "Mainline software support, harness hardware sold by comma, lots of users, primary development target."],
[Star.EMPTY.value, "Low user count, community maintained, harness hardware not sold by comma."],
],
},
}

@ -59,7 +59,6 @@ class CarInterface(CarInterfaceBase):
# LCA can steer down to zero # LCA can steer down to zero
ret.minSteerSpeed = 0. ret.minSteerSpeed = 0.
ret.steerRateCost = 1.0
ret.centerToFront = ret.wheelbase * 0.44 ret.centerToFront = ret.wheelbase * 0.44
ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase)

@ -9,6 +9,9 @@ RADAR_MSGS = list(range(0x500, 0x540))
def _create_radar_can_parser(car_fingerprint): def _create_radar_can_parser(car_fingerprint):
if DBC[car_fingerprint]['radar'] is None:
return None
msg_n = len(RADAR_MSGS) msg_n = len(RADAR_MSGS)
signals = list(zip(['X_Rel'] * msg_n + ['Angle'] * msg_n + ['V_Rel'] * msg_n, signals = list(zip(['X_Rel'] * msg_n + ['Angle'] * msg_n + ['V_Rel'] * msg_n,
RADAR_MSGS * 3)) RADAR_MSGS * 3))
@ -27,6 +30,9 @@ class RadarInterface(RadarInterfaceBase):
self.updated_messages = set() self.updated_messages = set()
def update(self, can_strings): def update(self, can_strings):
if self.rcp is None:
return super().update(None)
vls = self.rcp.update_strings(can_strings) vls = self.rcp.update_strings(can_strings)
self.updated_messages.update(vls) self.updated_messages.update(vls)

@ -79,6 +79,6 @@ FW_VERSIONS = {
DBC = { DBC = {
CAR.ESCAPE_MK4: dbc_dict('ford_lincoln_base_pt', 'ford_fusion_2018_adas'), CAR.ESCAPE_MK4: dbc_dict('ford_lincoln_base_pt', None),
CAR.FOCUS_MK4: dbc_dict('ford_lincoln_base_pt', 'ford_fusion_2018_adas'), CAR.FOCUS_MK4: dbc_dict('ford_lincoln_base_pt', None),
} }

@ -12,7 +12,7 @@ from selfdrive.car.interfaces import get_interface_attr
from selfdrive.car.fingerprints import FW_VERSIONS from selfdrive.car.fingerprints import FW_VERSIONS
from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery
from selfdrive.car.toyota.values import CAR as TOYOTA from selfdrive.car.toyota.values import CAR as TOYOTA
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu

@ -67,7 +67,7 @@ class CarState(CarStateBase):
ret.leftBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 1 ret.leftBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 1
ret.rightBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 2 ret.rightBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 2
ret.parkingBrake = pt_cp.vl["EPBStatus"]["EPBClosed"] == 1 ret.parkingBrake = pt_cp.vl["VehicleIgnitionAlt"]["ParkBrake"] == 1
ret.cruiseState.available = pt_cp.vl["ECMEngineStatus"]["CruiseMainOn"] != 0 ret.cruiseState.available = pt_cp.vl["ECMEngineStatus"]["CruiseMainOn"] != 0
ret.espDisabled = pt_cp.vl["ESPStatus"]["TractionControlOn"] != 1 ret.espDisabled = pt_cp.vl["ESPStatus"]["TractionControlOn"] != 1
ret.accFaulted = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.FAULTED ret.accFaulted = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.FAULTED
@ -104,7 +104,7 @@ class CarState(CarStateBase):
("LKATorqueDelivered", "PSCMStatus"), ("LKATorqueDelivered", "PSCMStatus"),
("LKATorqueDeliveredStatus", "PSCMStatus"), ("LKATorqueDeliveredStatus", "PSCMStatus"),
("TractionControlOn", "ESPStatus"), ("TractionControlOn", "ESPStatus"),
("EPBClosed", "EPBStatus"), ("ParkBrake", "VehicleIgnitionAlt"),
("CruiseMainOn", "ECMEngineStatus"), ("CruiseMainOn", "ECMEngineStatus"),
] ]
@ -114,7 +114,7 @@ class CarState(CarStateBase):
("PSCMStatus", 10), ("PSCMStatus", 10),
("ESPStatus", 10), ("ESPStatus", 10),
("BCMDoorBeltStatus", 10), ("BCMDoorBeltStatus", 10),
("EPBStatus", 20), ("VehicleIgnitionAlt", 10),
("EBCMWheelSpdFront", 20), ("EBCMWheelSpdFront", 20),
("EBCMWheelSpdRear", 20), ("EBCMWheelSpdRear", 20),
("AcceleratorPedal2", 33), ("AcceleratorPedal2", 33),

@ -59,24 +59,30 @@ class CarInterface(CarInterfaceBase):
ret.openpilotLongitudinalControl = True ret.openpilotLongitudinalControl = True
tire_stiffness_factor = 0.444 # not optimized yet tire_stiffness_factor = 0.444 # not optimized yet
# Start with a baseline lateral tuning for all GM vehicles. Override tuning as needed in each model section below. # Start with a baseline tuning for all GM vehicles. Override tuning as needed in each model section below.
ret.minSteerSpeed = 7 * CV.MPH_TO_MS ret.minSteerSpeed = 7 * CV.MPH_TO_MS
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.00]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.00]]
ret.lateralTuning.pid.kf = 0.00004 # full torque for 20 deg at 80mph means 0.00007818594 ret.lateralTuning.pid.kf = 0.00004 # full torque for 20 deg at 80mph means 0.00007818594
ret.steerRateCost = 1.0
ret.steerActuatorDelay = 0.1 # Default delay, not measured yet ret.steerActuatorDelay = 0.1 # Default delay, not measured yet
if candidate == CAR.VOLT: ret.longitudinalTuning.kpBP = [5., 35.]
# supports stop and go, but initial engage must be above 18mph (which include conservatism) ret.longitudinalTuning.kpV = [2.4, 1.5]
ret.longitudinalTuning.kiBP = [0.]
ret.longitudinalTuning.kiV = [0.36]
ret.steerLimitTimer = 0.4
ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz
# supports stop and go, but initial engage must (conservatively) be above 18mph
ret.minEnableSpeed = 18 * CV.MPH_TO_MS ret.minEnableSpeed = 18 * CV.MPH_TO_MS
if candidate == CAR.VOLT:
ret.mass = 1607. + STD_CARGO_KG ret.mass = 1607. + STD_CARGO_KG
ret.wheelbase = 2.69 ret.wheelbase = 2.69
ret.steerRatio = 17.7 # Stock 15.7, LiveParameters ret.steerRatio = 17.7 # Stock 15.7, LiveParameters
tire_stiffness_factor = 0.469 # Stock Michelin Energy Saver A/S, LiveParameters tire_stiffness_factor = 0.469 # Stock Michelin Energy Saver A/S, LiveParameters
ret.steerRatioRear = 0.
ret.centerToFront = ret.wheelbase * 0.45 # Volt Gen 1, TODO corner weigh ret.centerToFront = ret.wheelbase * 0.45 # Volt Gen 1, TODO corner weigh
ret.maxLateralAccel = 1.6
ret.lateralTuning.pid.kpBP = [0., 40.] ret.lateralTuning.pid.kpBP = [0., 40.]
ret.lateralTuning.pid.kpV = [0., 0.17] ret.lateralTuning.pid.kpV = [0., 0.17]
@ -86,12 +92,9 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.2 ret.steerActuatorDelay = 0.2
elif candidate == CAR.MALIBU: elif candidate == CAR.MALIBU:
# supports stop and go, but initial engage must be above 18mph (which include conservatism)
ret.minEnableSpeed = 18 * CV.MPH_TO_MS
ret.mass = 1496. + STD_CARGO_KG ret.mass = 1496. + STD_CARGO_KG
ret.wheelbase = 2.83 ret.wheelbase = 2.83
ret.steerRatio = 15.8 ret.steerRatio = 15.8
ret.steerRatioRear = 0.
ret.centerToFront = ret.wheelbase * 0.4 # wild guess ret.centerToFront = ret.wheelbase * 0.4 # wild guess
elif candidate == CAR.HOLDEN_ASTRA: elif candidate == CAR.HOLDEN_ASTRA:
@ -99,34 +102,26 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.662 ret.wheelbase = 2.662
# Remaining parameters copied from Volt for now # Remaining parameters copied from Volt for now
ret.centerToFront = ret.wheelbase * 0.4 ret.centerToFront = ret.wheelbase * 0.4
ret.minEnableSpeed = 18 * CV.MPH_TO_MS
ret.steerRatio = 15.7 ret.steerRatio = 15.7
ret.steerRatioRear = 0.
elif candidate == CAR.ACADIA: elif candidate == CAR.ACADIA:
ret.minEnableSpeed = -1. # engage speed is decided by pcm ret.minEnableSpeed = -1. # engage speed is decided by pcm
ret.mass = 4353. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4353. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.86 ret.wheelbase = 2.86
ret.steerRatio = 14.4 # end to end is 13.46 ret.steerRatio = 14.4 # end to end is 13.46
ret.steerRatioRear = 0.
ret.centerToFront = ret.wheelbase * 0.4 ret.centerToFront = ret.wheelbase * 0.4
ret.maxLateralAccel = 1.4
ret.lateralTuning.pid.kf = 1. # get_steer_feedforward_acadia() ret.lateralTuning.pid.kf = 1. # get_steer_feedforward_acadia()
elif candidate == CAR.BUICK_REGAL: elif candidate == CAR.BUICK_REGAL:
ret.minEnableSpeed = 18 * CV.MPH_TO_MS
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
ret.wheelbase = 2.83 # 111.4 inches in meters ret.wheelbase = 2.83 # 111.4 inches in meters
ret.steerRatio = 14.4 # guess for tourx ret.steerRatio = 14.4 # guess for tourx
ret.steerRatioRear = 0.
ret.centerToFront = ret.wheelbase * 0.4 # guess for tourx ret.centerToFront = ret.wheelbase * 0.4 # guess for tourx
elif candidate == CAR.CADILLAC_ATS: elif candidate == CAR.CADILLAC_ATS:
ret.minEnableSpeed = 18 * CV.MPH_TO_MS
ret.mass = 1601. + STD_CARGO_KG ret.mass = 1601. + STD_CARGO_KG
ret.wheelbase = 2.78 ret.wheelbase = 2.78
ret.steerRatio = 15.3 ret.steerRatio = 15.3
ret.steerRatioRear = 0.
ret.centerToFront = ret.wheelbase * 0.49 ret.centerToFront = ret.wheelbase * 0.49
elif candidate == CAR.ESCALADE_ESV: elif candidate == CAR.ESCALADE_ESV:
@ -149,14 +144,6 @@ class CarInterface(CarInterfaceBase):
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront,
tire_stiffness_factor=tire_stiffness_factor) tire_stiffness_factor=tire_stiffness_factor)
ret.longitudinalTuning.kpBP = [5., 35.]
ret.longitudinalTuning.kpV = [2.4, 1.5]
ret.longitudinalTuning.kiBP = [0.]
ret.longitudinalTuning.kiV = [0.36]
ret.steerLimitTimer = 0.4
ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz
return ret return ret
# returns a car.CarState # returns a car.CarState

@ -95,8 +95,8 @@ def process_hud_alert(hud_alert):
HUDData = namedtuple("HUDData", HUDData = namedtuple("HUDData",
["pcm_accel", "v_cruise", "car", ["pcm_accel", "v_cruise", "lead_visible",
"lanes", "fcw", "acc_alert", "steer_required"]) "lanes_visible", "fcw", "acc_alert", "steer_required"])
class CarController: class CarController:
@ -138,19 +138,6 @@ class CarController:
self.brake_last = rate_limit(pre_limit_brake, self.brake_last, -2., DT_CTRL) self.brake_last = rate_limit(pre_limit_brake, self.brake_last, -2., DT_CTRL)
# vehicle hud display, wait for one update from 10Hz 0x304 msg # vehicle hud display, wait for one update from 10Hz 0x304 msg
if hud_control.lanesVisible:
hud_lanes = 1
else:
hud_lanes = 0
if CC.enabled:
if hud_control.leadVisible:
hud_car = 2
else:
hud_car = 1
else:
hud_car = 0
fcw_display, steer_required, acc_alert = process_hud_alert(hud_control.visualAlert) fcw_display, steer_required, acc_alert = process_hud_alert(hud_control.visualAlert)
# **** process the car messages **** # **** process the car messages ****
@ -172,8 +159,6 @@ class CarController:
can_sends.append(hondacan.create_steering_control(self.packer, apply_steer, CC.latActive, self.CP.carFingerprint, can_sends.append(hondacan.create_steering_control(self.packer, apply_steer, CC.latActive, self.CP.carFingerprint,
idx, CS.CP.openpilotLongitudinalControl)) idx, CS.CP.openpilotLongitudinalControl))
stopping = actuators.longControlState == LongCtrlState.stopping
# wind brake from air resistance decel at high speed # wind brake from air resistance decel at high speed
wind_brake = interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15]) wind_brake = interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15])
# all of this is only relevant for HONDA NIDEC # all of this is only relevant for HONDA NIDEC
@ -222,6 +207,8 @@ class CarController:
if self.CP.carFingerprint in HONDA_BOSCH: if self.CP.carFingerprint in HONDA_BOSCH:
self.accel = clip(accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX) self.accel = clip(accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX)
self.gas = interp(accel, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V) self.gas = interp(accel, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V)
stopping = actuators.longControlState == LongCtrlState.stopping
can_sends.extend(hondacan.create_acc_commands(self.packer, CC.enabled, CC.longActive, self.accel, self.gas, can_sends.extend(hondacan.create_acc_commands(self.packer, CC.enabled, CC.longActive, self.accel, self.gas,
idx, stopping, self.CP.carFingerprint)) idx, stopping, self.CP.carFingerprint))
else: else:
@ -252,9 +239,9 @@ class CarController:
# Send dashboard UI commands. # Send dashboard UI commands.
if self.frame % 10 == 0: if self.frame % 10 == 0:
idx = (self.frame // 10) % 4 idx = (self.frame // 10) % 4
hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), hud_car, hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), hud_control.leadVisible,
hud_lanes, fcw_display, acc_alert, steer_required) hud_control.lanesVisible, fcw_display, acc_alert, steer_required)
can_sends.extend(hondacan.create_ui_commands(self.packer, self.CP, pcm_speed, hud, CS.is_metric, idx, CS.stock_hud)) can_sends.extend(hondacan.create_ui_commands(self.packer, self.CP, CC.enabled, pcm_speed, hud, CS.is_metric, idx, CS.stock_hud))
if self.CP.openpilotLongitudinalControl and self.CP.carFingerprint not in HONDA_BOSCH: if self.CP.openpilotLongitudinalControl and self.CP.carFingerprint not in HONDA_BOSCH:
self.speed = pcm_speed self.speed = pcm_speed

@ -22,9 +22,9 @@ def get_can_signals(CP, gearbox_msg, main_on_sig_msg):
("STEER_ANGLE_RATE", "STEERING_SENSORS"), ("STEER_ANGLE_RATE", "STEERING_SENSORS"),
("MOTOR_TORQUE", "STEER_MOTOR_TORQUE"), ("MOTOR_TORQUE", "STEER_MOTOR_TORQUE"),
("STEER_TORQUE_SENSOR", "STEER_STATUS"), ("STEER_TORQUE_SENSOR", "STEER_STATUS"),
("IMPERIAL_UNIT", "CAR_SPEED"),
("LEFT_BLINKER", "SCM_FEEDBACK"), ("LEFT_BLINKER", "SCM_FEEDBACK"),
("RIGHT_BLINKER", "SCM_FEEDBACK"), ("RIGHT_BLINKER", "SCM_FEEDBACK"),
("GEAR", gearbox_msg),
("SEATBELT_DRIVER_LAMP", "SEATBELT_STATUS"), ("SEATBELT_DRIVER_LAMP", "SEATBELT_STATUS"),
("SEATBELT_DRIVER_LATCHED", "SEATBELT_STATUS"), ("SEATBELT_DRIVER_LATCHED", "SEATBELT_STATUS"),
("BRAKE_PRESSED", "POWERTRAIN_DATA"), ("BRAKE_PRESSED", "POWERTRAIN_DATA"),
@ -35,6 +35,7 @@ def get_can_signals(CP, gearbox_msg, main_on_sig_msg):
("BRAKE_HOLD_ACTIVE", "VSA_STATUS"), ("BRAKE_HOLD_ACTIVE", "VSA_STATUS"),
("STEER_STATUS", "STEER_STATUS"), ("STEER_STATUS", "STEER_STATUS"),
("GEAR_SHIFTER", gearbox_msg), ("GEAR_SHIFTER", gearbox_msg),
("GEAR", gearbox_msg),
("PEDAL_GAS", "POWERTRAIN_DATA"), ("PEDAL_GAS", "POWERTRAIN_DATA"),
("CRUISE_SETTING", "SCM_BUTTONS"), ("CRUISE_SETTING", "SCM_BUTTONS"),
("ACC_STATUS", "POWERTRAIN_DATA"), ("ACC_STATUS", "POWERTRAIN_DATA"),
@ -48,6 +49,7 @@ def get_can_signals(CP, gearbox_msg, main_on_sig_msg):
("SEATBELT_STATUS", 10), ("SEATBELT_STATUS", 10),
("CRUISE", 10), ("CRUISE", 10),
("POWERTRAIN_DATA", 100), ("POWERTRAIN_DATA", 100),
("CAR_SPEED", 10),
("VSA_STATUS", 50), ("VSA_STATUS", 50),
("STEER_STATUS", 100), ("STEER_STATUS", 100),
("STEER_MOTOR_TORQUE", 0), # TODO: not on every car ("STEER_MOTOR_TORQUE", 0), # TODO: not on every car
@ -73,16 +75,11 @@ def get_can_signals(CP, gearbox_msg, main_on_sig_msg):
signals.append(("BRAKE_PRESSED", "BRAKE_MODULE")) signals.append(("BRAKE_PRESSED", "BRAKE_MODULE"))
checks.append(("BRAKE_MODULE", 50)) checks.append(("BRAKE_MODULE", 50))
if CP.carFingerprint in HONDA_BOSCH: if CP.carFingerprint in (HONDA_BOSCH | {CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN}):
signals += [ signals.append(("EPB_STATE", "EPB_STATUS"))
("EPB_STATE", "EPB_STATUS"), checks.append(("EPB_STATUS", 50))
("IMPERIAL_UNIT", "CAR_SPEED"),
]
checks += [
("EPB_STATUS", 50),
("CAR_SPEED", 10),
]
if CP.carFingerprint in HONDA_BOSCH:
if not CP.openpilotLongitudinalControl: if not CP.openpilotLongitudinalControl:
signals += [ signals += [
("CRUISE_CONTROL_LABEL", "ACC_HUD"), ("CRUISE_CONTROL_LABEL", "ACC_HUD"),
@ -121,17 +118,6 @@ def get_can_signals(CP, gearbox_msg, main_on_sig_msg):
("STANDSTILL", 50), ("STANDSTILL", 50),
] ]
if CP.carFingerprint == CAR.CIVIC:
signals += [("IMPERIAL_UNIT", "HUD_SETTING"),
("EPB_STATE", "EPB_STATUS")]
checks += [
("HUD_SETTING", 50),
("EPB_STATUS", 50),
]
elif CP.carFingerprint in (CAR.ODYSSEY, CAR.ODYSSEY_CHN):
signals.append(("EPB_STATE", "EPB_STATUS"))
checks.append(("EPB_STATUS", 50))
# add gas interceptor reading if we are using it # add gas interceptor reading if we are using it
if CP.enableGasInterceptor: if CP.enableGasInterceptor:
signals.append(("INTERCEPTOR_GAS", "GAS_SENSOR")) signals.append(("INTERCEPTOR_GAS", "GAS_SENSOR"))
@ -179,6 +165,11 @@ class CarState(CarStateBase):
# update prevs, update must run once per loop # update prevs, update must run once per loop
self.prev_cruise_buttons = self.cruise_buttons self.prev_cruise_buttons = self.cruise_buttons
self.prev_cruise_setting = self.cruise_setting self.prev_cruise_setting = self.cruise_setting
self.cruise_setting = cp.vl["SCM_BUTTONS"]["CRUISE_SETTING"]
self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"]
# used for car hud message
self.is_metric = not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
# ******************* parse out can ******************* # ******************* parse out can *******************
# STANDSTILL->WHEELS_MOVING bit can be noisy around zero, so use XMISSION_SPEED # STANDSTILL->WHEELS_MOVING bit can be noisy around zero, so use XMISSION_SPEED
@ -219,16 +210,12 @@ class CarState(CarStateBase):
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE"] ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE"]
ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE_RATE"] ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE_RATE"]
self.cruise_setting = cp.vl["SCM_BUTTONS"]["CRUISE_SETTING"]
self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"]
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_stalk( ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_stalk(
250, cp.vl["SCM_FEEDBACK"]["LEFT_BLINKER"], cp.vl["SCM_FEEDBACK"]["RIGHT_BLINKER"]) 250, cp.vl["SCM_FEEDBACK"]["LEFT_BLINKER"], cp.vl["SCM_FEEDBACK"]["RIGHT_BLINKER"])
ret.brakeHoldActive = cp.vl["VSA_STATUS"]["BRAKE_HOLD_ACTIVE"] == 1 ret.brakeHoldActive = cp.vl["VSA_STATUS"]["BRAKE_HOLD_ACTIVE"] == 1
# TODO: set for all cars # TODO: set for all cars
if self.CP.carFingerprint in (CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN, CAR.CRV_5G, CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, if self.CP.carFingerprint in (HONDA_BOSCH | {CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN}):
CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
ret.parkingBrake = cp.vl["EPB_STATUS"]["EPB_STATE"] != 0 ret.parkingBrake = cp.vl["EPB_STATUS"]["EPB_STATE"] != 0
gear = int(cp.vl[self.gearbox_msg]["GEAR_SHIFTER"]) gear = int(cp.vl[self.gearbox_msg]["GEAR_SHIFTER"])
@ -281,14 +268,6 @@ class CarState(CarStateBase):
if ret.brake > 0.1: if ret.brake > 0.1:
ret.brakePressed = True ret.brakePressed = True
# TODO: discover the CAN msg that has the imperial unit bit for all other cars
if self.CP.carFingerprint in (CAR.CIVIC, ):
self.is_metric = not cp.vl["HUD_SETTING"]["IMPERIAL_UNIT"]
elif self.CP.carFingerprint in HONDA_BOSCH:
self.is_metric = not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
else:
self.is_metric = False
if self.CP.carFingerprint in HONDA_BOSCH: if self.CP.carFingerprint in HONDA_BOSCH:
ret.stockAeb = (not self.CP.openpilotLongitudinalControl) and bool(cp.vl["ACC_CONTROL"]["AEB_STATUS"] and cp.vl["ACC_CONTROL"]["ACCEL_COMMAND"] < -1e-5) ret.stockAeb = (not self.CP.openpilotLongitudinalControl) and bool(cp.vl["ACC_CONTROL"]["AEB_STATUS"] and cp.vl["ACC_CONTROL"]["ACCEL_COMMAND"] < -1e-5)
else: else:

@ -98,47 +98,40 @@ def create_bosch_supplemental_1(packer, car_fingerprint, idx):
return packer.make_can_msg("BOSCH_SUPPLEMENTAL_1", bus, values, idx) return packer.make_can_msg("BOSCH_SUPPLEMENTAL_1", bus, values, idx)
def create_ui_commands(packer, CP, pcm_speed, hud, is_metric, idx, stock_hud): def create_ui_commands(packer, CP, enabled, pcm_speed, hud, is_metric, idx, stock_hud):
commands = [] commands = []
bus_pt = get_pt_bus(CP.carFingerprint) bus_pt = get_pt_bus(CP.carFingerprint)
radar_disabled = CP.carFingerprint in HONDA_BOSCH and CP.openpilotLongitudinalControl radar_disabled = CP.carFingerprint in HONDA_BOSCH and CP.openpilotLongitudinalControl
bus_lkas = get_lkas_cmd_bus(CP.carFingerprint, radar_disabled) bus_lkas = get_lkas_cmd_bus(CP.carFingerprint, radar_disabled)
if CP.openpilotLongitudinalControl: if CP.openpilotLongitudinalControl:
if CP.carFingerprint in HONDA_BOSCH:
acc_hud_values = {
'CRUISE_SPEED': hud.v_cruise,
'ENABLE_MINI_CAR': 1,
'SET_TO_1': 1,
'HUD_LEAD': hud.car,
'HUD_DISTANCE': 3,
'ACC_ON': hud.car != 0,
'SET_TO_X1': 1,
'IMPERIAL_UNIT': int(not is_metric),
'FCM_OFF': 1,
}
else:
acc_hud_values = { acc_hud_values = {
'PCM_SPEED': pcm_speed * CV.MS_TO_KPH,
'PCM_GAS': hud.pcm_accel,
'CRUISE_SPEED': hud.v_cruise, 'CRUISE_SPEED': hud.v_cruise,
'ENABLE_MINI_CAR': 1, 'ENABLE_MINI_CAR': 1,
'HUD_LEAD': hud.car,
'HUD_DISTANCE': 3, # max distance setting on display 'HUD_DISTANCE': 3, # max distance setting on display
'IMPERIAL_UNIT': int(not is_metric), 'IMPERIAL_UNIT': int(not is_metric),
'HUD_LEAD': 2 if enabled and hud.lead_visible else 1 if enabled else 0,
'SET_ME_X01_2': 1, 'SET_ME_X01_2': 1,
'SET_ME_X01': 1,
"FCM_OFF": stock_hud["FCM_OFF"],
"FCM_OFF_2": stock_hud["FCM_OFF_2"],
"FCM_PROBLEM": stock_hud["FCM_PROBLEM"],
"ICONS": stock_hud["ICONS"],
} }
if CP.carFingerprint in HONDA_BOSCH:
acc_hud_values['ACC_ON'] = int(enabled)
acc_hud_values['FCM_OFF'] = 1
acc_hud_values['FCM_OFF_2'] = 1
else:
acc_hud_values['PCM_SPEED'] = pcm_speed * CV.MS_TO_KPH
acc_hud_values['PCM_GAS'] = hud.pcm_accel
acc_hud_values['SET_ME_X01'] = 1
acc_hud_values['FCM_OFF'] = stock_hud['FCM_OFF']
acc_hud_values['FCM_OFF_2'] = stock_hud['FCM_OFF_2']
acc_hud_values['FCM_PROBLEM'] = stock_hud['FCM_PROBLEM']
acc_hud_values['ICONS'] = stock_hud['ICONS']
commands.append(packer.make_can_msg("ACC_HUD", bus_pt, acc_hud_values, idx)) commands.append(packer.make_can_msg("ACC_HUD", bus_pt, acc_hud_values, idx))
lkas_hud_values = { lkas_hud_values = {
'SET_ME_X41': 0x41, 'SET_ME_X41': 0x41,
'STEERING_REQUIRED': hud.steer_required, 'STEERING_REQUIRED': hud.steer_required,
'SOLID_LANES': hud.lanes, 'SOLID_LANES': hud.lanes_visible,
'BEEP': 0, 'BEEP': 0,
} }

@ -100,7 +100,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 8000], [0, 2560, 3840]] ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 8000], [0, 2560, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.1]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.1]]
else: else:
ret.maxLateralAccel = 1.7
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]] ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[1.1], [0.33]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[1.1], [0.33]]
tire_stiffness_factor = 1. tire_stiffness_factor = 1.
@ -113,7 +112,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 15.38 # 10.93 is end-to-end spec ret.steerRatio = 15.38 # 10.93 is end-to-end spec
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
tire_stiffness_factor = 1. tire_stiffness_factor = 1.
ret.maxLateralAccel = 1.6
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
elif candidate in (CAR.ACCORD, CAR.ACCORDH): elif candidate in (CAR.ACCORD, CAR.ACCORDH):
@ -128,7 +126,6 @@ class CarInterface(CarInterfaceBase):
if eps_modified: if eps_modified:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.09]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.09]]
else: else:
ret.maxLateralAccel = 1.6
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
elif candidate == CAR.ACURA_ILX: elif candidate == CAR.ACURA_ILX:
@ -165,7 +162,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 10000], [0, 2560, 3840]] ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 10000], [0, 2560, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.21], [0.07]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.21], [0.07]]
else: else:
ret.maxLateralAccel = 1.7
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.64], [0.192]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.64], [0.192]]
tire_stiffness_factor = 0.677 tire_stiffness_factor = 0.677
@ -190,7 +186,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.06 ret.steerRatio = 13.06
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
tire_stiffness_factor = 0.75 tire_stiffness_factor = 0.75
ret.maxLateralAccel = 1.7
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.05]]
elif candidate == CAR.FREED: elif candidate == CAR.FREED:
@ -222,7 +217,6 @@ class CarInterface(CarInterfaceBase):
ret.centerToFront = ret.wheelbase * 0.38 ret.centerToFront = ret.wheelbase * 0.38
ret.steerRatio = 15.0 # as spec ret.steerRatio = 15.0 # as spec
tire_stiffness_factor = 0.444 tire_stiffness_factor = 0.444
ret.maxLateralAccel = 0.9
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 1000], [0, 1000]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 1000], [0, 1000]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
@ -232,7 +226,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.75 ret.wheelbase = 2.75
ret.centerToFront = ret.wheelbase * 0.41 ret.centerToFront = ret.wheelbase * 0.41
ret.steerRatio = 11.95 # as spec ret.steerRatio = 11.95 # as spec
ret.maxLateralAccel = 1.2
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.06]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.06]]
tire_stiffness_factor = 0.677 tire_stiffness_factor = 0.677
@ -245,7 +238,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.35 # as spec ret.steerRatio = 14.35 # as spec
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
tire_stiffness_factor = 0.82 tire_stiffness_factor = 0.82
ret.maxLateralAccel = 1.5
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]]
elif candidate == CAR.ODYSSEY_CHN: elif candidate == CAR.ODYSSEY_CHN:
@ -266,7 +258,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 17.25 # as spec ret.steerRatio = 17.25 # as spec
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
tire_stiffness_factor = 0.444 tire_stiffness_factor = 0.444
ret.maxLateralAccel = 1.5
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]]
elif candidate == CAR.RIDGELINE: elif candidate == CAR.RIDGELINE:
@ -277,7 +268,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 15.59 # as spec ret.steerRatio = 15.59 # as spec
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
tire_stiffness_factor = 0.444 tire_stiffness_factor = 0.444
ret.maxLateralAccel = 1.3
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]]
elif candidate == CAR.INSIGHT: elif candidate == CAR.INSIGHT:
@ -288,7 +278,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 15.0 # 12.58 is spec end-to-end ret.steerRatio = 15.0 # 12.58 is spec end-to-end
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
tire_stiffness_factor = 0.82 tire_stiffness_factor = 0.82
ret.maxLateralAccel = 1.4
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
elif candidate == CAR.HONDA_E: elif candidate == CAR.HONDA_E:
@ -330,7 +319,6 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor=tire_stiffness_factor) tire_stiffness_factor=tire_stiffness_factor)
ret.steerActuatorDelay = 0.1 ret.steerActuatorDelay = 0.1
ret.steerRateCost = 0.5
ret.steerLimitTimer = 0.8 ret.steerLimitTimer = 0.8
return ret return ret

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os
from cereal import car from cereal import car
from panda import Panda from panda import Panda
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
@ -37,10 +38,11 @@ class CarInterface(CarInterfaceBase):
# These cars have been put into dashcam only due to both a lack of users and test coverage. # These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is # These cars likely still work fine. Once a user confirms each car works and a test route is
# added to selfdrive/car/tests/routes.py, we can remove it from this list. # added to selfdrive/car/tests/routes.py, we can remove it from this list.
ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, CAR.ELANTRA_GT_I30} or candidate in HDA2_CAR ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, CAR.ELANTRA_GT_I30}
if candidate in HDA2_CAR:
ret.dashcamOnly = not os.path.exists('/data/enable-ev6')
ret.steerActuatorDelay = 0.1 # Default delay ret.steerActuatorDelay = 0.1 # Default delay
ret.steerRateCost = 0.5
ret.steerLimitTimer = 0.4 ret.steerLimitTimer = 0.4
tire_stiffness_factor = 1. tire_stiffness_factor = 1.
@ -52,7 +54,7 @@ class CarInterface(CarInterfaceBase):
ret.stopAccel = 0.0 ret.stopAccel = 0.0
ret.longitudinalActuatorDelayUpperBound = 1.0 # s ret.longitudinalActuatorDelayUpperBound = 1.0 # s
torque_params = CarInterfaceBase.get_torque_params(candidate)
if candidate in (CAR.SANTA_FE, CAR.SANTA_FE_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022): if candidate in (CAR.SANTA_FE, CAR.SANTA_FE_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022):
ret.lateralTuning.pid.kf = 0.00005 ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3982. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3982. * CV.LB_TO_KG + STD_CARGO_KG
@ -60,24 +62,19 @@ class CarInterface(CarInterfaceBase):
# Values from optimizer # Values from optimizer
ret.steerRatio = 16.55 # 13.8 is spec end-to-end ret.steerRatio = 16.55 # 13.8 is spec end-to-end
tire_stiffness_factor = 0.82 tire_stiffness_factor = 0.82
ret.maxLateralAccel = 3.2
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[9., 22.], [9., 22.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[9., 22.], [9., 22.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2, 0.35], [0.05, 0.09]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2, 0.35], [0.05, 0.09]]
elif candidate in (CAR.SONATA, CAR.SONATA_HYBRID): elif candidate in (CAR.SONATA, CAR.SONATA_HYBRID):
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1513. + STD_CARGO_KG ret.mass = 1513. + STD_CARGO_KG
ret.wheelbase = 2.84 ret.wheelbase = 2.84
ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable
tire_stiffness_factor = 0.65 tire_stiffness_factor = 0.65
ret.maxLateralAccel = 2.5 set_torque_tune(ret.lateralTuning, torque_params['LAT_ACCEL_FACTOR'], torque_params['FRICTION'])
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.SONATA_LF: elif candidate == CAR.SONATA_LF:
ret.lateralTuning.pid.kf = 0.00005 ret.lateralTuning.pid.kf = 0.00005
ret.mass = 4497. * CV.LB_TO_KG ret.mass = 4497. * CV.LB_TO_KG
ret.wheelbase = 2.804 ret.wheelbase = 2.804
ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable
ret.maxLateralAccel = 1.8
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.PALISADE: elif candidate == CAR.PALISADE:
@ -86,7 +83,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.90 ret.wheelbase = 2.90
ret.steerRatio = 15.6 * 1.15 ret.steerRatio = 15.6 * 1.15
tire_stiffness_factor = 0.63 tire_stiffness_factor = 0.63
ret.maxLateralAccel = 2.5
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.05]]
elif candidate in (CAR.ELANTRA, CAR.ELANTRA_GT_I30): elif candidate in (CAR.ELANTRA, CAR.ELANTRA_GT_I30):
@ -99,21 +95,17 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
ret.minSteerSpeed = 32 * CV.MPH_TO_MS ret.minSteerSpeed = 32 * CV.MPH_TO_MS
elif candidate == CAR.ELANTRA_2021: elif candidate == CAR.ELANTRA_2021:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = (2800. * CV.LB_TO_KG) + STD_CARGO_KG ret.mass = (2800. * CV.LB_TO_KG) + STD_CARGO_KG
ret.wheelbase = 2.72 ret.wheelbase = 2.72
ret.steerRatio = 12.9 ret.steerRatio = 12.9
tire_stiffness_factor = 0.65 tire_stiffness_factor = 0.65
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] set_torque_tune(ret.lateralTuning, torque_params['LAT_ACCEL_FACTOR'], torque_params['FRICTION'])
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.ELANTRA_HEV_2021: elif candidate == CAR.ELANTRA_HEV_2021:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = (3017. * CV.LB_TO_KG) + STD_CARGO_KG ret.mass = (3017. * CV.LB_TO_KG) + STD_CARGO_KG
ret.wheelbase = 2.72 ret.wheelbase = 2.72
ret.steerRatio = 12.9 ret.steerRatio = 12.9
tire_stiffness_factor = 0.65 tire_stiffness_factor = 0.65
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] set_torque_tune(ret.lateralTuning, torque_params['LAT_ACCEL_FACTOR'], torque_params['FRICTION'])
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.HYUNDAI_GENESIS: elif candidate == CAR.HYUNDAI_GENESIS:
ret.lateralTuning.pid.kf = 0.00005 ret.lateralTuning.pid.kf = 0.00005
ret.mass = 2060. + STD_CARGO_KG ret.mass = 2060. + STD_CARGO_KG
@ -143,7 +135,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.7 ret.wheelbase = 2.7
ret.steerRatio = 13.73 # Spec ret.steerRatio = 13.73 # Spec
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
ret.maxLateralAccel = 3.0
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
if candidate not in (CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022): if candidate not in (CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022):
@ -170,9 +161,9 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 0.5 tire_stiffness_factor = 0.5
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.TUCSON_DIESEL_2019: elif candidate == CAR.TUCSON:
ret.lateralTuning.pid.kf = 0.00005 ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3633. * CV.LB_TO_KG ret.mass = 3520. * CV.LB_TO_KG
ret.wheelbase = 2.67 ret.wheelbase = 2.67
ret.steerRatio = 14.00 * 1.15 ret.steerRatio = 14.00 * 1.15
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
@ -193,7 +184,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.7 ret.wheelbase = 2.7
ret.steerRatio = 13.9 if CAR.KIA_NIRO_HEV_2021 else 13.73 # Spec ret.steerRatio = 13.9 if CAR.KIA_NIRO_HEV_2021 else 13.73 # Spec
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
ret.maxLateralAccel = 2.9
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
if candidate == CAR.KIA_NIRO_HEV: if candidate == CAR.KIA_NIRO_HEV:
@ -213,19 +203,17 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.indi.actuatorEffectivenessBP = [0.] ret.lateralTuning.indi.actuatorEffectivenessBP = [0.]
ret.lateralTuning.indi.actuatorEffectivenessV = [1.8] ret.lateralTuning.indi.actuatorEffectivenessV = [1.8]
elif candidate in (CAR.KIA_OPTIMA, CAR.KIA_OPTIMA_H): elif candidate in (CAR.KIA_OPTIMA, CAR.KIA_OPTIMA_H):
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3558. * CV.LB_TO_KG ret.mass = 3558. * CV.LB_TO_KG
ret.wheelbase = 2.80 ret.wheelbase = 2.80
ret.steerRatio = 13.75 ret.steerRatio = 13.75
tire_stiffness_factor = 0.5 tire_stiffness_factor = 0.5
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] torque_params = CarInterfaceBase.get_torque_params(CAR.KIA_OPTIMA)
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] set_torque_tune(ret.lateralTuning, torque_params['LAT_ACCEL_FACTOR'], torque_params['FRICTION'])
elif candidate == CAR.KIA_STINGER: elif candidate == CAR.KIA_STINGER:
ret.lateralTuning.pid.kf = 0.00005 ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1825. + STD_CARGO_KG ret.mass = 1825. + STD_CARGO_KG
ret.wheelbase = 2.78 ret.wheelbase = 2.78
ret.steerRatio = 14.4 * 1.15 # 15% higher at the center seems reasonable ret.steerRatio = 14.4 * 1.15 # 15% higher at the center seems reasonable
ret.maxLateralAccel = 2.4
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.KIA_FORTE: elif candidate == CAR.KIA_FORTE:
@ -251,7 +239,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.85 ret.wheelbase = 2.85
ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims) ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims)
tire_stiffness_factor = 0.5 tire_stiffness_factor = 0.5
ret.maxLateralAccel = 2.1
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.KIA_EV6: elif candidate == CAR.KIA_EV6:
@ -263,7 +250,8 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 0.65 tire_stiffness_factor = 0.65
ret.maxLateralAccel = 2. ret.maxLateralAccel = 2.
set_torque_tune(ret.lateralTuning, ret.maxLateralAccel, 0.01) # TODO override until there is more data
set_torque_tune(ret.lateralTuning, 2.0, 0.05)
# Genesis # Genesis
elif candidate == CAR.GENESIS_G70: elif candidate == CAR.GENESIS_G70:

@ -52,7 +52,7 @@ class CAR:
SANTA_FE_PHEV_2022 = "HYUNDAI SANTA FE PlUG-IN HYBRID 2022" SANTA_FE_PHEV_2022 = "HYUNDAI SANTA FE PlUG-IN HYBRID 2022"
SONATA = "HYUNDAI SONATA 2020" SONATA = "HYUNDAI SONATA 2020"
SONATA_LF = "HYUNDAI SONATA 2019" SONATA_LF = "HYUNDAI SONATA 2019"
TUCSON_DIESEL_2019 = "HYUNDAI TUCSON DIESEL 2019" TUCSON = "HYUNDAI TUCSON 2019"
PALISADE = "HYUNDAI PALISADE 2020" PALISADE = "HYUNDAI PALISADE 2020"
VELOSTER = "HYUNDAI VELOSTER 2019" VELOSTER = "HYUNDAI VELOSTER 2019"
SONATA_HYBRID = "HYUNDAI SONATA HYBRID 2021" SONATA_HYBRID = "HYUNDAI SONATA HYBRID 2021"
@ -80,6 +80,8 @@ class CAR:
@dataclass @dataclass
class HyundaiCarInfo(CarInfo): class HyundaiCarInfo(CarInfo):
# TODO: we can probably remove LKAS. LKAS is standard on many
# HKG and for others, it's likely packaged together with SCC
package: str = "SCC + LKAS" package: str = "SCC + LKAS"
good_torque: bool = True good_torque: bool = True
@ -105,7 +107,10 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", harness=Harness.hyundai_l), CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", harness=Harness.hyundai_l),
CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-22", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw", harness=Harness.hyundai_a), CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-22", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw", harness=Harness.hyundai_a),
CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", harness=Harness.hyundai_e), CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", harness=Harness.hyundai_e),
CAR.TUCSON_DIESEL_2019: HyundaiCarInfo("Hyundai Tucson Diesel 2019", harness=Harness.hyundai_l), CAR.TUCSON: [
HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_l),
HyundaiCarInfo("Hyundai Tucson Diesel 2019", harness=Harness.hyundai_l),
],
CAR.PALISADE: [ CAR.PALISADE: [
HyundaiCarInfo("Hyundai Palisade 2020-21", "All", video_link="https://youtu.be/TAnDqjF4fDY?t=456", harness=Harness.hyundai_h), HyundaiCarInfo("Hyundai Palisade 2020-21", "All", video_link="https://youtu.be/TAnDqjF4fDY?t=456", harness=Harness.hyundai_h),
HyundaiCarInfo("Kia Telluride 2020", harness=Harness.hyundai_h), HyundaiCarInfo("Kia Telluride 2020", harness=Harness.hyundai_h),
@ -118,7 +123,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
HyundaiCarInfo("Kia Forte 2018", harness=Harness.hyundai_b), HyundaiCarInfo("Kia Forte 2018", harness=Harness.hyundai_b),
HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g), HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g),
], ],
CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", "SCC + LFA", harness=Harness.hyundai_a), CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", "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-20", "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),
@ -498,6 +503,7 @@ FW_VERSIONS = {
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00LFF LKAS AT USA LHD 1.00 1.01 95740-C1000 E51', b'\xf1\x00LFF LKAS AT USA LHD 1.00 1.01 95740-C1000 E51',
b'\xf1\x00LFF LKAS AT USA LHD 1.01 1.02 95740-C1000 E52',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x006T6H0_C2\x00\x006T6B4051\x00\x00TLF0G24NL1\xb0\x9f\xee\xf5', b'\xf1\x006T6H0_C2\x00\x006T6B4051\x00\x00TLF0G24NL1\xb0\x9f\xee\xf5',
@ -506,20 +512,25 @@ FW_VERSIONS = {
b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6B4051\x00\x00\xf1\x006T6H0_C2\x00\x006T6B4051\x00\x00TLF0G24SL2n\x8d\xbe\xd8', b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6B4051\x00\x00\xf1\x006T6H0_C2\x00\x006T6B4051\x00\x00TLF0G24SL2n\x8d\xbe\xd8',
b'\xf1\x87LAHSGN012918KF10\x98\x88x\x87\x88\x88x\x87\x88\x88\x98\x88\x87w\x88w\x88\x88\x98\x886o\xf6\xff\x98w\x7f\xff3\x00\xf1\x816W3B1051\x00\x00\xf1\x006W351_C2\x00\x006W3B1051\x00\x00TLF0T20NL2\x00\x00\x00\x00', b'\xf1\x87LAHSGN012918KF10\x98\x88x\x87\x88\x88x\x87\x88\x88\x98\x88\x87w\x88w\x88\x88\x98\x886o\xf6\xff\x98w\x7f\xff3\x00\xf1\x816W3B1051\x00\x00\xf1\x006W351_C2\x00\x006W3B1051\x00\x00TLF0T20NL2\x00\x00\x00\x00',
b'\xf1\x87LAHSGN012918KF10\x98\x88x\x87\x88\x88x\x87\x88\x88\x98\x88\x87w\x88w\x88\x88\x98\x886o\xf6\xff\x98w\x7f\xff3\x00\xf1\x816W3B1051\x00\x00\xf1\x006W351_C2\x00\x006W3B1051\x00\x00TLF0T20NL2H\r\xbdm', b'\xf1\x87LAHSGN012918KF10\x98\x88x\x87\x88\x88x\x87\x88\x88\x98\x88\x87w\x88w\x88\x88\x98\x886o\xf6\xff\x98w\x7f\xff3\x00\xf1\x816W3B1051\x00\x00\xf1\x006W351_C2\x00\x006W3B1051\x00\x00TLF0T20NL2H\r\xbdm',
b'\xf1\x87LAJSG49645724HF0\x87x\x87\x88\x87www\x88\x99\xa8\x89\x88\x99\xa8\x89\x88\x99\xa8\x89S_\xfb\xff\x87f\x7f\xff^2\xf1\x816W3B1051\x00\x00\xf1\x006W351_C2\x00\x006W3B1051\x00\x00TLF0T20NL2H\r\xbdm',
], ],
}, },
CAR.TUCSON_DIESEL_2019: { CAR.TUCSON: {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00TL__ FCA F-CUP 1.00 1.01 99110-D3500 ', b'\xf1\x00TL__ FCA F-CUP 1.00 1.01 99110-D3500 ',
b'\xf1\x00TL__ FCA F-CUP 1.00 1.02 99110-D3510 ',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xf1\x8971TLC2NAIDDIR002\xf1\x8271TLC2NAIDDIR002', b'\xf1\x8971TLC2NAIDDIR002\xf1\x8271TLC2NAIDDIR002',
b'\xf1\x81606G3051\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00TL MFC AT KOR LHD 1.00 1.02 95895-D3800 180719', b'\xf1\x00TL MFC AT KOR LHD 1.00 1.02 95895-D3800 180719',
b'\xf1\x00TL MFC AT USA LHD 1.00 1.06 95895-D3800 190107',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x87LBJXAN202299KF22\x87x\x87\x88ww\x87xx\x88\x97\x88\x87\x88\x98x\x88\x99\x98\x89\x87o\xf6\xff\x87w\x7f\xff\x12\x9a\xf1\x81U083\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U083\x00\x00\x00\x00\x00\x00TTL2V20KL1\x8fRn\x8a', b'\xf1\x87LBJXAN202299KF22\x87x\x87\x88ww\x87xx\x88\x97\x88\x87\x88\x98x\x88\x99\x98\x89\x87o\xf6\xff\x87w\x7f\xff\x12\x9a\xf1\x81U083\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U083\x00\x00\x00\x00\x00\x00TTL2V20KL1\x8fRn\x8a',
b'\xf1\x87KMLDCU585233TJ20wx\x87\x88x\x88\x98\x89vfwfwwww\x87f\x9f\xff\x98\xff\x7f\xf9\xf7s\xf1\x816T6G4051\x00\x00\xf1\x006T6J0_C2\x00\x006T6G4051\x00\x00TTL4G24NH2\x00\x00\x00\x00',
], ],
}, },
CAR.SANTA_FE: { CAR.SANTA_FE: {
@ -845,7 +856,7 @@ FW_VERSIONS = {
}, },
CAR.KIA_CEED: { CAR.KIA_CEED: {
(Ecu.fwdRadar, 0x7D0, None): [b'\xf1\000CD__ SCC F-CUP 1.00 1.02 99110-J7000 ', ], (Ecu.fwdRadar, 0x7D0, None): [b'\xf1\000CD__ SCC F-CUP 1.00 1.02 99110-J7000 ', ],
(Ecu.esp, 0x7D4, None): [b'\xf1\000CD MDPS C 1.00 1.06 56310-XX000 4CDEC106', ], (Ecu.eps, 0x7D4, None): [b'\xf1\000CD MDPS C 1.00 1.06 56310-XX000 4CDEC106', ],
(Ecu.fwdCamera, 0x7C4, None): [b'\xf1\000CD LKAS AT EUR LHD 1.00 1.01 99211-J7000 B40', ], (Ecu.fwdCamera, 0x7C4, None): [b'\xf1\000CD LKAS AT EUR LHD 1.00 1.01 99211-J7000 B40', ],
(Ecu.engine, 0x7E0, None): [b'\001TCD-JECU4F202H0K', ], (Ecu.engine, 0x7E0, None): [b'\001TCD-JECU4F202H0K', ],
(Ecu.transmission, 0x7E1, None): [ (Ecu.transmission, 0x7E1, None): [
@ -1198,11 +1209,11 @@ CHECKSUM = {
FEATURES = { FEATURES = {
# which message has the gear # which message has the gear
"use_cluster_gears": {CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA}, "use_cluster_gears": {CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA},
"use_tcu_gears": {CAR.KIA_OPTIMA, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON_DIESEL_2019}, "use_tcu_gears": {CAR.KIA_OPTIMA, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON},
"use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019}, "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019},
# these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12
"use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.ELANTRA_GT_I30, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON_DIESEL_2019}, "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.ELANTRA_GT_I30, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON},
} }
HDA2_CAR = {CAR.KIA_EV6, } HDA2_CAR = {CAR.KIA_EV6, }
@ -1250,7 +1261,7 @@ DBC = {
CAR.SANTA_FE_PHEV_2022: dbc_dict('hyundai_kia_generic', None), CAR.SANTA_FE_PHEV_2022: dbc_dict('hyundai_kia_generic', None),
CAR.SONATA: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'), CAR.SONATA: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),
CAR.SONATA_LF: dbc_dict('hyundai_kia_generic', None), # Has 0x5XX messages, but different format CAR.SONATA_LF: dbc_dict('hyundai_kia_generic', None), # Has 0x5XX messages, but different format
CAR.TUCSON_DIESEL_2019: dbc_dict('hyundai_kia_generic', None), CAR.TUCSON: dbc_dict('hyundai_kia_generic', None),
CAR.PALISADE: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'), CAR.PALISADE: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),
CAR.VELOSTER: dbc_dict('hyundai_kia_generic', None), CAR.VELOSTER: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_CEED: dbc_dict('hyundai_kia_generic', None), CAR.KIA_CEED: dbc_dict('hyundai_kia_generic', None),

@ -1,3 +1,4 @@
import json
import os import os
import time import time
from abc import abstractmethod, ABC from abc import abstractmethod, ABC
@ -19,6 +20,7 @@ EventName = car.CarEvent.EventName
MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS
ACCEL_MAX = 2.0 ACCEL_MAX = 2.0
ACCEL_MIN = -3.5 ACCEL_MIN = -3.5
TORQUE_PARAMS_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data.json')
# generic car and radar interfaces # generic car and radar interfaces
@ -81,7 +83,7 @@ class CarInterfaceBase(ABC):
ret.steerControlType = car.CarParams.SteerControlType.torque ret.steerControlType = car.CarParams.SteerControlType.torque
ret.minSteerSpeed = 0. ret.minSteerSpeed = 0.
ret.wheelSpeedFactor = 1.0 ret.wheelSpeedFactor = 1.0
ret.maxLateralAccel = float('nan') ret.maxLateralAccel = CarInterfaceBase.get_torque_params(candidate)['MAX_LAT_ACCEL_MEASURED']
ret.pcmCruise = True # openpilot's state is tied to the PCM's cruise state on most cars ret.pcmCruise = True # openpilot's state is tied to the PCM's cruise state on most cars
ret.minEnableSpeed = -1. # enable is done by stock ACC, so ignore this ret.minEnableSpeed = -1. # enable is done by stock ACC, so ignore this
@ -105,6 +107,12 @@ class CarInterfaceBase(ABC):
ret.steerLimitTimer = 1.0 ret.steerLimitTimer = 1.0
return ret return ret
@staticmethod
def get_torque_params(candidate, default=float('NaN')):
with open(TORQUE_PARAMS_PATH) as f:
data = json.load(f)
return {key: data[key].get(candidate, default) for key in data}
@abstractmethod @abstractmethod
def _update(self, c: car.CarControl) -> car.CarState: def _update(self, c: car.CarControl) -> car.CarState:
pass pass

@ -4,13 +4,13 @@ from functools import partial
from typing import Optional from typing import Optional
import cereal.messaging as messaging import cereal.messaging as messaging
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
from selfdrive.boardd.boardd import can_list_to_can_capnp from selfdrive.boardd.boardd import can_list_to_can_capnp
from panda.python.uds import CanClient, IsoTpMessage, FUNCTIONAL_ADDRS, get_rx_addr_for_tx_addr from panda.python.uds import CanClient, IsoTpMessage, FUNCTIONAL_ADDRS, get_rx_addr_for_tx_addr
class IsoTpParallelQuery: class IsoTpParallelQuery:
def __init__(self, sendcan, logcan, bus, addrs, request, response, response_offset=0x8, functional_addr=False, debug=False): def __init__(self, sendcan, logcan, bus, addrs, request, response, response_offset=0x8, functional_addr=False, debug=False, response_pending_timeout=10):
self.sendcan = sendcan self.sendcan = sendcan
self.logcan = logcan self.logcan = logcan
self.bus = bus self.bus = bus
@ -18,6 +18,7 @@ class IsoTpParallelQuery:
self.response = response self.response = response
self.debug = debug self.debug = debug
self.functional_addr = functional_addr self.functional_addr = functional_addr
self.response_pending_timeout = response_pending_timeout
self.real_addrs = [] self.real_addrs = []
for a in addrs: for a in addrs:
@ -71,10 +72,7 @@ class IsoTpParallelQuery:
messaging.drain_sock(self.logcan) messaging.drain_sock(self.logcan)
self.msg_buffer = defaultdict(list) self.msg_buffer = defaultdict(list)
def get_data(self, timeout, total_timeout=None): def get_data(self, timeout, total_timeout=60.):
if total_timeout is None:
total_timeout = 10 * timeout
self._drain_rx() self._drain_rx()
# Create message objects # Create message objects
@ -100,7 +98,7 @@ class IsoTpParallelQuery:
results = {} results = {}
start_time = time.monotonic() start_time = time.monotonic()
last_response_time = start_time response_timeouts = {tx_addr: start_time + timeout for tx_addr in self.msg_addrs}
while True: while True:
self.rx() self.rx()
@ -123,21 +121,27 @@ class IsoTpParallelQuery:
response_valid = dat[:len(expected_response)] == expected_response response_valid = dat[:len(expected_response)] == expected_response
if response_valid: if response_valid:
last_response_time = time.monotonic() response_timeouts[tx_addr] = time.monotonic() + timeout
if counter + 1 < len(self.request): if counter + 1 < len(self.request):
msg.send(self.request[counter + 1]) msg.send(self.request[counter + 1])
request_counter[tx_addr] += 1 request_counter[tx_addr] += 1
else: else:
results[tx_addr] = dat[len(expected_response):] results[tx_addr] = dat[len(expected_response):]
request_done[tx_addr] = True request_done[tx_addr] = True
else:
error_code = dat[2] if len(dat) > 2 else -1
if error_code == 0x78:
response_timeouts[tx_addr] = time.monotonic() + self.response_pending_timeout
if self.debug:
cloudlog.warning(f"iso-tp query response pending: {tx_addr}")
else: else:
request_done[tx_addr] = True request_done[tx_addr] = True
cloudlog.warning(f"iso-tp query bad response: {tx_addr} - 0x{dat.hex()}") cloudlog.warning(f"iso-tp query bad response: {tx_addr} - 0x{dat.hex()}")
cur_time = time.monotonic() cur_time = time.monotonic()
if cur_time - last_response_time > timeout: if cur_time - max(response_timeouts.values()) > 0:
for tx_addr in msgs: for tx_addr in msgs:
if (request_counter[tx_addr] > 0) and (not request_done[tx_addr]): if request_counter[tx_addr] > 0 and not request_done[tx_addr]:
cloudlog.warning(f"iso-tp query timeout after receiving response: {tx_addr}") cloudlog.warning(f"iso-tp query timeout after receiving response: {tx_addr}")
break break

@ -25,7 +25,6 @@ class CarInterface(CarInterfaceBase):
ret.dashcamOnly = candidate not in (CAR.CX5_2022, CAR.CX9_2021) ret.dashcamOnly = candidate not in (CAR.CX5_2022, CAR.CX9_2021)
ret.steerActuatorDelay = 0.1 ret.steerActuatorDelay = 0.1
ret.steerRateCost = 1.0
ret.steerLimitTimer = 0.8 ret.steerLimitTimer = 0.8
tire_stiffness_factor = 0.70 # not optimized yet tire_stiffness_factor = 0.70 # not optimized yet

@ -2,7 +2,7 @@
import math import math
from cereal import car from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
import cereal.messaging as messaging import cereal.messaging as messaging
from selfdrive.car import gen_empty_fingerprint, get_safety_config from selfdrive.car import gen_empty_fingerprint, get_safety_config
from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.interfaces import CarInterfaceBase

@ -14,7 +14,6 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.nissan)] ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.nissan)]
ret.steerLimitTimer = 1.0 ret.steerLimitTimer = 1.0
ret.steerRateCost = 0.5
ret.steerActuatorDelay = 0.1 ret.steerActuatorDelay = 0.1

@ -22,7 +22,6 @@ class CarInterface(CarInterfaceBase):
ret.dashcamOnly = candidate in PREGLOBAL_CARS ret.dashcamOnly = candidate in PREGLOBAL_CARS
ret.steerRateCost = 0.7
ret.steerLimitTimer = 0.4 ret.steerLimitTimer = 0.4
if candidate == CAR.ASCENT: if candidate == CAR.ASCENT:
@ -51,7 +50,6 @@ class CarInterface(CarInterfaceBase):
ret.centerToFront = ret.wheelbase * 0.5 ret.centerToFront = ret.wheelbase * 0.5
ret.steerRatio = 17 # learned, 14 stock ret.steerRatio = 17 # learned, 14 stock
ret.steerActuatorDelay = 0.1 ret.steerActuatorDelay = 0.1
ret.maxLateralAccel = 1.3
ret.lateralTuning.pid.kf = 0.00005 ret.lateralTuning.pid.kf = 0.00005
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.045, 0.042, 0.20], [0.04, 0.035, 0.045]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.045, 0.042, 0.20], [0.04, 0.035, 0.045]]
@ -62,7 +60,6 @@ class CarInterface(CarInterfaceBase):
ret.centerToFront = ret.wheelbase * 0.5 ret.centerToFront = ret.wheelbase * 0.5
ret.steerRatio = 17 # learned, 14 stock ret.steerRatio = 17 # learned, 14 stock
ret.steerActuatorDelay = 0.1 ret.steerActuatorDelay = 0.1
ret.maxLateralAccel = 3.2
ret.lateralTuning.pid.kf = 0.000038 ret.lateralTuning.pid.kf = 0.000038
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.065, 0.2], [0.001, 0.015, 0.025]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.065, 0.2], [0.001, 0.015, 0.025]]

@ -41,7 +41,7 @@ class SubaruCarInfo(CarInfo):
CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = { CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = {
CAR.ASCENT: SubaruCarInfo("Subaru Ascent 2019-20"), CAR.ASCENT: SubaruCarInfo("Subaru Ascent 2019-20", "All"),
CAR.IMPREZA: [ CAR.IMPREZA: [
SubaruCarInfo("Subaru Impreza 2017-19"), SubaruCarInfo("Subaru Impreza 2017-19"),
SubaruCarInfo("Subaru Crosstrek 2018-19", video_link="https://youtu.be/Agww7oE1k-s?t=26"), SubaruCarInfo("Subaru Crosstrek 2018-19", video_link="https://youtu.be/Agww7oE1k-s?t=26"),
@ -50,7 +50,7 @@ CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = {
SubaruCarInfo("Subaru Impreza 2020-21"), SubaruCarInfo("Subaru Impreza 2020-21"),
SubaruCarInfo("Subaru Crosstrek 2020-21"), SubaruCarInfo("Subaru Crosstrek 2020-21"),
], ],
CAR.FORESTER: SubaruCarInfo("Subaru Forester 2019-21"), CAR.FORESTER: SubaruCarInfo("Subaru Forester 2019-21", "All"),
CAR.FORESTER_PREGLOBAL: SubaruCarInfo("Subaru Forester 2017-18"), CAR.FORESTER_PREGLOBAL: SubaruCarInfo("Subaru Forester 2017-18"),
CAR.LEGACY_PREGLOBAL: SubaruCarInfo("Subaru Legacy 2015-18"), CAR.LEGACY_PREGLOBAL: SubaruCarInfo("Subaru Legacy 2015-18"),
CAR.OUTBACK_PREGLOBAL: SubaruCarInfo("Subaru Outback 2015-17"), CAR.OUTBACK_PREGLOBAL: SubaruCarInfo("Subaru Outback 2015-17"),

@ -42,7 +42,6 @@ class CarInterface(CarInterfaceBase):
ret.steerLimitTimer = 1.0 ret.steerLimitTimer = 1.0
ret.steerActuatorDelay = 0.25 ret.steerActuatorDelay = 0.25
ret.steerRateCost = 0.5
if candidate in (CAR.AP2_MODELS, CAR.AP1_MODELS): if candidate in (CAR.AP2_MODELS, CAR.AP1_MODELS):
ret.mass = 2100. + STD_CARGO_KG ret.mass = 2100. + STD_CARGO_KG

@ -84,7 +84,7 @@ routes = [
TestRoute("c75a59efa0ecd502|2021-03-11--20-52-55", HYUNDAI.KIA_SELTOS), TestRoute("c75a59efa0ecd502|2021-03-11--20-52-55", HYUNDAI.KIA_SELTOS),
TestRoute("5b7c365c50084530|2020-04-15--16-13-24", HYUNDAI.SONATA), TestRoute("5b7c365c50084530|2020-04-15--16-13-24", HYUNDAI.SONATA),
TestRoute("b2a38c712dcf90bd|2020-05-18--18-12-48", HYUNDAI.SONATA_LF), TestRoute("b2a38c712dcf90bd|2020-05-18--18-12-48", HYUNDAI.SONATA_LF),
TestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.TUCSON_DIESEL_2019), TestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.TUCSON),
TestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO), TestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO),
TestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE), TestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE),
TestRoute("3f29334d6134fcd4|2022-03-30--22-00-50", HYUNDAI.IONIQ_PHEV_2019), TestRoute("3f29334d6134fcd4|2022-03-30--22-00-50", HYUNDAI.IONIQ_PHEV_2019),
@ -144,6 +144,7 @@ routes = [
TestRoute("ec429c0f37564e3c|2020-02-01--17-28-12", TOYOTA.LEXUS_NXH), TestRoute("ec429c0f37564e3c|2020-02-01--17-28-12", TOYOTA.LEXUS_NXH),
TestRoute("964c09eb11ca8089|2020-11-03--22-04-00", TOYOTA.LEXUS_NX), TestRoute("964c09eb11ca8089|2020-11-03--22-04-00", TOYOTA.LEXUS_NX),
TestRoute("3fd5305f8b6ca765|2021-04-28--19-26-49", TOYOTA.LEXUS_NX_TSS2), TestRoute("3fd5305f8b6ca765|2021-04-28--19-26-49", TOYOTA.LEXUS_NX_TSS2),
TestRoute("09ae96064ed85a14|2022-06-09--12-22-31", TOYOTA.LEXUS_NXH_TSS2),
TestRoute("0a302ffddbb3e3d3|2020-02-08--16-19-08", TOYOTA.HIGHLANDER_TSS2), TestRoute("0a302ffddbb3e3d3|2020-02-08--16-19-08", TOYOTA.HIGHLANDER_TSS2),
TestRoute("437e4d2402abf524|2021-05-25--07-58-50", TOYOTA.HIGHLANDERH_TSS2), TestRoute("437e4d2402abf524|2021-05-25--07-58-50", TOYOTA.HIGHLANDERH_TSS2),
TestRoute("3183cd9b021e89ce|2021-05-25--10-34-44", TOYOTA.HIGHLANDER), TestRoute("3183cd9b021e89ce|2021-05-25--10-34-44", TOYOTA.HIGHLANDER),

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import math
import unittest import unittest
import importlib import importlib
from parameterized import parameterized from parameterized import parameterized
@ -32,14 +33,15 @@ class TestCarInterfaces(unittest.TestCase):
assert car_interface assert car_interface
self.assertGreater(car_params.mass, 1) self.assertGreater(car_params.mass, 1)
self.assertGreater(car_params.steerRateCost, 1e-3)
if car_params.steerControlType != car.CarParams.SteerControlType.angle: if car_params.steerControlType != car.CarParams.SteerControlType.angle:
tuning = car_params.lateralTuning.which() tuning = car_params.lateralTuning.which()
if tuning == 'pid': if tuning == 'pid':
self.assertTrue(len(car_params.lateralTuning.pid.kpV)) self.assertTrue(len(car_params.lateralTuning.pid.kpV))
elif tuning == 'torque': elif tuning == 'torque':
self.assertTrue(car_params.lateralTuning.torque.kf > 0) kf = car_params.lateralTuning.torque.kf
self.assertTrue(not math.isnan(kf) and kf > 0)
self.assertTrue(not math.isnan(car_params.lateralTuning.torque.friction))
elif tuning == 'indi': elif tuning == 'indi':
self.assertTrue(len(car_params.lateralTuning.indi.outerLoopGainV)) self.assertTrue(len(car_params.lateralTuning.indi.outerLoopGainV))

@ -3,6 +3,7 @@ import unittest
from selfdrive.car.car_helpers import interfaces, get_interface_attr from selfdrive.car.car_helpers import interfaces, get_interface_attr
from selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE, generate_cars_md, get_all_car_info from selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE, generate_cars_md, get_all_car_info
from selfdrive.car.docs_definitions import Column, Star
class TestCarDocs(unittest.TestCase): class TestCarDocs(unittest.TestCase):
@ -37,6 +38,11 @@ class TestCarDocs(unittest.TestCase):
if "rav4" in tokens: if "rav4" in tokens:
self.assertIn("RAV4", car.model, "Use correct capitalization") self.assertIn("RAV4", car.model, "Use correct capitalization")
def test_torque_star(self):
for car in self.all_cars:
if car.car_name == "honda":
self.assertTrue(car.row[Column.STEERING_TORQUE] in (Star.EMPTY, Star.HALF), f"{car.name} has full torque star")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

@ -121,7 +121,6 @@ class TestCarModelBase(unittest.TestCase):
# make sure car params are within a valid range # make sure car params are within a valid range
self.assertGreater(self.CP.mass, 1) self.assertGreater(self.CP.mass, 1)
self.assertGreater(self.CP.steerRateCost, 1e-3)
if self.CP.steerControlType != car.CarParams.SteerControlType.angle: if self.CP.steerControlType != car.CarParams.SteerControlType.angle:
tuning = self.CP.lateralTuning.which() tuning = self.CP.lateralTuning.which()

File diff suppressed because one or more lines are too long

@ -2,6 +2,7 @@
from cereal import car from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from panda import Panda from panda import Panda
from selfdrive.controls.lib.latcontrol_torque import set_torque_tune
from selfdrive.car.toyota.tunes import LatTunes, LongTunes, set_long_tune, set_lat_tune from selfdrive.car.toyota.tunes import LatTunes, LongTunes, set_long_tune, set_lat_tune
from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, CarControllerParams from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, CarControllerParams
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
@ -31,6 +32,9 @@ class CarInterface(CarInterfaceBase):
ret.stoppingControl = False # Toyota starts braking more when it thinks you want to stop ret.stoppingControl = False # Toyota starts braking more when it thinks you want to stop
stop_and_go = False stop_and_go = False
torque_params = CarInterfaceBase.get_torque_params(candidate)
steering_angle_deadzone_deg = 0.0
set_torque_tune(ret.lateralTuning, torque_params['LAT_ACCEL_FACTOR'], torque_params['FRICTION'], steering_angle_deadzone_deg)
if candidate == CAR.PRIUS: if candidate == CAR.PRIUS:
stop_and_go = True stop_and_go = True
@ -38,8 +42,11 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 15.74 # unknown end-to-end spec ret.steerRatio = 15.74 # unknown end-to-end spec
tire_stiffness_factor = 0.6371 # hand-tune tire_stiffness_factor = 0.6371 # hand-tune
ret.mass = 3045. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3045. * CV.LB_TO_KG + STD_CARGO_KG
ret.maxLateralAccel = 1.7 # Only give steer angle deadzone to for bad angle sensor prius
set_lat_tune(ret.lateralTuning, LatTunes.TORQUE, MAX_LAT_ACCEL=ret.maxLateralAccel, FRICTION=0.06) for fw in car_fw:
if fw.ecu == "eps" and not fw.fwVersion == b'8965B47060\x00\x00\x00\x00\x00\x00':
steering_angle_deadzone_deg = 1.0
set_torque_tune(ret.lateralTuning, torque_params['LAT_ACCEL_FACTOR'], torque_params['FRICTION'], steering_angle_deadzone_deg)
elif candidate == CAR.PRIUS_V: elif candidate == CAR.PRIUS_V:
stop_and_go = True stop_and_go = True
@ -47,8 +54,10 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 17.4 ret.steerRatio = 17.4
tire_stiffness_factor = 0.5533 tire_stiffness_factor = 0.5533
ret.mass = 3340. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3340. * CV.LB_TO_KG + STD_CARGO_KG
# TODO override until there is enough data
ret.maxLateralAccel = 1.8 ret.maxLateralAccel = 1.8
set_lat_tune(ret.lateralTuning, LatTunes.TORQUE, MAX_LAT_ACCEL=ret.maxLateralAccel, FRICTION=0.06) torque_params = CarInterfaceBase.get_torque_params(CAR.PRIUS)
set_torque_tune(ret.lateralTuning, torque_params['LAT_ACCEL_FACTOR'], torque_params['FRICTION'], steering_angle_deadzone_deg)
elif candidate in (CAR.RAV4, CAR.RAV4H): elif candidate in (CAR.RAV4, CAR.RAV4H):
stop_and_go = True if (candidate in CAR.RAV4H) else False stop_and_go = True if (candidate in CAR.RAV4H) else False
@ -56,16 +65,12 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 16.88 # 14.5 is spec end-to-end ret.steerRatio = 16.88 # 14.5 is spec end-to-end
tire_stiffness_factor = 0.5533 tire_stiffness_factor = 0.5533
ret.mass = 3650. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid ret.mass = 3650. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid
ret.maxLateralAccel = 1.8
set_lat_tune(ret.lateralTuning, LatTunes.TORQUE, MAX_LAT_ACCEL=ret.maxLateralAccel, FRICTION=0.06)
elif candidate == CAR.COROLLA: elif candidate == CAR.COROLLA:
ret.wheelbase = 2.70 ret.wheelbase = 2.70
ret.steerRatio = 18.27 ret.steerRatio = 18.27
tire_stiffness_factor = 0.444 # not optimized yet tire_stiffness_factor = 0.444 # not optimized yet
ret.mass = 2860. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid ret.mass = 2860. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid
ret.maxLateralAccel = 2.8
set_lat_tune(ret.lateralTuning, LatTunes.TORQUE, MAX_LAT_ACCEL=ret.maxLateralAccel, FRICTION=0.024)
elif candidate in (CAR.LEXUS_RX, CAR.LEXUS_RXH, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2): elif candidate in (CAR.LEXUS_RX, CAR.LEXUS_RXH, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2):
stop_and_go = True stop_and_go = True
@ -74,7 +79,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelSpeedFactor = 1.035 ret.wheelSpeedFactor = 1.035
tire_stiffness_factor = 0.5533 tire_stiffness_factor = 0.5533
ret.mass = 4481. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max ret.mass = 4481. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max
ret.maxLateralAccel = 1.4
set_lat_tune(ret.lateralTuning, LatTunes.PID_C) set_lat_tune(ret.lateralTuning, LatTunes.PID_C)
elif candidate in (CAR.CHR, CAR.CHRH): elif candidate in (CAR.CHR, CAR.CHRH):
@ -83,7 +87,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.6 ret.steerRatio = 13.6
tire_stiffness_factor = 0.7933 tire_stiffness_factor = 0.7933
ret.mass = 3300. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3300. * CV.LB_TO_KG + STD_CARGO_KG
ret.maxLateralAccel = 1.3
set_lat_tune(ret.lateralTuning, LatTunes.PID_F) set_lat_tune(ret.lateralTuning, LatTunes.PID_F)
elif candidate in (CAR.CAMRY, CAR.CAMRYH, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2): elif candidate in (CAR.CAMRY, CAR.CAMRYH, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2):
@ -92,11 +95,7 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.7 ret.steerRatio = 13.7
tire_stiffness_factor = 0.7933 tire_stiffness_factor = 0.7933
ret.mass = 3400. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid ret.mass = 3400. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid
if candidate in (CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2): if candidate not in (CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2):
ret.maxLateralAccel = 2.4
set_lat_tune(ret.lateralTuning, LatTunes.TORQUE, MAX_LAT_ACCEL=ret.maxLateralAccel, FRICTION=0.05)
else:
ret.maxLateralAccel = 2.0
set_lat_tune(ret.lateralTuning, LatTunes.PID_C) set_lat_tune(ret.lateralTuning, LatTunes.PID_C)
elif candidate in (CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2): elif candidate in (CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2):
@ -105,7 +104,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 16.0 ret.steerRatio = 16.0
tire_stiffness_factor = 0.8 tire_stiffness_factor = 0.8
ret.mass = 4700. * CV.LB_TO_KG + STD_CARGO_KG # 4260 + 4-5 people ret.mass = 4700. * CV.LB_TO_KG + STD_CARGO_KG # 4260 + 4-5 people
ret.maxLateralAccel = 2.0
set_lat_tune(ret.lateralTuning, LatTunes.PID_G) set_lat_tune(ret.lateralTuning, LatTunes.PID_G)
elif candidate in (CAR.HIGHLANDER, CAR.HIGHLANDERH): elif candidate in (CAR.HIGHLANDER, CAR.HIGHLANDERH):
@ -114,7 +112,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 16.0 ret.steerRatio = 16.0
tire_stiffness_factor = 0.8 tire_stiffness_factor = 0.8
ret.mass = 4607. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid limited ret.mass = 4607. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid limited
ret.maxLateralAccel = 1.8
set_lat_tune(ret.lateralTuning, LatTunes.PID_G) set_lat_tune(ret.lateralTuning, LatTunes.PID_G)
elif candidate in (CAR.AVALON, CAR.AVALON_2019, CAR.AVALONH_2019, CAR.AVALON_TSS2, CAR.AVALONH_TSS2): elif candidate in (CAR.AVALON, CAR.AVALON_2019, CAR.AVALONH_2019, CAR.AVALON_TSS2, CAR.AVALONH_TSS2):
@ -125,7 +122,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.8 # Found at https://pressroom.toyota.com/releases/2016+avalon+product+specs.download ret.steerRatio = 14.8 # Found at https://pressroom.toyota.com/releases/2016+avalon+product+specs.download
tire_stiffness_factor = 0.7983 tire_stiffness_factor = 0.7983
ret.mass = 3505. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid ret.mass = 3505. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid
ret.maxLateralAccel = 1.6
set_lat_tune(ret.lateralTuning, LatTunes.PID_H) set_lat_tune(ret.lateralTuning, LatTunes.PID_H)
elif candidate in (CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022): elif candidate in (CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022):
@ -134,9 +130,12 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.3 ret.steerRatio = 14.3
tire_stiffness_factor = 0.7933 tire_stiffness_factor = 0.7933
ret.mass = 3585. * CV.LB_TO_KG + STD_CARGO_KG # Average between ICE and Hybrid ret.mass = 3585. * CV.LB_TO_KG + STD_CARGO_KG # Average between ICE and Hybrid
ret.maxLateralAccel = 2.5
set_lat_tune(ret.lateralTuning, LatTunes.PID_D) set_lat_tune(ret.lateralTuning, LatTunes.PID_D)
# TODO: remove once there's data
if candidate == CAR.RAV4_TSS2_2022:
ret.maxLateralAccel = CarInterfaceBase.get_torque_params(CAR.RAV4H_TSS2_2022)['MAX_LAT_ACCEL_MEASURED']
# 2019+ RAV4 TSS2 uses two different steering racks and specific tuning seems to be necessary. # 2019+ RAV4 TSS2 uses two different steering racks and specific tuning seems to be necessary.
# See https://github.com/commaai/openpilot/pull/21429#issuecomment-873652891 # See https://github.com/commaai/openpilot/pull/21429#issuecomment-873652891
for fw in car_fw: for fw in car_fw:
@ -150,8 +149,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.9 ret.steerRatio = 13.9
tire_stiffness_factor = 0.444 # not optimized yet tire_stiffness_factor = 0.444 # not optimized yet
ret.mass = 3060. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3060. * CV.LB_TO_KG + STD_CARGO_KG
ret.maxLateralAccel = 2.0
set_lat_tune(ret.lateralTuning, LatTunes.TORQUE, MAX_LAT_ACCEL=ret.maxLateralAccel, FRICTION=0.07)
elif candidate in (CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_ESH): elif candidate in (CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_ESH):
stop_and_go = True stop_and_go = True
@ -159,7 +156,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 16.0 # not optimized ret.steerRatio = 16.0 # not optimized
tire_stiffness_factor = 0.444 # not optimized yet tire_stiffness_factor = 0.444 # not optimized yet
ret.mass = 3677. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max ret.mass = 3677. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max
ret.maxLateralAccel = 2.2
set_lat_tune(ret.lateralTuning, LatTunes.PID_D) set_lat_tune(ret.lateralTuning, LatTunes.PID_D)
elif candidate == CAR.SIENNA: elif candidate == CAR.SIENNA:
@ -168,7 +164,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 15.5 ret.steerRatio = 15.5
tire_stiffness_factor = 0.444 tire_stiffness_factor = 0.444
ret.mass = 4590. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4590. * CV.LB_TO_KG + STD_CARGO_KG
ret.maxLateralAccel = 1.6
set_lat_tune(ret.lateralTuning, LatTunes.PID_J) set_lat_tune(ret.lateralTuning, LatTunes.PID_J)
elif candidate in (CAR.LEXUS_IS, CAR.LEXUS_RC): elif candidate in (CAR.LEXUS_IS, CAR.LEXUS_RC):
@ -186,13 +181,12 @@ class CarInterface(CarInterfaceBase):
ret.mass = 3108 * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max ret.mass = 3108 * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max
set_lat_tune(ret.lateralTuning, LatTunes.PID_M) set_lat_tune(ret.lateralTuning, LatTunes.PID_M)
elif candidate in (CAR.LEXUS_NXH, CAR.LEXUS_NX, CAR.LEXUS_NX_TSS2): elif candidate in (CAR.LEXUS_NX, CAR.LEXUS_NXH, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2):
stop_and_go = True stop_and_go = True
ret.wheelbase = 2.66 ret.wheelbase = 2.66
ret.steerRatio = 14.7 ret.steerRatio = 14.7
tire_stiffness_factor = 0.444 # not optimized yet tire_stiffness_factor = 0.444 # not optimized yet
ret.mass = 4070 * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4070 * CV.LB_TO_KG + STD_CARGO_KG
ret.maxLateralAccel = 2.0
set_lat_tune(ret.lateralTuning, LatTunes.PID_C) set_lat_tune(ret.lateralTuning, LatTunes.PID_C)
elif candidate == CAR.PRIUS_TSS2: elif candidate == CAR.PRIUS_TSS2:
@ -201,7 +195,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.4 # True steerRatio from older prius ret.steerRatio = 13.4 # True steerRatio from older prius
tire_stiffness_factor = 0.6371 # hand-tune tire_stiffness_factor = 0.6371 # hand-tune
ret.mass = 3115. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3115. * CV.LB_TO_KG + STD_CARGO_KG
ret.maxLateralAccel = 2.0
set_lat_tune(ret.lateralTuning, LatTunes.PID_N) set_lat_tune(ret.lateralTuning, LatTunes.PID_N)
elif candidate == CAR.MIRAI: elif candidate == CAR.MIRAI:
@ -210,7 +203,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.8 ret.steerRatio = 14.8
tire_stiffness_factor = 0.8 tire_stiffness_factor = 0.8
ret.mass = 4300. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4300. * CV.LB_TO_KG + STD_CARGO_KG
ret.maxLateralAccel = 2.4
set_lat_tune(ret.lateralTuning, LatTunes.PID_C) set_lat_tune(ret.lateralTuning, LatTunes.PID_C)
elif candidate in (CAR.ALPHARD_TSS2, CAR.ALPHARDH_TSS2): elif candidate in (CAR.ALPHARD_TSS2, CAR.ALPHARDH_TSS2):
@ -221,7 +213,6 @@ class CarInterface(CarInterfaceBase):
ret.mass = 4305. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4305. * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_J) set_lat_tune(ret.lateralTuning, LatTunes.PID_J)
ret.steerRateCost = 1.
ret.centerToFront = ret.wheelbase * 0.44 ret.centerToFront = ret.wheelbase * 0.44
# TODO: get actual value, for now starting with reasonable value for # TODO: get actual value, for now starting with reasonable value for

@ -50,9 +50,9 @@ def set_long_tune(tune, name):
###### LAT ###### ###### LAT ######
def set_lat_tune(tune, name, MAX_LAT_ACCEL=2.5, FRICTION=0.01, use_steering_angle=True): def set_lat_tune(tune, name, MAX_LAT_ACCEL=2.5, FRICTION=0.01, steering_angle_deadzone_deg=0.0, use_steering_angle=True):
if name == LatTunes.TORQUE: if name == LatTunes.TORQUE:
set_torque_tune(tune, MAX_LAT_ACCEL, FRICTION) set_torque_tune(tune, MAX_LAT_ACCEL, FRICTION, steering_angle_deadzone_deg)
elif 'PID' in str(name): elif 'PID' in str(name):
tune.init('pid') tune.init('pid')
tune.pid.kiBP = [0.0] tune.pid.kiBP = [0.0]

@ -77,6 +77,7 @@ class CAR:
LEXUS_NX = "LEXUS NX 2018" LEXUS_NX = "LEXUS NX 2018"
LEXUS_NXH = "LEXUS NX HYBRID 2018" LEXUS_NXH = "LEXUS NX HYBRID 2018"
LEXUS_NX_TSS2 = "LEXUS NX 2020" LEXUS_NX_TSS2 = "LEXUS NX 2020"
LEXUS_NXH_TSS2 = "LEXUS NX HYBRID 2020"
LEXUS_RC = "LEXUS RC 2020" LEXUS_RC = "LEXUS RC 2020"
LEXUS_RX = "LEXUS RX 2016" LEXUS_RX = "LEXUS RX 2016"
LEXUS_RXH = "LEXUS RX HYBRID 2017" LEXUS_RXH = "LEXUS RX HYBRID 2017"
@ -92,9 +93,6 @@ class Footnote(Enum):
CAMRY = CarFootnote( CAMRY = CarFootnote(
"28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.", "28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.",
Column.FSR_LONGITUDINAL) Column.FSR_LONGITUDINAL)
ANGLE_SENSOR = CarFootnote(
"An inaccurate steering wheel angle sensor makes precise control difficult.",
Column.STEERING_TORQUE, star=Star.HALF)
@dataclass @dataclass
@ -132,10 +130,10 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = {
CAR.HIGHLANDERH: ToyotaCarInfo("Toyota Highlander Hybrid 2017-19", footnotes=[Footnote.DSU]), CAR.HIGHLANDERH: ToyotaCarInfo("Toyota Highlander Hybrid 2017-19", footnotes=[Footnote.DSU]),
CAR.HIGHLANDERH_TSS2: ToyotaCarInfo("Toyota Highlander Hybrid 2020-22"), CAR.HIGHLANDERH_TSS2: ToyotaCarInfo("Toyota Highlander Hybrid 2020-22"),
CAR.PRIUS: [ CAR.PRIUS: [
ToyotaCarInfo("Toyota Prius 2016-20", "TSS-P", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU, Footnote.ANGLE_SENSOR]), ToyotaCarInfo("Toyota Prius 2016-20", "TSS-P", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU]),
ToyotaCarInfo("Toyota Prius Prime 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU, Footnote.ANGLE_SENSOR]), ToyotaCarInfo("Toyota Prius Prime 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU]),
], ],
CAR.PRIUS_V: ToyotaCarInfo("Toyota Prius v 2017", "TSS-P", min_enable_speed=MIN_ACC_SPEED, footnotes=[Footnote.DSU, Footnote.ANGLE_SENSOR]), CAR.PRIUS_V: ToyotaCarInfo("Toyota Prius v 2017", "TSS-P", min_enable_speed=MIN_ACC_SPEED, footnotes=[Footnote.DSU]),
CAR.PRIUS_TSS2: [ CAR.PRIUS_TSS2: [
ToyotaCarInfo("Toyota Prius 2021-22", video_link="https://www.youtube.com/watch?v=J58TvCpUd4U"), ToyotaCarInfo("Toyota Prius 2021-22", video_link="https://www.youtube.com/watch?v=J58TvCpUd4U"),
ToyotaCarInfo("Toyota Prius Prime 2021-22", video_link="https://www.youtube.com/watch?v=J58TvCpUd4U"), ToyotaCarInfo("Toyota Prius Prime 2021-22", video_link="https://www.youtube.com/watch?v=J58TvCpUd4U"),
@ -158,6 +156,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = {
CAR.LEXUS_NX: ToyotaCarInfo("Lexus NX 2018-19", footnotes=[Footnote.DSU]), CAR.LEXUS_NX: ToyotaCarInfo("Lexus NX 2018-19", footnotes=[Footnote.DSU]),
CAR.LEXUS_NXH: ToyotaCarInfo("Lexus NX Hybrid 2018-19", footnotes=[Footnote.DSU]), CAR.LEXUS_NXH: ToyotaCarInfo("Lexus NX Hybrid 2018-19", footnotes=[Footnote.DSU]),
CAR.LEXUS_NX_TSS2: ToyotaCarInfo("Lexus NX 2020"), CAR.LEXUS_NX_TSS2: ToyotaCarInfo("Lexus NX 2020"),
CAR.LEXUS_NXH_TSS2: ToyotaCarInfo("Lexus NX Hybrid 2020"),
CAR.LEXUS_RC: ToyotaCarInfo("Lexus RC 2020"), CAR.LEXUS_RC: ToyotaCarInfo("Lexus RC 2020"),
CAR.LEXUS_RX: ToyotaCarInfo("Lexus RX 2016-18", footnotes=[Footnote.DSU]), CAR.LEXUS_RX: ToyotaCarInfo("Lexus RX 2016-18", footnotes=[Footnote.DSU]),
CAR.LEXUS_RXH: ToyotaCarInfo("Lexus RX Hybrid 2016-19", footnotes=[Footnote.DSU]), CAR.LEXUS_RXH: ToyotaCarInfo("Lexus RX Hybrid 2016-19", footnotes=[Footnote.DSU]),
@ -558,6 +557,7 @@ FW_VERSIONS = {
b'\x033F401100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203102\x00\x00\x00\x00', b'\x033F401100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203102\x00\x00\x00\x00',
b'\x033F401200\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00', b'\x033F401200\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00',
b'\x033F424000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00', b'\x033F424000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00',
b'\x033F424000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00',
], ],
(Ecu.fwdRadar, 0x750, 0xf): [ (Ecu.fwdRadar, 0x750, 0xf): [
b'8821F0W01000 ', b'8821F0W01000 ',
@ -1251,6 +1251,7 @@ FW_VERSIONS = {
b'\x01F15260R220\x00\x00\x00\x00\x00\x00', b'\x01F15260R220\x00\x00\x00\x00\x00\x00',
b'\x01F15260R290\x00\x00\x00\x00\x00\x00', b'\x01F15260R290\x00\x00\x00\x00\x00\x00',
b'\x01F15260R300\x00\x00\x00\x00\x00\x00', b'\x01F15260R300\x00\x00\x00\x00\x00\x00',
b'\x01F15260R302\x00\x00\x00\x00\x00\x00',
b'\x01F152642551\x00\x00\x00\x00\x00\x00', b'\x01F152642551\x00\x00\x00\x00\x00\x00',
b'\x01F152642561\x00\x00\x00\x00\x00\x00', b'\x01F152642561\x00\x00\x00\x00\x00\x00',
b'\x01F152642700\x00\x00\x00\x00\x00\x00', b'\x01F152642700\x00\x00\x00\x00\x00\x00',
@ -1583,6 +1584,23 @@ FW_VERSIONS = {
b'\x028646F7803100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F7803100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00',
], ],
}, },
CAR.LEXUS_NXH_TSS2: {
(Ecu.engine, 0x7e0, None): [
b'\x0237887000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.esp, 0x7b0, None): [
b'F152678210\x00\x00\x00\x00\x00\x00',
],
(Ecu.eps, 0x7a1, None): [
b'8965B78120\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x750, 0xf): [
b'\x018821F3301400\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x750, 0x6d): [
b'\x028646F78030A0\x00\x00\x00\x008646G2601200\x00\x00\x00\x00',
],
},
CAR.LEXUS_NXH: { CAR.LEXUS_NXH: {
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\x0237841000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0237841000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
@ -1825,7 +1843,10 @@ FW_VERSIONS = {
}, },
CAR.MIRAI: { CAR.MIRAI: {
(Ecu.esp, 0x7D1, None): [b'\x01898A36203000\x00\x00\x00\x00',], (Ecu.esp, 0x7D1, None): [b'\x01898A36203000\x00\x00\x00\x00',],
(Ecu.esp, 0x7B0, None): [b'\x01F15266203200\x00\x00\x00\x00',], # a second ESP ECU (Ecu.esp, 0x7B0, None): [ # a second ESP ECU
b'\x01F15266203200\x00\x00\x00\x00',
b'\x01F15266203500\x00\x00\x00\x00',
],
(Ecu.eps, 0x7A1, None): [b'\x028965B6204100\x00\x00\x00\x008965B6203100\x00\x00\x00\x00',], (Ecu.eps, 0x7A1, None): [b'\x028965B6204100\x00\x00\x00\x008965B6203100\x00\x00\x00\x00',],
(Ecu.fwdRadar, 0x750, 0xf): [b'\x018821F6201200\x00\x00\x00\x00',], (Ecu.fwdRadar, 0x750, 0xf): [b'\x018821F6201200\x00\x00\x00\x00',],
(Ecu.fwdCamera, 0x750, 0x6d): [b'\x028646F6201400\x00\x00\x00\x008646G5301200\x00\x00\x00\x00',], (Ecu.fwdCamera, 0x750, 0x6d): [b'\x028646F6201400\x00\x00\x00\x008646G5301200\x00\x00\x00\x00',],
@ -1910,6 +1931,7 @@ DBC = {
CAR.LEXUS_NXH: dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), CAR.LEXUS_NXH: dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'),
CAR.LEXUS_NX: dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), CAR.LEXUS_NX: dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'),
CAR.LEXUS_NX_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.LEXUS_NX_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'),
CAR.LEXUS_NXH_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'),
CAR.PRIUS_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.PRIUS_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'),
CAR.MIRAI: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.MIRAI: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'),
CAR.ALPHARD_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.ALPHARD_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'),
@ -1922,7 +1944,7 @@ EPS_SCALE = defaultdict(lambda: 73, {CAR.PRIUS: 66, CAR.COROLLA: 88, CAR.LEXUS_I
# Toyota/Lexus Safety Sense 2.0 and 2.5 # Toyota/Lexus Safety Sense 2.0 and 2.5
TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022,
CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2,
CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.AVALONH_TSS2, CAR.ALPHARDH_TSS2} CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.AVALONH_TSS2, CAR.ALPHARDH_TSS2}
NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH}
@ -1931,7 +1953,7 @@ RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022}
EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2, CAR.CHRH, CAR.COROLLAH_TSS2, CAR.HIGHLANDERH, CAR.HIGHLANDERH_TSS2, CAR.PRIUS, EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2, CAR.CHRH, CAR.COROLLAH_TSS2, CAR.HIGHLANDERH, CAR.HIGHLANDERH_TSS2, CAR.PRIUS,
CAR.PRIUS_V, CAR.RAV4H, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.LEXUS_CTH, CAR.MIRAI, CAR.LEXUS_ESH, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_NXH, CAR.LEXUS_RXH, CAR.PRIUS_V, CAR.RAV4H, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.LEXUS_CTH, CAR.MIRAI, CAR.LEXUS_ESH, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_NXH, CAR.LEXUS_RXH,
CAR.LEXUS_RXH_TSS2, CAR.PRIUS_TSS2, CAR.ALPHARDH_TSS2} CAR.LEXUS_RXH_TSS2, CAR.LEXUS_NXH_TSS2, CAR.PRIUS_TSS2, CAR.ALPHARDH_TSS2}
# no resume button press required # no resume button press required
NO_STOP_TIMER_CAR = TSS2_CAR | {CAR.PRIUS_V, CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.SIENNA, CAR.LEXUS_ESH} NO_STOP_TIMER_CAR = TSS2_CAR | {CAR.PRIUS_V, CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.SIENNA, CAR.LEXUS_ESH}

@ -6,7 +6,7 @@ import cereal.messaging as messaging
import panda.python.uds as uds import panda.python.uds as uds
from panda.python.uds import FUNCTIONAL_ADDRS from panda.python.uds import FUNCTIONAL_ADDRS
from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
OBD_VIN_REQUEST = b'\x09\x02' OBD_VIN_REQUEST = b'\x09\x02'
OBD_VIN_RESPONSE = b'\x49\x02\x01' OBD_VIN_RESPONSE = b'\x49\x02\x01'

@ -45,7 +45,6 @@ class CarInterface(CarInterfaceBase):
# Global lateral tuning defaults, can be overridden per-vehicle # Global lateral tuning defaults, can be overridden per-vehicle
ret.steerActuatorDelay = 0.1 ret.steerActuatorDelay = 0.1
ret.steerRateCost = 1.0
ret.steerLimitTimer = 0.4 ret.steerLimitTimer = 0.4
ret.steerRatio = 15.6 # Let the params learner figure this out ret.steerRatio = 15.6 # Let the params learner figure this out
tire_stiffness_factor = 1.0 # Let the params learner figure this out tire_stiffness_factor = 1.0 # Let the params learner figure this out
@ -64,17 +63,14 @@ class CarInterface(CarInterfaceBase):
elif candidate == CAR.ATLAS_MK1: elif candidate == CAR.ATLAS_MK1:
ret.mass = 2011 + STD_CARGO_KG ret.mass = 2011 + STD_CARGO_KG
ret.wheelbase = 2.98 ret.wheelbase = 2.98
ret.maxLateralAccel = 1.4
elif candidate == CAR.GOLF_MK7: elif candidate == CAR.GOLF_MK7:
ret.mass = 1397 + STD_CARGO_KG ret.mass = 1397 + STD_CARGO_KG
ret.wheelbase = 2.62 ret.wheelbase = 2.62
ret.maxLateralAccel = 1.5
elif candidate == CAR.JETTA_MK7: elif candidate == CAR.JETTA_MK7:
ret.mass = 1328 + STD_CARGO_KG ret.mass = 1328 + STD_CARGO_KG
ret.wheelbase = 2.71 ret.wheelbase = 2.71
ret.maxLateralAccel = 1.2
elif candidate == CAR.PASSAT_MK8: elif candidate == CAR.PASSAT_MK8:
ret.mass = 1551 + STD_CARGO_KG ret.mass = 1551 + STD_CARGO_KG
@ -95,7 +91,6 @@ class CarInterface(CarInterfaceBase):
elif candidate == CAR.TIGUAN_MK2: elif candidate == CAR.TIGUAN_MK2:
ret.mass = 1715 + STD_CARGO_KG ret.mass = 1715 + STD_CARGO_KG
ret.wheelbase = 2.74 ret.wheelbase = 2.74
ret.maxLateralAccel = 1.1
elif candidate == CAR.TOURAN_MK2: elif candidate == CAR.TOURAN_MK2:
ret.mass = 1516 + STD_CARGO_KG ret.mass = 1516 + STD_CARGO_KG
@ -113,7 +108,6 @@ class CarInterface(CarInterfaceBase):
elif candidate == CAR.AUDI_A3_MK3: elif candidate == CAR.AUDI_A3_MK3:
ret.mass = 1335 + STD_CARGO_KG ret.mass = 1335 + STD_CARGO_KG
ret.wheelbase = 2.61 ret.wheelbase = 2.61
ret.maxLateralAccel = 1.7
elif candidate == CAR.AUDI_Q2_MK1: elif candidate == CAR.AUDI_Q2_MK1:
ret.mass = 1205 + STD_CARGO_KG ret.mass = 1205 + STD_CARGO_KG
@ -122,7 +116,6 @@ class CarInterface(CarInterfaceBase):
elif candidate == CAR.AUDI_Q3_MK2: elif candidate == CAR.AUDI_Q3_MK2:
ret.mass = 1623 + STD_CARGO_KG ret.mass = 1623 + STD_CARGO_KG
ret.wheelbase = 2.68 ret.wheelbase = 2.68
ret.maxLateralAccel = 1.6
elif candidate == CAR.SEAT_ATECA_MK1: elif candidate == CAR.SEAT_ATECA_MK1:
ret.mass = 1900 + STD_CARGO_KG ret.mass = 1900 + STD_CARGO_KG

@ -533,6 +533,7 @@ FW_VERSIONS = {
}, },
CAR.TIGUAN_MK2: { CAR.TIGUAN_MK2: {
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xf1\x8704E906027NB\xf1\x899504',
b'\xf1\x8704L906026EJ\xf1\x893661', b'\xf1\x8704L906026EJ\xf1\x893661',
b'\xf1\x8704L906027G \xf1\x899893', b'\xf1\x8704L906027G \xf1\x899893',
b'\xf1\x875N0906259 \xf1\x890002', b'\xf1\x875N0906259 \xf1\x890002',
@ -544,6 +545,7 @@ FW_VERSIONS = {
b'\xf1\x8709G927158DT\xf1\x893698', b'\xf1\x8709G927158DT\xf1\x893698',
b'\xf1\x8709G927158GC\xf1\x893821', b'\xf1\x8709G927158GC\xf1\x893821',
b'\xf1\x8709G927158GD\xf1\x893820', b'\xf1\x8709G927158GD\xf1\x893820',
b'\xf1\x870D9300043 \xf1\x895202',
b'\xf1\x870DL300011N \xf1\x892001', b'\xf1\x870DL300011N \xf1\x892001',
b'\xf1\x870DL300011N \xf1\x892012', b'\xf1\x870DL300011N \xf1\x892012',
b'\xf1\x870DL300013A \xf1\x893005', b'\xf1\x870DL300013A \xf1\x893005',
@ -555,11 +557,14 @@ FW_VERSIONS = {
b'\xf1\x875Q0959655BM\xf1\x890403\xf1\x82\02316143231313500314641011750179333423100', b'\xf1\x875Q0959655BM\xf1\x890403\xf1\x82\02316143231313500314641011750179333423100',
b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\02312110031333300314240583752379333423100', b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\02312110031333300314240583752379333423100',
b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\02331310031333336313140013950399333423100', b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\02331310031333336313140013950399333423100',
b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\x1331310031333334313140013750379333423100',
b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\x1331310031333334313140573752379333423100', b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\x1331310031333334313140573752379333423100',
b'\xf1\x875Q0959655CB\xf1\x890421\xf1\x82\x1316143231313500314647021750179333613100', b'\xf1\x875Q0959655CB\xf1\x890421\xf1\x82\x1316143231313500314647021750179333613100',
], ],
(Ecu.eps, 0x712, None): [ (Ecu.eps, 0x712, None): [
b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820529A6060603', b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820529A6060603',
b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\x0521A60604A1',
b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567A6000600',
b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\00571A60634A1', b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\00571A60634A1',
b'\xf1\x875QM909144B \xf1\x891081\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144B \xf1\x891081\xf1\x82\x0521A60604A1',
b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\x0521A60604A1',

@ -11,7 +11,7 @@ from common.params import Params, put_nonblocking
import cereal.messaging as messaging import cereal.messaging as messaging
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from panda import ALTERNATIVE_EXPERIENCE from panda import ALTERNATIVE_EXPERIENCE
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
from selfdrive.boardd.boardd import can_list_to_can_capnp from selfdrive.boardd.boardd import can_list_to_can_capnp
from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can
from selfdrive.controls.lib.lane_planner import CAMERA_OFFSET from selfdrive.controls.lib.lane_planner import CAMERA_OFFSET
@ -27,7 +27,7 @@ from selfdrive.controls.lib.events import Events, ET
from selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert from selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert
from selfdrive.controls.lib.vehicle_model import VehicleModel from selfdrive.controls.lib.vehicle_model import VehicleModel
from selfdrive.locationd.calibrationd import Calibration from selfdrive.locationd.calibrationd import Calibration
from selfdrive.hardware import HARDWARE from system.hardware import HARDWARE
from selfdrive.manager.process_config import managed_processes from selfdrive.manager.process_config import managed_processes
SOFT_DISABLE_TIME = 3 # seconds SOFT_DISABLE_TIME = 3 # seconds

@ -38,6 +38,16 @@ class MPC_COST_LAT:
STEER_RATE = 1.0 STEER_RATE = 1.0
def apply_deadzone(error, deadzone):
if error > deadzone:
error -= deadzone
elif error < - deadzone:
error += deadzone
else:
error = 0.
return error
def rate_limit(new_value, last_value, dw_step, up_step): def rate_limit(new_value, last_value, dw_step, up_step):
return clip(new_value, last_value + dw_step, last_value + up_step) return clip(new_value, last_value + dw_step, last_value + up_step)
@ -97,26 +107,27 @@ def get_lag_adjusted_curvature(CP, v_ego, psis, curvatures, curvature_rates):
psis = [0.0]*CONTROL_N psis = [0.0]*CONTROL_N
curvatures = [0.0]*CONTROL_N curvatures = [0.0]*CONTROL_N
curvature_rates = [0.0]*CONTROL_N curvature_rates = [0.0]*CONTROL_N
v_ego = max(v_ego, 0.1)
# TODO this needs more thought, use .2s extra for now to estimate other delays # TODO this needs more thought, use .2s extra for now to estimate other delays
delay = CP.steerActuatorDelay + .2 delay = CP.steerActuatorDelay + .2
current_curvature = curvatures[0]
psi = interp(delay, T_IDXS[:CONTROL_N], psis)
desired_curvature_rate = curvature_rates[0]
# MPC can plan to turn the wheel and turn back before t_delay. This means # MPC can plan to turn the wheel and turn back before t_delay. This means
# in high delay cases some corrections never even get commanded. So just use # in high delay cases some corrections never even get commanded. So just use
# psi to calculate a simple linearization of desired curvature # psi to calculate a simple linearization of desired curvature
curvature_diff_from_psi = psi / (max(v_ego, 1e-1) * delay) - current_curvature current_curvature_desired = curvatures[0]
desired_curvature = current_curvature + 2 * curvature_diff_from_psi psi = interp(delay, T_IDXS[:CONTROL_N], psis)
average_curvature_desired = psi / (v_ego * delay)
desired_curvature = 2 * average_curvature_desired - current_curvature_desired
v_ego = max(v_ego, 0.1) # This is the "desired rate of the setpoint" not an actual desired rate
desired_curvature_rate = curvature_rates[0]
max_curvature_rate = MAX_LATERAL_JERK / (v_ego**2) max_curvature_rate = MAX_LATERAL_JERK / (v_ego**2)
safe_desired_curvature_rate = clip(desired_curvature_rate, safe_desired_curvature_rate = clip(desired_curvature_rate,
-max_curvature_rate, -max_curvature_rate,
max_curvature_rate) max_curvature_rate)
safe_desired_curvature = clip(desired_curvature, safe_desired_curvature = clip(desired_curvature,
current_curvature - max_curvature_rate * DT_MDL, current_curvature_desired - max_curvature_rate * DT_MDL,
current_curvature + max_curvature_rate * DT_MDL) current_curvature_desired + max_curvature_rate * DT_MDL)
return safe_desired_curvature, safe_desired_curvature_rate return safe_desired_curvature, safe_desired_curvature_rate

@ -8,7 +8,7 @@ import cereal.messaging as messaging
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from common.realtime import DT_CTRL from common.realtime import DT_CTRL
from selfdrive.locationd.calibrationd import MIN_SPEED_FILTER from selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
from selfdrive.version import get_short_branch from system.version import get_short_branch
AlertSize = log.ControlsState.AlertSize AlertSize = log.ControlsState.AlertSize
AlertStatus = log.ControlsState.AlertStatus AlertStatus = log.ControlsState.AlertStatus

@ -3,7 +3,7 @@ from cereal import log
from common.filter_simple import FirstOrderFilter from common.filter_simple import FirstOrderFilter
from common.numpy_fast import interp from common.numpy_fast import interp
from common.realtime import DT_MDL from common.realtime import DT_MDL
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
TRAJECTORY_SIZE = 33 TRAJECTORY_SIZE = 33

@ -78,6 +78,7 @@ class LatControlINDI(LatControl):
steers_des += math.radians(params.angleOffsetDeg) steers_des += math.radians(params.angleOffsetDeg)
indi_log.steeringAngleDesiredDeg = math.degrees(steers_des) indi_log.steeringAngleDesiredDeg = math.degrees(steers_des)
# desired rate is the desired rate of change in the setpoint, not the absolute desired curvature
rate_des = VM.get_steer_from_curvature(-desired_curvature_rate, CS.vEgo, 0) rate_des = VM.get_steer_from_curvature(-desired_curvature_rate, CS.vEgo, 0)
indi_log.steeringRateDesiredDeg = math.degrees(rate_des) indi_log.steeringRateDesiredDeg = math.degrees(rate_des)

@ -4,6 +4,7 @@ from cereal import log
from common.numpy_fast import interp from common.numpy_fast import interp
from selfdrive.controls.lib.latcontrol import LatControl, MIN_STEER_SPEED from selfdrive.controls.lib.latcontrol import LatControl, MIN_STEER_SPEED
from selfdrive.controls.lib.pid import PIDController from selfdrive.controls.lib.pid import PIDController
from selfdrive.controls.lib.drive_helpers import apply_deadzone
from selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY from selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
# At higher speeds (25+mph) we can assume: # At higher speeds (25+mph) we can assume:
@ -18,17 +19,17 @@ from selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
# move it at all, this is compensated for too. # move it at all, this is compensated for too.
LOW_SPEED_FACTOR = 200 FRICTION_THRESHOLD = 0.2
JERK_THRESHOLD = 0.2
def set_torque_tune(tune, MAX_LAT_ACCEL=2.5, FRICTION=0.01): def set_torque_tune(tune, MAX_LAT_ACCEL=2.5, FRICTION=0.01, steering_angle_deadzone_deg=0.0):
tune.init('torque') tune.init('torque')
tune.torque.useSteeringAngle = True tune.torque.useSteeringAngle = True
tune.torque.kp = 1.0 / MAX_LAT_ACCEL tune.torque.kp = 1.0 / MAX_LAT_ACCEL
tune.torque.kf = 1.0 / MAX_LAT_ACCEL tune.torque.kf = 1.0 / MAX_LAT_ACCEL
tune.torque.ki = 0.1 / MAX_LAT_ACCEL tune.torque.ki = 0.1 / MAX_LAT_ACCEL
tune.torque.friction = FRICTION tune.torque.friction = FRICTION
tune.torque.steeringAngleDeadzoneDeg = steering_angle_deadzone_deg
class LatControlTorque(LatControl): class LatControlTorque(LatControl):
@ -40,10 +41,7 @@ class LatControlTorque(LatControl):
self.use_steering_angle = CP.lateralTuning.torque.useSteeringAngle self.use_steering_angle = CP.lateralTuning.torque.useSteeringAngle
self.friction = CP.lateralTuning.torque.friction self.friction = CP.lateralTuning.torque.friction
self.kf = CP.lateralTuning.torque.kf self.kf = CP.lateralTuning.torque.kf
self.steering_angle_deadzone_deg = CP.lateralTuning.torque.steeringAngleDeadzoneDeg
def reset(self):
super().reset()
self.pid.reset()
def update(self, active, CS, VM, params, last_actuators, desired_curvature, desired_curvature_rate, llk): def update(self, active, CS, VM, params, last_actuators, desired_curvature, desired_curvature_rate, llk):
pid_log = log.ControlsState.LateralTorqueState.new_message() pid_log = log.ControlsState.LateralTorqueState.new_message()
@ -54,22 +52,29 @@ class LatControlTorque(LatControl):
else: else:
if self.use_steering_angle: if self.use_steering_angle:
actual_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll) actual_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0))
else: else:
actual_curvature_vm = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll) actual_curvature_vm = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
actual_curvature_llk = llk.angularVelocityCalibrated.value[2] / CS.vEgo actual_curvature_llk = llk.angularVelocityCalibrated.value[2] / CS.vEgo
actual_curvature = interp(CS.vEgo, [2.0, 5.0], [actual_curvature_vm, actual_curvature_llk]) actual_curvature = interp(CS.vEgo, [2.0, 5.0], [actual_curvature_vm, actual_curvature_llk])
curvature_deadzone = 0.0
desired_lateral_accel = desired_curvature * CS.vEgo ** 2 desired_lateral_accel = desired_curvature * CS.vEgo ** 2
desired_lateral_jerk = desired_curvature_rate * CS.vEgo ** 2
# desired rate is the desired rate of change in the setpoint, not the absolute desired curvature
#desired_lateral_jerk = desired_curvature_rate * CS.vEgo ** 2
actual_lateral_accel = actual_curvature * CS.vEgo ** 2 actual_lateral_accel = actual_curvature * CS.vEgo ** 2
lateral_accel_deadzone = curvature_deadzone * CS.vEgo ** 2
setpoint = desired_lateral_accel + LOW_SPEED_FACTOR * desired_curvature low_speed_factor = interp(CS.vEgo, [0, 15], [500, 0])
measurement = actual_lateral_accel + LOW_SPEED_FACTOR * actual_curvature setpoint = desired_lateral_accel + low_speed_factor * desired_curvature
error = setpoint - measurement measurement = actual_lateral_accel + low_speed_factor * actual_curvature
error = apply_deadzone(setpoint - measurement, lateral_accel_deadzone)
pid_log.error = error pid_log.error = error
ff = desired_lateral_accel - params.roll * ACCELERATION_DUE_TO_GRAVITY ff = desired_lateral_accel - params.roll * ACCELERATION_DUE_TO_GRAVITY
# convert friction into lateral accel units for feedforward # convert friction into lateral accel units for feedforward
friction_compensation = interp(desired_lateral_jerk, [-JERK_THRESHOLD, JERK_THRESHOLD], [-self.friction, self.friction]) friction_compensation = interp(error, [-FRICTION_THRESHOLD, FRICTION_THRESHOLD], [-self.friction, self.friction])
ff += friction_compensation / self.kf ff += friction_compensation / self.kf
freeze_integrator = CS.steeringRateLimited or CS.steeringPressed or CS.vEgo < 5 freeze_integrator = CS.steeringRateLimited or CS.steeringPressed or CS.vEgo < 5
output_torque = self.pid.update(error, output_torque = self.pid.update(error,

@ -1,7 +1,7 @@
import numpy as np import numpy as np
from common.realtime import sec_since_boot, DT_MDL from common.realtime import sec_since_boot, DT_MDL
from common.numpy_fast import interp from common.numpy_fast import interp
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
from selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import LateralMpc from selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import LateralMpc
from selfdrive.controls.lib.drive_helpers import CONTROL_N, MPC_COST_LAT, LAT_MPC_N, CAR_ROTATION_RADIUS from selfdrive.controls.lib.drive_helpers import CONTROL_N, MPC_COST_LAT, LAT_MPC_N, CAR_ROTATION_RADIUS
from selfdrive.controls.lib.lane_planner import LanePlanner, TRAJECTORY_SIZE from selfdrive.controls.lib.lane_planner import LanePlanner, TRAJECTORY_SIZE
@ -11,13 +11,12 @@ from cereal import log
class LateralPlanner: class LateralPlanner:
def __init__(self, CP, use_lanelines=True, wide_camera=False): def __init__(self, use_lanelines=True, wide_camera=False):
self.use_lanelines = use_lanelines self.use_lanelines = use_lanelines
self.LP = LanePlanner(wide_camera) self.LP = LanePlanner(wide_camera)
self.DH = DesireHelper() self.DH = DesireHelper()
self.last_cloudlog_t = 0 self.last_cloudlog_t = 0
self.steer_rate_cost = CP.steerRateCost
self.solution_invalid_cnt = 0 self.solution_invalid_cnt = 0
self.path_xyz = np.zeros((TRAJECTORY_SIZE, 3)) self.path_xyz = np.zeros((TRAJECTORY_SIZE, 3))
@ -59,12 +58,12 @@ class LateralPlanner:
# Calculate final driving path and set MPC costs # Calculate final driving path and set MPC costs
if self.use_lanelines: if self.use_lanelines:
d_path_xyz = self.LP.get_d_path(v_ego, self.t_idxs, self.path_xyz) d_path_xyz = self.LP.get_d_path(v_ego, self.t_idxs, self.path_xyz)
self.lat_mpc.set_weights(MPC_COST_LAT.PATH, MPC_COST_LAT.HEADING, self.steer_rate_cost) self.lat_mpc.set_weights(MPC_COST_LAT.PATH, MPC_COST_LAT.HEADING, MPC_COST_LAT.STEER_RATE)
else: else:
d_path_xyz = self.path_xyz d_path_xyz = self.path_xyz
# Heading cost is useful at low speed, otherwise end of plan can be off-heading # Heading cost is useful at low speed, otherwise end of plan can be off-heading
heading_cost = interp(v_ego, [5.0, 10.0], [MPC_COST_LAT.HEADING, 0.15]) heading_cost = interp(v_ego, [5.0, 10.0], [MPC_COST_LAT.HEADING, 0.15])
self.lat_mpc.set_weights(MPC_COST_LAT.PATH, heading_cost, self.steer_rate_cost) self.lat_mpc.set_weights(MPC_COST_LAT.PATH, heading_cost, MPC_COST_LAT.STEER_RATE)
y_pts = np.interp(v_ego * self.t_idxs[:LAT_MPC_N + 1], np.linalg.norm(d_path_xyz, axis=1), d_path_xyz[:, 1]) y_pts = np.interp(v_ego * self.t_idxs[:LAT_MPC_N + 1], np.linalg.norm(d_path_xyz, axis=1), d_path_xyz[:, 1])
heading_pts = np.interp(v_ego * self.t_idxs[:LAT_MPC_N + 1], np.linalg.norm(self.path_xyz, axis=1), self.plan_yaw) heading_pts = np.interp(v_ego * self.t_idxs[:LAT_MPC_N + 1], np.linalg.norm(self.path_xyz, axis=1), self.plan_yaw)
@ -79,6 +78,9 @@ class LateralPlanner:
y_pts, y_pts,
heading_pts) heading_pts)
# init state for next # init state for next
# mpc.u_sol is the desired curvature rate given x0 curv state.
# with x0[3] = measured_curvature, this would be the actual desired rate.
# instead, interpolate x_sol so that x0[3] is the desired curvature for lat_control.
self.x0[3] = interp(DT_MDL, self.t_idxs[:LAT_MPC_N + 1], self.lat_mpc.x_sol[:, 3]) self.x0[3] = interp(DT_MDL, self.t_idxs[:LAT_MPC_N + 1], self.lat_mpc.x_sol[:, 3])
# Check for infeasible MPC solution # Check for infeasible MPC solution

@ -1,7 +1,7 @@
from cereal import car from cereal import car
from common.numpy_fast import clip, interp from common.numpy_fast import clip, interp
from common.realtime import DT_CTRL from common.realtime import DT_CTRL
from selfdrive.controls.lib.drive_helpers import CONTROL_N from selfdrive.controls.lib.drive_helpers import CONTROL_N, apply_deadzone
from selfdrive.controls.lib.pid import PIDController from selfdrive.controls.lib.pid import PIDController
from selfdrive.modeld.constants import T_IDXS from selfdrive.modeld.constants import T_IDXS
@ -12,16 +12,6 @@ ACCEL_MIN_ISO = -3.5 # m/s^2
ACCEL_MAX_ISO = 2.0 # m/s^2 ACCEL_MAX_ISO = 2.0 # m/s^2
def apply_deadzone(error, deadzone):
if error > deadzone:
error -= deadzone
elif error < - deadzone:
error += deadzone
else:
error = 0.
return error
def long_control_state_trans(CP, active, long_control_state, v_ego, v_target, def long_control_state_trans(CP, active, long_control_state, v_ego, v_target,
v_target_future, brake_pressed, cruise_standstill): v_target_future, brake_pressed, cruise_standstill):
"""Update longitudinal control state machine""" """Update longitudinal control state machine"""

@ -4,7 +4,7 @@ import numpy as np
from common.realtime import sec_since_boot from common.realtime import sec_since_boot
from common.numpy_fast import clip, interp from common.numpy_fast import clip, interp
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
from selfdrive.modeld.constants import index_function from selfdrive.modeld.constants import index_function
from selfdrive.controls.lib.radar_helpers import _LEAD_ACCEL_TAU from selfdrive.controls.lib.radar_helpers import _LEAD_ACCEL_TAU

@ -12,7 +12,7 @@ from selfdrive.controls.lib.longcontrol import LongCtrlState
from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc
from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC
from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, CONTROL_N from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, CONTROL_N
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
LON_MPC_STEP = 0.2 # first step is 0.2s LON_MPC_STEP = 0.2 # first step is 0.2s
AWARENESS_DECEL = -0.2 # car smoothly decel at .2m/s^2 when user is distracted AWARENESS_DECEL = -0.2 # car smoothly decel at .2m/s^2 when user is distracted

@ -2,7 +2,7 @@
from cereal import car from cereal import car
from common.params import Params from common.params import Params
from common.realtime import Priority, config_realtime_process from common.realtime import Priority, config_realtime_process
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
from selfdrive.controls.lib.longitudinal_planner import Planner from selfdrive.controls.lib.longitudinal_planner import Planner
from selfdrive.controls.lib.lateral_planner import LateralPlanner from selfdrive.controls.lib.lateral_planner import LateralPlanner
import cereal.messaging as messaging import cereal.messaging as messaging
@ -22,7 +22,7 @@ def plannerd_thread(sm=None, pm=None):
cloudlog.event("e2e mode", on=use_lanelines) cloudlog.event("e2e mode", on=use_lanelines)
longitudinal_planner = Planner(CP) longitudinal_planner = Planner(CP)
lateral_planner = LateralPlanner(CP, use_lanelines=use_lanelines, wide_camera=wide_camera) lateral_planner = LateralPlanner(use_lanelines=use_lanelines, wide_camera=wide_camera)
if sm is None: if sm is None:
sm = messaging.SubMaster(['carState', 'controlsState', 'radarState', 'modelV2'], sm = messaging.SubMaster(['carState', 'controlsState', 'radarState', 'modelV2'],

@ -10,7 +10,7 @@ from common.params import Params
from common.realtime import Ratekeeper, Priority, config_realtime_process from common.realtime import Ratekeeper, Priority, config_realtime_process
from selfdrive.controls.lib.cluster.fastcluster_py import cluster_points_centroid from selfdrive.controls.lib.cluster.fastcluster_py import cluster_points_centroid
from selfdrive.controls.lib.radar_helpers import Cluster, Track, RADAR_TO_CAMERA from selfdrive.controls.lib.radar_helpers import Cluster, Track, RADAR_TO_CAMERA
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
class KalmanParams(): class KalmanParams():

@ -4,6 +4,7 @@ from collections import Counter
from pprint import pprint from pprint import pprint
from tqdm import tqdm from tqdm import tqdm
from cereal.services import service_list
from tools.lib.route import Route from tools.lib.route import Route
from tools.lib.logreader import LogReader from tools.lib.logreader import LogReader
@ -13,6 +14,9 @@ if __name__ == "__main__":
cnt_valid: Counter = Counter() cnt_valid: Counter = Counter()
cnt_events: Counter = Counter() cnt_events: Counter = Counter()
cams = [s for s in service_list if s.endswith('CameraState')]
cnt_cameras = dict.fromkeys(cams, 0)
for q in tqdm(r.qlog_paths()): for q in tqdm(r.qlog_paths()):
if q is None: if q is None:
continue continue
@ -21,12 +25,21 @@ if __name__ == "__main__":
if msg.which() == 'carEvents': if msg.which() == 'carEvents':
for e in msg.carEvents: for e in msg.carEvents:
cnt_events[e.name] += 1 cnt_events[e.name] += 1
elif msg.which() in cams:
cnt_cameras[msg.which()] += 1
if not msg.valid: if not msg.valid:
cnt_valid[msg.which()] += 1 cnt_valid[msg.which()] += 1
print("Events") print("Events")
pprint(cnt_events) pprint(cnt_events)
print("\n\n") print("\n")
print("Not valid") print("Not valid")
pprint(cnt_valid) pprint(cnt_valid)
print("\n")
print("Cameras")
for k, v in cnt_cameras.items():
print(" ", k.ljust(20), v)

@ -3,7 +3,7 @@ import traceback
import cereal.messaging as messaging import cereal.messaging as messaging
from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery
from selfdrive.swaglog import cloudlog from system.swaglog import cloudlog
EXT_DIAG_REQUEST = b'\x10\x03' EXT_DIAG_REQUEST = b'\x10\x03'
EXT_DIAG_RESPONSE = b'\x50\x03' EXT_DIAG_RESPONSE = b'\x50\x03'

@ -0,0 +1 @@
../system/hardware/

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

Loading…
Cancel
Save