openpilot v0.9.5 release

date: 2023-11-17T23:53:40
master commit: d3aad9ca46
pull/31476/head
Vehicle Researcher 2 years ago
parent eff388b1b6
commit b2f2dabe71
  1. 6
      .gitignore
  2. 369
      Jenkinsfile
  3. 21
      README.md
  4. 19
      RELEASES.md
  5. 133
      SConstruct
  6. 2
      cereal/SConscript
  7. 12
      cereal/car.capnp
  8. 34
      cereal/log.capnp
  9. 23
      cereal/messaging/__init__.py
  10. 2
      cereal/messaging/bridge.cc
  11. 2
      cereal/messaging/impl_fake.h
  12. 7
      cereal/messaging/impl_msgq.cc
  13. 2
      cereal/messaging/impl_msgq.h
  14. 22
      cereal/messaging/impl_zmq.cc
  15. 3
      cereal/messaging/impl_zmq.h
  16. 20
      cereal/messaging/messaging.h
  17. 20
      cereal/messaging/socketmaster.cc
  18. 29
      cereal/services.py
  19. 3
      cereal/visionipc/__init__.py
  20. 33
      cereal/visionipc/visionbuf_ion.cc
  21. 5
      cereal/visionipc/visionipc.pxd
  22. 2
      cereal/visionipc/visionipc_client.h
  23. 5
      cereal/visionipc/visionipc_pyx.pxd
  24. 7
      cereal/visionipc/visionipc_pyx.pyx
  25. 1
      cereal/visionipc/visionipc_server.h
  26. 34
      common/SConscript
  27. 4
      common/api/__init__.py
  28. 2
      common/basedir.py
  29. 24
      common/clock.pyx
  30. 10
      common/clutil.cc
  31. 1
      common/clutil.h
  32. 2
      common/file_helpers.py
  33. 8
      common/gpio.cc
  34. 4
      common/gpio.h
  35. 4
      common/gpio.py
  36. 19
      common/i2c.cc
  37. 2
      common/i2c.h
  38. 4
      common/kalman/SConscript
  39. 13
      common/kalman/simple_kalman.py
  40. 8
      common/kalman/tests/test_simple_kalman.py
  41. 6
      common/logging_extra.py
  42. 4
      common/mat.h
  43. 10
      common/params.cc
  44. 6
      common/params.h
  45. 3
      common/params.py
  46. 2
      common/params_pyx.pyx
  47. 40
      common/ratekeeper.cc
  48. 23
      common/ratekeeper.h
  49. 17
      common/realtime.py
  50. 10
      common/spinner.py
  51. 12
      common/swaglog.cc
  52. 14
      common/swaglog.h
  53. 2
      common/text_window.py
  54. 5
      common/transformations/SConscript
  55. 18
      common/transformations/camera.py
  56. 6
      common/transformations/coordinates.cc
  57. 2
      common/transformations/coordinates.hpp
  58. 7
      common/transformations/coordinates.py
  59. 71
      common/transformations/model.py
  60. 4
      common/transformations/orientation.cc
  61. 2
      common/transformations/orientation.hpp
  62. 3
      common/transformations/orientation.py
  63. 30
      common/transformations/transformations.pyx
  64. 35
      common/util.cc
  65. 31
      common/util.h
  66. 2
      common/version.h
  67. 2
      common/watchdog.cc
  68. 535
      docs/CARS.md
  69. 9
      laika/__init__.py
  70. 396
      laika/astro_dog.py
  71. 34
      laika/constants.py
  72. 84
      laika/dcb.py
  73. 161
      laika/dgps.py
  74. 483
      laika/downloader.py
  75. 106
      laika/ephemeris.capnp
  76. 498
      laika/ephemeris.py
  77. 203
      laika/gps_time.py
  78. 221
      laika/helpers.py
  79. 255
      laika/iono.py
  80. 106
      laika/lib/coordinates.py
  81. 291
      laika/lib/orientation.py
  82. 192
      laika/opt.py
  83. 334
      laika/raw_gnss.py
  84. 252
      laika/rinex_file.py
  85. 34
      laika/trop.py
  86. 2
      opendbc/can/common.cc
  87. 3
      opendbc/can/common.h
  88. 13
      opendbc/can/common.pxd
  89. 12
      opendbc/can/common_dbc.h
  90. 2
      opendbc/can/packer.cc
  91. 2
      opendbc/can/packer_pyx.pyx
  92. 53
      opendbc/can/parser.cc
  93. 90
      opendbc/can/parser_pyx.pyx
  94. 20
      opendbc/gm_global_a_powertrain_generated.dbc
  95. 101
      opendbc/hyundai_canfd.dbc
  96. 2
      opendbc/hyundai_kia_generic.dbc
  97. 14
      opendbc/mazda_2017.dbc
  98. 11
      opendbc/subaru_forester_2017_generated.dbc
  99. 41
      opendbc/subaru_global_2017_generated.dbc
  100. 324
      opendbc/subaru_global_2020_hybrid_generated.dbc
  101. Some files were not shown because too many files have changed in this diff Show More

6
.gitignore vendored

@ -1,4 +1,6 @@
venv/ venv/
.venv/
.ci_cache
.env .env
.clang-format .clang-format
.DS_Store .DS_Store
@ -46,6 +48,7 @@ selfdrive/mapd/default_speeds_by_region.json
system/proclogd/proclogd system/proclogd/proclogd
selfdrive/ui/_ui selfdrive/ui/_ui
selfdrive/ui/translations/alerts_generated.h selfdrive/ui/translations/alerts_generated.h
selfdrive/ui/translations/tmp
selfdrive/test/longitudinal_maneuvers/out selfdrive/test/longitudinal_maneuvers/out
selfdrive/car/tests/cars_dump selfdrive/car/tests/cars_dump
system/camerad/camerad system/camerad/camerad
@ -56,7 +59,6 @@ selfdrive/modeld/_dmonitoringmodeld
/src/ /src/
one one
openpilot
notebooks notebooks
xx xx
yy yy
@ -77,6 +79,7 @@ comma*.sh
selfdrive/modeld/thneed/compile selfdrive/modeld/thneed/compile
selfdrive/modeld/models/*.thneed selfdrive/modeld/models/*.thneed
selfdrive/modeld/models/*.pkl
*.bz2 *.bz2
@ -85,3 +88,4 @@ build/
!**/.gitkeep !**/.gitkeep
poetry.toml poetry.toml
Pipfile

369
Jenkinsfile vendored

@ -1,4 +1,4 @@
def phone(String ip, String step_label, String cmd) { def device(String ip, String step_label, String cmd) {
withCredentials([file(credentialsId: 'id_rsa', variable: 'key_file')]) { withCredentials([file(credentialsId: 'id_rsa', variable: 'key_file')]) {
def ssh_cmd = """ def ssh_cmd = """
ssh -tt -o StrictHostKeyChecking=no -i ${key_file} 'comma@${ip}' /usr/bin/bash <<'END' ssh -tt -o StrictHostKeyChecking=no -i ${key_file} 'comma@${ip}' /usr/bin/bash <<'END'
@ -6,6 +6,7 @@ ssh -tt -o StrictHostKeyChecking=no -i ${key_file} 'comma@${ip}' /usr/bin/bash <
set -e set -e
export CI=1 export CI=1
export PYTHONWARNINGS=error
export LOGPRINT=debug export LOGPRINT=debug
export TEST_DIR=${env.TEST_DIR} export TEST_DIR=${env.TEST_DIR}
export SOURCE_DIR=${env.SOURCE_DIR} export SOURCE_DIR=${env.SOURCE_DIR}
@ -13,6 +14,8 @@ export GIT_BRANCH=${env.GIT_BRANCH}
export GIT_COMMIT=${env.GIT_COMMIT} export GIT_COMMIT=${env.GIT_COMMIT}
export AZURE_TOKEN='${env.AZURE_TOKEN}' export AZURE_TOKEN='${env.AZURE_TOKEN}'
export MAPBOX_TOKEN='${env.MAPBOX_TOKEN}' export MAPBOX_TOKEN='${env.MAPBOX_TOKEN}'
export PYTEST_ADDOPTS="-c selfdrive/test/pytest-tici.ini --rootdir ."
export GIT_SSH_COMMAND="ssh -i /data/gitkey" export GIT_SSH_COMMAND="ssh -i /data/gitkey"
@ -20,6 +23,8 @@ source ~/.bash_profile
if [ -f /TICI ]; then if [ -f /TICI ]; then
source /etc/profile source /etc/profile
rm -rf ~/.commacache
if ! systemctl is-active --quiet systemd-resolved; then if ! systemctl is-active --quiet systemd-resolved; then
echo "restarting resolved" echo "restarting resolved"
sudo systemctl start systemd-resolved sudo systemctl start systemd-resolved
@ -50,222 +55,192 @@ END"""
} }
} }
def phone_steps(String device_type, steps) { def deviceStage(String stageName, String deviceType, List env, def steps) {
lock(resource: "", label: device_type, inversePrecedence: true, variable: 'device_ip', quantity: 1) { stage(stageName) {
timeout(time: 20, unit: 'MINUTES') { if (currentBuild.result != null) {
phone(device_ip, "git checkout", readFile("selfdrive/test/setup_device_ci.sh"),) return
steps.each { item ->
phone(device_ip, item[0], item[1])
}
} }
}
}
pipeline { def extra = env.collect { "export ${it}" }.join('\n');
agent none
environment {
CI = "1"
TEST_DIR = "/data/openpilot"
SOURCE_DIR = "/data/openpilot_source/"
AZURE_TOKEN = credentials('azure_token')
MAPBOX_TOKEN = credentials('mapbox_token')
}
options {
timeout(time: 3, unit: 'HOURS')
disableConcurrentBuilds(abortPrevious: env.BRANCH_NAME != 'master')
}
stages { docker.image('ghcr.io/commaai/alpine-ssh').inside('--user=root') {
stage('build release3-staging') { lock(resource: "", label: deviceType, inversePrecedence: true, variable: 'device_ip', quantity: 1) {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } timeout(time: 20, unit: 'MINUTES') {
when { retry (3) {
branch 'devel-staging' device(device_ip, "git checkout", extra + "\n" + readFile("selfdrive/test/setup_device_ci.sh"))
} }
steps { steps.each { item ->
phone_steps("tici-needs-can", [ device(device_ip, item[0], item[1])
["build release3-staging & dashcam3-staging", "RELEASE_BRANCH=release3-staging DASHCAM_BRANCH=dashcam3-staging $SOURCE_DIR/release/build_release.sh"], }
]) }
} }
} }
}
}
stage('build nightly') { def pcStage(String stageName, Closure body) {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } node {
when { stage(stageName) {
branch 'master-ci' if (currentBuild.result != null) {
} return
steps {
phone_steps("tici-needs-can", [
["build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/release/build_release.sh"],
])
}
} }
stage('openpilot tests') { checkout scm
when {
not { def dockerArgs = "--user=batman -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/scons_cache:/tmp/scons_cache -e PYTHONPATH=${env.WORKSPACE}";
anyOf { docker.build("openpilot-base:build-${env.GIT_COMMIT}", "-f Dockerfile.openpilot_base .").inside(dockerArgs) {
branch 'master-ci'; branch 'devel'; branch 'devel-staging'; timeout(time: 20, unit: 'MINUTES') {
branch 'release3'; branch 'release3-staging'; branch 'dashcam3'; branch 'dashcam3-staging'; try {
branch 'testing-closet*'; branch 'hotfix-*' // TODO: remove these after all jenkins jobs are running as batman (merged with master)
} sh "sudo chown -R batman:batman /tmp/scons_cache"
sh "sudo chown -R batman:batman /tmp/comma_download_cache"
sh "git config --global --add safe.directory '*'"
sh "git submodule update --init --recursive"
sh "git lfs pull"
body()
} finally {
sh "rm -rf ${env.WORKSPACE}/* || true"
sh "rm -rf .* || true"
} }
} }
}
}
}
}
parallel { def setupCredentials() {
withCredentials([
/* string(credentialsId: 'azure_token', variable: 'AZURE_TOKEN'),
stage('simulator') { string(credentialsId: 'mapbox_token', variable: 'MAPBOX_TOKEN')
agent { ]) {
dockerfile { env.AZURE_TOKEN = "${AZURE_TOKEN}"
filename 'Dockerfile.sim_nvidia' env.MAPBOX_TOKEN = "${MAPBOX_TOKEN}"
dir 'tools/sim' }
args '--user=root' }
}
}
steps {
sh "git config --global --add safe.directory '*'"
sh "git submodule update --init --recursive"
sh "git lfs pull"
lock(resource: "", label: "simulator", inversePrecedence: true, quantity: 1) {
sh "${WORKSPACE}/tools/sim/build_container.sh"
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('scons build test') {
agent {
dockerfile {
filename 'Dockerfile.openpilot_base'
args '--user=root'
}
}
steps {
sh "git config --global --add safe.directory '*'"
sh "git submodule update --init --depth=1 --recursive"
sh "scons --clean && scons --no-cache -j42"
sh "scons --clean && scons --no-cache --random -j42"
}
post { node {
always { env.CI = "1"
sh "rm -rf ${WORKSPACE}/* || true" env.PYTHONWARNINGS = "error"
sh "rm -rf .* || true" env.TEST_DIR = "/data/openpilot"
} env.SOURCE_DIR = "/data/openpilot_source/"
} setupCredentials()
}
stage('tizi-tests') { env.GIT_BRANCH = checkout(scm).GIT_BRANCH
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } env.GIT_COMMIT = checkout(scm).GIT_COMMIT
steps {
phone_steps("tizi", [
["build openpilot", "cd selfdrive/manager && ./build.py"],
["test boardd loopback", "SINGLE_PANDA=1 pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
["test sensord", "cd system/sensord/tests && pytest test_sensord.py"],
["test camerad", "pytest system/camerad/test/test_camerad.py"],
["test exposure", "pytest system/camerad/test/test_exposure.py"],
["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"],
["test hw", "pytest system/hardware/tici/tests/test_hardware.py"],
["test rawgpsd", "pytest system/sensord/rawgps/test_rawgps.py"],
])
}
}
stage('build') { def excludeBranches = ['master-ci', 'devel', 'devel-staging', 'release3', 'release3-staging',
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } 'dashcam3', 'dashcam3-staging', 'testing-closet*', 'hotfix-*']
environment { def excludeRegex = excludeBranches.join('|').replaceAll('\\*', '.*')
R3_PUSH = "${env.BRANCH_NAME == 'master' ? '1' : ' '}"
}
steps {
phone_steps("tici-needs-can", [
["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR EXTRA_FILES='tools/' ./build_devel.sh"],
["build openpilot", "cd selfdrive/manager && ./build.py"],
["check dirty", "release/check-dirty.sh"],
["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"],
["time to onroad", "cd selfdrive/test/ && pytest test_time_to_onroad.py"],
])
}
}
stage('loopback-tests') { if (env.BRANCH_NAME != 'master') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } properties([
steps { disableConcurrentBuilds(abortPrevious: true)
phone_steps("tici-loopback", [ ])
["build openpilot", "cd selfdrive/manager && ./build.py"], }
["test boardd loopback", "pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
])
}
}
stage('HW + Unit Tests') { try {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } if (env.BRANCH_NAME == 'devel-staging') {
steps { deviceStage("build release3-staging", "tici-needs-can", [], [
phone_steps("tici-common", [ ["build release3-staging & dashcam3-staging", "RELEASE_BRANCH=release3-staging DASHCAM_BRANCH=dashcam3-staging $SOURCE_DIR/release/build_release.sh"],
["build", "cd selfdrive/manager && ./build.py"], ])
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"], }
["test power draw", "pytest system/hardware/tici/tests/test_power_draw.py"],
["test loggerd", "pytest system/loggerd/tests/test_loggerd.py"],
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"],
["test pigeond", "pytest system/sensord/tests/test_pigeond.py"],
["test manager", "pytest selfdrive/manager/test/test_manager.py"],
["test nav", "pytest selfdrive/navd/tests/"],
])
}
}
stage('camerad') { if (env.BRANCH_NAME == 'master-ci') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } deviceStage("build nightly", "tici-needs-can", [], [
steps { ["build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/release/build_release.sh"],
phone_steps("tici-ar0231", [ ])
["build", "cd selfdrive/manager && ./build.py"], }
["test camerad", "pytest system/camerad/test/test_camerad.py"],
["test exposure", "pytest system/camerad/test/test_exposure.py"],
])
phone_steps("tici-ox03c10", [
["build", "cd selfdrive/manager && ./build.py"],
["test camerad", "pytest system/camerad/test/test_camerad.py"],
["test exposure", "pytest system/camerad/test/test_exposure.py"],
])
}
}
stage('sensord') { if (!env.BRANCH_NAME.matches(excludeRegex)) {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } parallel (
steps { // tici tests
phone_steps("tici-lsmc", [ 'onroad tests': {
["build", "cd selfdrive/manager && ./build.py"], deviceStage("onroad", "tici-needs-can", ["SKIP_COPY=1"], [
["test sensord", "cd system/sensord/tests && pytest test_sensord.py"], ["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR ./build_devel.sh"],
]) ["build openpilot", "cd selfdrive/manager && ./build.py"],
phone_steps("tici-bmx-lsm", [ ["check dirty", "release/check-dirty.sh"],
["build", "cd selfdrive/manager && ./build.py"], ["onroad tests", "pytest selfdrive/test/test_onroad.py -s"],
["test sensord", "cd system/sensord/tests && pytest test_sensord.py"], ["time to onroad", "pytest selfdrive/test/test_time_to_onroad.py"],
]) ])
} },
'HW + Unit Tests': {
deviceStage("tici", "tici-common", ["UNSAFE=1"], [
["build", "cd selfdrive/manager && ./build.py"],
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
["test power draw", "./system/hardware/tici/tests/test_power_draw.py"],
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"],
["test pigeond", "pytest system/sensord/tests/test_pigeond.py"],
["test manager", "pytest selfdrive/manager/test/test_manager.py"],
["test nav", "pytest selfdrive/navd/tests/"],
])
},
'loopback': {
deviceStage("tici", "tici-loopback", ["UNSAFE=1"], [
["build openpilot", "cd selfdrive/manager && ./build.py"],
["test boardd loopback", "pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
])
},
'camerad': {
deviceStage("AR0231", "tici-ar0231", ["UNSAFE=1"], [
["build", "cd selfdrive/manager && ./build.py"],
["test camerad", "pytest system/camerad/test/test_camerad.py"],
["test exposure", "pytest system/camerad/test/test_exposure.py"],
])
deviceStage("OX03C10", "tici-ox03c10", ["UNSAFE=1"], [
["build", "cd selfdrive/manager && ./build.py"],
["test camerad", "pytest system/camerad/test/test_camerad.py"],
["test exposure", "pytest system/camerad/test/test_exposure.py"],
])
},
'sensord': {
deviceStage("LSM + MMC", "tici-lsmc", ["UNSAFE=1"], [
["build", "cd selfdrive/manager && ./build.py"],
["test sensord", "pytest system/sensord/tests/test_sensord.py"],
])
deviceStage("BMX + LSM", "tici-bmx-lsm", ["UNSAFE=1"], [
["build", "cd selfdrive/manager && ./build.py"],
["test sensord", "pytest system/sensord/tests/test_sensord.py"],
])
},
'replay': {
deviceStage("tici", "tici-replay", ["UNSAFE=1"], [
["build", "cd selfdrive/manager && ./build.py"],
["model replay", "selfdrive/test/process_replay/model_replay.py"],
])
},
'tizi': {
deviceStage("tizi", "tizi", ["UNSAFE=1"], [
["build openpilot", "cd selfdrive/manager && ./build.py"],
["test boardd loopback", "SINGLE_PANDA=1 pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"],
["test hw", "pytest system/hardware/tici/tests/test_hardware.py"],
["test rawgpsd", "pytest system/sensord/rawgps/test_rawgps.py"],
])
},
// *** PC tests ***
'PC tests': {
pcStage("PC tests") {
// tests that our build system's dependencies are configured properly,
// needs a machine with lots of cores
sh label: "test multi-threaded build", script: "scons --no-cache --random -j42"
} }
},
stage('replay') { 'car tests': {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } pcStage("car tests") {
steps { sh label: "build", script: "selfdrive/manager/build.py"
phone_steps("tici-replay", [ sh label: "test_models.py", script: "INTERNAL_SEG_CNT=250 INTERNAL_SEG_LIST=selfdrive/car/tests/test_models_segs.txt FILEREADER_CACHE=1 \
["build", "cd selfdrive/manager && ./build.py"], pytest -n42 --dist=loadscope selfdrive/car/tests/test_models.py"
["model replay", "cd selfdrive/test/process_replay && ./model_replay.py"], sh label: "test_car_interfaces.py", script: "MAX_EXAMPLES=100 pytest -n42 --dist=load selfdrive/car/tests/test_car_interfaces.py"
])
}
} }
},
} )
} }
} catch (Exception e) {
currentBuild.result = 'FAILED'
throw e
} }
} }

@ -1,4 +1,4 @@
![](https://i.imgur.com/b0ZyIx5.jpg) ![openpilot on the comma 3X](https://github.com/commaai/openpilot/assets/4038174/f1081737-8718-4241-a22a-3ceba526361a)
Table of Contents Table of Contents
======================= =======================
@ -39,13 +39,17 @@ 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
* A supported device to run this software: a [comma three](https://comma.ai/shop/products/three). 1. **Supported Device:** A comma 3/3X. You can purchase these devices from (https://comma.ai/shop/comma-3x)
* 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. 2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software.
* One of [the 250+ supported cars](docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run openpilot. To install the release version of openpilot, use the URL `openpilot.comma.ai`.
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car. To install openpilot master (for more advanced users), use the URL `installer.comma.ai/commaai/master`. You can replace "commaai" with another GitHub username to install a fork.
We have detailed instructions for [how to mount the device in a car](https://comma.ai/setup). 3. **Supported Car:** Ensure that you have one of [the 250+ supported cars](docs/CARS.md). openpilot supports a wide range of car makes including Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford, and many more.
If your car is not officially listed as supported but has adaptive cruise control and lane-keeping assist, it's likely capable of running openpilot.
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car.
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup).
Running on PC Running on PC
------ ------
@ -105,7 +109,6 @@ Directory Structure
├── third_party # External libraries ├── third_party # External libraries
└── system # Generic services └── system # Generic services
├── camerad # Driver to capture images from the camera sensors ├── camerad # Driver to capture images from the camera sensors
├── clocksd # Broadcasts current time
├── hardware # Hardware abstraction classes ├── hardware # Hardware abstraction classes
├── logcatd # systemd journal as a service ├── logcatd # systemd journal as a service
├── loggerd # Logger and uploader of car data ├── loggerd # Logger and uploader of car data

@ -1,5 +1,24 @@
Version 0.9.5 (2023-11-17)
========================
* New driving model
* Improved navigate on openpilot performance using navigation instructions as an additional model input
* Do lateral planning inside the model
* New vision transformer architecture
* Cadillac Escalade ESV 2019 support thanks to twilsonco!
* Hyundai Azera 2022 support thanks to sunnyhaibin!
* Hyundai Azera Hybrid 2020 support thanks to chanhojung and haram-KONA!
* Hyundai Custin 2023 support thanks to sunnyhaibin and Saber422!
* Hyundai Ioniq 6 2023 support thanks to sunnyhaibin and alamo3!
* Hyundai Kona Electric 2023 (Korean version) support thanks to sunnyhaibin and haram-KONA!
* Kia K8 Hybrid (with HDA II) 2023 support thanks to sunnyhaibin!
* Kia Optima Hybrid 2019 support
* Kia Sorento Hybrid 2023 support thanks to sunnyhaibin!
* Lexus GS F 2016 support thanks to snyperifle!
* Lexus IS 2023 support thanks to L3R5!
Version 0.9.4 (2023-07-27) Version 0.9.4 (2023-07-27)
======================== ========================
* comma 3X support
* Navigate on openpilot in Experimental mode * Navigate on openpilot in Experimental mode
* When navigation has a destination, openpilot will input the map information into the model, which provides useful context to help the model understand the scene * When navigation has a destination, openpilot will input the map information into the model, which provides useful context to help the model understand the scene
* When navigating on openpilot, openpilot will keep left or right appropriately at forks and exits * When navigating on openpilot, openpilot will keep left or right appropriately at forks and exits

@ -14,10 +14,6 @@ AGNOS = TICI
Decider('MD5-timestamp') Decider('MD5-timestamp')
AddOption('--extras',
action='store_true',
help='build misc extras, like setup and installer files')
AddOption('--kaitai', AddOption('--kaitai',
action='store_true', action='store_true',
help='Regenerate kaitai struct parsers') help='Regenerate kaitai struct parsers')
@ -30,6 +26,10 @@ AddOption('--ubsan',
action='store_true', action='store_true',
help='turn on UBSan') help='turn on UBSan')
AddOption('--coverage',
action='store_true',
help='build with test coverage options')
AddOption('--clazy', AddOption('--clazy',
action='store_true', action='store_true',
help='build with clazy') help='build with clazy')
@ -37,6 +37,12 @@ AddOption('--clazy',
AddOption('--compile_db', AddOption('--compile_db',
action='store_true', action='store_true',
help='build clang compilation database') help='build clang compilation database')
AddOption('--ccflags',
action='store',
type='string',
default='',
help='pass arbitrary flags over the command line')
AddOption('--snpe', AddOption('--snpe',
action='store_true', action='store_true',
@ -48,34 +54,34 @@ AddOption('--external-sconscript',
dest='external_sconscript', dest='external_sconscript',
help='add an external SConscript to the build') help='add an external SConscript to the build')
AddOption('--no-thneed',
action='store_true',
dest='no_thneed',
help='avoid using thneed')
AddOption('--pc-thneed', AddOption('--pc-thneed',
action='store_true', action='store_true',
dest='pc_thneed', dest='pc_thneed',
help='use thneed on pc') help='use thneed on pc')
AddOption('--no-test', AddOption('--minimal',
action='store_false', action='store_false',
dest='test', dest='extras',
default=os.path.islink(Dir('#laika/').abspath), default=os.path.islink(Dir('#rednose/').abspath), # minimal by default on release branch (where rednose is not a link)
help='skip building test files') help='the minimum build to run openpilot. no tests, tools, etc.')
## Architecture name breakdown (arch)
## - larch64: linux tici aarch64
## - aarch64: linux pc aarch64
## - x86_64: linux pc x64
## - Darwin: mac x64 or arm64
real_arch = arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() real_arch = arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
if platform.system() == "Darwin": if platform.system() == "Darwin":
arch = "Darwin" arch = "Darwin"
brew_prefix = subprocess.check_output(['brew', '--prefix'], encoding='utf8').strip() brew_prefix = subprocess.check_output(['brew', '--prefix'], encoding='utf8').strip()
elif arch == "aarch64" and AGNOS:
if arch == "aarch64" and AGNOS:
arch = "larch64" arch = "larch64"
assert arch in ["larch64", "aarch64", "x86_64", "Darwin"]
lenv = { lenv = {
"PATH": os.environ['PATH'], "PATH": os.environ['PATH'],
"LD_LIBRARY_PATH": [Dir(f"#third_party/acados/{arch}/lib").abspath], "LD_LIBRARY_PATH": [Dir(f"#third_party/acados/{arch}/lib").abspath],
"PYTHONPATH": Dir("#").abspath, "PYTHONPATH": Dir("#").abspath + ':' + Dir(f"#third_party/acados").abspath,
"ACADOS_SOURCE_DIR": Dir("#third_party/acados").abspath, "ACADOS_SOURCE_DIR": Dir("#third_party/acados").abspath,
"ACADOS_PYTHON_INTERFACE_PATH": Dir("#third_party/acados/acados_template").abspath, "ACADOS_PYTHON_INTERFACE_PATH": Dir("#third_party/acados/acados_template").abspath,
@ -117,9 +123,8 @@ else:
# MacOS # MacOS
if arch == "Darwin": if arch == "Darwin":
yuv_dir = "mac" if real_arch != "arm64" else "mac_arm64"
libpath = [ libpath = [
f"#third_party/libyuv/{yuv_dir}/lib", f"#third_party/libyuv/{arch}/lib",
f"#third_party/acados/{arch}/lib", f"#third_party/acados/{arch}/lib",
f"{brew_prefix}/lib", f"{brew_prefix}/lib",
f"{brew_prefix}/opt/openssl@3.0/lib", f"{brew_prefix}/opt/openssl@3.0/lib",
@ -133,21 +138,25 @@ else:
f"{brew_prefix}/opt/openssl@3.0/include", f"{brew_prefix}/opt/openssl@3.0/include",
] ]
lenv["DYLD_LIBRARY_PATH"] = lenv["LD_LIBRARY_PATH"] lenv["DYLD_LIBRARY_PATH"] = lenv["LD_LIBRARY_PATH"]
# Linux 86_64 # Linux
else: else:
libpath = [ libpath = [
"#third_party/acados/x86_64/lib", f"#third_party/acados/{arch}/lib",
"#third_party/snpe/x86_64-linux-clang", f"#third_party/libyuv/{arch}/lib",
"#third_party/libyuv/x64/lib", f"#third_party/mapbox-gl-native-qt/{arch}",
"#third_party/mapbox-gl-native-qt/x86_64",
"#cereal", "#cereal",
"#common", "#common",
"/usr/lib", "/usr/lib",
"/usr/local/lib", "/usr/local/lib",
] ]
rpath += [
Dir("#third_party/snpe/x86_64-linux-clang").abspath, if arch == "x86_64":
] libpath += [
f"#third_party/snpe/{arch}"
]
rpath += [
Dir(f"#third_party/snpe/{arch}").abspath,
]
if GetOption('asan'): if GetOption('asan'):
ccflags = ["-fsanitize=address", "-fno-omit-frame-pointer"] ccflags = ["-fsanitize=address", "-fno-omit-frame-pointer"]
@ -167,6 +176,10 @@ if arch != "Darwin":
cflags += ['-DSWAGLOG="\\"common/swaglog.h\\""'] cflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""'] cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
ccflags_option = GetOption('ccflags')
if ccflags_option:
ccflags += ccflags_option.split(' ')
env = Environment( env = Environment(
ENV=lenv, ENV=lenv,
CCFLAGS=[ CCFLAGS=[
@ -193,7 +206,6 @@ env = Environment(
"#third_party/catch2/include", "#third_party/catch2/include",
"#third_party/libyuv/include", "#third_party/libyuv/include",
"#third_party/json11", "#third_party/json11",
"#third_party/curl/include",
"#third_party/linux/include", "#third_party/linux/include",
"#third_party/snpe/include", "#third_party/snpe/include",
"#third_party/mapbox-gl-native-qt/include", "#third_party/mapbox-gl-native-qt/include",
@ -246,18 +258,6 @@ def progress_function(node):
if os.environ.get('SCONS_PROGRESS'): if os.environ.get('SCONS_PROGRESS'):
Progress(progress_function, interval=node_interval) Progress(progress_function, interval=node_interval)
SHARED = False
# TODO: this can probably be removed
def abspath(x):
if arch == 'aarch64':
pth = os.path.join("/data/pythonpath", x[0].path)
env.Depends(pth, x)
return File(pth)
else:
# rpath works elsewhere
return x[0].path.rsplit("/", 1)[1][:-3]
# Cython build environment # Cython build environment
py_include = sysconfig.get_paths()['include'] py_include = sysconfig.get_paths()['include']
envCython = env.Clone() envCython = env.Clone()
@ -268,9 +268,6 @@ envCython["CCFLAGS"].remove("-Werror")
envCython["LIBS"] = [] envCython["LIBS"] = []
if arch == "Darwin": if arch == "Darwin":
envCython["LINKFLAGS"] = ["-bundle", "-undefined", "dynamic_lookup"] + darwin_rpath_link_flags envCython["LINKFLAGS"] = ["-bundle", "-undefined", "dynamic_lookup"] + darwin_rpath_link_flags
elif arch == "aarch64":
envCython["LINKFLAGS"] = ["-shared"]
envCython["LIBS"] = [os.path.basename(py_include)]
else: else:
envCython["LINKFLAGS"] = ["-pthread", "-shared"] envCython["LINKFLAGS"] = ["-pthread", "-shared"]
@ -330,7 +327,6 @@ qt_flags = [
qt_env['CXXFLAGS'] += qt_flags qt_env['CXXFLAGS'] += qt_flags
qt_env['LIBPATH'] += ['#selfdrive/ui'] qt_env['LIBPATH'] += ['#selfdrive/ui']
qt_env['LIBS'] = qt_libs qt_env['LIBS'] = qt_libs
qt_env['QT_MOCHPREFIX'] = cache_dir + '/moc_files/moc_'
if GetOption("clazy"): if GetOption("clazy"):
checks = [ checks = [
@ -343,33 +339,35 @@ if GetOption("clazy"):
qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0] qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0]
qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks) qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks)
Export('env', 'qt_env', 'arch', 'real_arch', 'SHARED') Export('env', 'qt_env', 'arch', 'real_arch')
# Build common module
SConscript(['common/SConscript']) SConscript(['common/SConscript'])
Import('_common', '_gpucommon') Import('_common', '_gpucommon')
if SHARED: common = [_common, 'json11']
common, gpucommon = abspath(common), abspath(gpucommon) gpucommon = [_gpucommon]
else:
common = [_common, 'json11']
gpucommon = [_gpucommon]
Export('common', 'gpucommon') Export('common', 'gpucommon')
# cereal and messaging are shared with the system # Build cereal and messaging
SConscript(['cereal/SConscript']) SConscript(['cereal/SConscript'])
if SHARED:
cereal = abspath([File('cereal/libcereal_shared.so')])
messaging = abspath([File('cereal/libmessaging_shared.so')])
else:
cereal = [File('#cereal/libcereal.a')]
messaging = [File('#cereal/libmessaging.a')]
visionipc = [File('#cereal/libvisionipc.a')]
Export('cereal', 'messaging', 'visionipc') cereal = [File('#cereal/libcereal.a')]
messaging = [File('#cereal/libmessaging.a')]
visionipc = [File('#cereal/libvisionipc.a')]
messaging_python = [File('#cereal/messaging/messaging_pyx.so')]
# Build rednose library and ekf models Export('cereal', 'messaging', 'messaging_python', 'visionipc')
# Build other submodules
SConscript([
'body/board/SConscript',
'opendbc/can/SConscript',
'panda/SConscript',
])
# Build rednose library and ekf models
rednose_deps = [ rednose_deps = [
"#selfdrive/locationd/models/constants.py", "#selfdrive/locationd/models/constants.py",
"#selfdrive/locationd/models/gnss_helpers.py", "#selfdrive/locationd/models/gnss_helpers.py",
@ -398,7 +396,6 @@ SConscript(['rednose/SConscript'])
# Build system services # Build system services
SConscript([ SConscript([
'system/clocksd/SConscript',
'system/proclogd/SConscript', 'system/proclogd/SConscript',
'system/ubloxd/SConscript', 'system/ubloxd/SConscript',
'system/loggerd/SConscript', 'system/loggerd/SConscript',
@ -411,20 +408,8 @@ if arch != "Darwin":
]) ])
# Build openpilot # Build openpilot
# build submodules
SConscript([
'body/board/SConscript',
'cereal/SConscript',
'opendbc/can/SConscript',
'panda/SConscript',
])
SConscript(['third_party/SConscript']) SConscript(['third_party/SConscript'])
SConscript(['common/kalman/SConscript'])
SConscript(['common/transformations/SConscript'])
SConscript(['selfdrive/boardd/SConscript']) SConscript(['selfdrive/boardd/SConscript'])
SConscript(['selfdrive/controls/lib/lateral_mpc_lib/SConscript']) SConscript(['selfdrive/controls/lib/lateral_mpc_lib/SConscript'])
SConscript(['selfdrive/controls/lib/longitudinal_mpc_lib/SConscript']) SConscript(['selfdrive/controls/lib/longitudinal_mpc_lib/SConscript'])
@ -433,7 +418,7 @@ SConscript(['selfdrive/navd/SConscript'])
SConscript(['selfdrive/modeld/SConscript']) SConscript(['selfdrive/modeld/SConscript'])
SConscript(['selfdrive/ui/SConscript']) SConscript(['selfdrive/ui/SConscript'])
if (arch in ['x86_64', 'Darwin'] and Dir('#tools/cabana/').exists()) or GetOption('extras'): if arch in ['x86_64', 'aarch64', 'Darwin'] and Dir('#tools/cabana/').exists() and GetOption('extras'):
SConscript(['tools/replay/SConscript']) SConscript(['tools/replay/SConscript'])
SConscript(['tools/cabana/SConscript']) SConscript(['tools/cabana/SConscript'])

@ -69,7 +69,7 @@ else:
envCython.Program('visionipc/visionipc_pyx.so', 'visionipc/visionipc_pyx.pyx', envCython.Program('visionipc/visionipc_pyx.so', 'visionipc/visionipc_pyx.pyx',
LIBS=vipc_libs, FRAMEWORKS=vipc_frameworks) LIBS=vipc_libs, FRAMEWORKS=vipc_frameworks)
if GetOption('test'): if GetOption('extras'):
env.Program('messaging/test_runner', ['messaging/test_runner.cc', 'messaging/msgq_tests.cc'], LIBS=[messaging_lib, common]) env.Program('messaging/test_runner', ['messaging/test_runner.cc', 'messaging/msgq_tests.cc'], LIBS=[messaging_lib, common])
env.Program('visionipc/test_runner', ['visionipc/test_runner.cc', 'visionipc/visionipc_tests.cc'], env.Program('visionipc/test_runner', ['visionipc/test_runner.cc', 'visionipc/visionipc_tests.cc'],

@ -63,7 +63,6 @@ struct CarEvent @0x9b1657f34caf3ad3 {
driverUnresponsive @45; driverUnresponsive @45;
belowSteerSpeed @46; belowSteerSpeed @46;
lowBattery @48; lowBattery @48;
vehicleModelInvalid @50;
accFaulted @51; accFaulted @51;
sensorDataInvalid @52; sensorDataInvalid @52;
commIssue @53; commIssue @53;
@ -106,7 +105,6 @@ struct CarEvent @0x9b1657f34caf3ad3 {
roadCameraError @100; roadCameraError @100;
driverCameraError @101; driverCameraError @101;
wideRoadCameraError @102; wideRoadCameraError @102;
localizerMalfunction @103;
highCpuUsage @105; highCpuUsage @105;
cruiseMismatch @106; cruiseMismatch @106;
lkasDisabled @107; lkasDisabled @107;
@ -115,6 +113,10 @@ struct CarEvent @0x9b1657f34caf3ad3 {
resumeBlocked @113; resumeBlocked @113;
steerTimeLimit @115; steerTimeLimit @115;
vehicleSensorsInvalid @116; vehicleSensorsInvalid @116;
locationdTemporaryError @103;
locationdPermanentError @118;
paramsdTemporaryError @50;
paramsdPermanentError @119;
radarCanErrorDEPRECATED @15; radarCanErrorDEPRECATED @15;
communityFeatureDisallowedDEPRECATED @62; communityFeatureDisallowedDEPRECATED @62;
@ -450,6 +452,7 @@ struct CarParams {
# things we can derive # things we can derive
rotationalInertia @22 :Float32; # [kg*m2] body rotational inertia rotationalInertia @22 :Float32; # [kg*m2] body rotational inertia
tireStiffnessFactor @72 :Float32; # scaling factor used in calculating tireStiffness[Front,Rear]
tireStiffnessFront @23 :Float32; # [N/rad] front tire coeff of stiff tireStiffnessFront @23 :Float32; # [N/rad] front tire coeff of stiff
tireStiffnessRear @24 :Float32; # [N/rad] rear tire coeff of stiff tireStiffnessRear @24 :Float32; # [N/rad] rear tire coeff of stiff
@ -457,8 +460,8 @@ struct CarParams {
lateralParams @48 :LateralParams; lateralParams @48 :LateralParams;
lateralTuning :union { lateralTuning :union {
pid @26 :LateralPIDTuning; pid @26 :LateralPIDTuning;
indi @27 :LateralINDITuning; indiDEPRECATED @27 :LateralINDITuning;
lqr @40 :LateralLQRTuning; lqrDEPRECATED @40 :LateralLQRTuning;
torque @67 :LateralTorqueTuning; torque @67 :LateralTorqueTuning;
} }
@ -591,6 +594,7 @@ struct CarParams {
hongqi @26; hongqi @26;
body @27; body @27;
hyundaiCanfd @28; hyundaiCanfd @28;
volkswagenMqbEvo @29;
} }
enum SteerControlType { enum SteerControlType {

@ -46,6 +46,8 @@ struct InitData {
commands @19 :Map(Text, Data); commands @19 :Map(Text, Data);
wallTimeNanos @20 :UInt64;
enum DeviceType { enum DeviceType {
unknown @0; unknown @0;
neo @1; neo @1;
@ -586,6 +588,7 @@ struct RadarState @0x9a185389d6fdd05f {
aLeadTau @12 :Float32; aLeadTau @12 :Float32;
modelProb @13 :Float32; modelProb @13 :Float32;
radar @14 :Bool; radar @14 :Bool;
radarTrackId @15 :Int32 = -1;
aLeadDEPRECATED @5 :Float32; aLeadDEPRECATED @5 :Float32;
} }
@ -871,6 +874,8 @@ struct ModelDataV2 {
navEnabled @22 :Bool; navEnabled @22 :Bool;
locationMonoTime @24 :UInt64; locationMonoTime @24 :UInt64;
# e2e lateral planner
lateralPlannerSolution @25: LateralPlannerSolution;
struct LeadDataV2 { struct LeadDataV2 {
prob @0 :Float32; # probability that car is your lead at time t prob @0 :Float32; # probability that car is your lead at time t
@ -937,6 +942,18 @@ struct ModelDataV2 {
transStd @2 :List(Float32); # std m/s in device frame transStd @2 :List(Float32); # std m/s in device frame
rotStd @3 :List(Float32); # std rad/s in device frame rotStd @3 :List(Float32); # std rad/s in device frame
} }
struct LateralPlannerSolution {
x @0 :List(Float32);
y @1 :List(Float32);
yaw @2 :List(Float32);
yawRate @3 :List(Float32);
xStd @4 :List(Float32);
yStd @5 :List(Float32);
yawStd @6 :List(Float32);
yawRateStd @7 :List(Float32);
}
} }
struct EncodeIndex { struct EncodeIndex {
@ -2082,6 +2099,8 @@ struct NavInstruction {
speedLimit @10 :Float32; # m/s speedLimit @10 :Float32; # m/s
speedLimitSign @11 :SpeedLimitSign; speedLimitSign @11 :SpeedLimitSign;
allManeuvers @12 :List(Maneuver);
struct Lane { struct Lane {
directions @0 :List(Direction); directions @0 :List(Direction);
active @1 :Bool; active @1 :Bool;
@ -2093,12 +2112,20 @@ struct NavInstruction {
left @1; left @1;
right @2; right @2;
straight @3; straight @3;
slightLeft @4;
slightRight @5;
} }
enum SpeedLimitSign { enum SpeedLimitSign {
mutcd @0; # US Style mutcd @0; # US Style
vienna @1; # EU Style vienna @1; # EU Style
} }
struct Maneuver {
distance @0 :Float32;
type @1 :Text;
modifier @2 :Text;
}
} }
struct NavRoute { struct NavRoute {
@ -2177,6 +2204,7 @@ struct Event {
magnetometer @95 :SensorEventData; magnetometer @95 :SensorEventData;
lightSensor @96 :SensorEventData; lightSensor @96 :SensorEventData;
temperatureSensor @97 :SensorEventData; temperatureSensor @97 :SensorEventData;
temperatureSensor2 @123 :SensorEventData;
pandaStates @81 :List(PandaState); pandaStates @81 :List(PandaState);
peripheralState @80 :PeripheralState; peripheralState @80 :PeripheralState;
radarState @13 :RadarState; radarState @13 :RadarState;
@ -2253,6 +2281,10 @@ struct Event {
livestreamWideRoadEncodeData @121 :EncodeData; livestreamWideRoadEncodeData @121 :EncodeData;
livestreamDriverEncodeData @122 :EncodeData; livestreamDriverEncodeData @122 :EncodeData;
customReservedRawData0 @124 :Data;
customReservedRawData1 @125 :Data;
customReservedRawData2 @126 :Data;
# *********** Custom: reserved for forks *********** # *********** Custom: reserved for forks ***********
customReserved0 @107 :Custom.CustomReserved0; customReserved0 @107 :Custom.CustomReserved0;
customReserved1 @108 :Custom.CustomReserved1; customReserved1 @108 :Custom.CustomReserved1;

@ -1,6 +1,7 @@
# must be built with scons # must be built with scons
from .messaging_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, set_fake_prefix, get_fake_prefix, delete_fake_prefix, wait_for_one_event # pylint: disable=no-name-in-module, import-error from .messaging_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \
from .messaging_pyx import MultiplePublishersError, MessagingError # pylint: disable=no-name-in-module, import-error set_fake_prefix, get_fake_prefix, delete_fake_prefix, wait_for_one_event
from .messaging_pyx import MultiplePublishersError, MessagingError
import os import os
import capnp import capnp
@ -10,7 +11,7 @@ from typing import Optional, List, Union, Dict, Deque
from collections import deque from collections import deque
from cereal import log from cereal import log
from cereal.services import service_list from cereal.services import SERVICE_LIST
assert MultiplePublishersError assert MultiplePublishersError
assert MessagingError assert MessagingError
@ -23,13 +24,6 @@ assert wait_for_one_event
NO_TRAVERSAL_LIMIT = 2**64-1 NO_TRAVERSAL_LIMIT = 2**64-1
AVG_FREQ_HISTORY = 100 AVG_FREQ_HISTORY = 100
# sec_since_boot is faster, but allow to run standalone too
try:
from common.realtime import sec_since_boot
except ImportError:
sec_since_boot = time.time
print("Warning, using python time.time() instead of faster sec_since_boot")
context = Context() context = Context()
@ -49,7 +43,7 @@ def log_from_bytes(dat: bytes) -> capnp.lib.capnp._DynamicStructReader:
def new_message(service: Optional[str] = None, size: Optional[int] = None) -> capnp.lib.capnp._DynamicStructBuilder: def new_message(service: Optional[str] = None, size: Optional[int] = None) -> capnp.lib.capnp._DynamicStructBuilder:
dat = log.Event.new_message() dat = log.Event.new_message()
dat.logMonoTime = int(sec_since_boot() * 1e9) dat.logMonoTime = int(time.monotonic() * 1e9)
dat.valid = True dat.valid = True
if service is not None: if service is not None:
if size is None: if size is None:
@ -186,7 +180,7 @@ class SubMaster:
if addr is not None: if addr is not None:
p = self.poller if s not in self.non_polled_services else None p = self.poller if s not in self.non_polled_services else None
self.sock[s] = sub_sock(s, poller=p, addr=addr, conflate=True) self.sock[s] = sub_sock(s, poller=p, addr=addr, conflate=True)
self.freq[s] = service_list[s].frequency self.freq[s] = SERVICE_LIST[s].frequency
try: try:
data = new_message(s) data = new_message(s)
@ -212,7 +206,7 @@ class SubMaster:
# non-blocking receive for non-polled sockets # non-blocking receive for non-polled sockets
for s in self.non_polled_services: for s in self.non_polled_services:
msgs.append(recv_one_or_none(self.sock[s])) msgs.append(recv_one_or_none(self.sock[s]))
self.update_msgs(sec_since_boot(), msgs) self.update_msgs(time.monotonic(), msgs)
def update_msgs(self, cur_time: float, msgs: List[capnp.lib.capnp._DynamicStructReader]) -> None: def update_msgs(self, cur_time: float, msgs: List[capnp.lib.capnp._DynamicStructReader]) -> None:
self.frame += 1 self.frame += 1
@ -293,8 +287,7 @@ class PubMaster:
dat = dat.to_bytes() dat = dat.to_bytes()
self.sock[s].send(dat) self.sock[s].send(dat)
def wait_for_readers_to_update(self, s: str, timeout: int) -> bool: def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
dt = 0.05
for _ in range(int(timeout*(1./dt))): for _ in range(int(timeout*(1./dt))):
if self.sock[s].all_readers_updated(): if self.sock[s].all_readers_updated():
return True return True

@ -24,7 +24,7 @@ void sigpipe_handler(int sig) {
static std::vector<std::string> get_services(std::string whitelist_str, bool zmq_to_msgq) { static std::vector<std::string> get_services(std::string whitelist_str, bool zmq_to_msgq) {
std::vector<std::string> service_list; std::vector<std::string> service_list;
for (const auto& it : services) { for (const auto& it : services) {
std::string name = it.name; std::string name = it.second.name;
bool in_whitelist = whitelist_str.find(name) != std::string::npos; bool in_whitelist = whitelist_str.find(name) != std::string::npos;
if (name == "plusFrame" || name == "uiLayoutState" || (zmq_to_msgq && !in_whitelist)) { if (name == "plusFrame" || name == "uiLayoutState" || (zmq_to_msgq && !in_whitelist)) {
continue; continue;

@ -63,5 +63,5 @@ private:
public: public:
void registerSocket(SubSocket *socket) override; void registerSocket(SubSocket *socket) override;
std::vector<SubSocket*> poll(int timeout) override; std::vector<SubSocket*> poll(int timeout) override;
~FakePoller() {}; ~FakePoller() {}
}; };

@ -17,12 +17,7 @@ void sig_handler(int signal) {
} }
static bool service_exists(std::string path){ static bool service_exists(std::string path){
for (const auto& it : services) { return services.count(path) > 0;
if (it.name == path) {
return true;
}
}
return false;
} }

@ -63,5 +63,5 @@ private:
public: public:
void registerSocket(SubSocket *socket); void registerSocket(SubSocket *socket);
std::vector<SubSocket*> poll(int timeout); std::vector<SubSocket*> poll(int timeout);
~MSGQPoller(){}; ~MSGQPoller(){}
}; };

@ -3,22 +3,13 @@
#include <iostream> #include <iostream>
#include <cstdlib> #include <cstdlib>
#include <cerrno> #include <cerrno>
#include <unistd.h>
#include "cereal/services.h" #include "cereal/services.h"
#include "cereal/messaging/impl_zmq.h" #include "cereal/messaging/impl_zmq.h"
static int get_port(std::string endpoint) { static int get_port(std::string endpoint) {
int port = -1; return services.at(endpoint).port;
for (const auto& it : services) {
std::string name = it.name;
if (name == endpoint) {
port = it.port;
break;
}
}
assert(port >= 0);
return port;
} }
ZMQContext::ZMQContext() { ZMQContext::ZMQContext() {
@ -118,14 +109,19 @@ int ZMQPubSocket::connect(Context *context, std::string endpoint, bool check_end
full_endpoint += endpoint; full_endpoint += endpoint;
} }
// ZMQ pub sockets cannot be shared between processes, so we need to ensure pid stays the same
pid = getpid();
return zmq_bind(sock, full_endpoint.c_str()); return zmq_bind(sock, full_endpoint.c_str());
} }
int ZMQPubSocket::sendMessage(Message *message){ int ZMQPubSocket::sendMessage(Message *message) {
assert(pid == getpid());
return zmq_send(sock, message->getData(), message->getSize(), ZMQ_DONTWAIT); return zmq_send(sock, message->getData(), message->getSize(), ZMQ_DONTWAIT);
} }
int ZMQPubSocket::send(char *data, size_t size){ int ZMQPubSocket::send(char *data, size_t size) {
assert(pid == getpid());
return zmq_send(sock, data, size, ZMQ_DONTWAIT); return zmq_send(sock, data, size, ZMQ_DONTWAIT);
} }

@ -46,6 +46,7 @@ class ZMQPubSocket : public PubSocket {
private: private:
void * sock; void * sock;
std::string full_endpoint; std::string full_endpoint;
int pid = -1;
public: public:
int connect(Context *context, std::string endpoint, bool check_endpoint=true); int connect(Context *context, std::string endpoint, bool check_endpoint=true);
int sendMessage(Message *message); int sendMessage(Message *message);
@ -63,5 +64,5 @@ private:
public: public:
void registerSocket(SubSocket *socket); void registerSocket(SubSocket *socket);
std::vector<SubSocket*> poll(int timeout); std::vector<SubSocket*> poll(int timeout);
~ZMQPoller(){}; ~ZMQPoller(){}
}; };

@ -33,7 +33,7 @@ public:
virtual void close() = 0; virtual void close() = 0;
virtual size_t getSize() = 0; virtual size_t getSize() = 0;
virtual char * getData() = 0; virtual char * getData() = 0;
virtual ~Message(){}; virtual ~Message(){}
}; };
@ -45,7 +45,7 @@ public:
virtual void * getRawSocket() = 0; virtual void * getRawSocket() = 0;
static SubSocket * create(); static SubSocket * create();
static SubSocket * create(Context * context, std::string endpoint, std::string address="127.0.0.1", bool conflate=false, bool check_endpoint=true); static SubSocket * create(Context * context, std::string endpoint, std::string address="127.0.0.1", bool conflate=false, bool check_endpoint=true);
virtual ~SubSocket(){}; virtual ~SubSocket(){}
}; };
class PubSocket { class PubSocket {
@ -57,7 +57,7 @@ public:
static PubSocket * create(); static PubSocket * create();
static PubSocket * create(Context * context, std::string endpoint, bool check_endpoint=true); static PubSocket * create(Context * context, std::string endpoint, bool check_endpoint=true);
static PubSocket * create(Context * context, std::string endpoint, int port, bool check_endpoint=true); static PubSocket * create(Context * context, std::string endpoint, int port, bool check_endpoint=true);
virtual ~PubSocket(){}; virtual ~PubSocket(){}
}; };
class Poller { class Poller {
@ -66,7 +66,7 @@ public:
virtual std::vector<SubSocket*> poll(int timeout) = 0; virtual std::vector<SubSocket*> poll(int timeout) = 0;
static Poller * create(); static Poller * create();
static Poller * create(std::vector<SubSocket*> sockets); static Poller * create(std::vector<SubSocket*> sockets);
virtual ~Poller(){}; virtual ~Poller(){}
}; };
class SubMaster { class SubMaster {
@ -116,6 +116,18 @@ public:
return heapArray_.asBytes(); return heapArray_.asBytes();
} }
size_t getSerializedSize() {
return capnp::computeSerializedSizeInWords(*this) * sizeof(capnp::word);
}
int serializeToBuffer(unsigned char *buffer, size_t buffer_size) {
size_t serialized_size = getSerializedSize();
if (serialized_size > buffer_size) { return -1; }
kj::ArrayOutputStream out(kj::ArrayPtr<capnp::byte>(buffer, buffer_size));
capnp::writeMessage(out, *this);
return serialized_size;
}
private: private:
kj::Array<capnp::word> heapArray_; kj::Array<capnp::word> heapArray_;
}; };

@ -15,13 +15,6 @@ static inline uint64_t nanos_since_boot() {
return t.tv_sec * 1000000000ULL + t.tv_nsec; return t.tv_sec * 1000000000ULL + t.tv_nsec;
} }
static const service *get_service(const char *name) {
for (const auto &it : services) {
if (strcmp(it.name, name) == 0) return &it;
}
return nullptr;
}
static inline bool inList(const std::vector<const char *> &list, const char *value) { static inline bool inList(const std::vector<const char *> &list, const char *value) {
for (auto &v : list) { for (auto &v : list) {
if (strcmp(value, v) == 0) return true; if (strcmp(value, v) == 0) return true;
@ -31,7 +24,7 @@ static inline bool inList(const std::vector<const char *> &list, const char *val
class MessageContext { class MessageContext {
public: public:
MessageContext() : ctx_(nullptr) {}; MessageContext() : ctx_(nullptr) {}
~MessageContext() { delete ctx_; } ~MessageContext() { delete ctx_; }
inline Context *context() { inline Context *context() {
std::call_once(init_flag, [=]() { ctx_ = Context::create(); }); std::call_once(init_flag, [=]() { ctx_ = Context::create(); });
@ -61,8 +54,9 @@ SubMaster::SubMaster(const std::vector<const char *> &service_list, const std::v
const char *address, const std::vector<const char *> &ignore_alive) { const char *address, const std::vector<const char *> &ignore_alive) {
poller_ = Poller::create(); poller_ = Poller::create();
for (auto name : service_list) { for (auto name : service_list) {
const service *serv = get_service(name); assert(services.count(std::string(name)) > 0);
assert(serv != nullptr);
service serv = services.at(std::string(name));
SubSocket *socket = SubSocket::create(message_context.context(), name, address ? address : "127.0.0.1", true); SubSocket *socket = SubSocket::create(message_context.context(), name, address ? address : "127.0.0.1", true);
assert(socket != 0); assert(socket != 0);
bool is_polled = inList(poll, name) || poll.empty(); bool is_polled = inList(poll, name) || poll.empty();
@ -70,7 +64,7 @@ SubMaster::SubMaster(const std::vector<const char *> &service_list, const std::v
SubMessage *m = new SubMessage{ SubMessage *m = new SubMessage{
.name = name, .name = name,
.socket = socket, .socket = socket,
.freq = serv->frequency, .freq = serv.frequency,
.ignore_alive = inList(ignore_alive, name), .ignore_alive = inList(ignore_alive, name),
.allocated_msg_reader = malloc(sizeof(capnp::FlatArrayMessageReader)), .allocated_msg_reader = malloc(sizeof(capnp::FlatArrayMessageReader)),
.is_polled = is_polled}; .is_polled = is_polled};
@ -184,7 +178,7 @@ uint64_t SubMaster::rcv_time(const char *name) const {
cereal::Event::Reader &SubMaster::operator[](const char *name) const { cereal::Event::Reader &SubMaster::operator[](const char *name) const {
return services_.at(name)->event; return services_.at(name)->event;
}; }
SubMaster::~SubMaster() { SubMaster::~SubMaster() {
delete poller_; delete poller_;
@ -199,7 +193,7 @@ SubMaster::~SubMaster() {
PubMaster::PubMaster(const std::vector<const char *> &service_list) { PubMaster::PubMaster(const std::vector<const char *> &service_list) {
for (auto name : service_list) { for (auto name : service_list) {
assert(get_service(name) != nullptr); assert(services.count(name) > 0);
PubSocket *socket = PubSocket::create(message_context.context(), name); PubSocket *socket = PubSocket::create(message_context.context(), name);
assert(socket); assert(socket);
sockets_[name] = socket; sockets_[name] = socket;

@ -18,21 +18,22 @@ class Service:
self.decimation = decimation self.decimation = decimation
services = { services: dict[str, tuple] = {
# service: (should_log, frequency, qlog decimation (optional)) # service: (should_log, frequency, qlog decimation (optional))
# note: the "EncodeIdx" packets will still be in the log # note: the "EncodeIdx" packets will still be in the log
"gyroscope": (True, 104., 104), "gyroscope": (True, 104., 104),
"gyroscope2": (True, 100., 100), "gyroscope2": (True, 100., 100),
"accelerometer": (True, 104., 104), "accelerometer": (True, 104., 104),
"accelerometer2": (True, 100., 100), "accelerometer2": (True, 100., 100),
"magnetometer": (True, 100., 100), "magnetometer": (True, 25., 25),
"lightSensor": (True, 100., 100), "lightSensor": (True, 100., 100),
"temperatureSensor": (True, 100., 100), "temperatureSensor": (True, 2., 200),
"temperatureSensor2": (True, 2., 200),
"gpsNMEA": (True, 9.), "gpsNMEA": (True, 9.),
"deviceState": (True, 2., 1), "deviceState": (True, 2., 1),
"can": (True, 100., 1223), # decimation gives ~5 msgs in a full segment "can": (True, 100., 1223), # decimation gives ~5 msgs in a full segment
"controlsState": (True, 100., 10), "controlsState": (True, 100., 10),
"pandaStates": (True, 2., 1), "pandaStates": (True, 10., 1),
"peripheralState": (True, 2., 1), "peripheralState": (True, 2., 1),
"radarState": (True, 20., 5), "radarState": (True, 20., 5),
"roadEncodeIdx": (False, 20., 1), "roadEncodeIdx": (False, 20., 1),
@ -94,8 +95,11 @@ services = {
"livestreamWideRoadEncodeData": (False, 20.), "livestreamWideRoadEncodeData": (False, 20.),
"livestreamRoadEncodeData": (False, 20.), "livestreamRoadEncodeData": (False, 20.),
"livestreamDriverEncodeData": (False, 20.), "livestreamDriverEncodeData": (False, 20.),
"customReservedRawData0": (True, 0.),
"customReservedRawData1": (True, 0.),
"customReservedRawData2": (True, 0.),
} }
service_list = {name: Service(new_port(idx), *vals) for # type: ignore SERVICE_LIST = {name: Service(new_port(idx), *vals) for
idx, (name, vals) in enumerate(services.items())} idx, (name, vals) in enumerate(services.items())}
@ -104,14 +108,19 @@ def build_header():
h += "/* THIS IS AN AUTOGENERATED FILE, PLEASE EDIT services.py */\n" h += "/* THIS IS AN AUTOGENERATED FILE, PLEASE EDIT services.py */\n"
h += "#ifndef __SERVICES_H\n" h += "#ifndef __SERVICES_H\n"
h += "#define __SERVICES_H\n" h += "#define __SERVICES_H\n"
h += "struct service { char name[0x100]; int port; bool should_log; int frequency; int decimation; };\n"
h += "static struct service services[] = {\n" h += "#include <map>\n"
for k, v in service_list.items(): h += "#include <string>\n"
h += "struct service { std::string name; int port; bool should_log; int frequency; int decimation; };\n"
h += "static std::map<std::string, service> services = {\n"
for k, v in SERVICE_LIST.items():
should_log = "true" if v.should_log else "false" should_log = "true" if v.should_log else "false"
decimation = -1 if v.decimation is None else v.decimation decimation = -1 if v.decimation is None else v.decimation
h += ' { "%s", %d, %s, %d, %d },\n' % \ h += ' { "%s", {"%s", %d, %s, %d, %d}},\n' % \
(k, v.port, should_log, v.frequency, decimation) (k, k, v.port, should_log, v.frequency, decimation)
h += "};\n" h += "};\n"
h += "#endif\n" h += "#endif\n"
return h return h

@ -1,4 +1,5 @@
from cereal.visionipc.visionipc_pyx import VisionIpcClient, VisionIpcServer, VisionStreamType, get_endpoint_name # pylint: disable=no-name-in-module, import-error from cereal.visionipc.visionipc_pyx import VisionBuf, VisionIpcClient, VisionIpcServer, VisionStreamType, get_endpoint_name
assert VisionBuf
assert VisionIpcClient assert VisionIpcClient
assert VisionIpcServer assert VisionIpcServer
assert VisionStreamType assert VisionStreamType

@ -40,30 +40,35 @@
#define DEVICE_PAGE_SIZE_CL 4096 #define DEVICE_PAGE_SIZE_CL 4096
#define PADDING_CL 0 #define PADDING_CL 0
static int ion_fd = -1; struct IonFileHandle {
static void ion_init() { IonFileHandle() {
if (ion_fd == -1) { fd = open("/dev/ion", O_RDWR | O_NONBLOCK);
ion_fd = open("/dev/ion", O_RDWR | O_NONBLOCK); assert(fd >= 0);
} }
~IonFileHandle() {
close(fd);
}
int fd = -1;
};
int ion_fd() {
static IonFileHandle fh;
return fh.fd;
} }
void VisionBuf::allocate(size_t length) { void VisionBuf::allocate(size_t length) {
int err;
ion_init();
struct ion_allocation_data ion_alloc = {0}; struct ion_allocation_data ion_alloc = {0};
ion_alloc.len = length + PADDING_CL + sizeof(uint64_t); ion_alloc.len = length + PADDING_CL + sizeof(uint64_t);
ion_alloc.align = 4096; ion_alloc.align = 4096;
ion_alloc.heap_id_mask = 1 << ION_IOMMU_HEAP_ID; ion_alloc.heap_id_mask = 1 << ION_IOMMU_HEAP_ID;
ion_alloc.flags = ION_FLAG_CACHED; ion_alloc.flags = ION_FLAG_CACHED;
err = HANDLE_EINTR(ioctl(ion_fd, ION_IOC_ALLOC, &ion_alloc)); int err = HANDLE_EINTR(ioctl(ion_fd(), ION_IOC_ALLOC, &ion_alloc));
assert(err == 0); assert(err == 0);
struct ion_fd_data ion_fd_data = {0}; struct ion_fd_data ion_fd_data = {0};
ion_fd_data.handle = ion_alloc.handle; ion_fd_data.handle = ion_alloc.handle;
err = HANDLE_EINTR(ioctl(ion_fd, ION_IOC_SHARE, &ion_fd_data)); err = HANDLE_EINTR(ioctl(ion_fd(), ION_IOC_SHARE, &ion_fd_data));
assert(err == 0); assert(err == 0);
void *mmap_addr = mmap(NULL, ion_alloc.len, void *mmap_addr = mmap(NULL, ion_alloc.len,
@ -85,12 +90,10 @@ void VisionBuf::import(){
int err; int err;
assert(this->fd >= 0); assert(this->fd >= 0);
ion_init();
// Get handle // Get handle
struct ion_fd_data fd_data = {0}; struct ion_fd_data fd_data = {0};
fd_data.fd = this->fd; fd_data.fd = this->fd;
err = HANDLE_EINTR(ioctl(ion_fd, ION_IOC_IMPORT, &fd_data)); err = HANDLE_EINTR(ioctl(ion_fd(), ION_IOC_IMPORT, &fd_data));
assert(err == 0); assert(err == 0);
this->handle = fd_data.handle; this->handle = fd_data.handle;
@ -136,7 +139,7 @@ int VisionBuf::sync(int dir) {
ION_IOC_INV_CACHES : ION_IOC_CLEAN_CACHES; ION_IOC_INV_CACHES : ION_IOC_CLEAN_CACHES;
custom_data.arg = (unsigned long)&flush_data; custom_data.arg = (unsigned long)&flush_data;
return HANDLE_EINTR(ioctl(ion_fd, ION_IOC_CUSTOM, &custom_data)); return HANDLE_EINTR(ioctl(ion_fd(), ION_IOC_CUSTOM, &custom_data));
} }
int VisionBuf::free() { int VisionBuf::free() {
@ -154,5 +157,5 @@ int VisionBuf::free() {
if (err != 0) return err; if (err != 0) return err;
struct ion_handle_data handle_data = {.handle = this->handle}; struct ion_handle_data handle_data = {.handle = this->handle};
return HANDLE_EINTR(ioctl(ion_fd, ION_IOC_FREE, &handle_data)); return HANDLE_EINTR(ioctl(ion_fd(), ION_IOC_FREE, &handle_data));
} }

@ -8,7 +8,12 @@ from libc.stdint cimport uint32_t, uint64_t
from libcpp cimport bool, int from libcpp cimport bool, int
cdef extern from "cereal/visionipc/visionbuf.h": cdef extern from "cereal/visionipc/visionbuf.h":
struct _cl_device_id
struct _cl_context
struct _cl_mem struct _cl_mem
ctypedef _cl_device_id * cl_device_id
ctypedef _cl_context * cl_context
ctypedef _cl_mem * cl_mem ctypedef _cl_mem * cl_mem
cdef enum VisionStreamType: cdef enum VisionStreamType:

@ -19,8 +19,6 @@ private:
cl_device_id device_id = nullptr; cl_device_id device_id = nullptr;
cl_context ctx = nullptr; cl_context ctx = nullptr;
void init_msgq(bool conflate);
public: public:
bool connected = false; bool connected = false;
VisionStreamType type; VisionStreamType type;

@ -2,6 +2,11 @@
#cython: language_level=3 #cython: language_level=3
from .visionipc cimport VisionBuf as cppVisionBuf from .visionipc cimport VisionBuf as cppVisionBuf
from .visionipc cimport cl_device_id, cl_context
cdef class CLContext:
cdef cl_device_id device_id
cdef cl_context context
cdef class VisionBuf: cdef class VisionBuf:
cdef cppVisionBuf * buf cdef cppVisionBuf * buf

@ -98,8 +98,11 @@ cdef class VisionIpcClient:
cdef cppVisionIpcClient * client cdef cppVisionIpcClient * client
cdef VisionIpcBufExtra extra cdef VisionIpcBufExtra extra
def __cinit__(self, string name, VisionStreamType stream, bool conflate): def __cinit__(self, string name, VisionStreamType stream, bool conflate, CLContext context = None):
self.client = new cppVisionIpcClient(name, stream, conflate, NULL, NULL) if context:
self.client = new cppVisionIpcClient(name, stream, conflate, context.device_id, context.context)
else:
self.client = new cppVisionIpcClient(name, stream, conflate, NULL, NULL)
def __dealloc__(self): def __dealloc__(self):
del self.client del self.client

@ -23,7 +23,6 @@ class VisionIpcServer {
std::map<VisionStreamType, std::atomic<size_t> > cur_idx; std::map<VisionStreamType, std::atomic<size_t> > cur_idx;
std::map<VisionStreamType, std::vector<VisionBuf*> > buffers; std::map<VisionStreamType, std::vector<VisionBuf*> > buffers;
std::map<VisionStreamType, std::map<VisionBuf*, size_t> > idxs;
Context * msg_ctx; Context * msg_ctx;
std::map<VisionStreamType, PubSocket*> sockets; std::map<VisionStreamType, PubSocket*> sockets;

@ -1,9 +1,4 @@
Import('env', 'envCython', 'arch', 'SHARED') Import('env', 'envCython', 'arch')
if SHARED:
fxn = env.SharedLibrary
else:
fxn = env.Library
common_libs = [ common_libs = [
'params.cc', 'params.cc',
@ -12,24 +7,35 @@ common_libs = [
'util.cc', 'util.cc',
'i2c.cc', 'i2c.cc',
'watchdog.cc', 'watchdog.cc',
'ratekeeper.cc'
] ]
if arch != "Darwin": if arch != "Darwin":
common_libs.append('gpio.cc') common_libs.append('gpio.cc')
_common = fxn('common', common_libs, LIBS="json11") _common = env.Library('common', common_libs, LIBS="json11")
files = [ files = [
'clutil.cc', 'clutil.cc',
] ]
_gpucommon = fxn('gpucommon', files) _gpucommon = env.Library('gpucommon', files)
Export('_common', '_gpucommon') Export('_common', '_gpucommon')
if GetOption('test'): if GetOption('extras'):
env.Program('tests/test_util', ['tests/test_util.cc'], LIBS=[_common]) env.Program('tests/test_common',
env.Program('tests/test_swaglog', ['tests/test_swaglog.cc'], LIBS=[_common, 'json11', 'zmq', 'pthread']) ['tests/test_runner.cc', 'tests/test_util.cc', 'tests/test_swaglog.cc', 'tests/test_ratekeeper.cc'],
LIBS=[_common, 'json11', 'zmq', 'pthread'])
# Cython bindings
params_python = envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [_common, 'zmq', 'json11'])
SConscript([
'kalman/SConscript',
'transformations/SConscript'
])
Import('simple_kalman_python', 'transformations_python')
common_python = [params_python, simple_kalman_python, transformations_python]
# Cython Export('common_python')
envCython.Program('clock.so', 'clock.pyx')
envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [_common, 'zmq', 'json11'])

@ -2,8 +2,8 @@ import jwt
import os import os
import requests import requests
from datetime import datetime, timedelta from datetime import datetime, timedelta
from common.basedir import PERSIST from openpilot.common.basedir import PERSIST
from system.version import get_version from openpilot.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 system.hardware import PC from openpilot.system.hardware import PC
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")) BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../"))

@ -1,24 +0,0 @@
# distutils: language = c++
# cython: language_level = 3
from posix.time cimport clock_gettime, timespec, CLOCK_MONOTONIC_RAW, clockid_t
IF UNAME_SYSNAME == "Darwin":
# Darwin doesn't have a CLOCK_BOOTTIME
CLOCK_BOOTTIME = CLOCK_MONOTONIC_RAW
ELSE:
from posix.time cimport CLOCK_BOOTTIME
cdef double readclock(clockid_t clock_id):
cdef timespec ts
cdef double current
clock_gettime(clock_id, &ts)
current = ts.tv_sec + (ts.tv_nsec / 1000000000.)
return current
def monotonic_time():
return readclock(CLOCK_MONOTONIC_RAW)
def sec_since_boot():
return readclock(CLOCK_BOOTTIME)

@ -38,8 +38,8 @@ void cl_print_info(cl_platform_id platform, cl_device_id device) {
LOGD("extensions: %s", get_platform_info(platform, CL_PLATFORM_EXTENSIONS).c_str()); LOGD("extensions: %s", get_platform_info(platform, CL_PLATFORM_EXTENSIONS).c_str());
LOGD("name: %s", get_device_info(device, CL_DEVICE_NAME).c_str()); LOGD("name: %s", get_device_info(device, CL_DEVICE_NAME).c_str());
LOGD("device version: %s", get_device_info(device, CL_DEVICE_VERSION).c_str()); LOGD("device version: %s", get_device_info(device, CL_DEVICE_VERSION).c_str());
LOGD("max work group size: %d", work_group_size); LOGD("max work group size: %zu", work_group_size);
LOGD("type = %d = ", device_type, type_str); LOGD("type = %d, %s", (int)device_type, type_str);
} }
void cl_print_build_errors(cl_program program, cl_device_id device) { void cl_print_build_errors(cl_program program, cl_device_id device) {
@ -62,7 +62,7 @@ cl_device_id cl_get_device_id(cl_device_type device_type) {
CL_CHECK(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL)); CL_CHECK(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL));
for (size_t i = 0; i < num_platforms; ++i) { for (size_t i = 0; i < num_platforms; ++i) {
LOGD("platform[%d] CL_PLATFORM_NAME: %s", i, get_platform_info(platform_ids[i], CL_PLATFORM_NAME).c_str()); LOGD("platform[%zu] CL_PLATFORM_NAME: %s", i, get_platform_info(platform_ids[i], CL_PLATFORM_NAME).c_str());
// Get first device // Get first device
if (cl_device_id device_id = NULL; clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL) == 0 && device_id) { if (cl_device_id device_id = NULL; clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL) == 0 && device_id) {
@ -75,6 +75,10 @@ cl_device_id cl_get_device_id(cl_device_type device_type) {
return nullptr; return nullptr;
} }
cl_context cl_create_context(cl_device_id device_id) {
return CL_CHECK_ERR(clCreateContext(NULL, 1, &device_id, NULL, NULL, &err));
}
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args) { cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args) {
return cl_program_from_source(ctx, device_id, util::read_file(path), args); return cl_program_from_source(ctx, device_id, util::read_file(path), args);
} }

@ -22,6 +22,7 @@
}) })
cl_device_id cl_get_device_id(cl_device_type device_type); cl_device_id cl_get_device_id(cl_device_type device_type);
cl_context cl_create_context(cl_device_id device_id);
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args = nullptr); cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args = nullptr);
cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args = nullptr); cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args = nullptr);
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args); cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args);

@ -5,7 +5,7 @@ from atomicwrites import AtomicWriter
def mkdirs_exists_ok(path): def mkdirs_exists_ok(path):
if path.startswith('http://') or path.startswith('https://'): if path.startswith(('http://', 'https://')):
raise ValueError('URL path') raise ValueError('URL path')
try: try:
os.makedirs(path) os.makedirs(path)

@ -1,5 +1,7 @@
#include "common/gpio.h" #include "common/gpio.h"
#include <string>
#ifdef __APPLE__ #ifdef __APPLE__
int gpio_init(int pin_nr, bool output) { int gpio_init(int pin_nr, bool output) {
return 0; return 0;
@ -29,7 +31,7 @@ int gpio_init(int pin_nr, bool output) {
char pin_dir_path[50]; char pin_dir_path[50];
int pin_dir_path_len = snprintf(pin_dir_path, sizeof(pin_dir_path), int pin_dir_path_len = snprintf(pin_dir_path, sizeof(pin_dir_path),
"/sys/class/gpio/gpio%d/direction", pin_nr); "/sys/class/gpio/gpio%d/direction", pin_nr);
if(pin_dir_path_len <= 0) { if (pin_dir_path_len <= 0) {
return -1; return -1;
} }
const char *value = output ? "out" : "in"; const char *value = output ? "out" : "in";
@ -40,7 +42,7 @@ int gpio_set(int pin_nr, bool high) {
char pin_val_path[50]; char pin_val_path[50];
int pin_val_path_len = snprintf(pin_val_path, sizeof(pin_val_path), int pin_val_path_len = snprintf(pin_val_path, sizeof(pin_val_path),
"/sys/class/gpio/gpio%d/value", pin_nr); "/sys/class/gpio/gpio%d/value", pin_nr);
if(pin_val_path_len <= 0) { if (pin_val_path_len <= 0) {
return -1; return -1;
} }
return util::write_file(pin_val_path, (void*)(high ? "1" : "0"), 1); return util::write_file(pin_val_path, (void*)(high ? "1" : "0"), 1);
@ -68,7 +70,7 @@ int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int p
rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES; rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
strncpy(rq.consumer_label, consumer_label, std::size(rq.consumer_label) - 1); strncpy(rq.consumer_label, consumer_label, std::size(rq.consumer_label) - 1);
int ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &rq); int ret = util::safe_ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &rq);
if (ret == -1) { if (ret == -1) {
LOGE("Unable to get line event from ioctl : %s", strerror(errno)); LOGE("Unable to get line event from ioctl : %s", strerror(errno));
close(fd); close(fd);

@ -5,7 +5,7 @@
#define GPIO_HUB_RST_N 30 #define GPIO_HUB_RST_N 30
#define GPIO_UBLOX_RST_N 32 #define GPIO_UBLOX_RST_N 32
#define GPIO_UBLOX_SAFEBOOT_N 33 #define GPIO_UBLOX_SAFEBOOT_N 33
#define GPIO_UBLOX_PWR_EN 34 #define GPIO_GNSS_PWR_EN 34 /* SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN */
#define GPIO_STM_RST_N 124 #define GPIO_STM_RST_N 124
#define GPIO_STM_BOOT0 134 #define GPIO_STM_BOOT0 134
#define GPIO_BMX_ACCEL_INT 21 #define GPIO_BMX_ACCEL_INT 21
@ -17,7 +17,7 @@
#define GPIO_HUB_RST_N 0 #define GPIO_HUB_RST_N 0
#define GPIO_UBLOX_RST_N 0 #define GPIO_UBLOX_RST_N 0
#define GPIO_UBLOX_SAFEBOOT_N 0 #define GPIO_UBLOX_SAFEBOOT_N 0
#define GPIO_UBLOX_PWR_EN 0 #define GPIO_GNSS_PWR_EN 0 /* SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN */
#define GPIO_STM_RST_N 0 #define GPIO_STM_RST_N 0
#define GPIO_STM_BOOT0 0 #define GPIO_STM_BOOT0 0
#define GPIO_BMX_ACCEL_INT 0 #define GPIO_BMX_ACCEL_INT 0

@ -1,3 +1,4 @@
import os
from functools import lru_cache from functools import lru_cache
from typing import Optional, List from typing import Optional, List
@ -26,6 +27,9 @@ def gpio_read(pin: int) -> Optional[bool]:
return val return val
def gpio_export(pin: int) -> None: def gpio_export(pin: int) -> None:
if os.path.isdir(f"/sys/class/gpio/gpio{pin}"):
return
try: try:
with open("/sys/class/gpio/export", 'w') as f: with open("/sys/class/gpio/export", 'w') as f:
f.write(str(pin)) f.write(str(pin))

@ -8,7 +8,6 @@
#include <cstdio> #include <cstdio>
#include <stdexcept> #include <stdexcept>
#include "common/util.h"
#include "common/swaglog.h" #include "common/swaglog.h"
#include "common/util.h" #include "common/util.h"
@ -26,36 +25,42 @@ I2CBus::I2CBus(uint8_t bus_id) {
snprintf(bus_name, 20, "/dev/i2c-%d", bus_id); snprintf(bus_name, 20, "/dev/i2c-%d", bus_id);
i2c_fd = HANDLE_EINTR(open(bus_name, O_RDWR)); i2c_fd = HANDLE_EINTR(open(bus_name, O_RDWR));
if(i2c_fd < 0) { if (i2c_fd < 0) {
throw std::runtime_error("Failed to open I2C bus"); throw std::runtime_error("Failed to open I2C bus");
} }
} }
I2CBus::~I2CBus() { I2CBus::~I2CBus() {
if(i2c_fd >= 0) { close(i2c_fd); } if (i2c_fd >= 0) {
close(i2c_fd);
}
} }
int I2CBus::read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len) { int I2CBus::read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len) {
std::lock_guard lk(m);
int ret = 0; int ret = 0;
ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address)); ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address));
if(ret < 0) { goto fail; } if (ret < 0) { goto fail; }
ret = i2c_smbus_read_i2c_block_data(i2c_fd, register_address, len, buffer); ret = i2c_smbus_read_i2c_block_data(i2c_fd, register_address, len, buffer);
if((ret < 0) || (ret != len)) { goto fail; } if ((ret < 0) || (ret != len)) { goto fail; }
fail: fail:
return ret; return ret;
} }
int I2CBus::set_register(uint8_t device_address, uint register_address, uint8_t data) { int I2CBus::set_register(uint8_t device_address, uint register_address, uint8_t data) {
std::lock_guard lk(m);
int ret = 0; int ret = 0;
ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address)); ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address));
if(ret < 0) { goto fail; } if (ret < 0) { goto fail; }
ret = i2c_smbus_write_byte_data(i2c_fd, register_address, data); ret = i2c_smbus_write_byte_data(i2c_fd, register_address, data);
if(ret < 0) { goto fail; } if (ret < 0) { goto fail; }
fail: fail:
return ret; return ret;

@ -1,12 +1,14 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <mutex>
#include <sys/types.h> #include <sys/types.h>
class I2CBus { class I2CBus {
private: private:
int i2c_fd; int i2c_fd;
std::mutex m;
public: public:
I2CBus(uint8_t bus_id); I2CBus(uint8_t bus_id);

@ -1,3 +1,5 @@
Import('envCython') Import('envCython')
envCython.Program('simple_kalman_impl.so', 'simple_kalman_impl.pyx') simple_kalman_python = envCython.Program('simple_kalman_impl.so', 'simple_kalman_impl.pyx')
Export('simple_kalman_python')

@ -1,3 +1,12 @@
# pylint: skip-file from openpilot.common.kalman.simple_kalman_impl import KF1D as KF1D
from common.kalman.simple_kalman_impl import KF1D as KF1D
assert KF1D assert KF1D
import numpy as np
def get_kalman_gain(dt, A, C, Q, R, iterations=100):
P = np.zeros_like(Q)
for _ in range(iterations):
P = A.dot(P).dot(A.T) + dt * Q
S = C.dot(P).dot(C.T) + R
K = P.dot(C.T).dot(np.linalg.inv(S))
P = (np.eye(len(P)) - K.dot(C)).dot(P)
return K

@ -3,8 +3,8 @@ import random
import timeit import timeit
import numpy as np import numpy as np
from common.kalman.simple_kalman import KF1D from openpilot.common.kalman.simple_kalman import KF1D
from common.kalman.simple_kalman_old import KF1D as KF1D_old from openpilot.common.kalman.simple_kalman_old import KF1D as KF1D_old
class TestSimpleKalman(unittest.TestCase): class TestSimpleKalman(unittest.TestCase):
@ -54,8 +54,8 @@ class TestSimpleKalman(unittest.TestCase):
setup = """ setup = """
import numpy as np import numpy as np
from common.kalman.simple_kalman import KF1D from openpilot.common.kalman.simple_kalman import KF1D
from common.kalman.simple_kalman_old import KF1D as KF1D_old from openpilot.common.kalman.simple_kalman_old import KF1D as KF1D_old
dt = 0.01 dt = 0.01
x0_0 = 0.0 x0_0 = 0.0

@ -65,7 +65,7 @@ class SwagFormatter(logging.Formatter):
return record_dict return record_dict
def format(self, record): def format(self, record): # noqa: A003
if self.swaglogger is None: if self.swaglogger is None:
raise Exception("must set swaglogger before calling format()") raise Exception("must set swaglogger before calling format()")
return json_robust_dumps(self.format_dict(record)) return json_robust_dumps(self.format_dict(record))
@ -95,7 +95,7 @@ class SwagLogFileFormatter(SwagFormatter):
k += "$a" k += "$a"
return k, v return k, v
def format(self, record): def format(self, record): # noqa: A003
if isinstance(record, str): if isinstance(record, str):
v = json.loads(record) v = json.loads(record)
else: else:
@ -197,7 +197,7 @@ class SwagLogger(logging.Logger):
filename = os.path.normcase(co.co_filename) filename = os.path.normcase(co.co_filename)
# TODO: is this pylint exception correct? # TODO: is this pylint exception correct?
if filename == _srcfile: # pylint: disable=comparison-with-callable if filename == _srcfile:
f = f.f_back f = f.f_back
continue continue
sinfo = None sinfo = None

@ -1,7 +1,7 @@
#pragma once #pragma once
typedef struct vec3 { typedef struct vec3 {
float v[3]; float v[3];
} vec3; } vec3;
typedef struct vec4 { typedef struct vec4 {
@ -9,7 +9,7 @@ typedef struct vec4 {
} vec4; } vec4;
typedef struct mat3 { typedef struct mat3 {
float v[3*3]; float v[3*3];
} mat3; } mat3;
typedef struct mat4 { typedef struct mat4 {

@ -64,7 +64,9 @@ bool create_params_path(const std::string &param_path, const std::string &key_pa
std::string ensure_params_path(const std::string &prefix, const std::string &path = {}) { std::string ensure_params_path(const std::string &prefix, const std::string &path = {}) {
std::string params_path = path.empty() ? Path::params() : path; std::string params_path = path.empty() ? Path::params() : path;
if (!create_params_path(params_path, params_path + prefix)) { if (!create_params_path(params_path, params_path + prefix)) {
throw std::runtime_error(util::string_format("Failed to ensure params path, errno=%d", errno)); throw std::runtime_error(util::string_format(
"Failed to ensure params path, errno=%d, path=%s, param_prefix=%s",
errno, params_path.c_str(), prefix.c_str()));
} }
return params_path; return params_path;
} }
@ -86,7 +88,6 @@ private:
std::unordered_map<std::string, uint32_t> keys = { std::unordered_map<std::string, uint32_t> keys = {
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG}, {"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
{"ApiCache_Device", PERSISTENT}, {"ApiCache_Device", PERSISTENT},
{"ApiCache_DriveStats", PERSISTENT},
{"ApiCache_NavDestinations", PERSISTENT}, {"ApiCache_NavDestinations", PERSISTENT},
{"AssistNowToken", PERSISTENT}, {"AssistNowToken", PERSISTENT},
{"AthenadPid", PERSISTENT}, {"AthenadPid", PERSISTENT},
@ -98,6 +99,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"CarParamsCache", CLEAR_ON_MANAGER_START}, {"CarParamsCache", CLEAR_ON_MANAGER_START},
{"CarParamsPersistent", PERSISTENT}, {"CarParamsPersistent", PERSISTENT},
{"CarParamsPrevRoute", PERSISTENT},
{"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"CompletedTrainingVersion", PERSISTENT}, {"CompletedTrainingVersion", PERSISTENT},
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
@ -153,11 +155,11 @@ std::unordered_map<std::string, uint32_t> keys = {
{"LastUpdateException", CLEAR_ON_MANAGER_START}, {"LastUpdateException", CLEAR_ON_MANAGER_START},
{"LastUpdateTime", PERSISTENT}, {"LastUpdateTime", PERSISTENT},
{"LiveParameters", PERSISTENT}, {"LiveParameters", PERSISTENT},
{"LiveTorqueCarParams", PERSISTENT},
{"LiveTorqueParameters", PERSISTENT | DONT_LOG}, {"LiveTorqueParameters", PERSISTENT | DONT_LOG},
{"LongitudinalPersonality", PERSISTENT}, {"LongitudinalPersonality", PERSISTENT},
{"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"NavPastDestinations", PERSISTENT},
{"NavSettingLeftSide", PERSISTENT}, {"NavSettingLeftSide", PERSISTENT},
{"NavSettingTime24h", PERSISTENT}, {"NavSettingTime24h", PERSISTENT},
{"NavdRender", PERSISTENT}, {"NavdRender", PERSISTENT},
@ -178,7 +180,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START}, {"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
{"OpenpilotEnabledToggle", PERSISTENT}, {"OpenpilotEnabledToggle", PERSISTENT},
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"PandaLogState", PERSISTENT}, {"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"PandaSignatures", CLEAR_ON_MANAGER_START}, {"PandaSignatures", CLEAR_ON_MANAGER_START},
{"Passive", PERSISTENT}, {"Passive", PERSISTENT},
{"PrimeType", PERSISTENT}, {"PrimeType", PERSISTENT},

@ -15,7 +15,11 @@ enum ParamKeyType {
class Params { class Params {
public: public:
Params(const std::string &path = {}); explicit Params(const std::string &path = {});
// Not copyable.
Params(const Params&) = delete;
Params& operator=(const Params&) = delete;
std::vector<std::string> allKeys() const; std::vector<std::string> allKeys() const;
bool checkKey(const std::string &key); bool checkKey(const std::string &key);
ParamKeyType getKeyType(const std::string &key); ParamKeyType getKeyType(const std::string &key);

@ -1,4 +1,5 @@
from common.params_pyx import Params, ParamKeyType, UnknownKeyName, put_nonblocking, put_bool_nonblocking # pylint: disable=no-name-in-module, import-error from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName, put_nonblocking, \
put_bool_nonblocking
assert Params assert Params
assert ParamKeyType assert ParamKeyType
assert UnknownKeyName assert UnknownKeyName

@ -14,7 +14,7 @@ cdef extern from "common/params.h":
ALL ALL
cdef cppclass c_Params "Params": cdef cppclass c_Params "Params":
c_Params(string) nogil c_Params(string) except + nogil
string get(string, bool) nogil string get(string, bool) nogil
bool getBool(string, bool) nogil bool getBool(string, bool) nogil
int remove(string) nogil int remove(string) nogil

@ -0,0 +1,40 @@
#include "common/ratekeeper.h"
#include <algorithm>
#include "common/swaglog.h"
#include "common/timing.h"
#include "common/util.h"
RateKeeper::RateKeeper(const std::string &name, float rate, float print_delay_threshold)
: name(name),
print_delay_threshold(std::max(0.f, print_delay_threshold)) {
interval = 1 / rate;
last_monitor_time = seconds_since_boot();
next_frame_time = last_monitor_time + interval;
}
bool RateKeeper::keepTime() {
bool lagged = monitorTime();
if (remaining_ > 0) {
util::sleep_for(remaining_ * 1000);
}
return lagged;
}
bool RateKeeper::monitorTime() {
++frame_;
last_monitor_time = seconds_since_boot();
remaining_ = next_frame_time - last_monitor_time;
bool lagged = remaining_ < 0;
if (lagged) {
if (print_delay_threshold > 0 && remaining_ < -print_delay_threshold) {
LOGW("%s lagging by %.2f ms", name.c_str(), -remaining_ * 1000);
}
next_frame_time = last_monitor_time + interval;
} else {
next_frame_time += interval;
}
return lagged;
}

@ -0,0 +1,23 @@
#pragma once
#include <cstdint>
#include <string>
class RateKeeper {
public:
RateKeeper(const std::string &name, float rate, float print_delay_threshold = 0);
~RateKeeper() {}
bool keepTime();
bool monitorTime();
inline double frame() const { return frame_; }
inline double remaining() const { return remaining_; }
private:
double interval;
double next_frame_time;
double last_monitor_time;
double remaining_ = 0;
float print_delay_threshold = 0;
uint64_t frame_ = 0;
std::string name;
};

@ -5,10 +5,9 @@ import time
from collections import deque from collections import deque
from typing import Optional, List, Union from typing import Optional, List, Union
from setproctitle import getproctitle # pylint: disable=no-name-in-module from setproctitle import getproctitle
from common.clock import sec_since_boot # pylint: disable=no-name-in-module, import-error from openpilot.system.hardware import PC
from system.hardware import PC
# time step for each process # time step for each process
@ -31,12 +30,12 @@ class Priority:
def set_realtime_priority(level: int) -> None: def set_realtime_priority(level: int) -> None:
if not PC: if not PC:
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level)) # pylint: disable=no-member os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level))
def set_core_affinity(cores: List[int]) -> None: def set_core_affinity(cores: List[int]) -> None:
if not PC: if not PC:
os.sched_setaffinity(0, cores) # pylint: disable=no-member os.sched_setaffinity(0, cores)
def config_realtime_process(cores: Union[int, List[int]], priority: int) -> None: def config_realtime_process(cores: Union[int, List[int]], priority: int) -> None:
@ -50,13 +49,13 @@ class Ratekeeper:
def __init__(self, rate: float, print_delay_threshold: Optional[float] = 0.0) -> None: def __init__(self, rate: float, print_delay_threshold: Optional[float] = 0.0) -> None:
"""Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative.""" """Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative."""
self._interval = 1. / rate self._interval = 1. / rate
self._next_frame_time = sec_since_boot() + self._interval self._next_frame_time = time.monotonic() + self._interval
self._print_delay_threshold = print_delay_threshold self._print_delay_threshold = print_delay_threshold
self._frame = 0 self._frame = 0
self._remaining = 0.0 self._remaining = 0.0
self._process_name = getproctitle() self._process_name = getproctitle()
self._dts = deque([self._interval], maxlen=100) self._dts = deque([self._interval], maxlen=100)
self._last_monitor_time = sec_since_boot() self._last_monitor_time = time.monotonic()
@property @property
def frame(self) -> int: def frame(self) -> int:
@ -82,11 +81,11 @@ class Ratekeeper:
# this only monitor the cumulative lag, but does not enforce a rate # this only monitor the cumulative lag, but does not enforce a rate
def monitor_time(self) -> bool: def monitor_time(self) -> bool:
prev = self._last_monitor_time prev = self._last_monitor_time
self._last_monitor_time = sec_since_boot() self._last_monitor_time = time.monotonic()
self._dts.append(self._last_monitor_time - prev) self._dts.append(self._last_monitor_time - prev)
lagged = False lagged = False
remaining = self._next_frame_time - sec_since_boot() remaining = self._next_frame_time - time.monotonic()
self._next_frame_time += self._interval self._next_frame_time += self._interval
if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold: if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold:
print(f"{self._process_name} lagging by {-remaining * 1000:.2f} ms") print(f"{self._process_name} lagging by {-remaining * 1000:.2f} ms")

@ -1,6 +1,6 @@
import os import os
import subprocess import subprocess
from common.basedir import BASEDIR from openpilot.common.basedir import BASEDIR
class Spinner(): class Spinner():
@ -29,11 +29,11 @@ class Spinner():
def close(self): def close(self):
if self.spinner_proc is not None: if self.spinner_proc is not None:
self.spinner_proc.kill()
try: try:
self.spinner_proc.stdin.close() self.spinner_proc.communicate(timeout=2.)
except BrokenPipeError: except subprocess.TimeoutExpired:
pass print("WARNING: failed to kill spinner")
self.spinner_proc.terminate()
self.spinner_proc = None self.spinner_proc = None
def __del__(self): def __del__(self):

@ -12,7 +12,7 @@
#include <string> #include <string>
#include <zmq.h> #include <zmq.h>
#include "json11.hpp" #include "third_party/json11/json11.hpp"
#include "common/util.h" #include "common/util.h"
#include "common/version.h" #include "common/version.h"
@ -20,7 +20,7 @@
class SwaglogState : public LogState { class SwaglogState : public LogState {
public: public:
SwaglogState() : LogState("ipc:///tmp/logmessage") {} SwaglogState() : LogState(Path::swaglog_ipc().c_str()) {}
json11::Json::object ctx_j; json11::Json::object ctx_j;
@ -64,8 +64,7 @@ static void log(int levelnum, const char* filename, int lineno, const char* func
if (levelnum >= s.print_level) { if (levelnum >= s.print_level) {
printf("%s: %s\n", filename, msg); printf("%s: %s\n", filename, msg);
} }
char levelnum_c = levelnum; zmq_send(s.sock, log_s.data(), log_s.length(), ZMQ_NOBLOCK);
zmq_send(s.sock, (levelnum_c + log_s).c_str(), log_s.length() + 1, ZMQ_NOBLOCK);
} }
static void cloudlog_common(int levelnum, const char* filename, int lineno, const char* func, static void cloudlog_common(int levelnum, const char* filename, int lineno, const char* func,
@ -87,8 +86,11 @@ static void cloudlog_common(int levelnum, const char* filename, int lineno, cons
log_j["msg"] = msg_j; log_j["msg"] = msg_j;
} }
std::string log_s = ((json11::Json)log_j).dump(); std::string log_s;
log_s += (char)levelnum;
((json11::Json)log_j).dump(log_s);
log(levelnum, filename, lineno, func, msg_buf, log_s); log(levelnum, filename, lineno, func, msg_buf, log_s);
free(msg_buf); free(msg_buf);
} }

@ -9,14 +9,20 @@
#define CLOUDLOG_CRITICAL 50 #define CLOUDLOG_CRITICAL 50
#ifdef __GNUC__
#define SWAG_LOG_CHECK_FMT(a, b) __attribute__ ((format (printf, a, b)))
#else
#define SWAG_LOG_CHECK_FMT(a, b)
#endif
void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func, void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) /*__attribute__ ((format (printf, 6, 7)))*/; const char* fmt, ...) SWAG_LOG_CHECK_FMT(5, 6);
void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func, void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) /*__attribute__ ((format (printf, 6, 7)))*/; const char* fmt, ...) SWAG_LOG_CHECK_FMT(5, 6);
void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func, void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func,
uint32_t frame_id, const char* fmt, ...) /*__attribute__ ((format (printf, 6, 7)))*/; uint32_t frame_id, const char* fmt, ...) SWAG_LOG_CHECK_FMT(6, 7);
#define cloudlog(lvl, fmt, ...) cloudlog_e(lvl, __FILE__, __LINE__, \ #define cloudlog(lvl, fmt, ...) cloudlog_e(lvl, __FILE__, __LINE__, \
@ -38,7 +44,7 @@ void cloudlog_te(int levelnum, const char* filename, int lineno, const char* fun
int __millis = (millis); \ int __millis = (millis); \
uint64_t __ts = nanos_since_boot(); \ uint64_t __ts = nanos_since_boot(); \
\ \
if (!__begin) __begin = __ts; \ if (!__begin) { __begin = __ts; } \
\ \
if (__begin + __millis*1000000ULL < __ts) { \ if (__begin + __millis*1000000ULL < __ts) { \
if (__missed) { \ if (__missed) { \

@ -2,7 +2,7 @@
import os import os
import time import time
import subprocess import subprocess
from common.basedir import BASEDIR from openpilot.common.basedir import BASEDIR
class TextWindow: class TextWindow:

@ -1,6 +1,5 @@
Import('env', 'envCython') Import('env', 'envCython')
transformations = env.Library('transformations', ['orientation.cc', 'coordinates.cc']) transformations = env.Library('transformations', ['orientation.cc', 'coordinates.cc'])
Export('transformations') transformations_python = envCython.Program('transformations.so', 'transformations.pyx')
Export('transformations', 'transformations_python')
envCython.Program('transformations.so', 'transformations.pyx')

@ -1,6 +1,6 @@
import numpy as np import numpy as np
import common.transformations.orientation as orient import openpilot.common.transformations.orientation as orient
## -- hardcoded hardware params -- ## -- hardcoded hardware params --
eon_f_focal_length = 910.0 eon_f_focal_length = 910.0
@ -61,14 +61,6 @@ device_frame_from_view_frame = np.array([
view_frame_from_device_frame = device_frame_from_view_frame.T view_frame_from_device_frame = device_frame_from_view_frame.T
def get_calib_from_vp(vp):
vp_norm = normalize(vp)
yaw_calib = np.arctan(vp_norm[0])
pitch_calib = -np.arctan(vp_norm[1]*np.cos(yaw_calib))
roll_calib = 0
return roll_calib, pitch_calib, yaw_calib
# aka 'extrinsic_matrix' # aka 'extrinsic_matrix'
# road : x->forward, y -> left, z->up # road : x->forward, y -> left, z->up
def get_view_frame_from_road_frame(roll, pitch, yaw, height): def get_view_frame_from_road_frame(roll, pitch, yaw, height):
@ -131,6 +123,14 @@ def denormalize(img_pts, intrinsics=fcam_intrinsics, width=np.inf, height=np.inf
return img_pts_denormalized[:, :2].reshape(input_shape) return img_pts_denormalized[:, :2].reshape(input_shape)
def get_calib_from_vp(vp, intrinsics=fcam_intrinsics):
vp_norm = normalize(vp, intrinsics)
yaw_calib = np.arctan(vp_norm[0])
pitch_calib = -np.arctan(vp_norm[1]*np.cos(yaw_calib))
roll_calib = 0
return roll_calib, pitch_calib, yaw_calib
def device_from_ecef(pos_ecef, orientation_ecef, pt_ecef): def device_from_ecef(pos_ecef, orientation_ecef, pt_ecef):
# device from ecef frame # device from ecef frame
# device frame is x -> forward, y-> right, z -> down # device frame is x -> forward, y-> right, z -> down

@ -1,13 +1,11 @@
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include "common/transformations/coordinates.hpp"
#include <iostream> #include <iostream>
#include <cmath> #include <cmath>
#include <eigen3/Eigen/Dense> #include <eigen3/Eigen/Dense>
#include "coordinates.hpp"
double a = 6378137; // lgtm [cpp/short-global-name] double a = 6378137; // lgtm [cpp/short-global-name]
double b = 6356752.3142; // lgtm [cpp/short-global-name] double b = 6356752.3142; // lgtm [cpp/short-global-name]
double esq = 6.69437999014 * 0.001; // lgtm [cpp/short-global-name] double esq = 6.69437999014 * 0.001; // lgtm [cpp/short-global-name]

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <eigen3/Eigen/Dense>
#define DEG2RAD(x) ((x) * M_PI / 180.0) #define DEG2RAD(x) ((x) * M_PI / 180.0)
#define RAD2DEG(x) ((x) * 180.0 / M_PI) #define RAD2DEG(x) ((x) * 180.0 / M_PI)

@ -1,8 +1,7 @@
# pylint: skip-file from openpilot.common.transformations.orientation import numpy_wrap
from common.transformations.orientation import numpy_wrap from openpilot.common.transformations.transformations import (ecef2geodetic_single,
from common.transformations.transformations import (ecef2geodetic_single,
geodetic2ecef_single) geodetic2ecef_single)
from common.transformations.transformations import LocalCoord as LocalCoord_single from openpilot.common.transformations.transformations import LocalCoord as LocalCoord_single
class LocalCoord(LocalCoord_single): class LocalCoord(LocalCoord_single):

@ -1,7 +1,9 @@
import numpy as np import numpy as np
from common.transformations.camera import (FULL_FRAME_SIZE, from openpilot.common.transformations.orientation import rot_from_euler
get_view_frame_from_calib_frame) from openpilot.common.transformations.camera import (
FULL_FRAME_SIZE, get_view_frame_from_calib_frame, view_frame_from_device_frame,
eon_fcam_intrinsics, tici_ecam_intrinsics, tici_fcam_intrinsics)
# segnet # segnet
SEGNET_SIZE = (512, 384) SEGNET_SIZE = (512, 384)
@ -57,61 +59,20 @@ medmodel_frame_from_calib_frame = np.dot(medmodel_intrinsics,
medmodel_frame_from_bigmodel_frame = np.dot(medmodel_intrinsics, np.linalg.inv(bigmodel_intrinsics)) medmodel_frame_from_bigmodel_frame = np.dot(medmodel_intrinsics, np.linalg.inv(bigmodel_intrinsics))
calib_from_medmodel = np.linalg.inv(medmodel_frame_from_calib_frame[:, :3])
calib_from_sbigmodel = np.linalg.inv(sbigmodel_frame_from_calib_frame[:, :3])
### This function mimics the update_calibration logic in modeld.cc # This function is verified to give similar results to xx.uncommon.utils.transform_img
### Manually verified to give similar results to xx.uncommon.utils.transform_img def get_warp_matrix(device_from_calib_euler: np.ndarray, wide_camera: bool = False, bigmodel_frame: bool = False, tici: bool = True) -> np.ndarray:
def get_warp_matrix(rpy_calib, wide_cam=False, big_model=False, tici=True): if tici and wide_camera:
from common.transformations.orientation import rot_from_euler cam_intrinsics = tici_ecam_intrinsics
from common.transformations.camera import view_frame_from_device_frame, eon_fcam_intrinsics, tici_ecam_intrinsics, tici_fcam_intrinsics
if tici and wide_cam:
intrinsics = tici_ecam_intrinsics
elif tici:
intrinsics = tici_fcam_intrinsics
else:
intrinsics = eon_fcam_intrinsics
if big_model:
sbigmodel_from_calib = sbigmodel_frame_from_calib_frame[:, (0,1,2)]
calib_from_model = np.linalg.inv(sbigmodel_from_calib)
else:
medmodel_from_calib = medmodel_frame_from_calib_frame[:, (0,1,2)]
calib_from_model = np.linalg.inv(medmodel_from_calib)
device_from_calib = rot_from_euler(rpy_calib)
camera_from_calib = intrinsics.dot(view_frame_from_device_frame.dot(device_from_calib))
warp_matrix = camera_from_calib.dot(calib_from_model)
return warp_matrix
### This is old, just for debugging
def get_warp_matrix_old(rpy_calib, wide_cam=False, big_model=False, tici=True):
from common.transformations.orientation import rot_from_euler
from common.transformations.camera import view_frame_from_device_frame, eon_fcam_intrinsics, tici_ecam_intrinsics, tici_fcam_intrinsics
def get_view_frame_from_road_frame(roll, pitch, yaw, height):
device_from_road = rot_from_euler([roll, pitch, yaw]).dot(np.diag([1, -1, -1]))
view_from_road = view_frame_from_device_frame.dot(device_from_road)
return np.hstack((view_from_road, [[0], [height], [0]]))
if tici and wide_cam:
intrinsics = tici_ecam_intrinsics
elif tici: elif tici:
intrinsics = tici_fcam_intrinsics cam_intrinsics = tici_fcam_intrinsics
else: else:
intrinsics = eon_fcam_intrinsics cam_intrinsics = eon_fcam_intrinsics
model_height = 1.22 calib_from_model = calib_from_sbigmodel if bigmodel_frame else calib_from_medmodel
if big_model: device_from_calib = rot_from_euler(device_from_calib_euler)
model_from_road = np.dot(sbigmodel_intrinsics, camera_from_calib = cam_intrinsics @ view_frame_from_device_frame @ device_from_calib
get_view_frame_from_road_frame(0, 0, 0, model_height)) warp_matrix: np.ndarray = camera_from_calib @ calib_from_model
else:
model_from_road = np.dot(medmodel_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))
ground_from_model = np.linalg.inv(model_from_road[:, (0, 1, 3)])
E = get_view_frame_from_road_frame(*rpy_calib, 1.22)
camera_frame_from_road_frame = intrinsics.dot(E)
camera_frame_from_ground = camera_frame_from_road_frame[:,(0,1,3)]
warp_matrix = camera_frame_from_ground .dot(ground_from_model)
return warp_matrix return warp_matrix

@ -4,8 +4,8 @@
#include <cmath> #include <cmath>
#include <eigen3/Eigen/Dense> #include <eigen3/Eigen/Dense>
#include "orientation.hpp" #include "common/transformations/orientation.hpp"
#include "coordinates.hpp" #include "common/transformations/coordinates.hpp"
Eigen::Quaterniond ensure_unique(Eigen::Quaterniond quat){ Eigen::Quaterniond ensure_unique(Eigen::Quaterniond quat){
if (quat.w() > 0){ if (quat.w() > 0){

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <eigen3/Eigen/Dense> #include <eigen3/Eigen/Dense>
#include "coordinates.hpp" #include "common/transformations/coordinates.hpp"
Eigen::Quaterniond ensure_unique(Eigen::Quaterniond quat); Eigen::Quaterniond ensure_unique(Eigen::Quaterniond quat);

@ -1,8 +1,7 @@
# pylint: skip-file
import numpy as np import numpy as np
from typing import Callable from typing import Callable
from common.transformations.transformations import (ecef_euler_from_ned_single, from openpilot.common.transformations.transformations import (ecef_euler_from_ned_single,
euler2quat_single, euler2quat_single,
euler2rot_single, euler2rot_single,
ned_euler_from_ecef_single, ned_euler_from_ecef_single,

@ -1,20 +1,20 @@
# distutils: language = c++ # distutils: language = c++
# cython: language_level = 3 # cython: language_level = 3
from common.transformations.transformations cimport Matrix3, Vector3, Quaternion from openpilot.common.transformations.transformations cimport Matrix3, Vector3, Quaternion
from common.transformations.transformations cimport ECEF, NED, Geodetic from openpilot.common.transformations.transformations cimport ECEF, NED, Geodetic
from common.transformations.transformations cimport euler2quat as euler2quat_c from openpilot.common.transformations.transformations cimport euler2quat as euler2quat_c
from common.transformations.transformations cimport quat2euler as quat2euler_c from openpilot.common.transformations.transformations cimport quat2euler as quat2euler_c
from common.transformations.transformations cimport quat2rot as quat2rot_c from openpilot.common.transformations.transformations cimport quat2rot as quat2rot_c
from common.transformations.transformations cimport rot2quat as rot2quat_c from openpilot.common.transformations.transformations cimport rot2quat as rot2quat_c
from common.transformations.transformations cimport euler2rot as euler2rot_c from openpilot.common.transformations.transformations cimport euler2rot as euler2rot_c
from common.transformations.transformations cimport rot2euler as rot2euler_c from openpilot.common.transformations.transformations cimport rot2euler as rot2euler_c
from common.transformations.transformations cimport rot_matrix as rot_matrix_c from openpilot.common.transformations.transformations cimport rot_matrix as rot_matrix_c
from common.transformations.transformations cimport ecef_euler_from_ned as ecef_euler_from_ned_c from openpilot.common.transformations.transformations cimport ecef_euler_from_ned as ecef_euler_from_ned_c
from common.transformations.transformations cimport ned_euler_from_ecef as ned_euler_from_ecef_c from openpilot.common.transformations.transformations cimport ned_euler_from_ecef as ned_euler_from_ecef_c
from common.transformations.transformations cimport geodetic2ecef as geodetic2ecef_c from openpilot.common.transformations.transformations cimport geodetic2ecef as geodetic2ecef_c
from common.transformations.transformations cimport ecef2geodetic as ecef2geodetic_c from openpilot.common.transformations.transformations cimport ecef2geodetic as ecef2geodetic_c
from common.transformations.transformations cimport LocalCoord_c from openpilot.common.transformations.transformations cimport LocalCoord_c
import cython import cython

@ -2,7 +2,7 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <dirent.h> #include <sys/resource.h>
#include <cassert> #include <cassert>
#include <cerrno> #include <cerrno>
@ -60,6 +60,20 @@ int set_core_affinity(std::vector<int> cores) {
#endif #endif
} }
int set_file_descriptor_limit(uint64_t limit_val) {
struct rlimit limit;
int status;
if ((status = getrlimit(RLIMIT_NOFILE, &limit)) < 0)
return status;
limit.rlim_cur = limit_val;
if ((status = setrlimit(RLIMIT_NOFILE, &limit)) < 0)
return status;
return 0;
}
std::string read_file(const std::string& fn) { std::string read_file(const std::string& fn) {
std::ifstream f(fn, std::ios::binary | std::ios::in); std::ifstream f(fn, std::ios::binary | std::ios::in);
if (f.is_open()) { if (f.is_open()) {
@ -213,10 +227,17 @@ std::string hexdump(const uint8_t* in, const size_t size) {
return ss.str(); return ss.str();
} }
int random_int(int min, int max) {
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> dist(min, max);
return dist(rng);
}
std::string random_string(std::string::size_type length) { std::string random_string(std::string::size_type length) {
const char* chrs = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const std::string chrs = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::mt19937 rg{std::random_device{}()}; std::mt19937 rg{std::random_device{}()};
std::uniform_int_distribution<std::string::size_type> pick(0, sizeof(chrs) - 2); std::uniform_int_distribution<std::string::size_type> pick(0, chrs.length() - 1);
std::string s; std::string s;
s.reserve(length); s.reserve(length);
while (length--) { while (length--) {
@ -231,6 +252,14 @@ std::string dir_name(std::string const &path) {
return path.substr(0, pos); return path.substr(0, pos);
} }
bool starts_with(const std::string &s1, const std::string &s2) {
return strncmp(s1.c_str(), s2.c_str(), s2.size()) == 0;
}
bool ends_with(const std::string &s1, const std::string &s2) {
return strcmp(s1.c_str() + (s1.size() - s2.size()), s2.c_str()) == 0;
}
std::string check_output(const std::string& command) { std::string check_output(const std::string& command) {
char buffer[128]; char buffer[128];
std::string result; std::string result;

@ -44,6 +44,7 @@ namespace util {
void set_thread_name(const char* name); void set_thread_name(const char* name);
int set_realtime_priority(int level); int set_realtime_priority(int level);
int set_core_affinity(std::vector<int> cores); int set_core_affinity(std::vector<int> cores);
int set_file_descriptor_limit(uint64_t limit);
// ***** Time helpers ***** // ***** Time helpers *****
struct tm get_time(); struct tm get_time();
@ -75,10 +76,15 @@ int getenv(const char* key, int default_val);
float getenv(const char* key, float default_val); float getenv(const char* key, float default_val);
std::string hexdump(const uint8_t* in, const size_t size); std::string hexdump(const uint8_t* in, const size_t size);
std::string random_string(std::string::size_type length);
std::string dir_name(std::string const& path); std::string dir_name(std::string const& path);
bool starts_with(const std::string &s1, const std::string &s2);
bool ends_with(const std::string &s1, const std::string &s2);
// ***** random helpers *****
int random_int(int min, int max);
std::string random_string(std::string::size_type length);
// **** file fhelpers ***** // **** file helpers *****
std::string read_file(const std::string& fn); std::string read_file(const std::string& fn);
std::map<std::string, std::string> read_files_in_dir(const std::string& path); std::map<std::string, std::string> read_files_in_dir(const std::string& path);
int write_file(const char* path, const void* data, size_t size, int flags = O_WRONLY, mode_t mode = 0664); int write_file(const char* path, const void* data, size_t size, int flags = O_WRONLY, mode_t mode = 0664);
@ -111,7 +117,7 @@ public:
#ifndef __APPLE__ #ifndef __APPLE__
std::signal(SIGPWR, (sighandler_t)set_do_exit); std::signal(SIGPWR, (sighandler_t)set_do_exit);
#endif #endif
}; }
inline static std::atomic<bool> power_failure = false; inline static std::atomic<bool> power_failure = false;
inline static std::atomic<int> signal = 0; inline static std::atomic<int> signal = 0;
inline operator bool() { return do_exit; } inline operator bool() { return do_exit; }
@ -147,12 +153,18 @@ struct unique_fd {
class FirstOrderFilter { class FirstOrderFilter {
public: public:
FirstOrderFilter(float x0, float ts, float dt) { FirstOrderFilter(float x0, float ts, float dt, bool initialized = true) {
k_ = (dt / ts) / (1.0 + dt / ts); k_ = (dt / ts) / (1.0 + dt / ts);
x_ = x0; x_ = x0;
initialized_ = initialized;
} }
inline float update(float x) { inline float update(float x) {
x_ = (1. - k_) * x_ + k_ * x; if (initialized_) {
x_ = (1. - k_) * x_ + k_ * x;
} else {
initialized_ = true;
x_ = x;
}
return x_; return x_;
} }
inline void reset(float x) { x_ = x; } inline void reset(float x) { x_ = x; }
@ -160,12 +172,13 @@ public:
private: private:
float x_, k_; float x_, k_;
bool initialized_;
}; };
template<typename T> template<typename T>
void update_max_atomic(std::atomic<T>& max, T const& value) { void update_max_atomic(std::atomic<T>& max, T const& value) {
T prev = max; T prev = max;
while(prev < value && !max.compare_exchange_weak(prev, value)) {} while (prev < value && !max.compare_exchange_weak(prev, value)) {}
} }
class LogState { class LogState {
@ -175,9 +188,9 @@ class LogState {
void *zctx = nullptr; void *zctx = nullptr;
void *sock = nullptr; void *sock = nullptr;
int print_level; int print_level;
const char* endpoint; std::string endpoint;
LogState(const char* _endpoint) { LogState(std::string _endpoint) {
endpoint = _endpoint; endpoint = _endpoint;
} }
@ -189,7 +202,7 @@ class LogState {
int timeout = 100; int timeout = 100;
zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout)); zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout));
zmq_connect(sock, endpoint); zmq_connect(sock, endpoint.c_str());
initialized = true; initialized = true;
} }

@ -1 +1 @@
#define COMMA_VERSION "0.9.4" #define COMMA_VERSION "0.9.5"

@ -1,3 +1,5 @@
#include <string>
#include "common/watchdog.h" #include "common/watchdog.h"
#include "common/util.h" #include "common/util.h"

@ -2,280 +2,293 @@
# Supported Cars # Supported Cars
A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified. A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
# 255 Supported Cars # 268 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br>&nbsp;|Video| |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br>&nbsp;|Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Acura&model=ILX 2016-19">Buy Here</a></sub></details>|| |Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=ILX 2016-19">Buy Here</a></sub></details>||
|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Acura&model=RDX 2016-18">Buy Here</a></sub></details>|| |Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2016-18">Buy Here</a></sub></details>||
|Acura|RDX 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Acura&model=RDX 2019-22">Buy Here</a></sub></details>|| |Acura|RDX 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2019-22">Buy Here</a></sub></details>||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Audi&model=A3 2014-19">Buy Here</a></sub></details>|| |Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 2014-19">Buy Here</a></sub></details>||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Audi&model=A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>|| |Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Audi&model=Q2 2018">Buy Here</a></sub></details>|| |Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q2 2018">Buy Here</a></sub></details>||
|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Audi&model=Q3 2019-23">Buy Here</a></sub></details>|| |Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q3 2019-23">Buy Here</a></sub></details>||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Audi&model=RS3 2018">Buy Here</a></sub></details>|| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=RS3 2018">Buy Here</a></sub></details>||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Audi&model=S3 2015-17">Buy Here</a></sub></details>|| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=S3 2015-17">Buy Here</a></sub></details>||
|Buick|LaCrosse 2017-19[<sup>4</sup>](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 OBD-II connector<br>- 1 comma three<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Buick&model=LaCrosse 2017-19">Buy Here</a></sub></details>|| |Buick|LaCrosse 2017-19[<sup>4</sup>](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Buick&model=LaCrosse 2017-19">Buy Here</a></sub></details>||
|Cadillac|Escalade 2017[<sup>4</sup>](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 OBD-II connector<br>- 1 comma three<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Cadillac&model=Escalade 2017">Buy Here</a></sub></details>|| |Cadillac|Escalade 2017[<sup>4</sup>](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Cadillac&model=Escalade 2017">Buy Here</a></sub></details>||
|Cadillac|Escalade ESV 2016[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 OBD-II connector<br>- 1 comma three<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Cadillac&model=Escalade ESV 2016">Buy Here</a></sub></details>|| |Cadillac|Escalade ESV 2016[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Cadillac&model=Escalade ESV 2016">Buy Here</a></sub></details>||
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 GM connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Chevrolet&model=Bolt EUV 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Cadillac|Escalade ESV 2019[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Cadillac&model=Escalade ESV 2019">Buy Here</a></sub></details>||
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 GM connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Chevrolet&model=Bolt EV 2022-23">Buy Here</a></sub></details>|| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Bolt EUV 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 GM connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Chevrolet&model=Silverado 1500 2020-21">Buy Here</a></sub></details>|| |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Bolt EV 2022-23">Buy Here</a></sub></details>||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 GM connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Chevrolet&model=Trailblazer 2021-22">Buy Here</a></sub></details>|| |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Silverado 1500 2020-21">Buy Here</a></sub></details>||
|Chevrolet|Volt 2017-18[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 OBD-II connector<br>- 1 comma three<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Chevrolet&model=Volt 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/QeMCN_4TFfQ" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Trailblazer 2021-22">Buy Here</a></sub></details>||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Chrysler&model=Pacifica 2017-18">Buy Here</a></sub></details>|| |Chevrolet|Volt 2017-18[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Volt 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/QeMCN_4TFfQ" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Chrysler&model=Pacifica 2019-20">Buy Here</a></sub></details>|| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica 2017-18">Buy Here</a></sub></details>||
|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Chrysler&model=Pacifica 2021">Buy Here</a></sub></details>|| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica 2019-20">Buy Here</a></sub></details>||
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Chrysler&model=Pacifica Hybrid 2017-18">Buy Here</a></sub></details>|| |Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica 2021">Buy Here</a></sub></details>||
|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Chrysler&model=Pacifica Hybrid 2019-23">Buy Here</a></sub></details>|| |Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica Hybrid 2017-18">Buy Here</a></sub></details>||
|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica Hybrid 2019-23">Buy Here</a></sub></details>||
|comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None||
|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Ford&model=Bronco Sport 2021-22">Buy Here</a></sub></details>|| |Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Bronco Sport 2021-22">Buy Here</a></sub></details>||
|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Ford&model=Escape 2020-22">Buy Here</a></sub></details>|| |Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Escape 2020-22">Buy Here</a></sub></details>||
|Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Ford&model=Explorer 2020-22">Buy Here</a></sub></details>|| |Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Explorer 2020-22">Buy Here</a></sub></details>||
|Ford|Focus 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Ford&model=Focus 2018">Buy Here</a></sub></details>|| |Ford|Focus 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Focus 2018">Buy Here</a></sub></details>||
|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Ford&model=Kuga 2020-22">Buy Here</a></sub></details>|| |Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Kuga 2020-22">Buy Here</a></sub></details>||
|Ford|Maverick 2022-23|Co-Pilot360 Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Ford&model=Maverick 2022-23">Buy Here</a></sub></details>|| |Ford|Maverick 2022|LARIAT Luxury|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 2022">Buy Here</a></sub></details>||
|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=G70 2018-19">Buy Here</a></sub></details>|| |Ford|Maverick 2023|Co-Pilot360 Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 2023">Buy Here</a></sub></details>||
|Genesis|G70 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=G70 2020">Buy Here</a></sub></details>|| |Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G70 2018-19">Buy Here</a></sub></details>||
|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai J connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=G80 2017">Buy Here</a></sub></details>|| |Genesis|G70 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G70 2020">Buy Here</a></sub></details>||
|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=G80 2018-19">Buy Here</a></sub></details>|| |Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G80 2017">Buy Here</a></sub></details>||
|Genesis|G90 2017-18|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=G90 2017-18">Buy Here</a></sub></details>|| |Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G80 2018-19">Buy Here</a></sub></details>||
|Genesis|GV60 (Advanced Trim) 2023[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=GV60 (Advanced Trim) 2023">Buy Here</a></sub></details>|| |Genesis|G90 2017-18|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G90 2017-18">Buy Here</a></sub></details>||
|Genesis|GV60 (Performance Trim) 2023[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=GV60 (Performance Trim) 2023">Buy Here</a></sub></details>|| |Genesis|GV60 (Advanced Trim) 2023[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV60 (Advanced Trim) 2023">Buy Here</a></sub></details>||
|Genesis|GV70 (2.5T Trim) 2022-23[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=GV70 (2.5T Trim) 2022-23">Buy Here</a></sub></details>|| |Genesis|GV60 (Performance Trim) 2023[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV60 (Performance Trim) 2023">Buy Here</a></sub></details>||
|Genesis|GV70 (3.5T Trim) 2022-23[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai M connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=GV70 (3.5T Trim) 2022-23">Buy Here</a></sub></details>|| |Genesis|GV70 (2.5T Trim) 2022-23[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV70 (2.5T Trim) 2022-23">Buy Here</a></sub></details>||
|Genesis|GV80 2023[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai M connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=GV80 2023">Buy Here</a></sub></details>|| |Genesis|GV70 (3.5T Trim) 2022-23[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV70 (3.5T Trim) 2022-23">Buy Here</a></sub></details>||
|GMC|Acadia 2018[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 OBD-II connector<br>- 1 comma three<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=GMC&model=Acadia 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=0ZN6DdsBUZo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Genesis|GV80 2023[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV80 2023">Buy Here</a></sub></details>||
|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 GM connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=GMC&model=Sierra 1500 2020-21">Buy Here</a></sub></details>|<a href="https://youtu.be/5HbNoBLzRwE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |GMC|Acadia 2018[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=GMC&model=Acadia 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=0ZN6DdsBUZo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|Accord 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Accord 2018-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=mrUwlj3Mi58" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=GMC&model=Sierra 1500 2020-21">Buy Here</a></sub></details>|<a href="https://youtu.be/5HbNoBLzRwE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|Accord Hybrid 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Accord Hybrid 2018-22">Buy Here</a></sub></details>|| |Honda|Accord 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Accord 2018-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=mrUwlj3Mi58" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Civic 2016-18">Buy Here</a></sub></details>|<a href="https://youtu.be/-IkImTe1NYE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Honda|Accord Hybrid 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Accord Hybrid 2018-22">Buy Here</a></sub></details>||
|Honda|Civic 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|2 mph[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Civic 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=4Iz1Mz5LGF8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic 2016-18">Buy Here</a></sub></details>|<a href="https://youtu.be/-IkImTe1NYE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|Civic 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Civic 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Honda|Civic 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|2 mph[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=4Iz1Mz5LGF8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Civic Hatchback 2017-21">Buy Here</a></sub></details>|| |Honda|Civic 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|Civic Hatchback 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Civic Hatchback 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic Hatchback 2017-21">Buy Here</a></sub></details>||
|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=CR-V 2015-16">Buy Here</a></sub></details>|| |Honda|Civic Hatchback 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic Hatchback 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=CR-V 2017-22">Buy Here</a></sub></details>|| |Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=CR-V 2015-16">Buy Here</a></sub></details>||
|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=CR-V Hybrid 2017-19">Buy Here</a></sub></details>|| |Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=CR-V 2017-22">Buy Here</a></sub></details>||
|Honda|e 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=e 2020">Buy Here</a></sub></details>|| |Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=CR-V Hybrid 2017-19">Buy Here</a></sub></details>||
|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Fit 2018-20">Buy Here</a></sub></details>|| |Honda|e 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=e 2020">Buy Here</a></sub></details>||
|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Freed 2020">Buy Here</a></sub></details>|| |Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Fit 2018-20">Buy Here</a></sub></details>||
|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=HR-V 2019-22">Buy Here</a></sub></details>|| |Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Freed 2020">Buy Here</a></sub></details>||
|Honda|HR-V 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=HR-V 2023">Buy Here</a></sub></details>|| |Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=HR-V 2019-22">Buy Here</a></sub></details>||
|Honda|Insight 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Insight 2019-22">Buy Here</a></sub></details>|| |Honda|HR-V 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=HR-V 2023">Buy Here</a></sub></details>||
|Honda|Inspire 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Inspire 2018">Buy Here</a></sub></details>|| |Honda|Insight 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Insight 2019-22">Buy Here</a></sub></details>||
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Odyssey 2018-20">Buy Here</a></sub></details>|| |Honda|Inspire 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Inspire 2018">Buy Here</a></sub></details>||
|Honda|Passport 2019-23|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Passport 2019-23">Buy Here</a></sub></details>|| |Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Odyssey 2018-20">Buy Here</a></sub></details>||
|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Pilot 2016-22">Buy Here</a></sub></details>|| |Honda|Passport 2019-23|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Passport 2019-23">Buy Here</a></sub></details>||
|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Ridgeline 2017-23">Buy Here</a></sub></details>|| |Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Pilot 2016-22">Buy Here</a></sub></details>||
|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Elantra 2017-19">Buy Here</a></sub></details>|| |Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Ridgeline 2017-23">Buy Here</a></sub></details>||
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Elantra 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Azera 2022">Buy Here</a></sub></details>||
|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Elantra GT 2017-19">Buy Here</a></sub></details>|| |Hyundai|Azera Hybrid 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Azera Hybrid 2020">Buy Here</a></sub></details>||
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Hyundai|Custin 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Custin 2023">Buy Here</a></sub></details>||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai J connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Genesis 2015-16">Buy Here</a></sub></details>|| |Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra 2017-18">Buy Here</a></sub></details>||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=i30 2017-19">Buy Here</a></sub></details>|| |Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra 2019">Buy Here</a></sub></details>||
|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq 5 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>|| |Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Ioniq 5 (with HDA II) 2022-23[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq 5 (with HDA II) 2022-23">Buy Here</a></sub></details>|| |Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra GT 2017-19">Buy Here</a></sub></details>||
|Hyundai|Ioniq 5 (without HDA II) 2022-23[<sup>6</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq 5 (without HDA II) 2022-23">Buy Here</a></sub></details>|| |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Electric 2019">Buy Here</a></sub></details>|| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Genesis 2015-16">Buy Here</a></sub></details>||
|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Electric 2020">Buy Here</a></sub></details>|| |Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=i30 2017-19">Buy Here</a></sub></details>||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Hybrid 2017-19">Buy Here</a></sub></details>|| |Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>||
|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Hybrid 2020-22">Buy Here</a></sub></details>|| |Hyundai|Ioniq 5 (with HDA II) 2022-23[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (with HDA II) 2022-23">Buy Here</a></sub></details>||
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>|| |Hyundai|Ioniq 5 (without HDA II) 2022-23[<sup>6</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (without HDA II) 2022-23">Buy Here</a></sub></details>||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|| |Hyundai|Ioniq 6 (with HDA II) 2023[<sup>6</sup>](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 6 (with HDA II) 2023">Buy Here</a></sub></details>||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Kona 2020">Buy Here</a></sub></details>|| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2019">Buy Here</a></sub></details>||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Kona Electric 2018-21">Buy Here</a></sub></details>|| |Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2020">Buy Here</a></sub></details>||
|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai O connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Kona Electric 2022">Buy Here</a></sub></details>|| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2017-19">Buy Here</a></sub></details>||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai I connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Kona Hybrid 2020">Buy Here</a></sub></details>|<a href="https://youtu.be/0dwpAHiZgFo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2020-22">Buy Here</a></sub></details>||
|Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>||
|Hyundai|Santa Cruz 2022-23[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Santa Cruz 2022-23">Buy Here</a></sub></details>|| |Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||
|Hyundai|Santa Fe 2019-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Santa Fe 2019-20">Buy Here</a></sub></details>|| |Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona 2020">Buy Here</a></sub></details>||
|Hyundai|Santa Fe 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Santa Fe 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric 2018-21">Buy Here</a></sub></details>||
|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>|| |Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric 2022-23">Buy Here</a></sub></details>||
|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Santa Fe Plug-in Hybrid 2022">Buy Here</a></sub></details>|| |Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Sonata 2018-19">Buy Here</a></sub></details>|| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Hybrid 2020">Buy Here</a></sub></details>|<a href="https://youtu.be/0dwpAHiZgFo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Sonata 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Sonata Hybrid 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Sonata Hybrid 2020-23">Buy Here</a></sub></details>|| |Hyundai|Santa Cruz 2022-23[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Cruz 2022-23">Buy Here</a></sub></details>||
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Tucson 2021">Buy Here</a></sub></details>|| |Hyundai|Santa Fe 2019-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe 2019-20">Buy Here</a></sub></details>||
|Hyundai|Tucson 2022[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Tucson 2022">Buy Here</a></sub></details>|| |Hyundai|Santa Fe 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Tucson 2023[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Tucson 2023">Buy Here</a></sub></details>|| |Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>||
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Tucson Diesel 2019">Buy Here</a></sub></details>|| |Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|Hyundai|Tucson Hybrid 2022-23[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Tucson Hybrid 2022-23">Buy Here</a></sub></details>|| |Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Sonata 2018-19">Buy Here</a></sub></details>||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Veloster 2019-20">Buy Here</a></sub></details>|| |Hyundai|Sonata 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Jeep&model=Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Hyundai|Sonata Hybrid 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Sonata Hybrid 2020-23">Buy Here</a></sub></details>||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Jeep&model=Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson 2021">Buy Here</a></sub></details>||
|Kia|Carnival 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Carnival 2023">Buy Here</a></sub></details>|| |Hyundai|Tucson 2022[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson 2022">Buy Here</a></sub></details>||
|Kia|Carnival (China only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Carnival (China only) 2023">Buy Here</a></sub></details>|| |Hyundai|Tucson 2023[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson 2023">Buy Here</a></sub></details>||
|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Ceed 2019">Buy Here</a></sub></details>|| |Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson Diesel 2019">Buy Here</a></sub></details>||
|Kia|EV6 (Southeast Asia only) 2022-23[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=EV6 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>|| |Hyundai|Tucson Hybrid 2022-24[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson Hybrid 2022-24">Buy Here</a></sub></details>||
|Kia|EV6 (with HDA II) 2022-23[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=EV6 (with HDA II) 2022-23">Buy Here</a></sub></details>|| |Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Veloster 2019-20">Buy Here</a></sub></details>||
|Kia|EV6 (without HDA II) 2022-23[<sup>6</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=EV6 (without HDA II) 2022-23">Buy Here</a></sub></details>|| |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Jeep&model=Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Forte 2019-21">Buy Here</a></sub></details>|| |Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Jeep&model=Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Forte 2023">Buy Here</a></sub></details>|| |Kia|Carnival 2023-24[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival 2023-24">Buy Here</a></sub></details>||
|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=K5 2021-22">Buy Here</a></sub></details>|| |Kia|Carnival (China only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival (China only) 2023">Buy Here</a></sub></details>||
|Kia|K5 Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=K5 Hybrid 2020">Buy Here</a></sub></details>|| |Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Ceed 2019">Buy Here</a></sub></details>||
|Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro EV 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Kia|EV6 (Southeast Asia only) 2022-23[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>||
|Kia|Niro EV 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro EV 2020">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Kia|EV6 (with HDA II) 2022-23[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (with HDA II) 2022-23">Buy Here</a></sub></details>||
|Kia|Niro EV 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro EV 2021">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Kia|EV6 (without HDA II) 2022-23[<sup>6</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (without HDA II) 2022-23">Buy Here</a></sub></details>||
|Kia|Niro EV 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro EV 2022">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Forte 2019-21">Buy Here</a></sub></details>||
|Kia|Niro EV 2023[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro EV 2023">Buy Here</a></sub></details>|| |Kia|Forte 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Forte 2023">Buy Here</a></sub></details>||
|Kia|Niro Hybrid 2021-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro Hybrid 2021-22">Buy Here</a></sub></details>|| |Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=K5 2021-24">Buy Here</a></sub></details>||
|Kia|Niro Hybrid 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro Hybrid 2023">Buy Here</a></sub></details>|| |Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=K5 Hybrid 2020-22">Buy Here</a></sub></details>||
|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[<sup>1</sup>](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro Plug-in Hybrid 2018-19">Buy Here</a></sub></details>|| |Kia|K8 Hybrid (with HDA II) 2023[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=K8 Hybrid (with HDA II) 2023">Buy Here</a></sub></details>||
|Kia|Niro Plug-in Hybrid 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro Plug-in Hybrid 2020">Buy Here</a></sub></details>|| |Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Optima 2017">Buy Here</a></sub></details>|| |Kia|Niro EV 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2020">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Optima 2019-20">Buy Here</a></sub></details>|| |Kia|Niro EV 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2021">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Seltos 2021">Buy Here</a></sub></details>|| |Kia|Niro EV 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2022">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sorento 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Kia|Niro EV 2023[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2023">Buy Here</a></sub></details>||
|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sorento 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Kia|Niro Hybrid 2021-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Hybrid 2021-22">Buy Here</a></sub></details>||
|Kia|Sorento 2021-23[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sorento 2021-23">Buy Here</a></sub></details>|| |Kia|Niro Hybrid 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Hybrid 2023">Buy Here</a></sub></details>||
|Kia|Sorento Plug-in Hybrid 2022-23[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>|| |Kia|Niro Plug-in Hybrid 2018-19|All|Stock|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Plug-in Hybrid 2018-19">Buy Here</a></sub></details>||
|Kia|Sportage 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sportage 2023">Buy Here</a></sub></details>|| |Kia|Niro Plug-in Hybrid 2020|All|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Plug-in Hybrid 2020">Buy Here</a></sub></details>||
|Kia|Sportage Hybrid 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sportage Hybrid 2023">Buy Here</a></sub></details>|| |Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Optima 2017">Buy Here</a></sub></details>||
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Stinger 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Optima 2019-20">Buy Here</a></sub></details>||
|Kia|Stinger 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Stinger 2022">Buy Here</a></sub></details>|| |Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Optima Hybrid 2019">Buy Here</a></sub></details>||
|Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Telluride 2020-22">Buy Here</a></sub></details>|| |Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Seltos 2021">Buy Here</a></sub></details>||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=CT Hybrid 2017-18">Buy Here</a></sub></details>|| |Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Lexus|ES 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=ES 2017-18">Buy Here</a></sub></details>|| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=ES 2019-22">Buy Here</a></sub></details>|| |Kia|Sorento 2021-23[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento 2021-23">Buy Here</a></sub></details>||
|Lexus|ES Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=ES Hybrid 2017-18">Buy Here</a></sub></details>|| |Kia|Sorento Hybrid 2021-23[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento Hybrid 2021-23">Buy Here</a></sub></details>||
|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=ES Hybrid 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Kia|Sorento Plug-in Hybrid 2022-23[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=IS 2017-19">Buy Here</a></sub></details>|| |Kia|Sportage 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sportage 2023">Buy Here</a></sub></details>||
|Lexus|NX 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=NX 2018-19">Buy Here</a></sub></details>|| |Kia|Sportage Hybrid 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sportage Hybrid 2023">Buy Here</a></sub></details>||
|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=NX 2020-21">Buy Here</a></sub></details>|| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Stinger 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Lexus|NX Hybrid 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=NX Hybrid 2018-19">Buy Here</a></sub></details>|| |Kia|Stinger 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Stinger 2022-23">Buy Here</a></sub></details>||
|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=NX Hybrid 2020-21">Buy Here</a></sub></details>|| |Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Telluride 2020-22">Buy Here</a></sub></details>||
|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RC 2018-20">Buy Here</a></sub></details>|| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=CT Hybrid 2017-18">Buy Here</a></sub></details>||
|Lexus|RX 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX 2016">Buy Here</a></sub></details>|| |Lexus|ES 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES 2017-18">Buy Here</a></sub></details>||
|Lexus|RX 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX 2017-19">Buy Here</a></sub></details>|| |Lexus|ES 2019-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES 2019-24">Buy Here</a></sub></details>||
|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX 2020-22">Buy Here</a></sub></details>|| |Lexus|ES Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES Hybrid 2017-18">Buy Here</a></sub></details>||
|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX Hybrid 2016">Buy Here</a></sub></details>|| |Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES Hybrid 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Lexus|RX Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX Hybrid 2017-19">Buy Here</a></sub></details>|| |Lexus|GS F 2016|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=GS F 2016">Buy Here</a></sub></details>||
|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX Hybrid 2020-22">Buy Here</a></sub></details>|| |Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=IS 2017-19">Buy Here</a></sub></details>||
|Lexus|UX Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=UX Hybrid 2019-23">Buy Here</a></sub></details>|| |Lexus|IS 2022-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=IS 2022-23">Buy Here</a></sub></details>||
|Lincoln|Aviator 2020-21|Co-Pilot360 Plus|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Lincoln&model=Aviator 2020-21">Buy Here</a></sub></details>|| |Lexus|NX 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX 2018-19">Buy Here</a></sub></details>||
|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=MAN&model=eTGE 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX 2020-21">Buy Here</a></sub></details>||
|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=MAN&model=TGE 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Lexus|NX Hybrid 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX Hybrid 2018-19">Buy Here</a></sub></details>||
|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Mazda&model=CX-5 2022-23">Buy Here</a></sub></details>|| |Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX Hybrid 2020-21">Buy Here</a></sub></details>||
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Mazda&model=CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RC 2018-20">Buy Here</a></sub></details>||
|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Nissan B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Nissan&model=Altima 2019-20">Buy Here</a></sub></details>|| |Lexus|RX 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX 2016">Buy Here</a></sub></details>||
|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Nissan&model=Leaf 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Lexus|RX 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX 2017-19">Buy Here</a></sub></details>||
|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Nissan&model=Rogue 2018-20">Buy Here</a></sub></details>|| |Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX 2020-22">Buy Here</a></sub></details>||
|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Nissan&model=X-Trail 2017">Buy Here</a></sub></details>|| |Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX Hybrid 2016">Buy Here</a></sub></details>||
|Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Ram connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Ram&model=1500 2019-23">Buy Here</a></sub></details>|| |Lexus|RX Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX Hybrid 2017-19">Buy Here</a></sub></details>||
|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=SEAT&model=Ateca 2018">Buy Here</a></sub></details>|| |Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX Hybrid 2020-22">Buy Here</a></sub></details>||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=SEAT&model=Leon 2014-20">Buy Here</a></sub></details>|| |Lexus|UX Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=UX Hybrid 2019-23">Buy Here</a></sub></details>||
|Subaru|Ascent 2019-21|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Ascent 2019-21">Buy Here</a></sub></details>|| |Lincoln|Aviator 2020-21|Co-Pilot360 Plus|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lincoln&model=Aviator 2020-21">Buy Here</a></sub></details>||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Crosstrek 2018-19">Buy Here</a></sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=eTGE 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Crosstrek 2020-23">Buy Here</a></sub></details>|| |MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=TGE 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Forester 2019-21|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Forester 2019-21">Buy Here</a></sub></details>|| |Mazda|CX-5 2022-24|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-5 2022-24">Buy Here</a></sub></details>||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Impreza 2017-19">Buy Here</a></sub></details>|| |Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Impreza 2020-22">Buy Here</a></sub></details>|| |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Altima 2019-20">Buy Here</a></sub></details>||
|Subaru|Legacy 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru B connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Legacy 2020-22">Buy Here</a></sub></details>|| |Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Leaf 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Outback 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru B connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Outback 2020-22">Buy Here</a></sub></details>|| |Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Rogue 2018-20">Buy Here</a></sub></details>||
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=XV 2018-19">Buy Here</a></sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=X-Trail 2017">Buy Here</a></sub></details>||
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=XV 2020-21">Buy Here</a></sub></details>|| |Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Ram connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ram&model=1500 2019-23">Buy Here</a></sub></details>||
|Škoda|Fabia 2022-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Fabia 2022-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)|| |SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=SEAT&model=Ateca 2018">Buy Here</a></sub></details>||
|Škoda|Kamiq 2021[<sup>9,11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Kamiq 2021">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)|| |SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=SEAT&model=Leon 2014-20">Buy Here</a></sub></details>||
|Škoda|Karoq 2019-21[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Karoq 2019-21">Buy Here</a></sub></details>|| |Subaru|Ascent 2019-21|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Škoda|Kodiaq 2017-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Kodiaq 2017-23">Buy Here</a></sub></details>|| |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Škoda|Octavia 2015, 2018-19[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Octavia 2015, 2018-19">Buy Here</a></sub></details>|| |Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Škoda|Octavia RS 2016[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Octavia RS 2016">Buy Here</a></sub></details>|| |Subaru|Forester 2019-21|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Škoda|Scala 2020-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Scala 2020-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)|| |Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Škoda|Superb 2015-22[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Superb 2015-22">Buy Here</a></sub></details>|| |Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Alphard 2019-20">Buy Here</a></sub></details>|| |Subaru|Legacy 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru B connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Legacy 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Alphard Hybrid 2021">Buy Here</a></sub></details>|| |Subaru|Outback 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru B connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Outback 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon 2016">Buy Here</a></sub></details>|| |Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Avalon 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon 2017-18">Buy Here</a></sub></details>|| |Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Toyota|Avalon 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon 2019-21">Buy Here</a></sub></details>|| |Škoda|Fabia 2022-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Fabia 2022-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon 2022">Buy Here</a></sub></details>|| |Škoda|Kamiq 2021-23[<sup>9,11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kamiq 2021-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Toyota|Avalon Hybrid 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon Hybrid 2019-21">Buy Here</a></sub></details>|| |Škoda|Karoq 2019-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Karoq 2019-23">Buy Here</a></sub></details>||
|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon Hybrid 2022">Buy Here</a></sub></details>|| |Škoda|Kodiaq 2017-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kodiaq 2017-23">Buy Here</a></sub></details>||
|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=C-HR 2017-20">Buy Here</a></sub></details>|| |Škoda|Octavia 2015-19[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia 2015-19">Buy Here</a></sub></details>||
|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=C-HR 2021">Buy Here</a></sub></details>|| |Škoda|Octavia RS 2016[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia RS 2016">Buy Here</a></sub></details>||
|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=C-HR Hybrid 2017-20">Buy Here</a></sub></details>|| |Škoda|Scala 2020-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Scala 2020-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=C-HR Hybrid 2021-22">Buy Here</a></sub></details>|| |Škoda|Superb 2015-22[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Superb 2015-22">Buy Here</a></sub></details>||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>8</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Alphard 2019-20">Buy Here</a></sub></details>||
|Toyota|Camry 2021-23|All|openpilot|0 mph[<sup>8</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Camry 2021-23">Buy Here</a></sub></details>|| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Alphard Hybrid 2021">Buy Here</a></sub></details>||
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Camry Hybrid 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2016">Buy Here</a></sub></details>||
|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Camry Hybrid 2021-23">Buy Here</a></sub></details>|| |Toyota|Avalon 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2017-18">Buy Here</a></sub></details>||
|Toyota|Corolla 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla 2017-19">Buy Here</a></sub></details>|| |Toyota|Avalon 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2019-21">Buy Here</a></sub></details>||
|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla 2020-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2022">Buy Here</a></sub></details>||
|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla Cross (Non-US only) 2020-23">Buy Here</a></sub></details>|| |Toyota|Avalon Hybrid 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon Hybrid 2019-21">Buy Here</a></sub></details>||
|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla Cross Hybrid (Non-US only) 2020-22">Buy Here</a></sub></details>|| |Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon Hybrid 2022">Buy Here</a></sub></details>||
|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla Hatchback 2019-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR 2017-20">Buy Here</a></sub></details>||
|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla Hybrid 2020-22">Buy Here</a></sub></details>|| |Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR 2021">Buy Here</a></sub></details>||
|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla Hybrid (Non-US only) 2020-23">Buy Here</a></sub></details>|| |Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR Hybrid 2017-20">Buy Here</a></sub></details>||
|Toyota|Highlander 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Highlander 2017-19">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=0wS0wXSLzoo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR Hybrid 2021-22">Buy Here</a></sub></details>||
|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Highlander 2020-23">Buy Here</a></sub></details>|| |Toyota|Camry 2018-20|All|Stock|0 mph[<sup>8</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Highlander Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Highlander Hybrid 2017-19">Buy Here</a></sub></details>|| |Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>8</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry 2021-24">Buy Here</a></sub></details>||
|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Highlander Hybrid 2020-23">Buy Here</a></sub></details>|| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry Hybrid 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Mirai 2021">Buy Here</a></sub></details>|| |Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry Hybrid 2021-24">Buy Here</a></sub></details>||
|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius 2016">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Corolla 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla 2017-19">Buy Here</a></sub></details>||
|Toyota|Prius 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius 2017-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla 2020-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius 2021-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=J58TvCpUd4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Cross (Non-US only) 2020-23">Buy Here</a></sub></details>||
|Toyota|Prius Prime 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius Prime 2017-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Cross Hybrid (Non-US only) 2020-22">Buy Here</a></sub></details>||
|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius Prime 2021-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=J58TvCpUd4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hatchback 2019-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius v 2017">Buy Here</a></sub></details>|| |Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hybrid 2020-22">Buy Here</a></sub></details>||
|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 2016">Buy Here</a></sub></details>|| |Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hybrid (Non-US only) 2020-23">Buy Here</a></sub></details>||
|Toyota|RAV4 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 2017-18">Buy Here</a></sub></details>|| |Toyota|Highlander 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander 2017-19">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=0wS0wXSLzoo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=wJxjDd42gGA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander 2020-23">Buy Here</a></sub></details>||
|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 2022">Buy Here</a></sub></details>|| |Toyota|Highlander Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander Hybrid 2017-19">Buy Here</a></sub></details>||
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 Hybrid 2016">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander Hybrid 2020-23">Buy Here</a></sub></details>||
|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 Hybrid 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Mirai 2021">Buy Here</a></sub></details>||
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 Hybrid 2019-21">Buy Here</a></sub></details>|| |Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius 2016">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Prius 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius 2017-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Sienna 2018-20|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota connector<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius 2021-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=J58TvCpUd4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Prius Prime 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius Prime 2017-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius Prime 2021-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=J58TvCpUd4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius v 2017">Buy Here</a></sub></details>||
|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Atlas 2018-23">Buy Here</a></sub></details>|| |Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2016">Buy Here</a></sub></details>||
|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Atlas Cross Sport 2021-22">Buy Here</a></sub></details>|| |Toyota|RAV4 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2017-18">Buy Here</a></sub></details>||
|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=California 2021">Buy Here</a></sub></details>|| |Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=wJxjDd42gGA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Caravelle 2020">Buy Here</a></sub></details>|| |Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2022">Buy Here</a></sub></details>||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2016">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Crafter 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=e-Crafter 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2019-21">Buy Here</a></sub></details>||
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=e-Golf 2014-20">Buy Here</a></sub></details>|| |Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf 2015-20">Buy Here</a></sub></details>|| |Toyota|Sienna 2018-20|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf Alltrack 2015-19">Buy Here</a></sub></details>|| |Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf GTD 2015-20">Buy Here</a></sub></details>|| |Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf GTE 2015-20">Buy Here</a></sub></details>|| |Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf GTI 2015-21">Buy Here</a></sub></details>|| |Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas 2018-23">Buy Here</a></sub></details>||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf R 2015-19">Buy Here</a></sub></details>|| |Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas Cross Sport 2020-22">Buy Here</a></sub></details>||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf SportsVan 2015-20">Buy Here</a></sub></details>|| |Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=California 2021-23">Buy Here</a></sub></details>||
|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Grand California 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Caravelle 2020">Buy Here</a></sub></details>||
|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Jetta 2018-22">Buy Here</a></sub></details>|| |Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Jetta GLI 2021-22">Buy Here</a></sub></details>|| |Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Crafter 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Passat 2015-22[<sup>10</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Passat 2015-22">Buy Here</a></sub></details>|| |Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Crafter 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Passat Alltrack 2015-22">Buy Here</a></sub></details>|| |Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Golf 2014-20">Buy Here</a></sub></details>||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Passat GTE 2015-22">Buy Here</a></sub></details>|| |Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Polo 2018-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)|| |Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf Alltrack 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)|| |Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTD 2015-20">Buy Here</a></sub></details>||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=T-Cross 2021">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)|| |Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTE 2015-20">Buy Here</a></sub></details>||
|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=T-Roc 2021">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)|| |Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTI 2015-21">Buy Here</a></sub></details>||
|Volkswagen|Taos 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Taos 2022-23">Buy Here</a></sub></details>|| |Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf R 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Teramont 2018-22">Buy Here</a></sub></details>|| |Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf SportsVan 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Teramont Cross Sport 2021-22">Buy Here</a></sub></details>|| |Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Grand California 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Teramont X 2021-22">Buy Here</a></sub></details>|| |Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta 2018-22">Buy Here</a></sub></details>||
|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Tiguan 2018-23">Buy Here</a></sub></details>|| |Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta GLI 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Tiguan eHybrid 2021-23">Buy Here</a></sub></details>|| |Volkswagen|Passat 2015-22[<sup>10</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>View</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Touran 2016-23">Buy Here</a></sub></details>|| |Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat Alltrack 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat GTE 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Polo 2018-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=T-Cross 2021">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|T-Roc 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=T-Roc 2018-22">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|Taos 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Taos 2022-23">Buy Here</a></sub></details>||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont 2018-22">Buy Here</a></sub></details>||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont Cross Sport 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont X 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Tiguan 2018-23">Buy Here</a></sub></details>||
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Tiguan eHybrid 2021-23">Buy Here</a></sub></details>||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Touran 2016-23">Buy Here</a></sub></details>||
### Footnotes ### Footnotes
<sup>1</sup>Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`. <br /> <sup>1</sup>openpilot Longitudinal Control (Alpha) is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`. <br />
<sup>2</sup>By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b> <br /> <sup>2</sup>By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b> <br />
<sup>3</sup>Refers only to the Focus Mk4 (C519) available in Europe/China/Taiwan/Australasia, not the Focus Mk3 (C346) in North and South America/Southeast Asia. <br /> <sup>3</sup>Refers only to the Focus Mk4 (C519) available in Europe/China/Taiwan/Australasia, not the Focus Mk3 (C346) in North and South America/Southeast Asia. <br />
<sup>4</sup>Requires a <a href="https://github.com/commaai/openpilot/wiki/GM#hardware" target="_blank">community built ASCM harness</a>. <b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b> <br /> <sup>4</sup>Requires a <a href="https://github.com/commaai/openpilot/wiki/GM#hardware" target="_blank">community built ASCM harness</a>. <b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b> <br />
<sup>5</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br /> <sup>5</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
<sup>6</sup>Requires a <a href="https://comma.ai/shop/panda" target="_blank">red panda</a> for this <a href="https://en.wikipedia.org/wiki/CAN_FD" target="_blank">CAN FD car</a>. All the hardware needed is sold in the <a href="https://comma.ai/shop/can-fd-panda-kit" target="_blank">CAN FD kit</a>. <br /> <sup>6</sup>Requires a <a href="https://comma.ai/shop/can-fd-panda-kit" target="_blank">CAN FD panda kit</a> if not using comma 3X for this <a href="https://en.wikipedia.org/wiki/CAN_FD" target="_blank">CAN FD car</a>. <br />
<sup>7</sup>In the non-US market, openpilot requires the car to come equipped with EyeSight with Lane Keep Assistance. <br /> <sup>7</sup>In the non-US market, openpilot requires the car to come equipped with EyeSight with Lane Keep Assistance. <br />
<sup>8</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br /> <sup>8</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>9</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br /> <sup>9</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>10</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br /> <sup>10</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
<sup>11</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma three functionality. <br /> <sup>11</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma 3X functionality. <br />
<sup>12</sup>Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC. <br /> <sup>12</sup>Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC. <br />
<sup>13</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br /> <sup>13</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br />
@ -306,12 +319,12 @@ If your car has the following packages or features, then it's a good candidate f
### FlexRay ### FlexRay
All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a CAN bus isn't the only way that the cars in your computer can communicate. Most, if not all, vehicles from the following manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars may one day be supported, but we have no immediate plans to support FlexRay. All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a CAN bus isn't the only way that the computers in your car can communicate. Most, if not all, vehicles from the following manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars may one day be supported, but we have no immediate plans to support FlexRay.
### Toyota Security ### Toyota Security
openpilot does not yet support these Toyota models due to a new message authentication method. openpilot does not yet support these Toyota models due to a new message authentication method.
[Vote](https://comma.ai/shop/products/vote) if you'd like to see openpilot support on these models. [Vote](https://comma.ai/shop#toyota-security) if you'd like to see openpilot support on these models.
* Toyota RAV4 Prime 2021+ * Toyota RAV4 Prime 2021+
* Toyota Sienna 2021+ * Toyota Sienna 2021+

@ -1,9 +0,0 @@
import logging
import os
from .astro_dog import AstroDog
assert AstroDog is not None
# setup logging
LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO').upper()
logging.basicConfig(level=LOGLEVEL, format='%(message)s')

@ -1,396 +0,0 @@
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor
from typing import DefaultDict, Dict, Iterable, List, Optional, Union
from .constants import SECS_IN_DAY, SECS_IN_HR
from .helpers import ConstellationId, get_constellation, get_closest, get_el_az, TimeRangeHolder
from .ephemeris import Ephemeris, EphemerisType, GLONASSEphemeris, GPSEphemeris, PolyEphemeris, parse_sp3_orbits, parse_rinex_nav_msg_gps, \
parse_rinex_nav_msg_glonass
from .downloader import download_orbits_gps, download_orbits_russia_src, download_nav, download_ionex, download_dcb, download_prediction_orbits_russia_src
from .downloader import download_cors_station
from .trop import saast
from .iono import IonexMap, parse_ionex, get_slant_delay
from .dcb import DCB, parse_dcbs
from .gps_time import GPSTime
from .dgps import get_closest_station_names, parse_dgps
from . import constants
MAX_DGPS_DISTANCE = 100_000 # in meters, because we're not barbarians
class AstroDog:
'''
auto_update: flag indicating whether laika should fetch files from web automatically
cache_dir: directory where data files are downloaded to and cached
dgps: flag indicating whether laika should use dgps (CORS)
data to calculate pseudorange corrections
valid_const: list of constellation identifiers laika will try process
valid_ephem_types: set of ephemeris types that are allowed to use and download.
Default is set to use all orbit ephemeris types
clear_old_ephemeris: flag indicating if ephemeris for an individual satellite should be overwritten when new ephemeris is added.
'''
def __init__(self, auto_update=True,
cache_dir='/tmp/gnss/',
dgps=False,
valid_const=(ConstellationId.GPS, ConstellationId.GLONASS),
valid_ephem_types=EphemerisType.all_orbits(),
clear_old_ephemeris=False):
for const in valid_const:
if not isinstance(const, ConstellationId):
raise TypeError(f"valid_const must be a list of ConstellationId, got {const}")
self.auto_update = auto_update
self.cache_dir = cache_dir
self.clear_old_ephemeris = clear_old_ephemeris
self.dgps = dgps
if not isinstance(valid_ephem_types, Iterable):
valid_ephem_types = [valid_ephem_types]
self.pull_orbit = len(set(EphemerisType.all_orbits()) & set(valid_ephem_types)) > 0
self.pull_nav = EphemerisType.NAV in valid_ephem_types
self.use_qcom_poly = EphemerisType.QCOM_POLY in valid_ephem_types
self.valid_const = valid_const
self.valid_ephem_types = valid_ephem_types
self.orbit_fetched_times = TimeRangeHolder()
self.navs_fetched_times = TimeRangeHolder()
self.dcbs_fetched_times = TimeRangeHolder()
self.dgps_delays = []
self.ionex_maps: List[IonexMap] = []
self.orbits: DefaultDict[str, List[PolyEphemeris]] = defaultdict(list)
self.qcom_polys: DefaultDict[str, List[PolyEphemeris]] = defaultdict(list)
self.navs: DefaultDict[str, List[Union[GPSEphemeris, GLONASSEphemeris]]] = defaultdict(list)
self.dcbs: DefaultDict[str, List[DCB]] = defaultdict(list)
self.cached_ionex: Optional[IonexMap] = None
self.cached_dgps = None
self.cached_orbit: DefaultDict[str, Optional[PolyEphemeris]] = defaultdict(lambda: None)
self.cached_qcom_polys: DefaultDict[str, Optional[PolyEphemeris]] = defaultdict(lambda: None)
self.cached_nav: DefaultDict[str, Union[GPSEphemeris, GLONASSEphemeris, None]] = defaultdict(lambda: None)
self.cached_dcb: DefaultDict[str, Optional[DCB]] = defaultdict(lambda: None)
def get_ionex(self, time) -> Optional[IonexMap]:
ionex: Optional[IonexMap] = self._get_latest_valid_data(self.ionex_maps, self.cached_ionex, self.get_ionex_data, time)
if ionex is None:
if self.auto_update:
raise RuntimeError("Pulled ionex, but still can't get valid for time " + str(time))
else:
self.cached_ionex = ionex
return ionex
def get_nav(self, prn, time):
skip_download = time in self.navs_fetched_times
nav = self._get_latest_valid_data(self.navs[prn], self.cached_nav[prn], self.get_nav_data, time, skip_download)
if nav is not None:
self.cached_nav[prn] = nav
return nav
@staticmethod
def _select_valid_temporal_items(item_dict, time, cache):
'''Returns only valid temporal item for specific time from currently fetched
data.'''
result = {}
for prn, temporal_objects in item_dict.items():
cached = cache[prn]
if cached is not None and cached.valid(time):
obj = cached
else:
obj = get_closest(time, temporal_objects)
if obj is None or not obj.valid(time):
continue
cache[prn] = obj
result[prn] = obj
return result
def get_all_ephem_prns(self):
return set(self.orbits.keys()).union(set(self.navs.keys())).union(set(self.qcom_polys.keys()))
def get_navs(self, time):
if time not in self.navs_fetched_times:
self.get_nav_data(time)
return AstroDog._select_valid_temporal_items(self.navs, time, self.cached_nav)
def get_orbit(self, prn: str, time: GPSTime):
skip_download = time in self.orbit_fetched_times
orbit = self._get_latest_valid_data(self.orbits[prn], self.cached_orbit[prn], self.get_orbit_data, time, skip_download)
if orbit is not None:
self.cached_orbit[prn] = orbit
return orbit
def get_qcom_poly(self, prn: str, time: GPSTime):
poly = self._get_latest_valid_data(self.qcom_polys[prn], self.cached_qcom_polys[prn], None, time, True)
if poly is not None:
self.cached_qcom_polys[prn] = poly
return poly
def get_orbits(self, time):
if time not in self.orbit_fetched_times:
self.get_orbit_data(time)
return AstroDog._select_valid_temporal_items(self.orbits, time, self.cached_orbit)
def get_dcb(self, prn, time):
skip_download = time in self.dcbs_fetched_times
dcb = self._get_latest_valid_data(self.dcbs[prn], self.cached_dcb[prn], self.get_dcb_data, time, skip_download)
if dcb is not None:
self.cached_dcb[prn] = dcb
return dcb
def get_dgps_corrections(self, time, recv_pos):
latest_data = self._get_latest_valid_data(self.dgps_delays, self.cached_dgps, self.get_dgps_data, time, recv_pos=recv_pos)
if latest_data is None:
if self.auto_update:
raise RuntimeError("Pulled dgps, but still can't get valid for time " + str(time))
else:
self.cached_dgps = latest_data
return latest_data
def add_qcom_polys(self, new_ephems: Dict[str, List[Ephemeris]]):
self._add_ephems(new_ephems, self.qcom_polys)
def add_orbits(self, new_ephems: Dict[str, List[Ephemeris]]):
self._add_ephems(new_ephems, self.orbits)
def add_navs(self, new_ephems: Dict[str, List[Ephemeris]]):
self._add_ephems(new_ephems, self.navs)
def _add_ephems(self, new_ephems: Dict[str, List[Ephemeris]], ephems_dict):
for k, v in new_ephems.items():
if len(v) > 0:
if self.clear_old_ephemeris:
ephems_dict[k] = v
else:
ephems_dict[k].extend(v)
def add_ephem_fetched_time(self, ephems, fetched_times):
min_epochs = []
max_epochs = []
for v in ephems.values():
if len(v) > 0:
min_ephem, max_ephem = self.get_epoch_range(v)
min_epochs.append(min_ephem)
max_epochs.append(max_ephem)
if len(min_epochs) > 0:
min_epoch = min(min_epochs)
max_epoch = max(max_epochs)
fetched_times.add(min_epoch, max_epoch)
def get_nav_data(self, time):
def download_and_parse(constellation, parse_rinex_nav_func):
file_path = download_nav(time, cache_dir=self.cache_dir, constellation=constellation)
return parse_rinex_nav_func(file_path) if file_path else {}
fetched_ephems = {}
if ConstellationId.GPS in self.valid_const:
fetched_ephems = download_and_parse(ConstellationId.GPS, parse_rinex_nav_msg_gps)
if ConstellationId.GLONASS in self.valid_const:
for k, v in download_and_parse(ConstellationId.GLONASS, parse_rinex_nav_msg_glonass).items():
fetched_ephems.setdefault(k, []).extend(v)
self.add_navs(fetched_ephems)
if sum([len(v) for v in fetched_ephems.values()]) == 0:
begin_day = GPSTime(time.week, SECS_IN_DAY * (time.tow // SECS_IN_DAY))
end_day = GPSTime(time.week, SECS_IN_DAY * (1 + (time.tow // SECS_IN_DAY)))
self.navs_fetched_times.add(begin_day, end_day)
def download_parse_orbit(self, gps_time: GPSTime, skip_before_epoch=None) -> Dict[str, List[PolyEphemeris]]:
# Download multiple days to be able to polyfit at the start-end of the day
time_steps = [gps_time - SECS_IN_DAY, gps_time, gps_time + SECS_IN_DAY]
with ThreadPoolExecutor() as executor:
futures_other = [executor.submit(download_orbits_russia_src, t, self.cache_dir, self.valid_ephem_types) for t in time_steps]
futures_gps = None
if ConstellationId.GPS in self.valid_const:
futures_gps = [executor.submit(download_orbits_gps, t, self.cache_dir, self.valid_ephem_types) for t in time_steps]
ephems_other = parse_sp3_orbits([f.result() for f in futures_other if f.result()], self.valid_const, skip_before_epoch)
ephems_us = parse_sp3_orbits([f.result() for f in futures_gps if f.result()], self.valid_const, skip_before_epoch) if futures_gps else {}
return {k: ephems_other.get(k, []) + ephems_us.get(k, []) for k in set(list(ephems_other.keys()) + list(ephems_us.keys()))}
def download_parse_prediction_orbit(self, gps_time: GPSTime):
assert EphemerisType.ULTRA_RAPID_ORBIT in self.valid_ephem_types
skip_until_epoch = gps_time - 2 * SECS_IN_HR
result = download_prediction_orbits_russia_src(gps_time, self.cache_dir)
if result is not None:
result = [result]
elif ConstellationId.GPS in self.valid_const:
# Slower fallback. Russia src prediction orbits are published from 2022
result = [download_orbits_gps(t, self.cache_dir, self.valid_ephem_types) for t in [gps_time - SECS_IN_DAY, gps_time]]
if result is None:
return {}
return parse_sp3_orbits(result, self.valid_const, skip_until_epoch=skip_until_epoch)
def get_orbit_data(self, time: GPSTime, only_predictions=False):
if only_predictions:
ephems_sp3 = self.download_parse_prediction_orbit(time)
else:
ephems_sp3 = self.download_parse_orbit(time)
if sum([len(v) for v in ephems_sp3.values()]) < 5:
raise RuntimeError(f'No orbit data found. For Time {time.as_datetime()} constellations {self.valid_const} valid ephem types {self.valid_ephem_types}')
self.add_ephem_fetched_time(ephems_sp3, self.orbit_fetched_times)
self.add_orbits(ephems_sp3)
def get_dcb_data(self, time):
file_path_dcb = download_dcb(time, cache_dir=self.cache_dir)
dcbs = parse_dcbs(file_path_dcb, self.valid_const)
for dcb in dcbs:
self.dcbs[dcb.prn].append(dcb)
if len(dcbs) != 0:
min_epoch, max_epoch = self.get_epoch_range(dcbs)
self.dcbs_fetched_times.add(min_epoch, max_epoch)
def get_epoch_range(self, new_ephems):
min_ephem = min(new_ephems, key=lambda e: e.epoch)
max_ephem = max(new_ephems, key=lambda e: e.epoch)
min_epoch = min_ephem.epoch - min_ephem.max_time_diff
max_epoch = max_ephem.epoch + max_ephem.max_time_diff
return min_epoch, max_epoch
def get_ionex_data(self, time):
file_path_ionex = download_ionex(time, cache_dir=self.cache_dir)
ionex_maps = parse_ionex(file_path_ionex)
for im in ionex_maps:
self.ionex_maps.append(im)
def get_dgps_data(self, time, recv_pos):
station_names = get_closest_station_names(recv_pos, k=8, max_distance=MAX_DGPS_DISTANCE, cache_dir=self.cache_dir)
for station_name in station_names:
file_path_station = download_cors_station(time, station_name, cache_dir=self.cache_dir)
if file_path_station:
dgps = parse_dgps(station_name, file_path_station,
self, max_distance=MAX_DGPS_DISTANCE,
required_constellations=self.valid_const)
if dgps is not None:
self.dgps_delays.append(dgps)
break
def get_tgd_from_nav(self, prn, time):
if get_constellation(prn) not in self.valid_const:
return None
eph = self.get_nav(prn, time)
if eph:
return eph.get_tgd()
return None
def get_eph(self, prn, time):
if get_constellation(prn) not in self.valid_const:
return None
eph = None
if self.pull_orbit:
eph = self.get_orbit(prn, time)
if not eph and self.pull_nav:
eph = self.get_nav(prn, time)
if not eph and self.use_qcom_poly:
eph = self.get_qcom_poly(prn, time)
return eph
def get_sat_info(self, prn, time):
eph = self.get_eph(prn, time)
if eph:
return eph.get_sat_info(time)
return None
def get_all_sat_info(self, time):
ephs = {}
if self.pull_orbit:
ephs = self.get_orbits(time)
if len(ephs) == 0 and self.pull_nav:
ephs = self.get_navs(time)
return {prn: eph.get_sat_info(time) for prn, eph in ephs.items()}
def get_glonass_channel(self, prn, time):
nav = self.get_nav(prn, time)
if nav:
return nav.channel
return None
def get_frequency(self, prn, time, signal='C1C'):
if get_constellation(prn) == ConstellationId.GPS:
switch = {'1': constants.GPS_L1,
'2': constants.GPS_L2,
'5': constants.GPS_L5,
'6': constants.GALILEO_E6,
'7': constants.GALILEO_E5B,
'8': constants.GALILEO_E5AB}
freq = switch.get(signal[1])
if freq:
return freq
raise NotImplementedError("Dont know this GPS frequency: ", signal, prn)
elif get_constellation(prn) == ConstellationId.GLONASS:
n = self.get_glonass_channel(prn, time)
if n is None:
return None
switch = {'1': constants.GLONASS_L1 + n * constants.GLONASS_L1_DELTA,
'2': constants.GLONASS_L2 + n * constants.GLONASS_L2_DELTA,
'5': constants.GLONASS_L5 + n * constants.GLONASS_L5_DELTA,
'6': constants.GALILEO_E6,
'7': constants.GALILEO_E5B,
'8': constants.GALILEO_E5AB}
freq = switch.get(signal[1])
if freq:
return freq
raise NotImplementedError("Dont know this GLONASS frequency: ", signal, prn)
def get_delay(self, prn, time, rcv_pos, no_dgps=False, signal='C1C', freq=None):
sat_info = self.get_sat_info(prn, time)
if sat_info is None:
return None
sat_pos = sat_info[0]
el, az = get_el_az(rcv_pos, sat_pos)
if el < 0.2:
return None
if self.dgps and not no_dgps:
return self._get_delay_dgps(prn, rcv_pos, time)
ionex = self.get_ionex(time)
if not freq and ionex is not None:
freq = self.get_frequency(prn, time, signal)
dcb = self.get_dcb(prn, time)
# When using internet we expect all data or return None
if self.auto_update and (ionex is None or dcb is None or freq is None):
return None
if ionex is not None:
iono_delay = ionex.get_delay(rcv_pos, az, el, sat_pos, time, freq)
else:
# 5m vertical delay is a good default
iono_delay = get_slant_delay(rcv_pos, az, el, sat_pos, time, freq, vertical_delay=5.0)
trop_delay = saast(rcv_pos, el)
code_bias = dcb.get_delay(signal) if dcb is not None else 0.
return iono_delay + trop_delay + code_bias
def _get_delay_dgps(self, prn, rcv_pos, time):
dgps_corrections = self.get_dgps_corrections(time, rcv_pos)
if dgps_corrections is None:
return None
return dgps_corrections.get_delay(prn, time)
def _get_latest_valid_data(self, data, latest_data, download_data_func, time, skip_download=False, recv_pos=None):
def is_valid(latest_data):
if recv_pos is None:
return latest_data is not None and latest_data.valid(time)
else:
return latest_data is not None and latest_data.valid(time, recv_pos)
if is_valid(latest_data):
return latest_data
latest_data = get_closest(time, data, recv_pos=recv_pos)
if is_valid(latest_data):
return latest_data
if skip_download or not self.auto_update:
return None
if recv_pos is not None:
download_data_func(time, recv_pos)
else:
download_data_func(time)
latest_data = get_closest(time, data, recv_pos=recv_pos)
if is_valid(latest_data):
return latest_data
return None

@ -1,34 +0,0 @@
# These are all from IS-GPS-200G unless otherwise noted
SPEED_OF_LIGHT = 2.99792458e8 # m/s
# Physical parameters of the Earth
EARTH_GM = 3.986005e14 # m^3/s^2 (gravitational constant * mass of earth)
EARTH_RADIUS = 6.3781e6 # m
EARTH_ROTATION_RATE = 7.2921151467e-005 # rad/s (WGS84 earth rotation rate)
# GPS system parameters:
GPS_L1 = l1 = 1.57542e9 # Hz
GPS_L2 = l2 = 1.22760e9 # Hz
GPS_L5 = l5 = 1.17645e9 # Hz Also E5
#GLONASS system parameters
#TODO this is old convention
GLONASS_L1 = 1.602e9
GLONASS_L1_DELTA = 0.5625e6
GLONASS_L2 = 1.246e9
GLONASS_L2_DELTA = 0.4375e6
GLONASS_L5 = 1.201e9
GLONASS_L5_DELTA = 0.4375e6
#Galileo system parameters: # Has additional frequencies on E6
#Source RINEX 2.11 document
GALILEO_E5B = 1.207140e9 # Hz
GALILEO_E5AB = 1.191795e9 # Hz
GALILEO_E6 = 1.27875e9 # Hz
SECS_IN_MIN = 60
SECS_IN_HR = 60*SECS_IN_MIN
SECS_IN_DAY = 24*SECS_IN_HR
SECS_IN_WEEK = 7*SECS_IN_DAY
SECS_IN_YEAR = 365*SECS_IN_DAY

@ -1,84 +0,0 @@
from datetime import datetime
from .constants import SECS_IN_HR, SECS_IN_WEEK, \
SPEED_OF_LIGHT, GPS_L1, GPS_L2
from .gps_time import GPSTime
from .helpers import get_constellation
import warnings
class DCB:
def __init__(self, prn, data):
self.max_time_diff = 2*SECS_IN_WEEK
self.prn = prn
self.epoch = data['epoch']
self.healthy = True
if 'C1W_C2W' in data:
self.C1W_C2W = data['C1W_C2W']
elif 'C1P_C2P' in data:
self.C1W_C2W = data['C1P_C2P']
else:
self.healthy = False
if 'C1C_C1W' in data:
self.C1C_C1W = data['C1C_C1W']
elif 'C1C_C1P' in data:
self.C1C_C1W = data['C1C_C1P']
else:
self.healthy = False
def valid(self, time):
return abs(time - self.epoch) <= self.max_time_diff and self.healthy
def get_delay(self, signal):
if signal == 'C1C':
return (- SPEED_OF_LIGHT*1e-9*self.C1W_C2W*GPS_L2**2/(GPS_L1**2 - GPS_L2**2)
+ SPEED_OF_LIGHT*1e-9*self.C1C_C1W)
if signal == 'C2P':
return (- SPEED_OF_LIGHT*1e-9*self.C1W_C2W*GPS_L1**2/(GPS_L1**2 - GPS_L2**2))
if signal == 'C1P':
return (SPEED_OF_LIGHT*1e-9*self.C1C_C1W)
## Todo: update dcb database and get delay to include additional signals
if signal == 'C2C':
warnings.warn("Differential code bias not implemented for signal C2C", UserWarning)
return 0
if signal == 'C5C':
warnings.warn("Differential code bias not implemented for signal C5C", UserWarning)
return 0
if signal == 'C6C':
warnings.warn("Differential code bias not implemented for signal C6C", UserWarning)
return 0
if signal == 'C7C':
warnings.warn("Differential code bias not implemented for signal C7C", UserWarning)
return 0
if signal == 'C8C':
warnings.warn("Differential code bias not implemented for signal C8C", UserWarning)
return 0
def parse_dcbs(file_name, SUPPORTED_CONSTELLATIONS):
with open(file_name, 'r+') as DCB_file:
contents = DCB_file.readlines()
data_started = False
dcbs_dict = {}
for line in contents:
if not data_started:
if line[1:4] == 'DSB':
data_started = True
else:
continue
line_components = line.split()
if len(line_components[2]) < 3:
break
prn = line_components[2]
if get_constellation(prn) not in SUPPORTED_CONSTELLATIONS:
continue
dcb_type = line_components[3] + '_' + line_components[4]
epoch = GPSTime.from_datetime(datetime.strptime(line_components[5], '%Y:%j:%f')) + 12*SECS_IN_HR
if prn not in dcbs_dict:
dcbs_dict[prn] = {}
dcbs_dict[prn][dcb_type] = float(line_components[8])
dcbs_dict[prn]['epoch'] = epoch
dcbs = []
for prn in dcbs_dict:
dcbs.append(DCB(prn, dcbs_dict[prn]))
return dcbs

@ -1,161 +0,0 @@
import os
import numpy as np
from datetime import datetime
from .gps_time import GPSTime
from .constants import SECS_IN_YEAR
from . import raw_gnss as raw
from . import opt
from .rinex_file import RINEXFile
from .downloader import download_cors_coords
from .helpers import get_constellation, ConstellationId
def mean_filter(delay):
d2 = delay.copy()
max_step = 10
for i in range(max_step, len(delay) - max_step):
finite_idxs = np.where(np.isfinite(delay[i - max_step:i + max_step]))
if max_step in finite_idxs[0]:
step = min([max_step, finite_idxs[0][-1] - max_step, max_step - finite_idxs[0][0]])
d2[i] = np.nanmean(delay[i - step:i + step + 1])
return d2
def download_and_parse_station_postions(cors_station_positions_path, cache_dir):
if not os.path.isfile(cors_station_positions_path):
cors_stations = {}
coord_file_paths = download_cors_coords(cache_dir=cache_dir)
for coord_file_path in coord_file_paths:
try:
station_id = coord_file_path.split('/')[-1][:4]
with open(coord_file_path, 'r+') as coord_file:
contents = coord_file.readlines()
phase_center = False
for line_number in range(len(contents)):
if 'L1 Phase Center' in contents[line_number]:
phase_center = True
if not phase_center and 'ITRF2014 POSITION' in contents[line_number]:
velocity = [float(contents[line_number+8].split()[3]),
float(contents[line_number+9].split()[3]),
float(contents[line_number+10].split()[3])]
if phase_center and 'ITRF2014 POSITION' in contents[line_number]:
epoch = GPSTime.from_datetime(datetime(2005,1,1))
position = [float(contents[line_number+2].split()[3]),
float(contents[line_number+3].split()[3]),
float(contents[line_number+4].split()[3])]
cors_stations[station_id] = [epoch, position, velocity]
break
except ValueError:
pass
cors_station_positions_file = open(cors_station_positions_path, 'wb')
np.save(cors_station_positions_file, cors_stations)
cors_station_positions_file.close()
def get_closest_station_names(pos, k=5, max_distance=100000, cache_dir='/tmp/gnss/'):
from scipy.spatial import cKDTree
cors_station_positions_dict = load_cors_station_positions(cache_dir)
station_ids = list(cors_station_positions_dict.keys())
station_positions = []
for station_id in station_ids:
station_positions.append(cors_station_positions_dict[station_id][1])
tree = cKDTree(station_positions)
distances, idxs = tree.query(pos, k=k, distance_upper_bound=max_distance)
return np.array(station_ids)[idxs]
def load_cors_station_positions(cache_dir):
cors_station_positions_path = cache_dir + 'cors_coord/cors_station_positions'
download_and_parse_station_postions(cors_station_positions_path, cache_dir)
with open(cors_station_positions_path, 'rb') as f:
return np.load(f, allow_pickle=True).item() # pylint: disable=unexpected-keyword-arg
def get_station_position(station_id, cache_dir='/tmp/gnss/', time=GPSTime.from_datetime(datetime.utcnow())):
cors_station_positions_dict = load_cors_station_positions(cache_dir)
epoch, pos, vel = cors_station_positions_dict[station_id]
return ((time - epoch)/SECS_IN_YEAR)*np.array(vel) + np.array(pos)
def parse_dgps(station_id, station_obs_file_path, dog, max_distance=100000, required_constellations=[ConstellationId.GPS]):
station_pos = get_station_position(station_id, cache_dir=dog.cache_dir)
obsdata = RINEXFile(station_obs_file_path)
measurements = raw.read_rinex_obs(obsdata)
# if not all constellations in first 100 epochs bail
detected_constellations = set()
for m in sum(measurements[:100],[]):
detected_constellations.add(get_constellation(m.prn))
for constellation in required_constellations:
if constellation not in detected_constellations:
return None
proc_measurements = []
for measurement in measurements:
proc_measurements.append(raw.process_measurements(measurement, dog=dog))
# sample at 30s
if len(proc_measurements) > 2880:
proc_measurements = proc_measurements[::int(len(proc_measurements)/2880)]
if len(proc_measurements) != 2880:
return None
station_delays = {}
n = len(proc_measurements)
for signal in ['C1C', 'C2P']:
times = []
station_delays[signal] = {}
for i, proc_measurement in enumerate(proc_measurements):
times.append(proc_measurement[0].recv_time)
Fx_pos = opt.pr_residual(proc_measurement, signal=signal)
residual, _ = Fx_pos(list(station_pos) + [0,0])
residual = -np.array(residual)
for j, m in enumerate(proc_measurement):
prn = m.prn
if prn not in station_delays[signal]:
station_delays[signal][prn] = np.nan*np.ones(n)
station_delays[signal][prn][i] = residual[j]
assert len(times) == n
# TODO crude way to get dgps station's clock errors,
# could this be biased? Only use GPS for convenience.
model_delays = {}
for prn in station_delays['C1C']:
if get_constellation(prn) == ConstellationId.GPS:
model_delays[prn] = np.nan*np.zeros(n)
for i in range(n):
model_delays[prn][i] = dog.get_delay(prn, times[i], station_pos, no_dgps=True)
station_clock_errs = np.zeros(n)
for i in range(n):
station_clock_errs[i] = np.nanmean([(station_delays['C1C'][prn][i] - model_delays[prn][i]) for prn in model_delays])
# remove clock errors and smooth out signal
for prn in station_delays['C1C']:
station_delays['C1C'][prn] = mean_filter(station_delays['C1C'][prn] - station_clock_errs)
for prn in station_delays['C2P']:
station_delays['C2P'][prn] = station_delays['C2P'][prn] - station_clock_errs
return DGPSDelay(station_id, station_pos, station_delays,
times, max_distance)
class DGPSDelay:
def __init__(self, station_id, station_pos,
station_delays, station_delays_t, max_distance):
self.id = station_id
self.pos = station_pos
self.delays = station_delays
self.delays_t = station_delays_t
self.max_distance = max_distance
def get_delay(self, prn, time, signal='C1C'):
time_index = int((time - self.delays_t[0])/30)
assert abs(self.delays_t[time_index] - time) < 30
if prn in self.delays[signal] and np.isfinite(self.delays[signal][prn][time_index]):
return self.delays[signal][prn][time_index]
return None
def valid(self, time, recv_pos):
return (np.linalg.norm(recv_pos - self.pos) <= self.max_distance and
time - self.delays_t[0] > -30 and
self.delays_t[-1] - time > -30)

@ -1,483 +0,0 @@
import certifi
import ftplib
import hatanaka
import os
import urllib.request
import urllib.error
import pycurl
import re
import time
import socket
import logging
from datetime import datetime, timedelta
from urllib.parse import urlparse
from io import BytesIO
from ftplib import FTP_TLS
from atomicwrites import atomic_write
from laika.ephemeris import EphemerisType
from .constants import SECS_IN_HR, SECS_IN_DAY, SECS_IN_WEEK
from .gps_time import GPSTime, tow_to_datetime
from .helpers import ConstellationId
dir_path = os.path.dirname(os.path.realpath(__file__))
class DownloadFailed(Exception):
pass
def retryable(f):
"""
Decorator to allow us to pass multiple URLs from which to download.
Automatically retry the request with the next URL on failure
"""
def wrapped(url_bases, *args, **kwargs):
if isinstance(url_bases, str):
# only one url passed, don't do the retry thing
return f(url_bases, *args, **kwargs)
# not a string, must be a list of url_bases
for url_base in url_bases:
try:
return f(url_base, *args, **kwargs)
except DownloadFailed as e:
logging.warning(e)
# none of them succeeded
raise DownloadFailed("Multiple URL failures attempting to pull file(s)")
return wrapped
def ftp_connect(url):
parsed = urlparse(url)
assert parsed.scheme == 'ftp'
try:
domain = parsed.netloc
ftp = ftplib.FTP(domain, timeout=10)
ftp.login()
except (OSError, ftplib.error_perm):
raise DownloadFailed("Could not connect/auth to: " + domain)
try:
ftp.cwd(parsed.path)
except ftplib.error_perm:
raise DownloadFailed("Permission failure with folder: " + url)
return ftp
@retryable
def list_dir(url):
parsed = urlparse(url)
if parsed.scheme == 'ftp':
try:
ftp = ftp_connect(url)
return ftp.nlst()
except ftplib.error_perm:
raise DownloadFailed("Permission failure listing folder: " + url)
else:
# just connect and do simple url parsing
listing = https_download_file(url)
urls = re.findall(b"<a href=\"([^\"]+)\">", listing)
# decode the urls to normal strings. If they are complicated paths, ignore them
return [name.decode("latin1") for name in urls if name and b"/" not in name[1:]]
def ftp_download_files(url_base, folder_path, cacheDir, filenames):
"""
Like download file, but more of them. Keeps a persistent FTP connection open
to be more efficient.
"""
folder_path_abs = os.path.join(cacheDir, folder_path)
ftp = ftp_connect(url_base + folder_path)
filepaths = []
for filename in filenames:
# os.path.join will be dumb if filename has a leading /
# if there is a / in the filename, then it's using a different folder
filename = filename.lstrip("/")
if "/" in filename:
continue
filepath = os.path.join(folder_path_abs, filename)
logging.debug("pulling from", url_base, "to", filepath)
if not os.path.isfile(filepath):
os.makedirs(folder_path_abs, exist_ok=True)
try:
ftp.retrbinary('RETR ' + filename, open(filepath, 'wb').write)
except (ftplib.error_perm):
raise DownloadFailed("Could not download file from: " + url_base + folder_path + filename)
except (socket.timeout):
raise DownloadFailed("Read timed out from: " + url_base + folder_path + filename)
filepaths.append(filepath)
else:
filepaths.append(filepath)
return filepaths
def http_download_files(url_base, folder_path, cacheDir, filenames):
"""
Similar to ftp_download_files, attempt to download multiple files faster than
just downloading them one-by-one.
Returns a list of filepaths instead of the raw data
"""
folder_path_abs = os.path.join(cacheDir, folder_path)
def write_function(disk_path, handle):
def do_write(data):
open(disk_path, "wb").write(data)
return do_write
fetcher = pycurl.CurlMulti()
fetcher.setopt(pycurl.M_PIPELINING, 3)
fetcher.setopt(pycurl.M_MAX_HOST_CONNECTIONS, 64)
fetcher.setopt(pycurl.M_MAX_TOTAL_CONNECTIONS, 64)
filepaths = []
for filename in filenames:
# os.path.join will be dumb if filename has a leading /
# if there is a / in the filename, then it's using a different folder
filename = filename.lstrip("/")
if "/" in filename:
continue
filepath = os.path.join(folder_path_abs, filename)
if not os.path.isfile(filepath):
logging.debug("pulling from", url_base, "to", filepath)
os.makedirs(folder_path_abs, exist_ok=True)
url_path = url_base + folder_path + filename
handle = pycurl.Curl()
handle.setopt(pycurl.URL, url_path)
handle.setopt(pycurl.CONNECTTIMEOUT, 10)
handle.setopt(pycurl.WRITEFUNCTION, write_function(filepath, handle))
fetcher.add_handle(handle)
filepaths.append(filepath)
requests_processing = len(filepaths)
timeout = 10.0 # after 10 seconds of nothing happening, restart
deadline = time.time() + timeout
while requests_processing and time.time() < deadline:
while True:
ret, cur_requests_processing = fetcher.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM:
_, success, failed = fetcher.info_read()
break
if requests_processing > cur_requests_processing:
deadline = time.time() + timeout
requests_processing = cur_requests_processing
if fetcher.select(1) < 0:
continue
# if there are downloads left to be done, repeat, and don't overwrite
_, requests_processing = fetcher.perform()
if requests_processing > 0:
logging.warning("some requests stalled, retrying them")
return http_download_files(url_base, folder_path, cacheDir, filenames)
return filepaths
def https_download_file(url):
crl = pycurl.Curl()
crl.setopt(crl.CAINFO, certifi.where())
crl.setopt(crl.URL, url)
crl.setopt(crl.FOLLOWLOCATION, True)
crl.setopt(crl.SSL_CIPHER_LIST, 'DEFAULT@SECLEVEL=1')
crl.setopt(crl.COOKIEJAR, '/tmp/cddis_cookies')
crl.setopt(pycurl.CONNECTTIMEOUT, 10)
buf = BytesIO()
crl.setopt(crl.WRITEDATA, buf)
crl.perform()
response = crl.getinfo(pycurl.RESPONSE_CODE)
crl.close()
if response != 200:
raise DownloadFailed('HTTPS error ' + str(response))
return buf.getvalue()
def ftp_download_file(url):
try:
urlf = urllib.request.urlopen(url, timeout=10)
data_zipped = urlf.read()
urlf.close()
return data_zipped
except urllib.error.URLError as e:
raise DownloadFailed(e)
def ftps_download_file(url):
parsed = urlparse(url)
try:
buf = BytesIO()
with FTP_TLS(parsed.hostname) as ftps:
ftps.login(user='anonymous')
ftps.prot_p()
ftps.retrbinary('RETR ' + parsed.path, buf.write)
return buf.getvalue()
except ftplib.all_errors as e:
raise DownloadFailed(e)
@retryable
def download_files(url_base, folder_path, cacheDir, filenames):
parsed = urlparse(url_base)
if parsed.scheme == 'ftp':
return ftp_download_files(url_base, folder_path, cacheDir, filenames)
else:
return http_download_files(url_base, folder_path, cacheDir, filenames)
@retryable
def download_file(url_base, folder_path, filename_zipped):
url = url_base + folder_path + filename_zipped
logging.debug('Downloading ' + url)
if url.startswith('https://'):
return https_download_file(url)
elif url.startswith('ftp://'):
return ftp_download_file(url)
elif url.startswith('sftp://'):
return ftps_download_file(url)
raise NotImplementedError('Did not find supported url scheme')
def download_and_cache_file_return_first_success(url_bases, folder_and_file_names, cache_dir, compression='', overwrite=False, raise_error=False):
last_error = None
for folder_path, filename in folder_and_file_names:
try:
file = download_and_cache_file(url_bases, folder_path, cache_dir, filename, compression, overwrite)
return file
except DownloadFailed as e:
last_error = e
if last_error and raise_error:
raise last_error
def download_and_cache_file(url_base, folder_path: str, cache_dir: str, filename: str, compression='', overwrite=False):
filename_zipped = filename + compression
folder_path_abs = os.path.join(cache_dir, folder_path)
filepath = str(hatanaka.get_decompressed_path(os.path.join(folder_path_abs, filename)))
filepath_attempt = filepath + '.attempt_time'
if os.path.exists(filepath_attempt):
with open(filepath_attempt, 'r') as rf:
last_attempt_time = float(rf.read())
if time.time() - last_attempt_time < SECS_IN_HR:
raise DownloadFailed(f"Too soon to try downloading {folder_path + filename_zipped} from {url_base} again since last attempt")
if not os.path.isfile(filepath) or overwrite:
try:
data_zipped = download_file(url_base, folder_path, filename_zipped)
except (DownloadFailed, pycurl.error, socket.timeout):
unix_time = time.time()
os.makedirs(folder_path_abs, exist_ok=True)
with atomic_write(filepath_attempt, mode='w', overwrite=True) as wf:
wf.write(str(unix_time))
raise DownloadFailed(f"Could not download {folder_path + filename_zipped} from {url_base} ")
os.makedirs(folder_path_abs, exist_ok=True)
ephem_bytes = hatanaka.decompress(data_zipped)
try:
with atomic_write(filepath, mode='wb', overwrite=overwrite) as f:
f.write(ephem_bytes)
except FileExistsError:
# Only happens when same file is downloaded in parallel by another process.
pass
return filepath
# Currently, only GPS and Glonass are supported for daily and hourly data.
CONSTELLATION_NASA_CHAR = {ConstellationId.GPS: 'n', ConstellationId.GLONASS: 'g'}
def download_nav(time: GPSTime, cache_dir, constellation: ConstellationId):
t = time.as_datetime()
try:
if constellation not in CONSTELLATION_NASA_CHAR:
return None
c = CONSTELLATION_NASA_CHAR[constellation]
if GPSTime.from_datetime(datetime.utcnow()) - time > SECS_IN_DAY:
url_bases = (
'https://github.com/commaai/gnss-data/raw/master/gnss/data/daily/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/data/daily/',
)
filename = t.strftime(f"brdc%j0.%y{c}")
folder_path = t.strftime(f'%Y/%j/%y{c}/')
compression = '.gz' if folder_path >= '2020/335/' else '.Z'
return download_and_cache_file(url_bases, folder_path, cache_dir+'daily_nav/', filename, compression)
else:
url_bases = (
'https://github.com/commaai/gnss-data-hourly/raw/master/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/data/hourly/',
)
times = [t, (t - timedelta(hours=1))]
folder_and_filenames = [(t.strftime('%Y/%j/'), t.strftime(f"hour%j0.%y{c}")) for t in times]
compression = '.gz' if folder_and_filenames[0][0] >= '2020/336/' else '.Z'
# always overwrite as this file is appended
return download_and_cache_file_return_first_success(url_bases,
folder_and_filenames, cache_dir+'hourly_nav/', compression, overwrite=True)
except DownloadFailed:
pass
def download_orbits_gps_cod0(time, cache_dir, ephem_types):
url_bases = (
'https://github.com/commaai/gnss-data/raw/master/gnss/products/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/products/',
)
if EphemerisType.ULTRA_RAPID_ORBIT not in ephem_types:
# TODO: raise error here
return None
tm = tow_to_datetime(time.tow, time.week).timetuple()
doy = str(tm.tm_yday).zfill(3)
filename = f"COD0OPSULT_{tm.tm_year}{doy}0000_02D_05M_ORB.SP3"
# TODO: add hour management
folder_path = "%i/" % time.week
folder_file_names = [(folder_path, filename)]
return download_and_cache_file_return_first_success(url_bases, folder_file_names, cache_dir+'cddis_products/', compression='.gz')
def download_orbits_gps(time, cache_dir, ephem_types):
url_bases = (
'https://github.com/commaai/gnss-data/raw/master/gnss/products/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/products/',
'ftp://igs.ign.fr/pub/igs/products/',
)
folder_path = "%i/" % time.week
filenames = []
time_str = "%i%i" % (time.week, time.day)
# Download filenames in order of quality. Final -> Rapid -> Ultra-Rapid(newest first)
if EphemerisType.FINAL_ORBIT in ephem_types and GPSTime.from_datetime(datetime.utcnow()) - time > 3 * SECS_IN_WEEK:
filenames.append(f"igs{time_str}.sp3")
if EphemerisType.RAPID_ORBIT in ephem_types:
filenames.append(f"igr{time_str}.sp3")
if EphemerisType.ULTRA_RAPID_ORBIT in ephem_types:
filenames.extend([f"igu{time_str}_18.sp3",
f"igu{time_str}_12.sp3",
f"igu{time_str}_06.sp3",
f"igu{time_str}_00.sp3"])
folder_file_names = [(folder_path, filename) for filename in filenames]
ret = download_and_cache_file_return_first_success(url_bases, folder_file_names, cache_dir+'cddis_products/', compression='.Z')
if ret is not None:
return ret
# fallback to COD0 Ultra Rapid Orbits
return download_orbits_gps_cod0(time, cache_dir, ephem_types)
def download_prediction_orbits_russia_src(gps_time, cache_dir):
# Download single file that contains Ultra_Rapid predictions for GPS, GLONASS and other constellations
t = gps_time.as_datetime()
# Files exist starting at 29-01-2022
if t < datetime(2022, 1, 29):
return None
url_bases = 'https://github.com/commaai/gnss-data-alt/raw/master/MCC/PRODUCTS/'
folder_path = t.strftime('%y%j/ultra/')
file_prefix = "Stark_1D_" + t.strftime('%y%m%d')
# Predictions are 24H so previous day can also be used.
prev_day = (t - timedelta(days=1))
file_prefix_prev = "Stark_1D_" + prev_day.strftime('%y%m%d')
folder_path_prev = prev_day.strftime('%y%j/ultra/')
current_day = GPSTime.from_datetime(datetime(t.year, t.month, t.day))
# Ultra-Orbit is published in gnss-data-alt every 10th minute past the 5,11,17,23 hour.
# Predictions published are delayed by around 10 hours.
# Download latest file that includes gps_time with 20 minutes margin.:
if gps_time > current_day + 23.5 * SECS_IN_HR:
prev_day, current_day = [], [6, 12]
elif gps_time > current_day + 17.5 * SECS_IN_HR:
prev_day, current_day = [], [0, 6]
elif gps_time > current_day + 11.5 * SECS_IN_HR:
prev_day, current_day = [18], [0]
elif gps_time > current_day + 5.5 * SECS_IN_HR:
prev_day, current_day = [12, 18], []
else:
prev_day, current_day = [6, 12], []
# Example: Stark_1D_22060100.sp3
folder_and_file_names = [(folder_path, file_prefix + f"{h:02}.sp3") for h in reversed(current_day)] + \
[(folder_path_prev, file_prefix_prev + f"{h:02}.sp3") for h in reversed(prev_day)]
return download_and_cache_file_return_first_success(url_bases, folder_and_file_names, cache_dir+'russian_products/', raise_error=True)
def download_orbits_russia_src(time, cache_dir, ephem_types):
# Orbits from russian source. Contains GPS, GLONASS, GALILEO, BEIDOU
url_bases = (
'https://github.com/commaai/gnss-data-alt/raw/master/MCC/PRODUCTS/',
'ftp://ftp.glonass-iac.ru/MCC/PRODUCTS/',
)
t = time.as_datetime()
folder_paths = []
current_gps_time = GPSTime.from_datetime(datetime.utcnow())
filename = "Sta%i%i.sp3" % (time.week, time.day)
if EphemerisType.FINAL_ORBIT in ephem_types and current_gps_time - time > 2 * SECS_IN_WEEK:
folder_paths.append(t.strftime('%y%j/final/'))
if EphemerisType.RAPID_ORBIT in ephem_types:
folder_paths.append(t.strftime('%y%j/rapid/'))
if EphemerisType.ULTRA_RAPID_ORBIT in ephem_types:
folder_paths.append(t.strftime('%y%j/ultra/'))
folder_file_names = [(folder_path, filename) for folder_path in folder_paths]
return download_and_cache_file_return_first_success(url_bases, folder_file_names, cache_dir+'russian_products/')
def download_ionex(time, cache_dir):
t = time.as_datetime()
url_bases = (
'https://github.com/commaai/gnss-data/raw/master/gnss/products/ionex/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/products/ionex/',
'ftp://igs.ensg.ign.fr/pub/igs/products/ionosphere/',
'ftp://gssc.esa.int/gnss/products/ionex/',
)
folder_path = t.strftime('%Y/%j/')
filenames = [t.strftime("codg%j0.%yi"), t.strftime("c1pg%j0.%yi"), t.strftime("c2pg%j0.%yi")]
folder_file_names = [(folder_path, f) for f in filenames]
return download_and_cache_file_return_first_success(url_bases, folder_file_names, cache_dir+'ionex/', compression='.Z', raise_error=True)
def download_dcb(time, cache_dir):
filenames = []
folder_paths = []
url_bases = (
'https://github.com/commaai/gnss-data/raw/master/gnss/products/bias/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/products/bias/',
'ftp://igs.ign.fr/pub/igs/products/mgex/dcb/',
)
# seem to be a lot of data missing, so try many days
for time_step in [time - i * SECS_IN_DAY for i in range(14)]:
t = time_step.as_datetime()
folder_paths.append(t.strftime('%Y/'))
filenames.append(t.strftime("CAS0MGXRAP_%Y%j0000_01D_01D_DCB.BSX"))
return download_and_cache_file_return_first_success(url_bases, list(zip(folder_paths, filenames)), cache_dir+'dcb/', compression='.gz', raise_error=True)
def download_cors_coords(cache_dir):
cache_subdir = cache_dir + 'cors_coord/'
url_bases = (
'https://geodesy.noaa.gov/corsdata/coord/coord_14/',
'https://alt.ngs.noaa.gov/corsdata/coord/coord_14/',
)
file_names = list_dir(url_bases)
file_names = [file_name for file_name in file_names if file_name.endswith('coord.txt')]
filepaths = download_files(url_bases, '', cache_subdir, file_names)
return filepaths
def download_cors_station(time, station_name, cache_dir):
t = time.as_datetime()
folder_path = t.strftime('%Y/%j/') + station_name + '/'
filename = station_name + t.strftime("%j0.%yd")
url_bases = (
'https://geodesy.noaa.gov/corsdata/rinex/',
'https://alt.ngs.noaa.gov/corsdata/rinex/',
)
try:
filepath = download_and_cache_file(url_bases, folder_path, cache_dir+'cors_obs/', filename, compression='.gz')
return filepath
except DownloadFailed:
logging.warning("File not downloaded, check availability on server.")
return None

@ -1,106 +0,0 @@
@0xb3ca6d2462778bb1;
struct Ephemeris {
# This is according to the rinex (2?) format
svId @0 :UInt16;
year @1 :UInt16;
month @2 :UInt16;
day @3 :UInt16;
hour @4 :UInt16;
minute @5 :UInt16;
second @6 :Float32;
af0 @7 :Float64;
af1 @8 :Float64;
af2 @9 :Float64;
iode @10 :Float64;
crs @11 :Float64;
deltaN @12 :Float64;
m0 @13 :Float64;
cuc @14 :Float64;
ecc @15 :Float64;
cus @16 :Float64;
a @17 :Float64; # note that this is not the root!!
toe @18 :Float64;
cic @19 :Float64;
omega0 @20 :Float64;
cis @21 :Float64;
i0 @22 :Float64;
crc @23 :Float64;
omega @24 :Float64;
omegaDot @25 :Float64;
iDot @26 :Float64;
codesL2 @27 :Float64;
gpsWeekDEPRECATED @28 :Float64;
l2 @29 :Float64;
svAcc @30 :Float64;
svHealth @31 :Float64;
tgd @32 :Float64;
iodc @33 :Float64;
transmissionTime @34 :Float64;
fitInterval @35 :Float64;
toc @36 :Float64;
ionoCoeffsValid @37 :Bool;
ionoAlpha @38 :List(Float64);
ionoBeta @39 :List(Float64);
towCount @40 :UInt32;
toeWeek @41 :UInt16;
tocWeek @42 :UInt16;
}
struct GlonassEphemeris {
svId @0 :UInt16;
year @1 :UInt16;
dayInYear @2 :UInt16;
hour @3 :UInt16;
minute @4 :UInt16;
second @5 :Float32;
x @6 :Float64;
xVel @7 :Float64;
xAccel @8 :Float64;
y @9 :Float64;
yVel @10 :Float64;
yAccel @11 :Float64;
z @12 :Float64;
zVel @13 :Float64;
zAccel @14 :Float64;
svType @15 :UInt8;
svURA @16 :Float32;
age @17 :UInt8;
svHealth @18 :UInt8;
tkDEPRECATED @19 :UInt16;
tb @20 :UInt16;
tauN @21 :Float64;
deltaTauN @22 :Float64;
gammaN @23 :Float64;
p1 @24 :UInt8;
p2 @25 :UInt8;
p3 @26 :UInt8;
p4 @27 :UInt8;
freqNumDEPRECATED @28 :UInt32;
n4 @29 :UInt8;
nt @30 :UInt16;
freqNum @31 :Int16;
tkSeconds @32 :UInt32;
}
struct EphemerisCache {
gpsEphemerides @0 :List(Ephemeris);
glonassEphemerides @1 :List(GlonassEphemeris);
}

@ -1,498 +0,0 @@
import warnings
from abc import ABC, abstractmethod
from collections import defaultdict
from enum import IntEnum
from typing import Dict, List, Optional
import numpy as np
import numpy.polynomial.polynomial as poly
from datetime import datetime
from math import sin, cos, sqrt, fabs, atan2
from .gps_time import GPSTime, utc_to_gpst
from .constants import SPEED_OF_LIGHT, SECS_IN_MIN, SECS_IN_HR, SECS_IN_DAY, \
EARTH_ROTATION_RATE, EARTH_GM
from .helpers import get_constellation, get_prn_from_nmea_id
import capnp
import os
capnp.remove_import_hook()
capnp_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "ephemeris.capnp"))
ephemeris_structs = capnp.load(capnp_path)
def read4(f, rinex_ver):
line = f.readline()[:-1]
if rinex_ver == 2:
line = ' ' + line # Shift 1 char to the right
line = line.replace('D', 'E') # Handle bizarro float format
return float(line[4:23]), float(line[23:42]), float(line[42:61]), float(line[61:80])
class EphemerisType(IntEnum):
# Matches the enum in log.capnp
NAV = 0
FINAL_ORBIT = 1
RAPID_ORBIT = 2
ULTRA_RAPID_ORBIT = 3
QCOM_POLY = 4
@staticmethod
def all_orbits():
return EphemerisType.FINAL_ORBIT, EphemerisType.RAPID_ORBIT, EphemerisType.ULTRA_RAPID_ORBIT
@classmethod
def from_file_name(cls, file_name: str):
if "/final" in file_name or "/igs" in file_name:
return EphemerisType.FINAL_ORBIT
if "/rapid" in file_name or "/igr" in file_name:
return EphemerisType.RAPID_ORBIT
if "/ultra" in file_name or "/igu" in file_name or "COD0OPSULT" in file_name:
return EphemerisType.ULTRA_RAPID_ORBIT
raise RuntimeError(f"Ephemeris type not found in filename: {file_name}")
class Ephemeris(ABC):
def __init__(self, prn: str, epoch: GPSTime, eph_type: EphemerisType, healthy: bool, max_time_diff: float,
file_epoch: Optional[GPSTime] = None, file_name=None):
self.prn = prn
self.epoch = epoch
self.eph_type = eph_type
self.healthy = healthy
self.max_time_diff = max_time_diff
self.file_epoch = file_epoch
self.file_name = file_name
self.file_source = '' if file_name is None else file_name.split('/')[-1][:3] # File source for the ephemeris (e.g. igu, igr, Sta)
def valid(self, time):
return abs(time - self.epoch) <= self.max_time_diff
def __repr__(self):
time = self.epoch.as_datetime().strftime('%Y-%m-%dT%H:%M:%S.%f')
return f"<{self.__class__.__name__} from {self.prn} at {time}>"
def get_sat_info(self, time: GPSTime):
"""
Returns: (pos, vel, clock_err, clock_rate_err, ephemeris)
"""
if not self.healthy:
return None
return list(self._get_sat_info(time)) + [self]
@abstractmethod
def _get_sat_info(self, time):
pass
class GLONASSEphemeris(Ephemeris):
def __init__(self, data, file_name=None):
self.epoch = GPSTime.from_glonass(data.n4, data.nt, data.tb*15*SECS_IN_MIN)
super().__init__('R%02i' % data.svId, self.epoch, EphemerisType.NAV, data.svHealth==0, max_time_diff=25*SECS_IN_MIN, file_name=file_name)
self.data = data
self.epoch = GPSTime.from_glonass(data.n4, data.nt, data.tb*15 * SECS_IN_MIN)
self.channel = data.freqNum
def _get_sat_info(self, time: GPSTime):
# see the russian doc for this:
# http://gauss.gge.unb.ca/GLONASS.ICD.pdf
eph = self.data
tdiff = time - self.epoch
# Clock correction (except for general relativity which is applied later)
clock_err = -eph.tauN + tdiff * eph.gammaN
clock_rate_err = eph.gammaN
def glonass_diff_eq(state, acc):
J2 = 1.0826257e-3
mu = 3.9860044e14
omega = 7.292115e-5
ae = 6378136.0
r = np.sqrt(state[0]**2 + state[1]**2 + state[2]**2)
ders = np.zeros(6)
if r**2 < 0:
return ders
a = 1.5 * J2 * mu * (ae**2)/ (r**5)
b = 5 * (state[2]**2) / (r**2)
c = -mu/(r**3) - a*(1-b)
ders[0:3] = state[3:6]
ders[3] = (c + omega**2)*state[0] + 2*omega*state[4] + acc[0]
ders[4] = (c + omega**2)*state[1] - 2*omega*state[3] + acc[1]
ders[5] = (c - 2*a)*state[2] + acc[2]
return ders
init_state = np.empty(6)
init_state[0] = eph.x
init_state[1] = eph.y
init_state[2] = eph.z
init_state[3] = eph.xVel
init_state[4] = eph.yVel
init_state[5] = eph.zVel
init_state = 1000*init_state
acc = 1000*np.array([eph.xAccel, eph.yAccel, eph.zAccel])
state = init_state
tstep = 90
if tdiff < 0:
tt = -tstep
elif tdiff > 0:
tt = tstep
while abs(tdiff) > 1e-9:
if abs(tdiff) < tstep:
tt = tdiff
k1 = glonass_diff_eq(state, acc)
k2 = glonass_diff_eq(state + k1*tt/2, -acc)
k3 = glonass_diff_eq(state + k2*tt/2, -acc)
k4 = glonass_diff_eq(state + k3*tt, -acc)
state += (k1 + 2*k2 + 2*k3 + k4)*tt/6.0
tdiff -= tt
pos = state[0:3]
vel = state[3:6]
return pos, vel, clock_err, clock_rate_err
class PolyEphemeris(Ephemeris):
def __init__(self, prn: str, data, epoch: GPSTime, ephem_type: EphemerisType,
file_epoch: Optional[GPSTime] = None, file_name: Optional[str] = None, healthy=True, tgd=0,
max_time_diff: int=SECS_IN_HR):
super().__init__(prn, epoch, ephem_type, healthy, max_time_diff=max_time_diff, file_epoch=file_epoch, file_name=file_name)
self.data = data
self.tgd = tgd
def _get_sat_info(self, time: GPSTime):
dt = time - self.data['t0']
deg = self.data['deg']
deg_t = self.data['deg_t']
indices = np.arange(deg+1)[:,np.newaxis]
sat_pos = np.sum((dt**indices)*self.data['xyz'], axis=0)
indices = indices[1:]
sat_vel = np.sum(indices*(dt**(indices-1)*self.data['xyz'][1:]), axis=0)
time_err = sum((dt**p)*self.data['clock'][deg_t-p] for p in range(deg_t+1))
time_err_rate = sum(p*(dt**(p-1))*self.data['clock'][deg_t-p] for p in range(1,deg_t+1))
time_err_with_rel = time_err - 2*np.inner(sat_pos, sat_vel)/SPEED_OF_LIGHT**2
return sat_pos, sat_vel, time_err_with_rel, time_err_rate
class GPSEphemeris(Ephemeris):
def __init__(self, data, file_name=None):
self.toe = GPSTime(data.toeWeek, data.toe)
self.toc = GPSTime(data.tocWeek, data.toc)
self.epoch = self.toc
super().__init__('G%02i' % data.svId, self.epoch, EphemerisType.NAV, data.svHealth==0, max_time_diff=2*SECS_IN_HR, file_name=file_name)
self.max_time_diff_tgd = SECS_IN_DAY
self.data = data
self.sqrta = np.sqrt(data.a)
def get_tgd(self):
return self.datatgd
def _get_sat_info(self, time: GPSTime):
eph = self.data
tdiff = time - self.toc # Time of clock
clock_err = eph.af0 + tdiff * (eph.af1 + tdiff * eph.af2)
clock_rate_err = eph.af1 + 2 * tdiff * eph.af2\
# Orbit propagation
tdiff = time - self.toe # Time of ephemeris (might be different from time of clock)
# Calculate position per IS-GPS-200D p 97 Table 20-IV
a = self.sqrta * self.sqrta # [m] Semi-major axis
ma_dot = sqrt(EARTH_GM / (a * a * a)) + eph.deltaN # [rad/sec] Corrected mean motion
ma = eph.m0 + ma_dot * tdiff # [rad] Corrected mean anomaly
# Iteratively solve for the Eccentric Anomaly (from Keith Alter and David Johnston)
ea = ma # Starting value for E
ea_old = 2222
while fabs(ea - ea_old) > 1.0E-14:
ea_old = ea
tempd1 = 1.0 - eph.ecc * cos(ea_old)
ea = ea + (ma - ea_old + eph.ecc * sin(ea_old)) / tempd1
ea_dot = ma_dot / tempd1
# Relativistic correction term
einstein = -4.442807633E-10 * eph.ecc * self.sqrta * sin(ea)
# Begin calc for True Anomaly and Argument of Latitude
tempd2 = sqrt(1.0 - eph.ecc * eph.ecc)
# [rad] Argument of Latitude = True Anomaly + Argument of Perigee
al = atan2(tempd2 * sin(ea), cos(ea) - eph.ecc) + eph.omega
al_dot = tempd2 * ea_dot / tempd1
# Calculate corrected argument of latitude based on position
cal = al + eph.cus * sin(2.0 * al) + eph.cuc * cos(2.0 * al)
cal_dot = al_dot * (1.0 + 2.0 * (eph.cus * cos(2.0 * al) -
eph.cuc * sin(2.0 * al)))
# Calculate corrected radius based on argument of latitude
r = a * tempd1 + eph.crc * cos(2.0 * al) + eph.crs * sin(2.0 * al)
r_dot = (a * eph.ecc * sin(ea) * ea_dot +
2.0 * al_dot * (eph.crs * cos(2.0 * al) -
eph.crc * sin(2.0 * al)))
# Calculate inclination based on argument of latitude
inc = (eph.i0 + eph.iDot * tdiff +
eph.cic * cos(2.0 * al) +
eph.cis * sin(2.0 * al))
inc_dot = (eph.iDot +
2.0 * al_dot * (eph.cis * cos(2.0 * al) -
eph.cic * sin(2.0 * al)))
# Calculate position and velocity in orbital plane
x = r * cos(cal)
y = r * sin(cal)
x_dot = r_dot * cos(cal) - y * cal_dot
y_dot = r_dot * sin(cal) + x * cal_dot
# Corrected longitude of ascending node
om_dot = eph.omegaDot - EARTH_ROTATION_RATE
om = eph.omega0 + tdiff * om_dot - EARTH_ROTATION_RATE * self.toe.tow
# Compute the satellite's position in Earth-Centered Earth-Fixed coordinates
pos = np.empty(3)
pos[0] = x * cos(om) - y * cos(inc) * sin(om)
pos[1] = x * sin(om) + y * cos(inc) * cos(om)
pos[2] = y * sin(inc)
tempd3 = y_dot * cos(inc) - y * sin(inc) * inc_dot
# Compute the satellite's velocity in Earth-Centered Earth-Fixed coordinates
vel = np.empty(3)
vel[0] = -om_dot * pos[1] + x_dot * cos(om) - tempd3 * sin(om)
vel[1] = om_dot * pos[0] + x_dot * sin(om) + tempd3 * cos(om)
vel[2] = y * cos(inc) * inc_dot + y_dot * sin(inc)
clock_err += einstein
return pos, vel, clock_err, clock_rate_err
def parse_sp3_orbits(file_names, supported_constellations, skip_until_epoch: Optional[GPSTime] = None) -> Dict[str, List[PolyEphemeris]]:
if skip_until_epoch is None:
skip_until_epoch = GPSTime(0, 0)
data: Dict[str, List] = {}
for file_name in file_names:
if file_name is None:
continue
with open(file_name) as f:
ephem_type = EphemerisType.from_file_name(file_name)
file_epoch = None
while True:
line = f.readline()[:-1]
if not line:
break
# epoch header
if line[0:2] == '* ':
year = int(line[3:7])
month = int(line[8:10])
day = int(line[11:13])
hour = int(line[14:16])
minute = int(line[17:19])
second = int(float(line[20:31]))
epoch = GPSTime.from_datetime(datetime(year, month, day, hour, minute, second))
if file_epoch is None:
file_epoch = epoch
# pos line
elif line[0] == 'P':
# Skipping data can reduce the time significantly when parsing the ephemeris
if epoch < skip_until_epoch:
continue
prn = line[1:4].replace(' ', '0')
# In old SP3 files vehicle ID doesn't contain constellation
# identifier. We assume that constellation is GPS when missing.
if prn[0] == '0':
prn = 'G' + prn[1:]
if get_constellation(prn) not in supported_constellations:
continue
if prn not in data:
data[prn] = []
#TODO this is a crappy way to deal with overlapping ultra rapid
if len(data[prn]) < 1 or epoch - data[prn][-1][1] > 0:
parsed = [(ephem_type, file_epoch, file_name),
epoch,
1e3 * float(line[4:18]),
1e3 * float(line[18:32]),
1e3 * float(line[32:46]),
1e-6 * float(line[46:60])]
if (np.array(parsed[2:]) != 0).all():
data[prn].append(parsed)
ephems = {}
for prn in data:
ephems[prn] = read_prn_data(data, prn)
return ephems
def read_prn_data(data, prn, deg=16, deg_t=1):
np_data_prn = np.array(data[prn], dtype=object)
# Currently, don't even bother with satellites that have unhealthy times
if len(np_data_prn) == 0 or (np_data_prn[:, 5] > .99).any():
return []
ephems = []
for i in range(len(np_data_prn) - deg):
epoch_index = i + deg // 2
epoch = np_data_prn[epoch_index][1]
measurements = np_data_prn[i:i + deg + 1, 1:5]
times = (measurements[:, 0] - epoch).astype(float)
if not (np.diff(times) != 900).any() and not (np.diff(times) != 300).any():
continue
poly_data = {}
poly_data['t0'] = epoch
with warnings.catch_warnings():
warnings.simplefilter("ignore") # Ignores: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
poly_data['xyz'] = poly.polyfit(times, measurements[:, 1:].astype(float), deg)
poly_data['clock'] = [(np_data_prn[epoch_index + 1][5] - np_data_prn[epoch_index - 1][5]) / 1800, np_data_prn[epoch_index][5]]
poly_data['deg'] = deg
poly_data['deg_t'] = deg_t
# It can happen that a mix of orbit ephemeris types are used in the polyfit.
ephem_type, file_epoch, file_name = np_data_prn[epoch_index][0]
ephems.append(PolyEphemeris(prn, poly_data, epoch, ephem_type, file_epoch, file_name, healthy=True))
return ephems
def parse_rinex_nav_msg_gps(file_name):
ephems = defaultdict(list)
got_header = False
rinex_ver = None
#ion_alpha = None
#ion_beta = None
f = open(file_name)
while True:
line = f.readline()[:-1]
if not line:
break
if not got_header:
if rinex_ver is None:
if line[60:80] != "RINEX VERSION / TYPE":
raise RuntimeError("Doesn't appear to be a RINEX file")
rinex_ver = int(float(line[0:9]))
if line[20] != "N":
raise RuntimeError("Doesn't appear to be a Navigation Message file")
#if line[60:69] == "ION ALPHA":
# line = line.replace('D', 'E') # Handle bizarro float format
# ion_alpha= [float(line[3:14]), float(line[15:26]), float(line[27:38]), float(line[39:50])]
#if line[60:68] == "ION BETA":
# line = line.replace('D', 'E') # Handle bizarro float format
# ion_beta= [float(line[3:14]), float(line[15:26]), float(line[27:38]), float(line[39:50])]
if line[60:73] == "END OF HEADER":
#ion = ion_alpha + ion_beta
got_header = True
continue
if rinex_ver == 3:
if line[0] != 'G':
continue
if rinex_ver == 3:
sv_id = int(line[1:3])
epoch = GPSTime.from_datetime(datetime.strptime(line[4:23], "%y %m %d %H %M %S"))
elif rinex_ver == 2:
sv_id = int(line[0:2])
# 2000 year is in RINEX file as 0, but Python requires two digit year: 00
epoch_str = line[3:20]
if epoch_str[0] == ' ':
epoch_str = '0' + epoch_str[1:]
epoch = GPSTime.from_datetime(datetime.strptime(epoch_str, "%y %m %d %H %M %S"))
line = ' ' + line # Shift 1 char to the right
line = line.replace('D', 'E') # Handle bizarro float format
e = {'svId': sv_id}
# TODO are TOC and TOE the same?
e['toc'] = epoch.tow
e['tocWeek'] = epoch.week
e['af0'] = float(line[23:42])
e['af1'] = float(line[42:61])
e['af2'] = float(line[61:80])
e['iode'], e['crs'], e['deltaN'], e['m0'] = read4(f, rinex_ver)
e['cuc'], e['ecc'], e['cus'], sqrta = read4(f, rinex_ver)
e['a'] = sqrta ** 2
e['toe'], e['cic'], e['omega0'], e['cis'] = read4(f, rinex_ver)
e['i0'], e['crc'], e['omega'], e['omegaDot'] = read4(f, rinex_ver)
e['iDot'], e['codesL2'], e['toeWeek'], l2_pflag = read4(f, rinex_ver)
e['svAcc'], e['svHealth'], e['tgd'], e['iodc'] = read4(f, rinex_ver)
f.readline() # Discard last row
data_struct = ephemeris_structs.Ephemeris.new_message(**e)
ephem = GPSEphemeris(data_struct, file_name=file_name)
ephems[ephem.prn].append(ephem)
f.close()
return ephems
def parse_rinex_nav_msg_glonass(file_name):
ephems = defaultdict(list)
f = open(file_name)
got_header = False
rinex_ver = None
while True:
line = f.readline()[:-1]
if not line:
break
if not got_header:
if rinex_ver is None:
if line[60:80] != "RINEX VERSION / TYPE":
raise RuntimeError("Doesn't appear to be a RINEX file")
rinex_ver = int(float(line[0:9]))
if line[20] != "G":
raise RuntimeError("Doesn't appear to be a Navigation Message file")
if line[60:73] == "END OF HEADER":
got_header = True
continue
if rinex_ver == 3:
sv_id = int(line[1:3])
epoch = utc_to_gpst(GPSTime.from_datetime(datetime.strptime(line[4:23], "%y %m %d %H %M %S")))
elif rinex_ver == 2:
sv_id = int(line[0:2])
epoch = utc_to_gpst(GPSTime.from_datetime(datetime.strptime(line[3:20], "%y %m %d %H %M %S")))
line = ' ' + line # Shift 1 char to the right
line = line.replace('D', 'E') # Handle bizarro float format
e = {'svId': sv_id}
e['n4'], e['nt'], toe_seconds = epoch.as_glonass()
tb = toe_seconds / (15 * SECS_IN_MIN)
e['tb'] = tb
e['tauN'] = -float(line[23:42])
e['gammaN'] = float(line[42:61])
e['tkSeconds'] = float(line[61:80])
e['x'], e['xVel'], e['xAccel'], e['svHealth'] = read4(f, rinex_ver)
e['y'], e['yVel'], e['yAccel'], e['freqNum'] = read4(f, rinex_ver)
e['z'], e['zVel'], e['zAccel'], e['age'] = read4(f, rinex_ver)
# TODO unclear why glonass sometimes has nav messages 3s after correct one
if abs(tb - int(tb)) > 1e-3:
continue
data_struct = ephemeris_structs.GlonassEphemeris.new_message(**e)
ephem = GLONASSEphemeris(data_struct, file_name=file_name)
ephems[ephem.prn].append(ephem)
f.close()
return ephems
def parse_qcom_ephem(qcom_poly):
svId = qcom_poly.svId
prn = get_prn_from_nmea_id(svId)
epoch = GPSTime(qcom_poly.gpsWeek, qcom_poly.gpsTow)
data = qcom_poly
poly_data = {}
poly_data['t0'] = epoch
poly_data['xyz'] = np.array([
[data.xyz0[0], data.xyzN[0], data.xyzN[1], data.xyzN[2]],
[data.xyz0[1], data.xyzN[3], data.xyzN[4], data.xyzN[5]],
[data.xyz0[2], data.xyzN[6], data.xyzN[7], data.xyzN[8]] ]).T
poly_data['clock'] = [1e-3*data.other[3], 1e-3*data.other[2], 1e-3*data.other[1], 1e-3*data.other[0]]
poly_data['deg'] = 3
poly_data['deg_t'] = 3
return PolyEphemeris(prn, poly_data, epoch, ephem_type=EphemerisType.QCOM_POLY, max_time_diff=300, file_name='qcom')

@ -1,203 +0,0 @@
import datetime
def datetime_to_tow(t):
"""
Convert a Python datetime object to GPS Week and Time Of Week.
Does *not* convert from UTC to GPST.
Fractional seconds are supported.
Parameters
----------
t : datetime
A time to be converted, on the GPST timescale.
mod1024 : bool, optional
If True (default), the week number will be output in 10-bit form.
Returns
-------
week, tow : tuple (int, float)
The GPS week number and time-of-week.
"""
# DateTime to GPS week and TOW
wk_ref = datetime.datetime(2014, 2, 16, 0, 0, 0, 0, None)
refwk = 1780
wk = (t - wk_ref).days // 7 + refwk
tow = ((t - wk_ref) - datetime.timedelta((wk - refwk) * 7.0)).total_seconds()
return wk, tow
def tow_to_datetime(tow, week):
"""
Convert a GPS Week and Time Of Week to Python datetime object.
Does *not* convert from GPST to UTC.
Fractional seconds are supported.
Parameters
----------
tow : time of week in seconds
weeks : gps week
Returns
-------
t : datetime
Python datetime
"""
# GPS week and TOW to DateTime
t = datetime.datetime(1980, 1, 6, 0, 0, 0, 0, None)
t += datetime.timedelta(seconds=tow)
t += datetime.timedelta(weeks=week)
return t
def get_leap_seconds(time):
# TODO use library for this
if time <= GPSTime.from_datetime(datetime.datetime(2006, 1, 1)):
raise ValueError("Don't know how many leap seconds to use before 2006")
elif time <= GPSTime.from_datetime(datetime.datetime(2009, 1, 1)):
return 14
elif time <= GPSTime.from_datetime(datetime.datetime(2012, 7, 1)):
return 15
elif time <= GPSTime.from_datetime(datetime.datetime(2015, 7, 1)):
return 16
elif time <= GPSTime.from_datetime(datetime.datetime(2017, 1, 1)):
return 17
else:
return 18
def gpst_to_utc(t_gpst):
t_utc = t_gpst - get_leap_seconds(t_gpst)
if utc_to_gpst(t_utc) - t_gpst != 0:
return t_utc + 1
else:
return t_utc
def utc_to_gpst(t_utc):
t_gpst = t_utc + get_leap_seconds(t_utc)
return t_gpst
class GPSTime:
"""
GPS time class to add and subtract [week, tow]
"""
def __init__(self, week, tow):
self.week = week
self.tow = tow
self.seconds_in_week = 604800
@classmethod
def from_datetime(cls, datetime):
week, tow = datetime_to_tow(datetime)
return cls(week, tow)
@classmethod
def from_glonass(cls, cycle, days, tow):
# https://en.wikipedia.org/wiki/GLONASS
# Day number (1 to 1461) within a four-year interval
# starting on 1 January of the last leap year
t = datetime.datetime(1992, 1, 1, 0, 0, 0, 0, None)
t += datetime.timedelta(days=cycle*(365*4+1)+(days-1))
# according to Moscow decree time.
t -= datetime.timedelta(hours=3)
t += datetime.timedelta(seconds=tow)
ret = cls.from_datetime(t)
return utc_to_gpst(ret)
@classmethod
def from_meas(cls, meas):
return cls(meas[1], meas[2])
def __sub__(self, other):
if isinstance(other, type(self)):
return (self.week - other.week)*self.seconds_in_week + self.tow - other.tow
elif isinstance(other, float) or isinstance(other, int):
new_week = self.week
new_tow = self.tow - other
while new_tow < 0:
new_tow += self.seconds_in_week
new_week -= 1
return GPSTime(new_week, new_tow)
raise NotImplementedError(f"subtracting {other} from {self}")
def __add__(self, other):
if isinstance(other, float) or isinstance(other, int):
new_week = self.week
new_tow = self.tow + other
while new_tow >= self.seconds_in_week:
new_tow -= self.seconds_in_week
new_week += 1
return GPSTime(new_week, new_tow)
raise NotImplementedError(f"adding {other} from {self}")
def __lt__(self, other):
return self - other < 0
def __gt__(self, other):
return self - other > 0
def __le__(self, other):
return self - other <= 0
def __ge__(self, other):
return self - other >= 0
def __eq__(self, other):
return self - other == 0
def as_datetime(self):
return tow_to_datetime(self.tow, self.week)
def as_glonass(self):
time_utc = gpst_to_utc(self)
datetime_utc = time_utc.as_datetime()
datetime_glonass = datetime_utc + datetime.timedelta(hours=3)
year = datetime_glonass.year
cycle = (year - 1992) // 4
days = (datetime_glonass - datetime.datetime(1992 + cycle*4, 1, 1)).days + 1
tod = (datetime_glonass - datetime_glonass.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds()
return cycle, days, tod
def as_unix_timestamp(self):
return (gpst_to_utc(self).as_datetime() - datetime.datetime(1970, 1, 1)).total_seconds()
@property
def day(self):
return int(self.tow/(24*3600))
def __repr__(self):
return f"GPSTime(week={self.week}, tow={self.tow})"
class TimeSyncer:
"""
Converts logmonotime to gps_time and vice versa
"""
def __init__(self, mono_time, gps_time):
self.ref_mono_time = mono_time
self.ref_gps_time = gps_time
@classmethod
def from_datetime(cls, datetime):
week, tow = datetime_to_tow(datetime)
return cls(week, tow)
@classmethod
def from_logs(cls, raw_qcom_measurement_report, clocks):
#TODO
#return cls(week, mono_time, gps_time)
return None
def mono2gps(self, mono_time):
return self.ref_gps_time + mono_time - self.ref_mono_time
def gps2mono(self, gps_time):
return gps_time - self.ref_gps_time + self.ref_mono_time
def __str__(self):
return f"Reference mono time: {self.ref_mono_time} \n Reference gps time: {self.ref_gps_time}"

@ -1,221 +0,0 @@
from enum import IntEnum
from typing import Dict
import numpy as np
from .lib.coordinates import LocalCoord
class ConstellationId(IntEnum):
# Int values match Ublox gnssid version 8
GPS = 0
SBAS = 1
GALILEO = 2
BEIDOU = 3
IMES = 4
QZNSS = 5
GLONASS = 6
# Not supported by Ublox:
IRNSS = 7
def to_rinex_char(self) -> str:
# returns single character id
return RINEX_CONSTELLATION_TO_ID[self]
@classmethod
def from_rinex_char(cls, c: str):
if c in RINEX_ID_TO_CONSTELLATION:
return RINEX_ID_TO_CONSTELLATION[c]
else:
raise ValueError("Unknown rinex constellation id: ", c)
@classmethod
def from_qcom_source(cls, report_source: int):
if report_source == 0:
return ConstellationId.GPS
if report_source == 1:
return ConstellationId.GLONASS
if report_source == 2:
return ConstellationId.BEIDOU
if report_source == 6:
return ConstellationId.SBAS
raise NotImplementedError('Only GPS (0), GLONASS (1), BEIDOU (2) and SBAS (6) are supported from qcom, not:', {report_source})
# From https://gpsd.gitlab.io/gpsd/NMEA.html#_satellite_ids
# NmeaId is the unique 3 digits id for every satellite globally. (Example: 001, 201)
# SvId is the 2 digits satellite id that is unique within a constellation. (Get the unique satellite with the constellation id. Examples: G01, R01)
CONSTELLATION_TO_NMEA_RANGES = {
# NmeaId ranges for each constellation with its svId offset.
# constellation: [(start, end, svIdOffset)]
# svId = nmeaId + offset
ConstellationId.GPS: [(1, 32, 0)], # svId [1,32]
ConstellationId.SBAS: [(33, 64, -32), (120, 158, -87)], # svId [1,71]
ConstellationId.GLONASS: [(65, 96, -64)], # svId [1,31]
ConstellationId.IMES: [(173, 182, -172)], # svId [1,9]
ConstellationId.QZNSS: [(193, 200, -192)], # svId [1,28] # todo should be QZSS
ConstellationId.BEIDOU: [(201, 235, -200), (401, 437, -365)], # svId 1-72
ConstellationId.GALILEO: [(301, 336, -300)] # svId 1-36
}
#
# # Source: RINEX 3.04
RINEX_CONSTELLATION_TO_ID: Dict[ConstellationId, str] = {
ConstellationId.GPS: 'G',
ConstellationId.GLONASS: 'R',
ConstellationId.SBAS: 'S',
ConstellationId.GALILEO: 'E',
ConstellationId.BEIDOU: 'C',
ConstellationId.QZNSS: 'J',
ConstellationId.IRNSS: 'I'
}
# Make above dictionary bidirectional map:
# Now you can ask for constellation using:
# >>> RINEX_CONSTELLATION_IDENTIFIERS['R']
# "GLONASS"
RINEX_ID_TO_CONSTELLATION: Dict[str, ConstellationId] = {id: con for con, id in RINEX_CONSTELLATION_TO_ID.items()}
def get_el_az(pos, sat_pos):
converter = LocalCoord.from_ecef(pos)
sat_ned = converter.ecef2ned(sat_pos)
sat_range = np.linalg.norm(sat_ned)
el = np.arcsin(-sat_ned[2] / sat_range) # pylint: disable=unsubscriptable-object
az = np.arctan2(sat_ned[1], sat_ned[0]) # pylint: disable=unsubscriptable-object
return el, az
def get_closest(time, candidates, recv_pos=None):
if recv_pos is None:
# Takes a list of object that have an epoch(GPSTime) value
# and return the one that is closest the given time (GPSTime)
return min(candidates, key=lambda candidate: abs(time - candidate.epoch), default=None)
return min(
(candidate for candidate in candidates if candidate.valid(time, recv_pos)),
key=lambda candidate: np.linalg.norm(recv_pos - candidate.pos),
default=None,
)
def get_constellation(prn: str):
identifier = prn[0]
return ConstellationId.from_rinex_char(identifier)
def get_sv_id(prn: str):
return int(prn[1:])
def get_constellation_and_sv_id(nmea_id):
for c, ranges in CONSTELLATION_TO_NMEA_RANGES.items():
for (start, end, sv_id_offset) in ranges:
if start <= nmea_id <= end:
sv_id = nmea_id + sv_id_offset
return c, sv_id
raise ValueError(f"constellation not found for nmeaid {nmea_id}")
def get_prn_from_nmea_id(nmea_id: int):
c_id, sv_id = get_constellation_and_sv_id(nmea_id)
return "%s%02d" % (c_id.to_rinex_char(), sv_id)
def get_nmea_id_from_prn(prn: str):
constellation = get_constellation(prn)
sv_id = int(prn[1:]) # satellite id
return get_nmea_id_from_constellation_and_svid(constellation, sv_id)
def get_nmea_id_from_constellation_and_svid(constellation: ConstellationId, sv_id: int):
ranges = CONSTELLATION_TO_NMEA_RANGES[constellation]
for (start, end, sv_id_offset) in ranges:
new_nmea_id = sv_id - sv_id_offset
if start <= new_nmea_id <= end:
return new_nmea_id
raise ValueError(f"NMEA ID not found for constellation {constellation.name} with satellite id {sv_id}")
def rinex3_obs_from_rinex2_obs(observable):
if observable == 'P2':
return 'C2P'
if len(observable) == 2:
return observable + 'C'
raise NotImplementedError("Don't know this: " + observable)
class TimeRangeHolder:
'''Class to support test if date is in any of the multiple, sparse ranges'''
def __init__(self):
# Sorted list
self._ranges = []
def _previous_and_contains_index(self, time):
prev = None
current = None
for idx, (start, end) in enumerate(self._ranges):
# Time may be in next range
if time > end:
continue
# Time isn't in any next range
if time < start:
prev = idx - 1
current = None
# Time is in current range
else:
prev = idx - 1
current = idx
break
# Break in last loop
if prev is None:
prev = len(self._ranges) - 1
return prev, current
def add(self, start_time, end_time):
prev_start, current_start = self._previous_and_contains_index(start_time)
_, current_end = self._previous_and_contains_index(end_time)
# Merge ranges
if current_start is not None and current_end is not None:
# If ranges are different then merge
if current_start != current_end:
new_start, _ = self._ranges[current_start]
_, new_end = self._ranges[current_end]
new_range = (new_start, new_end)
# Required reversed order to correct remove
del self._ranges[current_end]
del self._ranges[current_start]
self._ranges.insert(current_start, new_range)
# Extend range - left
elif current_start is not None:
new_start, _ = self._ranges[current_start]
new_range = (new_start, end_time)
del self._ranges[current_start]
self._ranges.insert(current_start, new_range)
# Extend range - right
elif current_end is not None:
_, new_end = self._ranges[current_end]
new_range = (start_time, new_end)
del self._ranges[current_end]
self._ranges.insert(prev_start + 1, new_range)
# Create new range
else:
new_range = (start_time, end_time)
self._ranges.insert(prev_start + 1, new_range)
def __contains__(self, time):
for start, end in self._ranges:
# Time may be in next range
if time > end:
continue
# Time isn't in any next range
if time < start:
return False
# Time is in current range
return True
return False

@ -1,255 +0,0 @@
import datetime as dt
import numpy as np
import re
from math import cos, sin, pi, floor
from .constants import SECS_IN_MIN, SECS_IN_HR, EARTH_RADIUS
from .lib.coordinates import LocalCoord
from .gps_time import GPSTime
# Altitude of Ionospheric-pierce-point
IPP_ALT = 6821000
def get_alpha_beta(rcv_pos, el):
geocentric_alt = np.linalg.norm(rcv_pos)
alpha = np.pi/2 + el
beta = np.arcsin(geocentric_alt*np.sin(alpha)/IPP_ALT)
return alpha, beta
def get_slant_delay(rcv_pos, az, el, sat_pos, time, freq, vertical_delay):
alpha, beta = get_alpha_beta(rcv_pos, el)
slant_delay = vertical_delay * ((1 - ((EARTH_RADIUS * np.sin(beta)) /
(EARTH_RADIUS + 3.5e5))**2)**(-0.5))
return slant_delay
def closest_in_list(lst, val, num=2):
"""
Returns two (`num` in general) closest values of `val` in list `lst`
"""
idxs = sorted(lst, key=lambda x: abs(x - val))[:num]
return sorted(list(lst).index(x) for x in idxs)
def get_header_line(headr, proprty):
"""
:param headr: the header of the RINEX-file
:param proprty: string-like property to search for (e.g. 'delta-utc')
:return: the string of the ``headr`` containing ``property``
"""
pattern = re.compile(proprty, re.IGNORECASE)
for d in headr:
if pattern.search(d):
return d
def get_header_body(file_path):
"""
Opens `file_path`, reads file and returns header and body
separated with "END OF HEADER"
:param file_path: path to RINEX-like file
:return: header, body (arrays of lines)
"""
with open(file_path) as fd:
data = fd.readlines()
for j, d in enumerate(data):
if "END OF HEADER" in d:
header_end = j
break
return data[:header_end], data[header_end + 1:]
def get_int_from_header(hdr, seq):
"""
Returns the first int from the line that contains `seq` of lines `hdr`.
In fact, _header_ here may not be header of RINEX/IONEX, just some set of lines.
"""
return int(get_header_line(hdr, seq).split()[0])
def compute_grid_lats_lons(data):
grid = np.array([], dtype='uint16')
lats = np.array([])
for j, line in enumerate(data[1:]):
if "LAT" in line:
lat, lon1, lon2, dlon, h = (float(line[x:x + 6]) for x in range(2, 32, 6))
lats = np.append(lats, lat)
row_length = (lon2 - lon1) / dlon + 1 # total number of values of longitudes
next_lines_with_numbers = int(np.ceil(row_length / 16))
elems_in_row = [
min(16, int(row_length - i * 16)) for i in range(next_lines_with_numbers)
]
row = np.array([], dtype='int16')
for i, elem in enumerate(elems_in_row):
row = np.append(
row,
np.array(
[int(data[j + 2 + i][5 * x:5 * x + 5]) for x in range(elem)],
dtype='int16',
),
)
if len(grid) > 0:
grid = np.vstack((grid, row))
else:
grid = np.append(grid, row)
lons = np.linspace(lon1, lon2, int(row_length))
return (grid, lats, lons)
class IonexMap:
def __init__(self, exp, data1, data2):
self.exp = exp
self.t1 = GPSTime.from_datetime(dt.datetime(*[int(d) for d in data1[0].split()[:6]]))
self.t2 = GPSTime.from_datetime(dt.datetime(*[int(d) for d in data2[0].split()[:6]]))
assert self.t2 - self.t1 == SECS_IN_HR
assert len(data1) == len(data2)
self.max_time_diff = SECS_IN_MIN*30
self.epoch = self.t1 + self.max_time_diff
self.grid_TEC1, self.lats, self.lons = compute_grid_lats_lons(data1)
self.grid_TEC2, self.lats, self.lons = compute_grid_lats_lons(data2)
def valid(self, time):
return abs(time - self.epoch) <= self.max_time_diff
@staticmethod
def find_nearest(lst, val):
return (np.abs(lst - val)).argmin()
def get_TEC(self, pos, time):
"""
Returns TEC in a position `pos` of ionosphere
:param pos: (lat, lon) [deg, deg]
:return:
"""
if pos[0] in self.lats and pos[1] in self.lons:
lat = self.find_nearest(self.lats, pos[0])
lon = self.find_nearest(self.lons, pos[1])
E = self.grid_TEC1[lat][lon] + self.grid_TEC2[lat][lon]
return E
lat_idxs = closest_in_list(self.lats, pos[0])
lon_idxs = closest_in_list(self.lons, pos[1])
lat0, lat1 = self.lats[lat_idxs[0]], self.lats[lat_idxs[1]]
lon0, lon1 = self.lons[lon_idxs[0]], self.lons[lon_idxs[1]]
dlat = lat1 - lat0
dlon = lon1 - lon0
p = float(pos[0] - lat0) / dlat
q = float(pos[1] - lon0) / dlon
(E00, E10), (E01, E11) = self.grid_TEC1[lat_idxs[0]:lat_idxs[1] + 1, lon_idxs[0]:lon_idxs[1] + 1]
TEC_1 = ((1 - p) * (1 - q) * E00 + p * (1 - q) * E01 + (1 - p) * q * E10 + p * q * E11)
(E00, E10), (E01, E11) = self.grid_TEC2[lat_idxs[0]:lat_idxs[1] + 1, lon_idxs[0]:lon_idxs[1] + 1]
TEC_2 = ((1 - p) * (1 - q) * E00 + p * (1 - q) * E01 + (1 - p) * q * E10 + p * q * E11)
return (1 - (time - self.t1)/SECS_IN_HR)*TEC_1 + ((time - self.t1)/SECS_IN_HR)*TEC_2
def get_delay(self, rcv_pos, az, el, sat_pos, time, freq):
# To get a delay from a TEC map, we need to calculate
# the ionospheric pierce point, geometry described here
# https://en.wikipedia.org/wiki/Ionospheric_pierce_point
alpha, beta = get_alpha_beta(rcv_pos, el)
conv = LocalCoord.from_ecef(rcv_pos)
gamma = np.pi - alpha - beta
geocentric_alt = np.linalg.norm(rcv_pos)
ipp_dist = geocentric_alt*np.sin(gamma)/np.sin(beta)
ipp_ned = conv.ecef2ned(sat_pos)*(ipp_dist)/np.linalg.norm(sat_pos)
ipp_geo = conv.ned2geodetic(ipp_ned)
factor = 40.30E16 / (freq**2) * 10**(self.exp)
vertical_delay = self.get_TEC(ipp_geo, time) * factor
slant_delay = get_slant_delay(rcv_pos, az, el, sat_pos, time, freq, vertical_delay)
return slant_delay
@staticmethod
def round_to_grid(number, base):
return int(base * round(float(number) / base))
def parse_ionex(ionex_file):
"""
:param ionex_file: path to the IONEX file
:return: TEC interpolation function `f( (lat,lon), datetime )`
"""
header, body = get_header_body(ionex_file)
exponent = get_int_from_header(header, "EXPONENT")
maps_count = get_int_from_header(header, "MAPS IN FILE")
# =============
# Separate maps
# =============
map_start_idx = []
map_end_idx = []
for j, line in enumerate(body):
if "START OF TEC MAP" in line:
map_start_idx += [j]
elif "END OF TEC MAP" in line:
map_end_idx += [j]
if maps_count != len(map_start_idx):
raise LookupError("Parsing error: the number of maps in the header "
"is not equal to the number of maps in the body.")
if len(map_start_idx) != len(map_end_idx):
raise IndexError("Starts end ends numbers are not equal.")
map_dates = []
for i in range(maps_count):
date_components = body[map_start_idx[i] + 1].split()[:6]
map_dates.append(dt.datetime(*[int(d) for d in date_components]))
maps = []
iono_map = iono_map_prev = None
for m in range(maps_count):
iono_map_prev = iono_map
iono_map = body[map_start_idx[m] + 1:map_end_idx[m]]
if iono_map and iono_map_prev:
maps += [IonexMap(exponent, iono_map_prev, iono_map)]
return maps
def klobuchar(pos, az, el, time, iono_coeffs):
"""
Details are taken from [5]: IS-GPS-200H, Fig. 20-4
Note: result is referred to the GPS L₁ frequency;
if the user is operating on the GPS L₂ frequency, the correction term must
be multiplied by γ = f₂²/f₁¹ = 0.6071850227694382
:param pos: [lat, lon, alt] in radians and meters
"""
tow = time.tow
if pos[2] < -1E3 or el < 0:
return 0.0
if len(iono_coeffs) < 8:
return None
# earth centered angle (semi-circle)
psi = 0.0137 / (el / pi + 0.11) - 0.022
# subionospheric latitude/longitude (semi-circle)
phi = pos[0] / pi + psi * cos(az)
if phi > 0.416:
phi = 0.416
elif phi < -0.416:
phi = -0.416
lam = pos[1] / pi + psi * sin(az) / cos(phi * pi)
# geomagnetic latitude (semi-circle) */
phi += 0.064 * cos((lam - 1.617) * pi)
# local time (s)
tt = 43200.0 * lam + tow
tt -= floor(tt / 86400.0) * 86400.0 # 0<=tt<86400
# slant factor
f = 1.0 + 16.0 * pow(0.53 - el / pi, 3.0)
# ionospheric delay
amp = iono_coeffs[0] + phi * (iono_coeffs[1] + phi *
(iono_coeffs[2] + phi * iono_coeffs[3]))
per = iono_coeffs[4] + phi * (iono_coeffs[5] + phi *
(iono_coeffs[6] + phi * iono_coeffs[7]))
if amp < 0.0:
amp = 0.
if per < 72000.0:
per = 72000.0
x = 2.0 * pi * (tt - 50400.0) / per
mul = 5E-9
if abs(x) < 1.57:
mul = (5E-9 + amp * (1.0 + x * x * (-0.5 + x * x / 24.0)))
return 2.99792458E8 * f * mul

@ -1,106 +0,0 @@
import numpy as np
"""
Coordinate transformation module. All methods accept arrays as input
with each row as a position.
"""
a = 6378137
b = 6356752.3142
esq = 6.69437999014 * 0.001
e1sq = 6.73949674228 * 0.001
def geodetic2ecef(geodetic, radians=False):
geodetic = np.array(geodetic)
input_shape = geodetic.shape
geodetic = np.atleast_2d(geodetic)
ratio = 1.0 if radians else (np.pi / 180.0)
lat = ratio*geodetic[:,0]
lon = ratio*geodetic[:,1]
alt = geodetic[:,2]
xi = np.sqrt(1 - esq * np.sin(lat)**2)
x = (a / xi + alt) * np.cos(lat) * np.cos(lon)
y = (a / xi + alt) * np.cos(lat) * np.sin(lon)
z = (a / xi * (1 - esq) + alt) * np.sin(lat)
ecef = np.array([x, y, z]).T
return ecef.reshape(input_shape)
def ecef2geodetic(ecef, radians=False):
"""
Convert ECEF coordinates to geodetic using ferrari's method
"""
# Save shape and export column
ecef = np.atleast_1d(ecef)
input_shape = ecef.shape
ecef = np.atleast_2d(ecef)
x, y, z = ecef[:, 0], ecef[:, 1], ecef[:, 2]
ratio = 1.0 if radians else (180.0 / np.pi)
# Conver from ECEF to geodetic using Ferrari's methods
# https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#Ferrari.27s_solution
r = np.sqrt(x * x + y * y)
Esq = a * a - b * b
F = 54 * b * b * z * z
G = r * r + (1 - esq) * z * z - esq * Esq
C = (esq * esq * F * r * r) / (pow(G, 3))
S = np.cbrt(1 + C + np.sqrt(C * C + 2 * C))
P = F / (3 * pow((S + 1 / S + 1), 2) * G * G)
Q = np.sqrt(1 + 2 * esq * esq * P)
r_0 = -(P * esq * r) / (1 + Q) + np.sqrt(0.5 * a * a*(1 + 1.0 / Q) -
P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r)
U = np.sqrt(pow((r - esq * r_0), 2) + z * z)
V = np.sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z)
Z_0 = b * b * z / (a * V)
h = U * (1 - b * b / (a * V))
lat = ratio*np.arctan((z + e1sq * Z_0) / r)
lon = ratio*np.arctan2(y, x)
# stack the new columns and return to the original shape
geodetic = np.column_stack((lat, lon, h))
return geodetic.reshape(input_shape)
class LocalCoord:
"""
Allows conversions to local frames. In this case NED.
That is: North East Down from the start position in
meters.
"""
def __init__(self, init_geodetic, init_ecef):
self.init_ecef = init_ecef
lat, lon, _ = (np.pi/180)*np.array(init_geodetic)
self.ned2ecef_matrix = np.array([[-np.sin(lat)*np.cos(lon), -np.sin(lon), -np.cos(lat)*np.cos(lon)],
[-np.sin(lat)*np.sin(lon), np.cos(lon), -np.cos(lat)*np.sin(lon)],
[np.cos(lat), 0, -np.sin(lat)]])
self.ecef2ned_matrix = self.ned2ecef_matrix.T
@classmethod
def from_geodetic(cls, init_geodetic):
init_ecef = geodetic2ecef(init_geodetic)
return LocalCoord(init_geodetic, init_ecef)
@classmethod
def from_ecef(cls, init_ecef):
init_geodetic = ecef2geodetic(init_ecef)
return LocalCoord(init_geodetic, init_ecef)
def ecef2ned(self, ecef):
ecef = np.array(ecef)
return np.dot(self.ecef2ned_matrix, (ecef - self.init_ecef).T).T
def ned2ecef(self, ned):
ned = np.array(ned)
# Transpose so that init_ecef will broadcast correctly for 1d or 2d ned.
return (np.dot(self.ned2ecef_matrix, ned.T).T + self.init_ecef)
def geodetic2ned(self, geodetic):
ecef = geodetic2ecef(geodetic)
return self.ecef2ned(ecef)
def ned2geodetic(self, ned):
ecef = self.ned2ecef(ned)
return ecef2geodetic(ecef)

@ -1,291 +0,0 @@
import numpy as np
from numpy import dot, inner, array, linalg
from .coordinates import LocalCoord
'''
Vectorized functions that transform between
rotation matrices, euler angles and quaternions.
All support lists, array or array of arrays as inputs.
Supports both x2y and y_from_x format (y_from_x preferred!).
'''
def euler2quat(eulers):
eulers = array(eulers)
if len(eulers.shape) > 1:
output_shape = (-1,4)
else:
output_shape = (4,)
eulers = np.atleast_2d(eulers)
gamma, theta, psi = eulers[:,0], eulers[:,1], eulers[:,2]
cos_half_gamma = np.cos(gamma / 2)
cos_half_theta = np.cos(theta / 2)
cos_half_psi = np.cos(psi / 2)
sin_half_gamma = np.sin(gamma / 2)
sin_half_theta = np.sin(theta / 2)
sin_half_psi = np.sin(psi / 2)
q0 = cos_half_gamma * cos_half_theta * cos_half_psi + sin_half_gamma * sin_half_theta * sin_half_psi
q1 = sin_half_gamma * cos_half_theta * cos_half_psi - cos_half_gamma * sin_half_theta * sin_half_psi
q2 = cos_half_gamma * sin_half_theta * cos_half_psi + sin_half_gamma * cos_half_theta * sin_half_psi
q3 = cos_half_gamma * cos_half_theta * sin_half_psi - sin_half_gamma * sin_half_theta * cos_half_psi
quats = array([q0, q1, q2, q3]).T
for i in range(len(quats)):
if quats[i,0] < 0:
quats[i] = -quats[i]
return quats.reshape(output_shape)
def quat2euler(quats):
quats = array(quats)
if len(quats.shape) > 1:
output_shape = (-1,3)
else:
output_shape = (3,)
quats = np.atleast_2d(quats)
q0, q1, q2, q3 = quats[:,0], quats[:,1], quats[:,2], quats[:,3]
gamma = np.arctan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1**2 + q2**2))
theta = np.arcsin(2 * (q0 * q2 - q3 * q1))
psi = np.arctan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2**2 + q3**2))
eulers = array([gamma, theta, psi]).T
return eulers.reshape(output_shape)
def quat2rot(quats):
quats = array(quats)
input_shape = quats.shape
quats = np.atleast_2d(quats)
Rs = np.zeros((quats.shape[0], 3, 3))
q0 = quats[:, 0]
q1 = quats[:, 1]
q2 = quats[:, 2]
q3 = quats[:, 3]
Rs[:, 0, 0] = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3
Rs[:, 0, 1] = 2 * (q1 * q2 - q0 * q3)
Rs[:, 0, 2] = 2 * (q0 * q2 + q1 * q3)
Rs[:, 1, 0] = 2 * (q1 * q2 + q0 * q3)
Rs[:, 1, 1] = q0 * q0 - q1 * q1 + q2 * q2 - q3 * q3
Rs[:, 1, 2] = 2 * (q2 * q3 - q0 * q1)
Rs[:, 2, 0] = 2 * (q1 * q3 - q0 * q2)
Rs[:, 2, 1] = 2 * (q0 * q1 + q2 * q3)
Rs[:, 2, 2] = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3
if len(input_shape) < 2:
return Rs[0]
return Rs
def rot2quat(rots):
input_shape = rots.shape
if len(input_shape) < 3:
rots = array([rots])
K3 = np.empty((len(rots), 4, 4))
K3[:, 0, 0] = (rots[:, 0, 0] - rots[:, 1, 1] - rots[:, 2, 2]) / 3.0
K3[:, 0, 1] = (rots[:, 1, 0] + rots[:, 0, 1]) / 3.0
K3[:, 0, 2] = (rots[:, 2, 0] + rots[:, 0, 2]) / 3.0
K3[:, 0, 3] = (rots[:, 1, 2] - rots[:, 2, 1]) / 3.0
K3[:, 1, 0] = K3[:, 0, 1]
K3[:, 1, 1] = (rots[:, 1, 1] - rots[:, 0, 0] - rots[:, 2, 2]) / 3.0
K3[:, 1, 2] = (rots[:, 2, 1] + rots[:, 1, 2]) / 3.0
K3[:, 1, 3] = (rots[:, 2, 0] - rots[:, 0, 2]) / 3.0
K3[:, 2, 0] = K3[:, 0, 2]
K3[:, 2, 1] = K3[:, 1, 2]
K3[:, 2, 2] = (rots[:, 2, 2] - rots[:, 0, 0] - rots[:, 1, 1]) / 3.0
K3[:, 2, 3] = (rots[:, 0, 1] - rots[:, 1, 0]) / 3.0
K3[:, 3, 0] = K3[:, 0, 3]
K3[:, 3, 1] = K3[:, 1, 3]
K3[:, 3, 2] = K3[:, 2, 3]
K3[:, 3, 3] = (rots[:, 0, 0] + rots[:, 1, 1] + rots[:, 2, 2]) / 3.0
q = np.empty((len(rots), 4))
for i in range(len(rots)):
_, eigvecs = linalg.eigh(K3[i].T)
eigvecs = eigvecs[:,3:]
q[i, 0] = eigvecs[-1]
q[i, 1:] = -eigvecs[:-1].flatten()
if q[i, 0] < 0:
q[i] = -q[i]
if len(input_shape) < 3:
return q[0]
return q
def euler2rot(eulers):
return rotations_from_quats(euler2quat(eulers))
def rot2euler(rots):
return quat2euler(quats_from_rotations(rots))
quats_from_rotations = rot2quat
quat_from_rot = rot2quat
rotations_from_quats = quat2rot
rot_from_quat= quat2rot
rot_from_quat= quat2rot
euler_from_rot = rot2euler
euler_from_quat = quat2euler
rot_from_euler = euler2rot
quat_from_euler = euler2quat
'''
Random helpers below
'''
def quat_product(q, r):
t = np.zeros(4)
t[0] = r[0] * q[0] - r[1] * q[1] - r[2] * q[2] - r[3] * q[3]
t[1] = r[0] * q[1] + r[1] * q[0] - r[2] * q[3] + r[3] * q[2]
t[2] = r[0] * q[2] + r[1] * q[3] + r[2] * q[0] - r[3] * q[1]
t[3] = r[0] * q[3] - r[1] * q[2] + r[2] * q[1] + r[3] * q[0]
return t
def rot_matrix(roll, pitch, yaw):
cr, sr = np.cos(roll), np.sin(roll)
cp, sp = np.cos(pitch), np.sin(pitch)
cy, sy = np.cos(yaw), np.sin(yaw)
rr = array([[1,0,0],[0, cr,-sr],[0, sr, cr]])
rp = array([[cp,0,sp],[0, 1,0],[-sp, 0, cp]])
ry = array([[cy,-sy,0],[sy, cy,0],[0, 0, 1]])
return ry.dot(rp.dot(rr))
def rot(axis, angle):
# Rotates around an arbitrary axis
ret_1 = (1 - np.cos(angle)) * array([[axis[0]**2, axis[0] * axis[1], axis[0] * axis[2]], [
axis[1] * axis[0], axis[1]**2, axis[1] * axis[2]
], [axis[2] * axis[0], axis[2] * axis[1], axis[2]**2]])
ret_2 = np.cos(angle) * np.eye(3)
ret_3 = np.sin(angle) * array([[0, -axis[2], axis[1]], [axis[2], 0, -axis[0]],
[-axis[1], axis[0], 0]])
return ret_1 + ret_2 + ret_3
def ecef_euler_from_ned(ned_ecef_init, ned_pose):
'''
Got it from here:
Using Rotations to Build Aerospace Coordinate Systems
-Don Koks
'''
converter = LocalCoord.from_ecef(ned_ecef_init)
x0 = converter.ned2ecef([1, 0, 0]) - converter.ned2ecef([0, 0, 0])
y0 = converter.ned2ecef([0, 1, 0]) - converter.ned2ecef([0, 0, 0])
z0 = converter.ned2ecef([0, 0, 1]) - converter.ned2ecef([0, 0, 0])
x1 = rot(z0, ned_pose[2]).dot(x0)
y1 = rot(z0, ned_pose[2]).dot(y0)
z1 = rot(z0, ned_pose[2]).dot(z0)
x2 = rot(y1, ned_pose[1]).dot(x1)
y2 = rot(y1, ned_pose[1]).dot(y1)
z2 = rot(y1, ned_pose[1]).dot(z1)
x3 = rot(x2, ned_pose[0]).dot(x2)
y3 = rot(x2, ned_pose[0]).dot(y2)
#z3 = rot(x2, ned_pose[0]).dot(z2)
x0 = array([1, 0, 0])
y0 = array([0, 1, 0])
z0 = array([0, 0, 1])
psi = np.arctan2(inner(x3, y0), inner(x3, x0))
theta = np.arctan2(-inner(x3, z0), np.sqrt(inner(x3, x0)**2 + inner(x3, y0)**2))
y2 = rot(z0, psi).dot(y0)
z2 = rot(y2, theta).dot(z0)
phi = np.arctan2(inner(y3, z2), inner(y3, y2))
ret = array([phi, theta, psi])
return ret
def ned_euler_from_ecef(ned_ecef_init, ecef_poses):
'''
Got the math from here:
Using Rotations to Build Aerospace Coordinate Systems
-Don Koks
Also accepts array of ecef_poses and array of ned_ecef_inits.
Where each row is a pose and an ecef_init.
'''
ned_ecef_init = array(ned_ecef_init)
ecef_poses = array(ecef_poses)
output_shape = ecef_poses.shape
ned_ecef_init = np.atleast_2d(ned_ecef_init)
if ned_ecef_init.shape[0] == 1:
ned_ecef_init = np.tile(ned_ecef_init[0], (output_shape[0], 1))
ecef_poses = np.atleast_2d(ecef_poses)
ned_poses = np.zeros(ecef_poses.shape)
for i, ecef_pose in enumerate(ecef_poses):
converter = LocalCoord.from_ecef(ned_ecef_init[i])
x0 = array([1, 0, 0])
y0 = array([0, 1, 0])
z0 = array([0, 0, 1])
x1 = rot(z0, ecef_pose[2]).dot(x0)
y1 = rot(z0, ecef_pose[2]).dot(y0)
z1 = rot(z0, ecef_pose[2]).dot(z0)
x2 = rot(y1, ecef_pose[1]).dot(x1)
y2 = rot(y1, ecef_pose[1]).dot(y1)
z2 = rot(y1, ecef_pose[1]).dot(z1)
x3 = rot(x2, ecef_pose[0]).dot(x2)
y3 = rot(x2, ecef_pose[0]).dot(y2)
#z3 = rot(x2, ecef_pose[0]).dot(z2)
x0 = converter.ned2ecef([1, 0, 0]) - converter.ned2ecef([0, 0, 0])
y0 = converter.ned2ecef([0, 1, 0]) - converter.ned2ecef([0, 0, 0])
z0 = converter.ned2ecef([0, 0, 1]) - converter.ned2ecef([0, 0, 0])
psi = np.arctan2(inner(x3, y0), inner(x3, x0))
theta = np.arctan2(-inner(x3, z0), np.sqrt(inner(x3, x0)**2 + inner(x3, y0)**2))
y2 = rot(z0, psi).dot(y0)
z2 = rot(y2, theta).dot(z0)
phi = np.arctan2(inner(y3, z2), inner(y3, y2))
ned_poses[i] = array([phi, theta, psi])
return ned_poses.reshape(output_shape)
def ecef2car(car_ecef, psi, theta, points_ecef, ned_converter):
"""
TODO: add roll rotation
Converts an array of points in ecef coordinates into
x-forward, y-left, z-up coordinates
Parameters
----------
psi: yaw, radian
theta: pitch, radian
Returns
-------
[x, y, z] coordinates in car frame
"""
# input is an array of points in ecef cocrdinates
# output is an array of points in car's coordinate (x-front, y-left, z-up)
# convert points to NED
points_ned = []
for p in points_ecef:
points_ned.append(ned_converter.ecef2ned_matrix.dot(array(p) - car_ecef))
points_ned = np.vstack(points_ned).T
# n, e, d -> x, y, z
# Calculate relative positions and rotate wrt to heading and pitch of car
invert_R = array([[1., 0., 0.], [0., -1., 0.], [0., 0., -1.]])
c, s = np.cos(psi), np.sin(psi)
yaw_R = array([[c, s, 0.], [-s, c, 0.], [0., 0., 1.]])
c, s = np.cos(theta), np.sin(theta)
pitch_R = array([[c, 0., -s], [0., 1., 0.], [s, 0., c]])
return dot(pitch_R, dot(yaw_R, dot(invert_R, points_ned)))

@ -1,192 +0,0 @@
import sympy
import numpy as np
from typing import List
from .constants import EARTH_ROTATION_RATE, SPEED_OF_LIGHT
from .helpers import ConstellationId
from .raw_gnss import GNSSMeasurement
def gauss_newton(fun, b, M, xtol=1e-8, max_n=25):
W = np.linalg.inv(M)
for _ in range(max_n):
# Compute function and jacobian on current estimate
r, J = fun(b)
# Update estimate, WLS https://en.wikipedia.org/wiki/Weighted_least_squares
delta = np.linalg.pinv(J.T.dot(W).dot(J)).dot(J.T).dot(W) @ r
b -= delta
# Check step size for stopping condition
if np.linalg.norm(delta) < xtol:
break
r, J = fun(b)
Mb = np.linalg.pinv(J.T.dot(W).dot(J))
x_std = np.sqrt(np.diagonal(Mb))
return b, r, x_std
def calc_pos_fix(measurements, posfix_functions=None, x0=None, signal='C1C', min_measurements=5):
'''
Calculates gps fix using gauss newton method
To solve the problem a minimal of 4 measurements are required.
If Glonass is included 5 are required to solve for the additional free variable.
returns:
0 -> list with positions
1 -> pseudorange errs
'''
if x0 is None:
x0 = [0, 0, 0, 0, 0]
if len(measurements) < min_measurements:
return [],[],[]
Fx_pos = pr_residual(measurements, posfix_functions, signal=signal, no_nans=True)
meas_cov = np.diag([meas.observables_std[signal]**2 for meas in measurements])
x, residual, x_std = gauss_newton(Fx_pos, x0, meas_cov)
return x.tolist(), residual.tolist(), x_std
def calc_vel_fix(measurements, est_pos, velfix_function=None, v0=None, signal='D1C', min_measurements=5):
'''
Calculates gps velocity fix using gauss newton method
returns:
0 -> list with velocities
1 -> pseudorange_rate errs
'''
if v0 is None:
v0 = [0, 0, 0, 0]
if len(measurements) < min_measurements:
return [], [], []
Fx_vel = prr_residual(measurements, est_pos, velfix_function, signal=signal, no_nans=True)
meas_cov = np.diag([meas.observables_std[signal]**2 for meas in measurements])
v, residual, x_std = gauss_newton(Fx_vel, v0, meas_cov)
return v.tolist(), residual.tolist(), x_std
def get_posfix_sympy_fun(constellation):
# Unknowns
x, y, z = sympy.Symbol('x'), sympy.Symbol('y'), sympy.Symbol('z')
bc = sympy.Symbol('bc')
bg = sympy.Symbol('bg')
zero_theta = sympy.Symbol('zero_theta')
var = [x, y, z, bc, bg]
# Knowns
pr = sympy.Symbol('pr')
sat_x, sat_y, sat_z = sympy.Symbol('sat_x'), sympy.Symbol('sat_y'), sympy.Symbol('sat_z')
theta = (EARTH_ROTATION_RATE * (pr - bc) / SPEED_OF_LIGHT)*zero_theta
val = sympy.sqrt(
(sat_x * sympy.cos(theta) + sat_y * sympy.sin(theta) - x) ** 2 +
(sat_y * sympy.cos(theta) - sat_x * sympy.sin(theta) - y) ** 2 +
(sat_z - z) ** 2
)
if constellation == ConstellationId.GLONASS:
res = val - (pr - bc - bg)
elif constellation == ConstellationId.GPS:
res = val - (pr - bc)
else:
raise NotImplementedError(f"Constellation {constellation} not supported")
res = [res] + [sympy.diff(res, v) for v in var]
return sympy.lambdify([x, y, z, bc, bg, pr, zero_theta, sat_x, sat_y, sat_z], res, modules=["numpy"])
def get_velfix_sympy_func():
# implementing this without sympy.Matrix gives a 2x speedup at generation
# knowns, receiver position, satellite position, satellite velocity
ep_x, ep_y, ep_z = sympy.Symbol('ep_x'), sympy.Symbol('ep_y'), sympy.Symbol('ep_z')
est_pos = np.array([ep_x, ep_y, ep_z])
sp_x, sp_y, sp_z = sympy.Symbol('sp_x'), sympy.Symbol('sp_y'), sympy.Symbol('sp_z')
sat_pos = np.array([sp_x, sp_y, sp_z])
sv_x, sv_y, sv_z = sympy.Symbol('sv_x'), sympy.Symbol('sv_y'), sympy.Symbol('sv_z')
sat_vel = np.array([sv_x, sv_y, sv_z])
observables = sympy.Symbol('observables')
# unknown, receiver velocity
v_x, v_y, v_z = sympy.Symbol('v_x'), sympy.Symbol('v_y'), sympy.Symbol('v_z')
vel = np.array([v_x, v_y, v_z])
vel_o = sympy.Symbol('vel_o')
loss = sat_pos - est_pos
loss /= sympy.sqrt(loss.dot(loss))
res = loss.dot(sat_vel - vel) - (observables - vel_o)
res = [res] + [sympy.diff(res, v) for v in [v_x, v_y, v_z, vel_o]]
return sympy.lambdify([
ep_x, ep_y, ep_z, sp_x, sp_y, sp_z,
sv_x, sv_y, sv_z, observables,
v_x, v_y, v_z, vel_o
],
res, modules=["numpy"])
def pr_residual(measurements: List[GNSSMeasurement], posfix_functions=None, signal='C1C', no_nans=False):
if posfix_functions is None:
posfix_functions = {constellation: get_posfix_sympy_fun(constellation) for constellation in (ConstellationId.GPS, ConstellationId.GLONASS)}
def Fx_pos(inp):
vals, gradients = [], []
for meas in measurements:
if signal in meas.observables_final and np.isfinite(meas.observables_final[signal]):
pr = meas.observables_final[signal]
sat_pos = meas.sat_pos_final
zero_theta = 0
elif signal in meas.observables and np.isfinite(meas.observables[signal]) and meas.processed:
pr = meas.observables[signal]
pr += meas.sat_clock_err * SPEED_OF_LIGHT
sat_pos = meas.sat_pos
zero_theta = 1
else:
if not no_nans:
vals.append(np.nan)
gradients.append(np.nan)
continue
val, *gradient = posfix_functions[meas.constellation_id](*inp, pr, zero_theta, *sat_pos)
vals.append(val)
gradients.append(gradient)
return np.asarray(vals), np.asarray(gradients)
return Fx_pos
def prr_residual(measurements: List[GNSSMeasurement], est_pos, velfix_function=None, signal='D1C', no_nans=False):
if velfix_function is None:
velfix_function = get_velfix_sympy_func()
def Fx_vel(vel):
vals, gradients = [], []
for meas in measurements:
if signal not in meas.observables or not np.isfinite(meas.observables[signal]):
if not no_nans:
vals.append(np.nan)
gradients.append(np.nan)
continue
sat_pos = meas.sat_pos_final if meas.corrected else meas.sat_pos
val, *gradient = velfix_function(est_pos[0], est_pos[1], est_pos[2],
sat_pos[0], sat_pos[1], sat_pos[2],
meas.sat_vel[0], meas.sat_vel[1], meas.sat_vel[2],
meas.observables[signal],
vel[0], vel[1], vel[2], vel[3])
vals.append(val)
gradients.append(gradient)
return np.asarray(vals), np.asarray(gradients)
return Fx_vel

@ -1,334 +0,0 @@
from math import sqrt
from typing import Dict, List, Optional, Union
import numpy as np
import datetime
import struct
from . import constants
from .ephemeris import Ephemeris
from .lib.coordinates import LocalCoord
from .gps_time import GPSTime
from .helpers import ConstellationId, get_constellation_and_sv_id, get_nmea_id_from_constellation_and_svid, \
rinex3_obs_from_rinex2_obs
def array_from_normal_meas(meas):
return np.concatenate(([meas.get_nmea_id()],
[meas.recv_time_week],
[meas.recv_time_sec],
[meas.glonass_freq],
[meas.observables['C1C']],
[meas.observables_std['C1C']],
[meas.observables['D1C']],
[meas.observables_std['D1C']],
[meas.observables['S1C']],
[meas.observables['L1C']]))
def normal_meas_from_array(arr):
observables, observables_std = {}, {}
observables['C1C'] = arr[4]
observables_std['C1C'] = arr[5]
observables['D1C'] = arr[6]
observables_std['D1C'] = arr[7]
observables['S1C'] = arr[8]
observables['L1C'] = arr[9]
constellation_id, sv_id = get_constellation_and_sv_id(nmea_id=arr[0])
return GNSSMeasurement(constellation_id, sv_id, arr[1], arr[2],
observables, observables_std, arr[3])
class GNSSMeasurement:
PRN = 0
RECV_TIME_WEEK = 1
RECV_TIME_SEC = 2
GLONASS_FREQ = 3
PR = 4
PR_STD = 5
PRR = 6
PRR_STD = 7
SAT_POS = slice(8, 11)
SAT_VEL = slice(11, 14)
def __init__(self, constellation_id: ConstellationId, sv_id: int, recv_time_week: int, recv_time_sec: float, observables: Dict[str, float], observables_std: Dict[str, float],
glonass_freq: Union[int, float, None] = None):
# Metadata
# prn: unique satellite id
self.prn = "%s%02d" % (constellation_id.to_rinex_char(), sv_id) # satellite ID in rinex convention
self.constellation_id = constellation_id
self.sv_id = sv_id # satellite id per constellation
self.recv_time_week = recv_time_week
self.recv_time_sec = recv_time_sec
self.recv_time = GPSTime(recv_time_week, recv_time_sec)
self.glonass_freq = glonass_freq # glonass channel
# Measurements
self.observables = observables
self.observables_std = observables_std
# flags
self.processed = False
self.corrected = False
# sat info
self.sat_pos = np.array([np.nan, np.nan, np.nan])
self.sat_vel = np.array([np.nan, np.nan, np.nan])
self.sat_clock_err = np.nan
self.sat_ephemeris: Optional[Ephemeris] = None
self.sat_pos_final = np.array([np.nan, np.nan, np.nan]) # sat_pos in receiver time's ECEF frame instead of satellite time's ECEF frame
self.observables_final: Dict[str, float] = {}
def process(self, dog):
sat_time = self.recv_time - self.observables['C1C']/constants.SPEED_OF_LIGHT
sat_info = dog.get_sat_info(self.prn, sat_time)
if sat_info is None:
return False
self.sat_pos, self.sat_vel, self.sat_clock_err, _, self.sat_ephemeris = sat_info
self.processed = True
return True
def correct(self, est_pos, dog, correct_delay=True):
for obs in self.observables:
if obs[0] == 'C': # or obs[0] == 'L':
if correct_delay:
delay = dog.get_delay(self.prn, self.recv_time, est_pos, signal=obs)
else:
delay = 0.0
if delay is not None:
self.observables_final[obs] = (self.observables[obs] +
self.sat_clock_err*constants.SPEED_OF_LIGHT -
delay)
else:
self.observables_final[obs] = self.observables[obs]
if 'C1C' in self.observables_final and 'C2P' in self.observables_final:
self.observables_final['IOF'] = (((constants.GPS_L1**2)*self.observables_final['C1C'] -
(constants.GPS_L2**2)*self.observables_final['C2P'])/
(constants.GPS_L1**2 - constants.GPS_L2**2))
geometric_range = np.linalg.norm(self.sat_pos - est_pos)
theta_1 = constants.EARTH_ROTATION_RATE * geometric_range / constants.SPEED_OF_LIGHT
self.sat_pos_final = np.array([self.sat_pos[0] * np.cos(theta_1) + self.sat_pos[1] * np.sin(theta_1),
self.sat_pos[1] * np.cos(theta_1) - self.sat_pos[0] * np.sin(theta_1),
self.sat_pos[2]])
if 'C1C' in self.observables_final and np.isfinite(self.observables_final['C1C']):
self.corrected = True
return True
return False
def as_array(self, only_corrected=True):
observables = self.observables_final
sat_pos = self.sat_pos_final
if not self.corrected:
if only_corrected:
raise NotImplementedError('Only corrected measurements can be put into arrays')
else:
observables = self.observables
sat_pos = self.sat_pos
ret = np.array([self.get_nmea_id(), self.recv_time_week, self.recv_time_sec, self.glonass_freq,
observables['C1C'], self.observables_std['C1C'],
observables['D1C'], self.observables_std['D1C']])
return np.concatenate((ret, sat_pos, self.sat_vel))
def __repr__(self):
time = self.recv_time.as_datetime().strftime('%Y-%m-%dT%H:%M:%S.%f')
return f"<GNSSMeasurement from {self.prn} at {time}>"
def get_nmea_id(self):
return get_nmea_id_from_constellation_and_svid(self.constellation_id, self.sv_id)
def process_measurements(measurements: List[GNSSMeasurement], dog) -> List[GNSSMeasurement]:
proc_measurements = []
for meas in measurements:
if meas.process(dog):
proc_measurements.append(meas)
return proc_measurements
def correct_measurements(measurements: List[GNSSMeasurement], est_pos, dog, correct_delay=True) -> List[GNSSMeasurement]:
corrected_measurements = []
for meas in measurements:
if meas.correct(est_pos, dog, correct_delay=correct_delay):
corrected_measurements.append(meas)
return corrected_measurements
def group_measurements_by_epoch(measurements):
meas_filt_by_t = [[measurements[0]]]
for m in measurements[1:]:
if abs(m.recv_time - meas_filt_by_t[-1][-1].recv_time) > 1e-9:
meas_filt_by_t.append([])
meas_filt_by_t[-1].append(m)
return meas_filt_by_t
def group_measurements_by_sat(measurements):
measurements_by_sat = {}
sats = {m.prn for m in measurements}
for sat in sats:
measurements_by_sat[sat] = [m for m in measurements if m.prn == sat]
return measurements_by_sat
def read_raw_qcom(report):
dr = 'DrMeasurementReport' in str(report.schema)
# Only gps/sbas and glonass are supported
constellation_id = ConstellationId.from_qcom_source(report.source)
if constellation_id in [ConstellationId.GPS, ConstellationId.SBAS]: # gps/sbas
if dr:
recv_tow = report.gpsMilliseconds / 1000.0 # seconds
time_bias_ms = struct.unpack("f", struct.pack("I", report.gpsTimeBiasMs))[0]
else:
recv_tow = report.milliseconds / 1000.0 # seconds
time_bias_ms = report.timeBias
recv_time = GPSTime(report.gpsWeek, recv_tow)
elif constellation_id == ConstellationId.GLONASS:
if dr:
recv_tow = report.glonassMilliseconds / 1000.0 # seconds
recv_time = GPSTime.from_glonass(report.glonassYear, report.glonassDay, recv_tow)
time_bias_ms = report.glonassTimeBias
else:
recv_tow = report.milliseconds / 1000.0 # seconds
recv_time = GPSTime.from_glonass(report.glonassCycleNumber, report.glonassNumberOfDays, recv_tow)
time_bias_ms = report.timeBias
else:
raise NotImplementedError('Only GPS (0), SBAS (1) and GLONASS (6) are supported from qcom, not:', {report.source})
# logging.debug(recv_time, report.source, time_bias_ms, dr)
measurements = []
for i in report.sv:
nmea_id = i.svId # todo change svId to nmea_id in cereal message. Or better: change the publisher to publish correct svId's, since constellation id is also given
if nmea_id == 255:
# TODO nmea_id is not valid. Fix publisher
continue
_, sv_id = get_constellation_and_sv_id(nmea_id)
if not i.measurementStatus.measurementNotUsable and i.measurementStatus.satelliteTimeIsKnown:
sat_tow = (i.unfilteredMeasurementIntegral + i.unfilteredMeasurementFraction + i.latency + time_bias_ms) / 1000
observables, observables_std = {}, {}
observables['C1C'] = (recv_tow - sat_tow)*constants.SPEED_OF_LIGHT
observables_std['C1C'] = i.unfilteredTimeUncertainty * 1e-3 * constants.SPEED_OF_LIGHT
if i.measurementStatus.fineOrCoarseVelocity:
# about 10x better, perhaps filtered with carrier phase?
observables['D1C'] = i.fineSpeed
observables_std['D1C'] = i.fineSpeedUncertainty
else:
observables['D1C'] = i.unfilteredSpeed
observables_std['D1C'] = i.unfilteredSpeedUncertainty
observables['S1C'] = (i.carrierNoise/100.) if i.carrierNoise != 0 else np.nan
observables['L1C'] = np.nan
# logging.debug(" %.5f %3d %10.2f %7.2f %7.2f %.2f %d" % (recv_time.tow, nmea_id,
# observables['C1C'], observables_std['C1C'],
# observables_std['D1C'], observables['S1C'], i.latency), i.observationState, i.measurementStatus.fineOrCoarseVelocity)
glonass_freq = (i.glonassFrequencyIndex - 7) if constellation_id == ConstellationId.GLONASS else np.nan
measurements.append(GNSSMeasurement(constellation_id, sv_id,
recv_time.week,
recv_time.tow,
observables,
observables_std,
glonass_freq))
return measurements
def read_raw_ublox(report) -> List[GNSSMeasurement]:
recv_tow = report.rcvTow # seconds
recv_week = report.gpsWeek
measurements = []
for i in report.measurements:
# only add Gps and Glonass fixes
if i.gnssId in [ConstellationId.GPS, ConstellationId.GLONASS]:
if i.svId > 32 or i.pseudorange > 2**32:
continue
observables = {}
observables_std = {}
if i.trackingStatus.pseudorangeValid and i.sigId == 0:
observables['C1C'] = i.pseudorange
# Empirically it seems obvious ublox's std is
# actually a variation
observables_std['C1C'] = sqrt(i.pseudorangeStdev)*10
if i.gnssId == ConstellationId.GLONASS:
glonass_freq = i.glonassFrequencyIndex - 7
observables['D1C'] = -(constants.SPEED_OF_LIGHT / (constants.GLONASS_L1 + glonass_freq * constants.GLONASS_L1_DELTA)) * i.doppler
else: # GPS
glonass_freq = np.nan
observables['D1C'] = -(constants.SPEED_OF_LIGHT / constants.GPS_L1) * i.doppler
observables_std['D1C'] = (constants.SPEED_OF_LIGHT / constants.GPS_L1) * i.dopplerStdev
observables['S1C'] = i.cno
if i.trackingStatus.carrierPhaseValid:
observables['L1C'] = i.carrierCycles
else:
observables['L1C'] = np.nan
measurements.append(GNSSMeasurement(ConstellationId(i.gnssId), i.svId, recv_week, recv_tow,
observables, observables_std, glonass_freq))
return measurements
def read_rinex_obs(obsdata) -> List[List[GNSSMeasurement]]:
measurements: List[List[GNSSMeasurement]] = []
obsdata_keys = list(obsdata.data.keys())
first_sat = obsdata_keys[0]
n = len(obsdata.data[first_sat]['Epochs'])
for i in range(n):
recv_time_datetime = obsdata.data[first_sat]['Epochs'][i]
recv_time_datetime = recv_time_datetime.astype(datetime.datetime)
recv_time = GPSTime.from_datetime(recv_time_datetime)
measurements.append([])
for sat_str in obsdata_keys:
if np.isnan(obsdata.data[sat_str]['C1'][i]):
continue
observables, observables_std = {}, {}
for obs in obsdata.data[sat_str]:
if obs == 'Epochs':
continue
rinex3_obs_key = rinex3_obs_from_rinex2_obs(obs)
observables[rinex3_obs_key] = obsdata.data[sat_str][obs][i]
observables_std[rinex3_obs_key] = 1.
constellation_id, sv_id = get_constellation_and_sv_id(int(sat_str))
measurements[-1].append(GNSSMeasurement(constellation_id, sv_id,
recv_time.week, recv_time.tow,
observables, observables_std))
return measurements
def get_Q(recv_pos, sat_positions):
local = LocalCoord.from_ecef(recv_pos)
sat_positions_rel = local.ecef2ned(sat_positions)
sat_distances = np.linalg.norm(sat_positions_rel, axis=1)
A = np.column_stack((sat_positions_rel[:,0]/sat_distances, # pylint: disable=unsubscriptable-object
sat_positions_rel[:,1]/sat_distances, # pylint: disable=unsubscriptable-object
sat_positions_rel[:,2]/sat_distances, # pylint: disable=unsubscriptable-object
-np.ones(len(sat_distances))))
if A.shape[0] < 4 or np.linalg.matrix_rank(A) < 4:
return np.inf*np.ones((4,4))
Q = np.linalg.inv(A.T.dot(A))
return Q
def get_DOP(recv_pos, sat_positions):
Q = get_Q(recv_pos, sat_positions)
return np.sqrt(np.trace(Q))
def get_HDOP(recv_pos, sat_positions):
Q = get_Q(recv_pos, sat_positions)
return np.sqrt(np.trace(Q[:2,:2]))
def get_VDOP(recv_pos, sat_positions):
Q = get_Q(recv_pos, sat_positions)
return np.sqrt(Q[2,2])
def get_TDOP(recv_pos, sat_positions):
Q = get_Q(recv_pos, sat_positions)
return np.sqrt(Q[3,3])
def get_PDOP(recv_pos, sat_positions):
Q = get_Q(recv_pos, sat_positions)
return np.sqrt(np.trace(Q[:3,:3]))

@ -1,252 +0,0 @@
#!/usr/bin/env python
# Copyright (C) 2014 Swift Navigation Inc.
#
# This source is subject to the license found in the file 'LICENSE' which must
# be be distributed together with this source. All other rights reserved.
#
# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
import datetime
import numpy as np
import logging
def floatornan(x):
if x == '' or x[-1] == ' ':
return np.NaN
return float(x)
def digitorzero(x):
if x == ' ' or x == '':
return 0
return int(x)
def padline(l, n=16):
x = len(l)
x_ = n * ((x + n - 1) // n)
padded = l + ' ' * (x_ - x)
while len(padded) < 70:
padded += ' ' * 16
return padded
TOTAL_SATS = 132 # Increased to support Galileo
class DownloadError(Exception):
pass
class RINEXFile:
def __init__(self, filename, rate=None):
self.rate = rate
try:
with open(filename) as f:
self._read_header(f)
self._read_data(f)
except TypeError:
logging.exception("TypeError, file likely not downloaded.")
raise DownloadError("file download failure")
except FileNotFoundError:
logging.exception("File not found in directory.")
raise DownloadError("file missing in download cache")
def _read_header(self, f):
version_line = padline(f.readline(), 80)
self.version = float(version_line[0:9])
if (self.version > 2.11):
raise ValueError(
f"RINEX file versions > 2.11 not supported (file version {self.version:f})")
self.filetype = version_line[20]
if self.filetype not in "ONGM": # Check valid file type
raise ValueError(f"RINEX file type '{self.filetype}' not supported")
if self.filetype != 'O':
raise ValueError("Only 'OBSERVATION DATA' RINEX files are currently supported")
self.gnss = version_line[40]
if self.gnss not in " GRSEM": # Check valid satellite system
raise ValueError(f"Satellite system '{self.filetype}' not supported")
if self.gnss == ' ':
self.gnss = 'G'
if self.gnss != 'G':
#raise ValueError("Only GPS data currently supported")
pass
self.comment = ""
while True: # Read the rest of the header
line = padline(f.readline(), 80)
label = line[60:80].rstrip()
if label == "END OF HEADER":
break
if label == "COMMENT":
self.comment += line[:60] + '\n'
if label == "MARKER NAME":
self.marker_name = line[:60].rstrip()
if self.marker_name == '':
self.marker_name = 'UNKNOWN'
if label == "# / TYPES OF OBSERV":
# RINEX files can have multiple line headers
# This code handles the case
try:
n_obs = int(line[0:6])
self.obs_types = []
except ValueError:
pass
if n_obs <= 9:
for i in range(0, n_obs):
self.obs_types.append(line[10 + 6 * i:12 + 6 * i])
if n_obs > 9:
for i in range(0, 9):
self.obs_types.append(line[10 + 6 * i:12 + 6 * i])
n_obs -= 9
def _read_next_non_comment(self, f):
line = f.readline()
while line and line.find('COMMENT') != -1:
line = f.readline()
return line
def _read_epoch_header(self, f):
epoch_hdr = self._read_next_non_comment(f)
if epoch_hdr == '':
return None
# ignore any line with these three strings
skippable = ('0.0000000 4 5', 'MARKER NUMBER', ' 4 1')
while any(skip in epoch_hdr for skip in skippable):
epoch_hdr = self._read_next_non_comment(f)
if epoch_hdr == '':
return None
year = int(epoch_hdr[1:3])
if year >= 80:
year += 1900
else:
year += 2000
month = int(epoch_hdr[4:6])
day = int(epoch_hdr[7:9])
hour = int(epoch_hdr[10:12])
minute = int(epoch_hdr[13:15])
second = int(epoch_hdr[15:18])
microsecond = int(
epoch_hdr[19:25]) # Discard the least sig. fig. (use microseconds only).
epoch = datetime.datetime(year, month, day, hour, minute, second, microsecond)
flag = int(epoch_hdr[28])
allowed_flags = {0, 3, 4}
if flag not in allowed_flags:
raise ValueError("Don't know how to handle epoch flag %d in epoch header:\n%s" %
(flag, epoch_hdr))
n_sats = int(epoch_hdr[29:32])
if flag > 1: # event flag: nsats is number of records
for i in range(n_sats):
f.readline()
return None
sats = []
for i in range(0, n_sats):
if ((i % 12) == 0) and (i > 0):
epoch_hdr = f.readline()
sats.append(epoch_hdr[(32 + (i % 12) * 3):(35 + (i % 12) * 3)])
return epoch, flag, sats
def _read_obs(self, f, n_sat, sat_map):
obs = np.empty((TOTAL_SATS, len(self.obs_types)), dtype=np.float64) * np.NaN
lli = np.zeros((TOTAL_SATS, len(self.obs_types)), dtype=np.uint8)
signal_strength = np.zeros((TOTAL_SATS, len(self.obs_types)), dtype=np.uint8)
for i in range(n_sat):
# Join together observations for a single satellite if split across lines.
obs_line = ''.join(
padline(f.readline()[:-1], 16) for _ in range((len(self.obs_types) + 4) // 5))
for j in range(len(self.obs_types)):
obs_record = obs_line[16 * j:16 * (j + 1)]
obs[int(sat_map[i]), j] = floatornan(obs_record[0:14])
lli[int(sat_map[i]), j] = digitorzero(obs_record[14:15])
signal_strength[int(sat_map[i]), j] = digitorzero(obs_record[15:16])
return obs, lli, signal_strength
def _skip_obs(self, f, n_sat):
for i in range(n_sat):
for _ in range((len(self.obs_types) + 4) // 5):
f.readline()
def _read_data_chunk(self, f, CHUNK_SIZE=10000):
obss = np.empty(
(CHUNK_SIZE, TOTAL_SATS, len(self.obs_types)), dtype=np.float64) * np.NaN
llis = np.zeros((CHUNK_SIZE, TOTAL_SATS, len(self.obs_types)), dtype=np.uint8)
signal_strengths = np.zeros(
(CHUNK_SIZE, TOTAL_SATS, len(self.obs_types)), dtype=np.uint8)
epochs = np.zeros(CHUNK_SIZE, dtype='datetime64[us]')
flags = np.zeros(CHUNK_SIZE, dtype=np.uint8)
i = 0
while True:
hdr = self._read_epoch_header(f)
if hdr is None:
break
# data faster than desired rate: ignore it
if self.rate and (hdr[0].microsecond or hdr[0].second % self.rate != 0):
self._skip_obs(f, len(hdr[2]))
continue
epoch, flags[i], sats = hdr
epochs[i] = np.datetime64(epoch)
sat_map = np.ones(len(sats)) * -1
for n, sat in enumerate(sats):
if sat[0] == 'G':
sat_map[n] = int(sat[1:]) - 1
if sat[0] == 'R':
sat_map[n] = int(sat[1:]) - 1 + 64
obss[i], llis[i], signal_strengths[i] = self._read_obs(f, len(sats), sat_map)
i += 1
if i >= CHUNK_SIZE:
break
return obss[:i], llis[:i], signal_strengths[:i], epochs[:i], flags[:i]
def _read_data(self, f):
self.data = {}
while True:
obss, llis, signal_strengths, epochs, flags = self._read_data_chunk(f)
if obss.shape[0] == 0:
break
for i, sv in enumerate(['%02d' % d for d in range(1, TOTAL_SATS+1)]):
if sv not in self.data:
self.data[sv] = {}
for j, obs_type in enumerate(self.obs_types):
if obs_type in self.data[sv]:
self.data[sv][obs_type] = np.append(self.data[sv][obs_type], obss[:, i, j])
else:
self.data[sv][obs_type] = obss[:, i, j]
if 'Epochs' in self.data[sv]:
self.data[sv]['Epochs'] = np.append(self.data[sv]['Epochs'], epochs)
else:
self.data[sv]['Epochs'] = epochs
for sat in list(self.data.keys()):
if np.all(np.isnan(self.data[sat]['C1'])):
del self.data[sat]

@ -1,34 +0,0 @@
#!/usr/bin/python
from numpy import cos, exp, pi
from .lib.coordinates import ecef2geodetic
def saast(pos, el, humi=0.75, temp0=15.0):
"""
Function from RTKlib: https://github.com/tomojitakasu/RTKLIB/blob/master/src/rtkcmn.c#L3362-3362
with no changes
:param time: time
:param pos: receiver position {ecef} m)
:param el: azimuth/elevation angle {az,el} (rad) -- we do not use az
:param humi: relative humidity
:param temp0: temperature (Celsius)
:return: tropospheric delay (m)
"""
pos_rad = ecef2geodetic(pos, radians=True)
if pos_rad[2] < -1E3 or 1E4 < pos_rad[2] or el <= 0:
return 0.0
# /* standard atmosphere */
hgt = 0.0 if pos_rad[2] < 0.0 else pos_rad[2]
pres = 1013.25 * pow(1.0 - 2.2557E-5 * hgt, 5.2568)
temp = temp0 - 6.5E-3 * hgt + 273.16
e = 6.108 * humi * exp((17.15 * temp - 4684.0) / (temp - 38.45))
# /* saastamoninen model */
z = pi / 2.0 - el
trph = 0.0022768 * pres / (
1.0 - 0.00266 * cos(2.0 * pos_rad[0]) - 0.00028 * hgt / 1E3) / cos(z)
trpw = 0.002277 * (1255.0 / temp + 0.05) * e / cos(z)
return trph + trpw

@ -29,7 +29,7 @@ unsigned int subaru_checksum(uint32_t address, const Signal &sig, const std::vec
while (address) { s += address & 0xFF; address >>= 8; } while (address) { s += address & 0xFF; address >>= 8; }
// skip checksum in first byte // skip checksum in first byte
for (int i = 1; i < d.size(); i++) { s += d[i]; }; for (int i = 1; i < d.size(); i++) { s += d[i]; }
return s & 0xFF; return s & 0xFF;
} }

@ -76,8 +76,7 @@ public:
uint64_t can_invalid_cnt = CAN_INVALID_CNT; uint64_t can_invalid_cnt = CAN_INVALID_CNT;
CANParser(int abus, const std::string& dbc_name, CANParser(int abus, const std::string& dbc_name,
const std::vector<MessageParseOptions> &options, const std::vector<std::pair<uint32_t, int>> &messages);
const std::vector<SignalParseOptions> &sigoptions);
CANParser(int abus, const std::string& dbc_name, bool ignore_checksum, bool ignore_counter); CANParser(int abus, const std::string& dbc_name, bool ignore_checksum, bool ignore_counter);
#ifndef DYNAMIC_CAPNP #ifndef DYNAMIC_CAPNP
void update_string(const std::string &data, bool sendcan); void update_string(const std::string &data, bool sendcan);

@ -3,6 +3,7 @@
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t
from libcpp cimport bool from libcpp cimport bool
from libcpp.pair cimport pair
from libcpp.string cimport string from libcpp.string cimport string
from libcpp.vector cimport vector from libcpp.vector cimport vector
@ -48,14 +49,6 @@ cdef extern from "common_dbc.h":
vector[Msg] msgs vector[Msg] msgs
vector[Val] vals vector[Val] vals
cdef struct SignalParseOptions:
uint32_t address
string name
cdef struct MessageParseOptions:
uint32_t address
int check_frequency
cdef struct SignalValue: cdef struct SignalValue:
uint32_t address uint32_t address
uint64_t ts_nanos uint64_t ts_nanos
@ -74,8 +67,8 @@ cdef extern from "common.h":
cdef cppclass CANParser: cdef cppclass CANParser:
bool can_valid bool can_valid
bool bus_timeout bool bus_timeout
CANParser(int, string, vector[MessageParseOptions], vector[SignalParseOptions]) CANParser(int, string, vector[pair[uint32_t, int]]) except +
void update_strings(vector[string]&, vector[SignalValue]&, bool) void update_strings(vector[string]&, vector[SignalValue]&, bool) except +
cdef cppclass CANPacker: cdef cppclass CANPacker:
CANPacker(string) CANPacker(string)

@ -5,23 +5,11 @@
#include <string> #include <string>
#include <vector> #include <vector>
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
struct SignalPackValue { struct SignalPackValue {
std::string name; std::string name;
double value; double value;
}; };
struct SignalParseOptions {
uint32_t address;
std::string name;
};
struct MessageParseOptions {
uint32_t address;
int check_frequency;
};
struct SignalValue { struct SignalValue {
uint32_t address; uint32_t address;
uint64_t ts_nanos; uint64_t ts_nanos;

@ -35,7 +35,7 @@ CANPacker::CANPacker(const std::string& dbc_name) {
for (const auto& msg : dbc->msgs) { for (const auto& msg : dbc->msgs) {
message_lookup[msg.address] = msg; message_lookup[msg.address] = msg;
for (const auto& sig : msg.sigs) { for (const auto& sig : msg.sigs) {
signal_lookup[std::make_pair(msg.address, std::string(sig.name))] = sig; signal_lookup[std::make_pair(msg.address, sig.name)] = sig;
} }
} }
init_crc_lookup_tables(); init_crc_lookup_tables();

@ -40,7 +40,7 @@ cdef class CANPacker:
cpdef make_can_msg(self, name_or_addr, bus, values): cpdef make_can_msg(self, name_or_addr, bus, values):
cdef int addr cdef int addr
if type(name_or_addr) == int: if isinstance(name_or_addr, int):
addr = name_or_addr addr = name_or_addr
else: else:
addr = self.name_to_address[name_or_addr.encode("utf8")] addr = self.name_to_address[name_or_addr.encode("utf8")]

@ -2,6 +2,8 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <limits> #include <limits>
#include <stdexcept>
#include <sstream>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
@ -89,9 +91,7 @@ bool MessageState::update_counter_generic(int64_t v, int cnt_size) {
} }
CANParser::CANParser(int abus, const std::string& dbc_name, CANParser::CANParser(int abus, const std::string& dbc_name, const std::vector<std::pair<uint32_t, int>> &messages)
const std::vector<MessageParseOptions> &options,
const std::vector<SignalParseOptions> &sigoptions)
: bus(abus), aligned_buf(kj::heapArray<capnp::word>(1024)) { : bus(abus), aligned_buf(kj::heapArray<capnp::word>(1024)) {
dbc = dbc_lookup(dbc_name); dbc = dbc_lookup(dbc_name);
assert(dbc); assert(dbc);
@ -99,14 +99,21 @@ CANParser::CANParser(int abus, const std::string& dbc_name,
bus_timeout_threshold = std::numeric_limits<uint64_t>::max(); bus_timeout_threshold = std::numeric_limits<uint64_t>::max();
for (const auto& op : options) { for (const auto& [address, frequency] : messages) {
MessageState &state = message_states[op.address]; // disallow duplicate message checks
state.address = op.address; if (message_states.find(address) != message_states.end()) {
std::stringstream is;
is << "Duplicate Message Check: " << address;
throw std::runtime_error(is.str());
}
MessageState &state = message_states[address];
state.address = address;
// state.check_frequency = op.check_frequency, // state.check_frequency = op.check_frequency,
// msg is not valid if a message isn't received for 10 consecutive steps // msg is not valid if a message isn't received for 10 consecutive steps
if (op.check_frequency > 0) { if (frequency > 0) {
state.check_threshold = (1000000000ULL / op.check_frequency) * 10; state.check_threshold = (1000000000ULL / frequency) * 10;
// bus timeout threshold should be 10x the fastest msg // bus timeout threshold should be 10x the fastest msg
bus_timeout_threshold = std::min(bus_timeout_threshold, state.check_threshold); bus_timeout_threshold = std::min(bus_timeout_threshold, state.check_threshold);
@ -114,13 +121,13 @@ CANParser::CANParser(int abus, const std::string& dbc_name,
const Msg* msg = NULL; const Msg* msg = NULL;
for (const auto& m : dbc->msgs) { for (const auto& m : dbc->msgs) {
if (m.address == op.address) { if (m.address == address) {
msg = &m; msg = &m;
break; break;
} }
} }
if (!msg) { if (!msg) {
fprintf(stderr, "CANParser: could not find message 0x%X in DBC %s\n", op.address, dbc_name.c_str()); fprintf(stderr, "CANParser: could not find message 0x%X in DBC %s\n", address, dbc_name.c_str());
assert(false); assert(false);
} }
@ -128,28 +135,10 @@ CANParser::CANParser(int abus, const std::string& dbc_name,
state.size = msg->size; state.size = msg->size;
assert(state.size <= 64); // max signal size is 64 bytes assert(state.size <= 64); // max signal size is 64 bytes
// track checksums and counters for this message // track all signals for this message
for (const auto& sig : msg->sigs) { state.parse_sigs = msg->sigs;
if (sig.type != SignalType::DEFAULT) { state.vals.resize(msg->sigs.size());
state.parse_sigs.push_back(sig); state.all_vals.resize(msg->sigs.size());
state.vals.push_back(0);
state.all_vals.push_back({});
}
}
// track requested signals for this message
for (const auto& sigop : sigoptions) {
if (sigop.address != op.address) continue;
for (const auto& sig : msg->sigs) {
if (sig.name == sigop.name && sig.type == SignalType::DEFAULT) {
state.parse_sigs.push_back(sig);
state.vals.push_back(0);
state.all_vals.push_back({});
break;
}
}
}
} }
} }

@ -2,14 +2,14 @@
# cython: c_string_encoding=ascii, language_level=3 # cython: c_string_encoding=ascii, language_level=3
from cython.operator cimport dereference as deref, preincrement as preinc from cython.operator cimport dereference as deref, preincrement as preinc
from libcpp.pair cimport pair
from libcpp.string cimport string from libcpp.string cimport string
from libcpp.vector cimport vector from libcpp.vector cimport vector
from libcpp.unordered_set cimport unordered_set from libcpp.unordered_set cimport unordered_set
from libc.stdint cimport uint32_t from libc.stdint cimport uint32_t
from libcpp.map cimport map
from .common cimport CANParser as cpp_CANParser from .common cimport CANParser as cpp_CANParser
from .common cimport SignalParseOptions, MessageParseOptions, dbc_lookup, SignalValue, DBC from .common cimport dbc_lookup, SignalValue, DBC
import numbers import numbers
from collections import defaultdict from collections import defaultdict
@ -19,7 +19,6 @@ cdef class CANParser:
cdef: cdef:
cpp_CANParser *can cpp_CANParser *can
const DBC *dbc const DBC *dbc
map[uint32_t, string] address_to_msg_name
vector[SignalValue] can_values vector[SignalValue] can_values
cdef readonly: cdef readonly:
@ -28,10 +27,7 @@ cdef class CANParser:
dict ts_nanos dict ts_nanos
string dbc_name string dbc_name
def __init__(self, dbc_name, signals, checks=None, bus=0, enforce_checks=True): def __init__(self, dbc_name, messages, bus=0):
if checks is None:
checks = []
self.dbc_name = dbc_name self.dbc_name = dbc_name
self.dbc = dbc_lookup(dbc_name) self.dbc = dbc_lookup(dbc_name)
if not self.dbc: if not self.dbc:
@ -41,71 +37,33 @@ cdef class CANParser:
self.vl_all = {} self.vl_all = {}
self.ts_nanos = {} self.ts_nanos = {}
msg_name_to_address = {} msg_name_to_address = {}
msg_address_to_signals = {} address_to_msg_name = {}
for i in range(self.dbc[0].msgs.size()): for i in range(self.dbc[0].msgs.size()):
msg = self.dbc[0].msgs[i] msg = self.dbc[0].msgs[i]
name = msg.name.decode("utf8") name = msg.name.decode("utf8")
msg_name_to_address[name] = msg.address msg_name_to_address[name] = msg.address
msg_address_to_signals[msg.address] = set() address_to_msg_name[msg.address] = name
for sig in msg.sigs:
msg_address_to_signals[msg.address].add(sig.name.decode("utf8")) # Convert message names into addresses and check existence in DBC
cdef vector[pair[uint32_t, int]] message_v
self.address_to_msg_name[msg.address] = name for i in range(len(messages)):
self.vl[msg.address] = {} c = messages[i]
self.vl[name] = self.vl[msg.address] address = c[0] if isinstance(c[0], numbers.Number) else msg_name_to_address.get(c[0])
self.vl_all[msg.address] = {} if address not in address_to_msg_name:
self.vl_all[name] = self.vl_all[msg.address] raise RuntimeError(f"could not find message {repr(c[0])} in DBC {self.dbc_name}")
self.ts_nanos[msg.address] = {} message_v.push_back((address, c[1]))
self.ts_nanos[name] = self.ts_nanos[msg.address]
name = address_to_msg_name[address]
# Convert message names into addresses self.vl[address] = {}
for i in range(len(signals)): self.vl[name] = self.vl[address]
s = signals[i] self.vl_all[address] = {}
address = s[1] if isinstance(s[1], numbers.Number) else msg_name_to_address.get(s[1]) self.vl_all[name] = self.vl_all[address]
if address not in msg_address_to_signals: self.ts_nanos[address] = {}
raise RuntimeError(f"could not find message {repr(s[1])} in DBC {self.dbc_name}") self.ts_nanos[name] = self.ts_nanos[address]
if s[0] not in msg_address_to_signals[address]:
raise RuntimeError(f"could not find signal {repr(s[0])} in {repr(s[1])}, DBC {self.dbc_name}") self.can = new cpp_CANParser(bus, dbc_name, message_v)
signals[i] = (s[0], address)
for i in range(len(checks)):
c = checks[i]
if not isinstance(c[0], numbers.Number):
if c[0] not in msg_name_to_address:
print(msg_name_to_address)
raise RuntimeError(f"could not find message {repr(c[0])} in DBC {self.dbc_name}")
c = (msg_name_to_address[c[0]], c[1])
checks[i] = c
if enforce_checks:
checked_addrs = {c[0] for c in checks}
signal_addrs = {s[1] for s in signals}
unchecked = signal_addrs - checked_addrs
if len(unchecked):
err_msg = ", ".join(f"{self.address_to_msg_name[addr].decode()} ({hex(addr)})" for addr in unchecked)
raise RuntimeError(f"Unchecked addrs: {err_msg}")
cdef vector[SignalParseOptions] signal_options_v
cdef SignalParseOptions spo
for sig_name, sig_address in signals:
spo.address = sig_address
spo.name = sig_name
signal_options_v.push_back(spo)
message_options = dict((address, 0) for _, address in signals)
message_options.update(dict(checks))
cdef vector[MessageParseOptions] message_options_v
cdef MessageParseOptions mpo
for msg_address, freq in message_options.items():
mpo.address = msg_address
mpo.check_frequency = freq
message_options_v.push_back(mpo)
self.can = new cpp_CANParser(bus, dbc_name, message_options_v, signal_options_v)
self.update_strings([]) self.update_strings([])
def update_strings(self, strings, sendcan=False): def update_strings(self, strings, sendcan=False):

@ -176,12 +176,13 @@ BO_ 489 EBCMVehicleDynamic: 8 K17_EBCM
SG_ YawRate : 35|12@0- (0.625,0) [0|1] "" NEO SG_ YawRate : 35|12@0- (0.625,0) [0|1] "" NEO
SG_ YawRate2 : 51|12@0- (0.0625,0) [-2047|2047] "grad/s" NEO SG_ YawRate2 : 51|12@0- (0.0625,0) [-2047|2047] "grad/s" NEO
BO_ 352 VehicleIgnition: 5 XXX BO_ 352 BCMImmobilizer: 5 K9_BCM
SG_ Ignition : 7|32@0+ (1,0) [0|4294967295] "" XXX SG_ ImmobilizerInfo : 7|32@0+ (1,0) [0|4294967295] "" XXX
BO_ 497 VehicleIgnitionAlt: 8 XXX BO_ 497 BCMGeneralPlatformStatus: 8 K9_BCM
SG_ Ignition : 5|1@0+ (1,0) [0|1] "" XXX SG_ SystemPowerMode : 1|2@0+ (1,0) [0|3] "" XXX
SG_ ParkBrake : 36|1@0+ (1,0) [0|3] "" XXX SG_ SystemBackUpPowerMode : 5|2@0+ (1,0) [0|3] "" XXX
SG_ ParkBrakeSwActive : 36|1@0+ (1,0) [0|3] "" XXX
BO_ 501 ECMPRDNL2: 8 K20_ECM BO_ 501 ECMPRDNL2: 8 K20_ECM
SG_ TransmissionState : 48|4@1+ (1,0) [0|7] "" NEO SG_ TransmissionState : 48|4@1+ (1,0) [0|7] "" NEO
@ -194,7 +195,7 @@ BO_ 532 BRAKE_RELATED: 6 XXX
BO_ 560 EPBStatus: 8 EPB BO_ 560 EPBStatus: 8 EPB
SG_ EPBClosed : 12|1@0+ (1,0) [0|1] "" NEO SG_ EPBClosed : 12|1@0+ (1,0) [0|1] "" NEO
BO_ 562 EBCMFrictionBrakeStatus: 8 XXX BO_ 562 EBCMFrictionBrakeStatus: 8 K17_EBCM
SG_ FrictionBrakeUnavailable : 46|1@0+ (1,0) [0|1] "" XXX SG_ FrictionBrakeUnavailable : 46|1@0+ (1,0) [0|1] "" XXX
BO_ 608 SPEED_RELATED: 8 XXX BO_ 608 SPEED_RELATED: 8 XXX
@ -316,11 +317,12 @@ CM_ BU_ K124_ASCM "Active Safety Control Module";
CM_ SG_ 381 MSG17D_AccPower "Need to investigate"; CM_ SG_ 381 MSG17D_AccPower "Need to investigate";
CM_ BO_ 190 "Length varies from 6 to 8 bytes by car"; CM_ BO_ 190 "Length varies from 6 to 8 bytes by car";
CM_ SG_ 190 GasPedalAndAcc "ACC baseline is 62"; CM_ SG_ 190 GasPedalAndAcc "ACC baseline is 62";
CM_ SG_ 352 Ignition "Non-zero when ignition is on"; CM_ SG_ 352 ImmobilizerInfo "Non-zero when ignition or accessory mode";
CM_ SG_ 451 GasPedalAndAcc2 "ACC baseline is 62"; CM_ SG_ 451 GasPedalAndAcc2 "ACC baseline is 62";
CM_ SG_ 481 ACCAlwaysOne "Usually 1 if the car is equipped with ACC"; CM_ SG_ 481 ACCAlwaysOne "Usually 1 if the car is equipped with ACC";
CM_ SG_ 562 FrictionBrakeUnavailable "1 when ACC brake control is unavailable. Stays high if brake command messages are blocked for a period of time"; CM_ SG_ 562 FrictionBrakeUnavailable "1 when ACC brake control is unavailable. Stays high if brake command messages are blocked for a period of time";
CM_ SG_ 497 Ignition "Describes ignition + preconditioning mode, noisy"; CM_ SG_ 497 SystemPowerMode "Describes ignition";
CM_ SG_ 497 SystemBackUpPowerMode "Describes ignition + preconditioning mode, noisy";
CM_ SG_ 501 PRNDL2 "When ManualMode is Active, Value is 13=L1 12=L2 11=L3 ... 4=L10"; CM_ SG_ 501 PRNDL2 "When ManualMode is Active, Value is 13=L1 12=L2 11=L3 ... 4=L10";
CM_ SG_ 532 UserBrakePressure "can be lower than other brake position signals when the brakes are pre-filled from ACC braking and the user presses on the brakes. user-only pressure?"; CM_ SG_ 532 UserBrakePressure "can be lower than other brake position signals when the brakes are pre-filled from ACC braking and the user presses on the brakes. user-only pressure?";
CM_ SG_ 608 ClusterSpeed "Cluster speed signal seems to match dash on newer cars, but is a lower rate and can be noisier."; CM_ SG_ 608 ClusterSpeed "Cluster speed signal seems to match dash on newer cars, but is a lower rate and can be noisier.";
@ -335,6 +337,8 @@ BA_DEF_DEF_ "BusType" "";
BA_ "BusType" "CAN"; BA_ "BusType" "CAN";
BA_ "ProtocolType" "GMLAN"; BA_ "ProtocolType" "GMLAN";
BA_ "UseGMParameterIDs" 0; BA_ "UseGMParameterIDs" 0;
VAL_ 497 SystemPowerMode 3 "Crank Request" 2 "Run" 1 "Accessory" 0 "Off";
VAL_ 497 SystemBackUpPowerMode 3 "Crank Request" 2 "Run" 1 "Accessory" 0 "Off";
VAL_ 481 DistanceButton 1 "Active" 0 "Inactive" ; VAL_ 481 DistanceButton 1 "Active" 0 "Inactive" ;
VAL_ 481 LKAButton 1 "Active" 0 "Inactive" ; VAL_ 481 LKAButton 1 "Active" 0 "Inactive" ;
VAL_ 481 ACCButtons 6 "Cancel" 5 "Main" 3 "Set" 2 "Resume" 1 "None" ; VAL_ 481 ACCButtons 6 "Cancel" 5 "Main" 3 "Set" 2 "Resume" 1 "None" ;

@ -65,7 +65,7 @@ BO_ 80 LKAS: 16 XXX
SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
SG_ SET_ME_1 : 80|1@0+ (1,0) [0|1] "" XXX SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_3 : 111|8@0+ (1,0) [0|255] "" XXX SG_ NEW_SIGNAL_3 : 111|8@0+ (1,0) [0|255] "" XXX
SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
@ -98,10 +98,10 @@ BO_ 160 WHEEL_SPEEDS: 24 XXX
SG_ MOVING_BACKWARD : 57|1@0+ (1,0) [0|1] "" XXX SG_ MOVING_BACKWARD : 57|1@0+ (1,0) [0|1] "" XXX
SG_ MOVING_FORWARD2 : 58|1@0+ (1,0) [0|1] "" XXX SG_ MOVING_FORWARD2 : 58|1@0+ (1,0) [0|1] "" XXX
SG_ MOVING_BACKWARD2 : 59|1@0+ (1,0) [0|1] "" XXX SG_ MOVING_BACKWARD2 : 59|1@0+ (1,0) [0|1] "" XXX
SG_ WHEEL_SPEED_1 : 64|16@1+ (0.03125,0) [0|65535] "m/s" XXX SG_ WHEEL_SPEED_1 : 64|16@1+ (0.03125,0) [0|65535] "kph" XXX
SG_ WHEEL_SPEED_2 : 80|16@1+ (0.03125,0) [0|65535] "m/s" XXX SG_ WHEEL_SPEED_2 : 80|16@1+ (0.03125,0) [0|65535] "kph" XXX
SG_ WHEEL_SPEED_3 : 96|16@1+ (0.03125,0) [0|65535] "m/s" XXX SG_ WHEEL_SPEED_3 : 96|16@1+ (0.03125,0) [0|65535] "kph" XXX
SG_ WHEEL_SPEED_4 : 112|16@1+ (0.03125,0) [0|65535] "m/s" XXX SG_ WHEEL_SPEED_4 : 112|16@1+ (0.03125,0) [0|65535] "kph" XXX
BO_ 234 MDPS: 24 XXX BO_ 234 MDPS: 24 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@ -124,6 +124,23 @@ BO_ 261 ACCELERATOR_ALT: 32 XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ ACCELERATOR_PEDAL : 103|10@1+ (0.25,0) [0|1022] "" XXX SG_ ACCELERATOR_PEDAL : 103|10@1+ (0.25,0) [0|1022] "" XXX
BO_ 272 LKAS_ALT: 32 XXX
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_1 : 27|2@1+ (1,0) [0|255] "" XXX
SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_3 : 111|8@0+ (1,0) [0|255] "" XXX
SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
BO_ 293 STEERING_SENSORS: 16 XXX BO_ 293 STEERING_SENSORS: 16 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
@ -143,7 +160,7 @@ BO_ 298 LFA: 16 ADRV
SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
SG_ SET_ME_1 : 80|1@0+ (1,0) [0|1] "" XXX SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_3 : 111|8@0+ (1,0) [0|255] "" XXX SG_ NEW_SIGNAL_3 : 111|8@0+ (1,0) [0|255] "" XXX
BO_ 304 GEAR_SHIFTER: 16 XXX BO_ 304 GEAR_SHIFTER: 16 XXX
@ -453,7 +470,10 @@ BO_ 676 CAM_0x2a4: 24 XXX
SG_ BYTE4 : 32|8@1+ (1,0) [0|255] "" XXX SG_ BYTE4 : 32|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE5 : 40|8@1+ (1,0) [0|255] "" XXX SG_ BYTE5 : 40|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE6 : 48|8@1+ (1,0) [0|255] "" XXX SG_ BYTE6 : 48|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE7 : 56|8@1+ (1,0) [0|255] "" XXX SG_ LEFT_LANE_LINE : 56|2@1+ (1,0) [0|3] "" XXX
SG_ SET_ME_0 : 58|2@1+ (1,0) [0|3] "" XXX
SG_ RIGHT_LANE_LINE : 60|2@1+ (1,0) [0|3] "" XXX
SG_ SET_ME_0_2 : 62|2@1+ (1,0) [0|3] "" XXX
SG_ BYTE8 : 64|8@1+ (1,0) [0|255] "" XXX SG_ BYTE8 : 64|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE9 : 72|8@1+ (1,0) [0|255] "" XXX SG_ BYTE9 : 72|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE10 : 80|8@1+ (1,0) [0|255] "" XXX SG_ BYTE10 : 80|8@1+ (1,0) [0|255] "" XXX
@ -487,11 +507,55 @@ BO_ 702 CAM_0x2be: 32 CAMERA
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
BO_ 736 MANUAL_SPEED_LIMIT_ASSIST: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ MSLA_STATUS : 26|2@1+ (1,0) [0|3] "" XXX
SG_ MSLA_ENABLED : 38|1@1+ (1,0) [0|1] "" XXX
SG_ MAX_SPEED : 55|8@0+ (1,0) [0|255] "" XXX
SG_ MAX_SPEED_COPY : 144|8@1+ (1,0) [0|255] "" XXX
BO_ 837 ADRV_0x345: 8 ADRV BO_ 837 ADRV_0x345: 8 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ SET_ME_15 : 24|8@1+ (1,0) [0|255] "" XXX SG_ SET_ME_15 : 24|8@1+ (1,0) [0|255] "" XXX
BO_ 866 CAM_0x362: 32 CAMERA
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE3 : 24|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE4 : 32|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE5 : 40|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE6 : 48|8@1+ (1,0) [0|255] "" XXX
SG_ LEFT_LANE_LINE : 56|2@1+ (1,0) [0|3] "" XXX
SG_ SET_ME_0 : 58|2@1+ (1,0) [0|3] "" XXX
SG_ RIGHT_LANE_LINE : 60|2@1+ (1,0) [0|3] "" XXX
SG_ SET_ME_0_2 : 62|2@1+ (1,0) [0|3] "" XXX
SG_ BYTE8 : 64|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE9 : 72|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE10 : 80|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE11 : 88|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE12 : 96|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE13 : 104|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE14 : 112|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE15 : 120|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE16 : 128|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE17 : 136|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE18 : 144|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE19 : 152|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE20 : 160|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE21 : 168|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE22 : 176|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE23 : 184|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE24 : 192|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE25 : 200|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE26 : 208|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE27 : 216|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE28 : 224|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE29 : 232|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE30 : 240|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE31 : 248|8@1+ (1,0) [0|255] "" XXX
BO_ 961 BLINKER_STALKS: 8 XXX BO_ 961 BLINKER_STALKS: 8 XXX
SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM_MAYBE : 7|8@0+ (1,0) [0|255] "" XXX SG_ CHECKSUM_MAYBE : 7|8@0+ (1,0) [0|255] "" XXX
@ -512,9 +576,14 @@ BO_ 1041 DOORS_SEATBELTS: 8 XXX
SG_ PASSENGER_SEATBELT : 36|1@0+ (1,0) [0|1] "" XXX SG_ PASSENGER_SEATBELT : 36|1@0+ (1,0) [0|1] "" XXX
BO_ 1043 BLINKERS: 8 XXX BO_ 1043 BLINKERS: 8 XXX
SG_ LEFT_STALK : 8|1@0+ (1,0) [0|1] "" XXX
SG_ RIGHT_STALK : 10|1@0+ (1,0) [0|1] "" XXX
SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX
SG_ LEFT_LAMP : 20|1@0+ (1,0) [0|1] "" XXX SG_ LEFT_LAMP : 20|1@0+ (1,0) [0|1] "" XXX
SG_ RIGHT_LAMP : 22|1@0+ (1,0) [0|1] "" XXX SG_ RIGHT_LAMP : 22|1@0+ (1,0) [0|1] "" XXX
SG_ LEFT_LAMP_ALT : 59|1@0+ (1,0) [0|1] "" XXX
SG_ RIGHT_LAMP_ALT : 61|1@0+ (1,0) [0|1] "" XXX
SG_ USE_ALT_LAMP : 62|1@0+ (1,0) [0|1] "" XXX
BO_ 1240 CLUSTER_INFO: 8 XXX BO_ 1240 CLUSTER_INFO: 8 XXX
SG_ DISTANCE_UNIT : 0|1@1+ (1,0) [0|1] "" XXX SG_ DISTANCE_UNIT : 0|1@1+ (1,0) [0|1] "" XXX
@ -589,7 +658,12 @@ BO_ 1264 LOCAL_TIME: 8 XXX
SG_ MINUTES : 21|6@0+ (1,0) [0|63] "" XXX SG_ MINUTES : 21|6@0+ (1,0) [0|63] "" XXX
SG_ SECONDS : 31|8@0+ (1,0) [0|59] "" XXX SG_ SECONDS : 31|8@0+ (1,0) [0|59] "" XXX
CM_ 272 "Alternative LKAS message, used on cars such as 2023 Ioniq 6, 2nd gen Kona. Matches LKAS except size is 32 bytes";
CM_ 676 "Contains signals with detailed lane line information. Used by ADAS ECU on HDA 2 vehicles to operate LFA.";
CM_ 866 "Contains signals with detailed lane line information. Used by ADAS ECU on HDA 2 vehicles to operate LFA. Used on cars that use message 272.";
CM_ 1043 "Lamp signals do not seem universal on cars that use LKAS_ALT, but stalk signals do.";
CM_ SG_ 80 HAS_LANE_SAFETY "If 0, hides LKAS 'Lane Safety' menu from vehicle settings";
CM_ SG_ 96 BRAKE_PRESSURE "User applied brake pedal pressure. Ramps from computer applied pressure on falling edge of cruise. Cruise cancels if !=0"; CM_ SG_ 96 BRAKE_PRESSURE "User applied brake pedal pressure. Ramps from computer applied pressure on falling edge of cruise. Cruise cancels if !=0";
CM_ SG_ 101 BRAKE_POSITION "User applied brake pedal position, max is ~700. Signed on some vehicles"; CM_ SG_ 101 BRAKE_POSITION "User applied brake pedal position, max is ~700. Signed on some vehicles";
CM_ SG_ 373 PROBABLY_EQUIP "aeb equip?"; CM_ SG_ 373 PROBABLY_EQUIP "aeb equip?";
@ -598,9 +672,15 @@ CM_ SG_ 373 DriverBraking "Likely derived from BRAKE->BRAKE_POSITION";
CM_ SG_ 373 DriverBrakingLowSens "Higher threshold version of DriverBraking"; CM_ SG_ 373 DriverBrakingLowSens "Higher threshold version of DriverBraking";
CM_ SG_ 352 SET_ME_9 "has something to do with AEB settings"; CM_ SG_ 352 SET_ME_9 "has something to do with AEB settings";
CM_ SG_ 416 VSetDis "set speed in display units"; CM_ SG_ 416 VSetDis "set speed in display units";
CM_ SG_ 676 LEFT_LANE_LINE "Left lane line confidence";
CM_ SG_ 676 RIGHT_LANE_LINE "Right lane line confidence";
CM_ SG_ 736 MAX_SPEED "Display units. Restricts car from driving above this speed unless accelerator pedal is depressed beyond pressure point";
CM_ SG_ 866 LEFT_LANE_LINE "Left lane line confidence";
CM_ SG_ 866 RIGHT_LANE_LINE "Right lane line confidence";
CM_ SG_ 961 COUNTER_ALT "only increments on change"; CM_ SG_ 961 COUNTER_ALT "only increments on change";
CM_ SG_ 1041 COUNTER_ALT "only increments on change"; CM_ SG_ 1041 COUNTER_ALT "only increments on change";
CM_ SG_ 1043 COUNTER_ALT "only increments on change"; CM_ SG_ 1043 COUNTER_ALT "only increments on change";
CM_ SG_ 1043 USE_ALT_LAMP "likely 1 on cars that use alt lamp signals";
VAL_ 53 GEAR 0 "P" 5 "D" 6 "N" 7 "R" ; VAL_ 53 GEAR 0 "P" 5 "D" 6 "N" 7 "R" ;
VAL_ 64 GEAR 0 "P" 5 "D" 6 "N" 7 "R" ; VAL_ 64 GEAR 0 "P" 5 "D" 6 "N" 7 "R" ;
VAL_ 69 GEAR 0 "P" 5 "D" 6 "N" 7 "R" ; VAL_ 69 GEAR 0 "P" 5 "D" 6 "N" 7 "R" ;
@ -609,6 +689,8 @@ VAL_ 80 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green" ;
VAL_ 80 LKA_MODE 1 "warning only" 2 "assist" 6 "off" ; VAL_ 80 LKA_MODE 1 "warning only" 2 "assist" 6 "off" ;
VAL_ 96 TRACTION_AND_STABILITY_CONTROL 0 "On" 5 "Limited" 1 "Off"; VAL_ 96 TRACTION_AND_STABILITY_CONTROL 0 "On" 5 "Limited" 1 "Off";
VAL_ 234 LKA_FAULT 0 "ok" 1 "lka fault" ; VAL_ 234 LKA_FAULT 0 "ok" 1 "lka fault" ;
VAL_ 272 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green" ;
VAL_ 272 LKA_MODE 1 "warning only" 2 "assist" 6 "off" ;
VAL_ 298 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green" ; VAL_ 298 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green" ;
VAL_ 298 LKA_MODE 1 "warning only" 2 "assist" 6 "off" ; VAL_ 298 LKA_MODE 1 "warning only" 2 "assist" 6 "off" ;
VAL_ 304 PARK_BUTTON 1 "Pressed" 2 "Not Pressed"; VAL_ 304 PARK_BUTTON 1 "Pressed" 2 "Not Pressed";
@ -622,6 +704,11 @@ VAL_ 426 CRUISE_BUTTONS 0 "none" 1 "res_accel" 2 "set_decel" 3 "gap_distance" 4
VAL_ 463 CRUISE_BUTTONS 0 "none" 1 "res_accel" 2 "set_decel" 3 "gap_distance" 4 "pause_resume" ; VAL_ 463 CRUISE_BUTTONS 0 "none" 1 "res_accel" 2 "set_decel" 3 "gap_distance" 4 "pause_resume" ;
VAL_ 463 RIGHT_PADDLE 0 "Not Pulled" 1 "Pulled"; VAL_ 463 RIGHT_PADDLE 0 "Not Pulled" 1 "Pulled";
VAL_ 463 LEFT_PADDLE 0 "Not Pulled" 1 "Pulled"; VAL_ 463 LEFT_PADDLE 0 "Not Pulled" 1 "Pulled";
VAL_ 676 LEFT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
VAL_ 676 RIGHT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
VAL_ 736 MSLA_STATUS 0 "disabled" 1 "active" 2 "paused";
VAL_ 866 LEFT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
VAL_ 866 RIGHT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
VAL_ 1041 DRIVER_DOOR 0 "Closed" 1 "Opened"; VAL_ 1041 DRIVER_DOOR 0 "Closed" 1 "Opened";
VAL_ 1041 PASSENGER_DOOR 0 "Closed" 1 "Opened"; VAL_ 1041 PASSENGER_DOOR 0 "Closed" 1 "Opened";
VAL_ 1041 DRIVER_REAR_DOOR 0 "Closed" 1 "Opened"; VAL_ 1041 DRIVER_REAR_DOOR 0 "Closed" 1 "Opened";

@ -1645,6 +1645,7 @@ BO_ 1348 Navi_HU: 8 XXX
CM_ "BO_ E_EMS11: All (plug-in) hybrids use this gas signal: CR_Vcu_AccPedDep_Pos, and all EVs use the Accel_Pedal_Pos signal. See hyundai/values.py for a specific car list"; CM_ "BO_ E_EMS11: All (plug-in) hybrids use this gas signal: CR_Vcu_AccPedDep_Pos, and all EVs use the Accel_Pedal_Pos signal. See hyundai/values.py for a specific car list";
CM_ SG_ 871 CF_Lvr_IsgState "Idle Stop and Go"; CM_ SG_ 871 CF_Lvr_IsgState "Idle Stop and Go";
CM_ SG_ 1056 SCCInfoDisplay "Goes to 1 for a second while transitioning from Cruise Control to No Message";
CM_ SG_ 1348 SpeedLim_Nav_Clu "Speed limit displayed on Nav, Cluster and HUD"; CM_ SG_ 1348 SpeedLim_Nav_Clu "Speed limit displayed on Nav, Cluster and HUD";
VAL_ 274 CUR_GR 1 "D" 2 "D" 3 "D" 4 "D" 5 "D" 6 "D" 7 "D" 8 "D" 14 "R" 0 "P"; VAL_ 274 CUR_GR 1 "D" 2 "D" 3 "D" 4 "D" 5 "D" 6 "D" 7 "D" 8 "D" 14 "R" 0 "P";
@ -1654,6 +1655,7 @@ VAL_ 882 Elect_Gear_Shifter 5 "D" 8 "S" 6 "N" 7 "R" 0 "P";
VAL_ 905 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault" 4 "cancelled"; VAL_ 905 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault" 4 "cancelled";
VAL_ 909 CF_VSM_Warn 2 "FCW" 3 "AEB"; VAL_ 909 CF_VSM_Warn 2 "FCW" 3 "AEB";
VAL_ 916 ACCEnable 0 "SCC ready" 1 "SCC temp fault" 2 "SCC permanent fault" 3 "SCC permanent fault, communication issue"; VAL_ 916 ACCEnable 0 "SCC ready" 1 "SCC temp fault" 2 "SCC permanent fault" 3 "SCC permanent fault, communication issue";
VAL_ 1056 SCCInfoDisplay 0 "No Message" 2 "Cruise Control" 3 "Lost Lead" 4 "Standstill";
VAL_ 1057 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault"; VAL_ 1057 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault";
VAL_ 1157 HDA_Icon_State 0 "no_hda" 1 "white_hda" 2 "green_hda"; VAL_ 1157 HDA_Icon_State 0 "no_hda" 1 "white_hda" 2 "green_hda";
VAL_ 1157 LFA_SysWarning 0 "no_message" 1 "switching_to_hda" 2 "switching_to_scc" 3 "lfa_error" 4 "check_hda" 5 "keep_hands_on_wheel_orange" 6 "keep_hands_on_wheel_red"; VAL_ 1157 LFA_SysWarning 0 "no_message" 1 "switching_to_hda" 2 "switching_to_scc" 3 "lfa_error" 4 "check_hda" 5 "keep_hands_on_wheel_orange" 6 "keep_hands_on_wheel_red";

@ -209,6 +209,8 @@ BO_ 1088 CAM_LANEINFO: 8 XXX
SG_ LINE_VISIBLE : 0|1@0+ (1,0) [0|3] "" XXX SG_ LINE_VISIBLE : 0|1@0+ (1,0) [0|3] "" XXX
SG_ LDW_WARN_RL : 58|1@0+ (1,0) [0|1] "" XXX SG_ LDW_WARN_RL : 58|1@0+ (1,0) [0|1] "" XXX
SG_ LDW_WARN_LL : 57|1@0+ (1,0) [0|1] "" XXX SG_ LDW_WARN_LL : 57|1@0+ (1,0) [0|1] "" XXX
SG_ TJA : 38|3@0+ (1,0) [0|7] "" XXX
SG_ TJA_TRANSITION : 27|2@0+ (1,0) [0|63] "" XXX
BO_ 1479 NEW_MSG_470: 8 XXX BO_ 1479 NEW_MSG_470: 8 XXX
@ -554,6 +556,8 @@ BO_ 535 CURVE_CTRS: 8 XXX
BO_ 540 CRZ_CTRL: 8 XXX BO_ 540 CRZ_CTRL: 8 XXX
SG_ NEW_SIGNAL_6 : 10|1@0+ (1,0) [0|1] "" XXX SG_ NEW_SIGNAL_6 : 10|1@0+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_9 : 31|1@0+ (1,0) [0|255] "" XXX
SG_ ACC_GAS_MAYBE2 : 29|1@0+ (1,0) [0|1] "" XXX
SG_ HANDS_OFF_STEERING : 48|1@0+ (1,0) [0|1] "" XXX SG_ HANDS_OFF_STEERING : 48|1@0+ (1,0) [0|1] "" XXX
SG_ HANDS_ON_STEER_WARN : 59|4@0+ (1,0) [0|255] "" XXX SG_ HANDS_ON_STEER_WARN : 59|4@0+ (1,0) [0|255] "" XXX
SG_ CRZ_ACTIVE : 3|1@0+ (1,0) [0|1] "" XXX SG_ CRZ_ACTIVE : 3|1@0+ (1,0) [0|1] "" XXX
@ -561,7 +565,9 @@ BO_ 540 CRZ_CTRL: 8 XXX
SG_ DISTANCE_SETTING : 20|3@0+ (1,0) [0|7] "" XXX SG_ DISTANCE_SETTING : 20|3@0+ (1,0) [0|7] "" XXX
SG_ MSG_1_INV : 1|1@0+ (1,0) [0|1] "" XXX SG_ MSG_1_INV : 1|1@0+ (1,0) [0|1] "" XXX
SG_ MSG_1_COPY : 9|1@0+ (1,0) [0|1] "" XXX SG_ MSG_1_COPY : 9|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_GAS_MAYBE : 23|1@0+ (1,0) [0|31] "" XXX
SG_ ACC_ACTIVE_2 : 52|1@0+ (1,0) [0|1] "" XXX SG_ ACC_ACTIVE_2 : 52|1@0+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_10 : 30|1@0+ (1,0) [0|1] "" XXX
SG_ MSG_1 : 0|1@0+ (1,0) [0|3] "" XXX SG_ MSG_1 : 0|1@0+ (1,0) [0|3] "" XXX
SG_ 5_SEC_DISABLE_TIMER : 45|3@0+ (1,0) [0|7] "" XXX SG_ 5_SEC_DISABLE_TIMER : 45|3@0+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_3 : 13|1@0+ (1,0) [0|3] "" XXX SG_ NEW_SIGNAL_3 : 13|1@0+ (1,0) [0|3] "" XXX
@ -701,6 +707,12 @@ BO_ 1143 BSM: 8 XXX
SG_ NEW_SIGNAL_1 : 32|1@0+ (1,0) [0|1] "" XXX SG_ NEW_SIGNAL_1 : 32|1@0+ (1,0) [0|1] "" XXX
SG_ REAR_CT_ALERT : 23|5@0+ (1,0) [0|63] "" XXX SG_ REAR_CT_ALERT : 23|5@0+ (1,0) [0|63] "" XXX
BO_ 480 ACCEL_TEST: 8 XXX
SG_ ACCEL_COMMAND : 7|32@0- (1,0) [-2147483647|2147483647] "" XXX
SG_ ENABLED : 32|1@0+ (1,0) [0|1] "" XXX
SG_ STARTING : 40|1@0+ (1,0) [0|1] "" XXX
SG_ STOPPING : 48|1@0+ (1,0) [0|1] "" XXX
BO_ 1361 KEY_POSITION: 8 XXX BO_ 1361 KEY_POSITION: 8 XXX
BO_ 1283 KEY_POSITION2: 8 XXX BO_ 1283 KEY_POSITION2: 8 XXX
@ -760,6 +772,8 @@ CM_ SG_ 1157 LKAS_SENSETIVITY "0 low, 1 high";
CM_ SG_ 1157 LANEE_DEPARTURE_ALERT "1 off, 2 on"; CM_ SG_ 1157 LANEE_DEPARTURE_ALERT "1 off, 2 on";
CM_ SG_ 1157 WARNING "1 Rare, 0 often"; CM_ SG_ 1157 WARNING "1 Rare, 0 often";
CM_ SG_ 1088 LANE_LINES "0 LKAS disabled, 1 no lines, 2 two lines, 3 left line, 4 right line"; CM_ SG_ 1088 LANE_LINES "0 LKAS disabled, 1 no lines, 2 two lines, 3 left line, 4 right line";
CM_ SG_ 1088 TJA "2: crz not active, 3: TJA not allowed, 4: TJA allowed";
CM_ SG_ 1088 TJA_TRANSITION "3: if TJA signal is 3, otherwise set to 0";
CM_ SG_ 1045 ABS_MALFUNCTION "off: 0, solid: 1, slow blink: 2, fast blink: 3"; CM_ SG_ 1045 ABS_MALFUNCTION "off: 0, solid: 1, slow blink: 2, fast blink: 3";
CM_ SG_ 120 VEHICLE_ACC_X "Vehicle acceleration of X-axis wrt. NED frame."; CM_ SG_ 120 VEHICLE_ACC_X "Vehicle acceleration of X-axis wrt. NED frame.";
CM_ SG_ 120 VEHICLE_ACC_Y "Vehicle acceleration of Y-axis wrt. NED frame."; CM_ SG_ 120 VEHICLE_ACC_Y "Vehicle acceleration of Y-axis wrt. NED frame.";

@ -127,10 +127,11 @@ BO_ 338 Stalk: 8 XXX
BO_ 352 ES_Brake: 8 XXX BO_ 352 ES_Brake: 8 XXX
SG_ Brake_Pressure : 0|16@1+ (1,0) [0|255] "" XXX SG_ Brake_Pressure : 0|16@1+ (1,0) [0|255] "" XXX
SG_ Brake_Light : 20|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Brake_Lights : 20|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Fault : 21|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Fault : 21|1@1+ (1,0) [0|1] "" XXX
SG_ Brake_On : 22|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Brake_Active : 22|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Activated : 23|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Activated : 23|1@1+ (1,0) [0|1] "" XXX
SG_ SET_1 : 45|1@0+ (1,0) [0|1] "" XXX
SG_ COUNTER : 48|3@1+ (1,0) [0|7] "" XXX SG_ COUNTER : 48|3@1+ (1,0) [0|7] "" XXX
SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
@ -139,7 +140,7 @@ BO_ 353 ES_Distance: 8 XXX
SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX
SG_ Car_Follow : 16|1@1+ (1,0) [0|1] "" XXX SG_ Car_Follow : 16|1@1+ (1,0) [0|1] "" XXX
SG_ Signal2 : 17|3@1+ (1,0) [0|7] "" XXX SG_ Signal2 : 17|3@1+ (1,0) [0|7] "" XXX
SG_ Brake_On : 20|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Brake_Active : 20|1@1+ (1,0) [0|1] "" XXX
SG_ Distance_Swap : 21|1@1+ (1,0) [0|1] "" XXX SG_ Distance_Swap : 21|1@1+ (1,0) [0|1] "" XXX
SG_ Standstill : 22|1@1+ (1,0) [0|1] "" XXX SG_ Standstill : 22|1@1+ (1,0) [0|1] "" XXX
SG_ Signal3 : 23|1@1+ (1,0) [0|1] "" XXX SG_ Signal3 : 23|1@1+ (1,0) [0|1] "" XXX
@ -154,10 +155,10 @@ BO_ 353 ES_Distance: 8 XXX
SG_ Signal7 : 51|5@1+ (1,0) [0|31] "" XXX SG_ Signal7 : 51|5@1+ (1,0) [0|31] "" XXX
SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
BO_ 354 ES_RPM: 8 XXX BO_ 354 ES_Status: 8 XXX
SG_ Brake : 8|1@1+ (1,0) [0|1] "" XXX SG_ Brake : 8|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Activated : 9|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Activated : 9|1@1+ (1,0) [0|1] "" XXX
SG_ RPM : 16|16@1+ (1,0) [0|65535] "" XXX SG_ Cruise_RPM : 16|16@1+ (1,0) [0|65535] "" XXX
SG_ Checksum : 32|8@1+ (1,0) [0|255] "" XXX SG_ Checksum : 32|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 48|3@1+ (1,0) [0|7] "" XXX SG_ COUNTER : 48|3@1+ (1,0) [0|7] "" XXX

@ -140,11 +140,11 @@ BO_ 290 ES_LKAS: 8 XXX
SG_ LKAS_Output : 16|13@1- (-1,0) [-8191|8191] "" XXX SG_ LKAS_Output : 16|13@1- (-1,0) [-8191|8191] "" XXX
SG_ LKAS_Request : 29|1@0+ (1,0) [0|1] "" XXX SG_ LKAS_Request : 29|1@0+ (1,0) [0|1] "" XXX
BO_ 292 ES_LKAS_ALT: 8 XXX BO_ 292 ES_LKAS_ANGLE: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|1] "" XXX SG_ CHECKSUM : 0|8@1+ (1,0) [0|1] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|1] "" XXX SG_ COUNTER : 8|4@1+ (1,0) [0|1] "" XXX
SG_ LKAS_Request : 12|1@1+ (1,0) [0|1] "" XXX SG_ LKAS_Request : 12|1@1+ (1,0) [0|1] "" XXX
SG_ LKAS_Output : 40|17@1- (-1,0) [0|1] "" XXX SG_ LKAS_Output : 40|17@1- (-0.01,0) [0|1] "deg" XXX
SG_ SET_3 : 60|2@1+ (1,0) [0|1] "" XXX SG_ SET_3 : 60|2@1+ (1,0) [0|1] "" XXX
BO_ 544 ES_Brake: 8 XXX BO_ 544 ES_Brake: 8 XXX
@ -162,9 +162,9 @@ BO_ 544 ES_Brake: 8 XXX
BO_ 577 Cruise_Status: 8 XXX BO_ 577 Cruise_Status: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Cruise_Set_Speed : 51|12@0+ (1,0) [0|120] "" XXX
SG_ Cruise_On : 54|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_On : 54|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Activated : 55|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Activated : 55|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Active : 57|4@1+ (1,0) [0|15] "" XXX
BO_ 552 BSD_RCTA: 8 XXX BO_ 552 BSD_RCTA: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
@ -246,6 +246,14 @@ BO_ 802 ES_LKAS_State: 8 XXX
SG_ LKAS_Alert : 32|5@1+ (1,0) [0|31] "" XXX SG_ LKAS_Alert : 32|5@1+ (1,0) [0|31] "" XXX
SG_ Signal3 : 37|27@1+ (1,0) [0|1] "" XXX SG_ Signal3 : 37|27@1+ (1,0) [0|1] "" XXX
BO_ 803 ES_Infotainment: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ LKAS_Blue_Lines : 15|4@0+ (1,0) [0|15] "" XXX
SG_ Signal1 : 19|4@0+ (1,0) [0|15] "" XXX
SG_ LKAS_State_Infotainment : 22|3@0+ (1,0) [0|7] "" XXX
SG_ Signal2 : 24|1@0+ (1,0) [0|1] "" XXX
BO_ 722 AC_State: 8 XXX BO_ 722 AC_State: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
@ -257,6 +265,21 @@ BO_ 1677 Dash_State: 8 XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Units : 29|3@1+ (1,0) [0|7] "" XXX SG_ Units : 29|3@1+ (1,0) [0|7] "" XXX
BO_ 554 ES_HighBeamAssist: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ HBA_Available : 13|1@0+ (1,0) [0|1] "" XXX
BO_ 805 ES_STATIC_1: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ SET_3 : 23|2@0+ (1,0) [0|3] "" XXX
BO_ 289 ES_STATIC_2: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ SET_3 : 15|2@1+ (1,0) [0|3] "" XXX
CM_ SG_ 64 Throttle_Combo "Throttle Cruise + Pedal"; CM_ SG_ 64 Throttle_Combo "Throttle Cruise + Pedal";
CM_ SG_ 313 Brake_Lights "Driver or Cruise Brake on"; CM_ SG_ 313 Brake_Lights "Driver or Cruise Brake on";
CM_ SG_ 544 Cruise_Brake_Lights "1 = switch on brake lights"; CM_ SG_ 544 Cruise_Brake_Lights "1 = switch on brake lights";
@ -287,7 +310,7 @@ BO_ 72 Transmission: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Gear : 24|8@1+ (1,0) [0|255] "" XXX SG_ Gear : 24|8@1+ (1,0) [0|255] "" XXX
SG_ RPM : 40|16@1+ (1,0) [0|65535] "" XXX SG_ RPM : 40|15@1+ (1,0) [0|65535] "" XXX
BO_ 73 CVT: 8 XXX BO_ 73 CVT: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
@ -302,7 +325,7 @@ BO_ 545 ES_Distance: 8 XXX
SG_ Cruise_Throttle : 16|12@1+ (1,0) [0|4095] "" XXX SG_ Cruise_Throttle : 16|12@1+ (1,0) [0|4095] "" XXX
SG_ Signal2 : 28|4@1+ (1,0) [0|15] "" XXX SG_ Signal2 : 28|4@1+ (1,0) [0|15] "" XXX
SG_ Car_Follow : 32|1@1+ (1,0) [0|1] "" XXX SG_ Car_Follow : 32|1@1+ (1,0) [0|1] "" XXX
SG_ Signal3 : 33|1@1+ (1,0) [0|1] "" XXX SG_ Low_Speed_Follow : 33|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Soft_Disable : 34|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Soft_Disable : 34|1@1+ (1,0) [0|1] "" XXX
SG_ Signal7 : 35|1@1+ (1,0) [0|1] "" XXX SG_ Signal7 : 35|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Brake_Active : 36|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Brake_Active : 36|1@1+ (1,0) [0|1] "" XXX
@ -336,14 +359,6 @@ BO_ 576 CruiseControl: 8 XXX
SG_ Cruise_Activated : 41|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Activated : 41|1@1+ (1,0) [0|1] "" XXX
SG_ Signal2 : 42|22@1+ (1,0) [0|4194303] "" XXX SG_ Signal2 : 42|22@1+ (1,0) [0|4194303] "" XXX
BO_ 803 ES_Infotainment: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ LKAS_Blue_Lines : 15|4@0+ (1,0) [0|15] "" XXX
SG_ Signal1 : 19|4@0+ (1,0) [0|15] "" XXX
SG_ LKAS_State_Infotainment : 22|3@0+ (1,0) [0|7] "" XXX
SG_ Signal2 : 24|1@0+ (1,0) [0|1] "" XXX
CM_ SG_ 545 Cruise_Throttle "RPM-like output signal"; CM_ SG_ 545 Cruise_Throttle "RPM-like output signal";
CM_ SG_ 545 Cruise_EPB "1 = Electric Parking Brake set"; CM_ SG_ 545 Cruise_EPB "1 = Electric Parking Brake set";
CM_ SG_ 545 Distance_Swap "Switch from Close to Far distance"; CM_ SG_ 545 Distance_Swap "Switch from Close to Far distance";

@ -0,0 +1,324 @@
CM_ "AUTOGENERATED FILE, DO NOT EDIT";
CM_ "Imported file _subaru_global.dbc starts here";
VERSION ""
NS_ :
NS_DESC_
CM_
BA_DEF_
BA_
VAL_
CAT_DEF_
CAT_
FILTER
BA_DEF_DEF_
EV_DATA_
ENVVAR_DATA_
SGTYPE_
SGTYPE_VAL_
BA_DEF_SGTYPE_
BA_SGTYPE_
SIG_TYPE_REF_
VAL_TABLE_
SIG_GROUP_
SIG_VALTYPE_
SIGTYPE_VALTYPE_
BO_TX_BU_
BA_DEF_REL_
BA_REL_
BA_DEF_DEF_REL_
BU_SG_REL_
BU_EV_REL_
BU_BO_REL_
SG_MUL_VAL_
BS_:
BU_: XXX X
BO_ 2 Steering: 8 XXX
SG_ Steering_Angle : 7|16@0- (0.1,0) [0|65535] "" XXX
SG_ COUNTER : 25|3@1+ (1,0) [0|7] "" XXX
SG_ CHECKSUM : 32|8@1+ (1,0) [0|255] "" XXX
BO_ 64 Throttle: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX
SG_ Engine_RPM : 16|12@1+ (1,0) [0|4095] "" XXX
SG_ Signal2 : 28|4@1+ (1,0) [0|15] "" XXX
SG_ Throttle_Pedal : 32|8@1+ (1,0) [0|255] "" XXX
SG_ Throttle_Cruise : 40|8@1+ (1,0) [0|255] "" XXX
SG_ Throttle_Combo : 48|8@1+ (1,0) [0|255] "" XXX
SG_ Signal3 : 56|4@1+ (1,0) [0|15] "" XXX
SG_ Off_Accel : 60|4@1+ (1,0) [0|15] "" XXX
BO_ 316 Brake_Status: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Signal1 : 12|46@1+ (1,0) [0|1] "" XXX
SG_ ES_Brake : 58|1@1+ (1,0) [0|1] "" XXX
SG_ Signal2 : 59|3@1+ (1,0) [0|1] "" XXX
SG_ Brake : 62|1@1+ (1,0) [0|1] "" XXX
SG_ Signal3 : 63|1@1+ (1,0) [0|1] "" XXX
BO_ 326 Cruise_Buttons: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Signal1 : 12|30@1+ (1,0) [0|1073741823] "" XXX
SG_ Main : 42|1@1+ (1,0) [0|1] "" XXX
SG_ Set : 43|1@1+ (1,0) [0|1] "" XXX
SG_ Resume : 44|1@1+ (1,0) [0|1] "" XXX
SG_ Signal2 : 45|19@1+ (1,0) [0|524287] "" XXX
BO_ 315 G_Sensor: 8 XXX
SG_ Lateral : 48|8@1- (-0.1,0) [0|255] "m/s2" XXX
SG_ Longitudinal : 56|8@1- (-0.1,0) [0|255] "m/s2" XXX
BO_ 314 Wheel_Speeds: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ FR : 12|13@1+ (0.057,0) [0|255] "kph" XXX
SG_ RR : 25|13@1+ (0.057,0) [0|255] "kph" XXX
SG_ FL : 51|13@1+ (0.057,0) [0|255] "kph" XXX
SG_ RL : 38|13@1+ (0.057,0) [0|255] "kph" XXX
BO_ 280 Steering_Torque_2: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Steer_Torque_Output : 13|11@1- (-10,0) [0|255] "" XXX
SG_ Signal1 : 24|8@1+ (1,0) [0|511] "" XXX
SG_ Steer_Torque_Sensor : 45|11@1- (-1,0) [0|255] "" XXX
SG_ Steering_Active : 61|1@0+ (1,0) [0|1] "" XXX
SG_ Steering_Disabled : 63|1@1+ (1,0) [0|1] "" XXX
BO_ 281 Steering_Torque: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Steer_Error_1 : 12|1@0+ (1,0) [0|1] "" XXX
SG_ Steer_Torque_Sensor : 16|11@1- (-1,0) [-1000|1000] "" XXX
SG_ Steer_Error_2 : 28|1@1+ (1,0) [0|1] "" XXX
SG_ Steer_Warning : 29|1@1+ (1,0) [0|1] "" XXX
SG_ Steering_Angle : 32|16@1- (-0.0217,0) [-600|600] "" X
SG_ Steer_Torque_Output : 48|11@1- (-10,0) [-1000|1000] "" XXX
BO_ 282 Steering_2: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|1] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|1] "" XXX
SG_ Steering_Angle : 24|17@1- (-0.01,0) [0|1] "" XXX
BO_ 312 Brake_Pressure_L_R: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Brake_1 : 48|8@1+ (1,0) [0|255] "" XXX
SG_ Brake_2 : 56|8@1+ (1,0) [0|255] "" XXX
BO_ 313 Brake_Pedal: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX
SG_ Speed : 16|12@1+ (0.05625,0) [0|255] "kph" XXX
SG_ Signal2 : 28|6@1+ (1,0) [0|63] "" XXX
SG_ Brake_Lights : 34|1@1+ (1,0) [0|1] "" XXX
SG_ Signal3 : 35|1@1+ (1,0) [0|1] "" XXX
SG_ Brake_Pedal : 36|12@1+ (1,0) [0|4095] "" XXX
SG_ Signal4 : 48|16@1+ (1,0) [0|65535] "" XXX
BO_ 372 Engine_Stop_Start: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
SG_ STOP_START_STATE : 39|2@0+ (1,0) [0|3] "" XXX
BO_ 290 ES_LKAS: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ SET_1 : 12|1@0+ (1,0) [0|1] "" XXX
SG_ LKAS_Output : 16|13@1- (-1,0) [-8191|8191] "" XXX
SG_ LKAS_Request : 29|1@0+ (1,0) [0|1] "" XXX
BO_ 292 ES_LKAS_ANGLE: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|1] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|1] "" XXX
SG_ LKAS_Request : 12|1@1+ (1,0) [0|1] "" XXX
SG_ LKAS_Output : 40|17@1- (-0.01,0) [0|1] "deg" XXX
SG_ SET_3 : 60|2@1+ (1,0) [0|1] "" XXX
BO_ 544 ES_Brake: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX
SG_ Brake_Pressure : 16|16@1+ (1,0) [0|65535] "" XXX
SG_ AEB_Status : 32|4@1+ (1,0) [0|15] "" XXX
SG_ Cruise_Brake_Lights : 36|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Brake_Fault : 37|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Brake_Active : 38|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Activated : 39|1@1+ (1,0) [0|1] "" XXX
SG_ Signal3 : 40|24@1+ (1,0) [0|16777215] "" XXX
BO_ 577 Cruise_Status: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Cruise_Set_Speed : 51|12@0+ (1,0) [0|120] "" XXX
SG_ Cruise_On : 54|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Activated : 55|1@1+ (1,0) [0|1] "" XXX
BO_ 552 BSD_RCTA: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ R_ADJACENT : 48|1@1+ (1,0) [0|1] "" XXX
SG_ L_ADJACENT : 49|1@1+ (1,0) [0|1] "" XXX
SG_ R_APPROACHING : 58|1@1+ (1,0) [0|1] "" XXX
SG_ L_APPROACHING : 59|1@1+ (1,0) [0|1] "" XXX
BO_ 912 Dashlights: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ UNITS : 24|1@1+ (1,0) [0|1] "" XXX
SG_ ICY_ROAD : 32|2@1+ (1,0) [0|3] "" XXX
SG_ SEATBELT_FL : 48|1@1+ (1,0) [0|1] "" XXX
SG_ LEFT_BLINKER : 50|1@1+ (1,0) [0|1] "" XXX
SG_ RIGHT_BLINKER : 51|1@1+ (1,0) [0|1] "" XXX
SG_ STOP_START : 54|1@0+ (1,0) [0|1] "" XXX
BO_ 940 BodyInfo: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ DOOR_OPEN_FL : 32|1@1+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_FR : 33|1@1+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_RL : 34|1@1+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_RR : 35|1@1+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_TRUNK : 36|1@0+ (1,0) [0|1] "" XXX
SG_ BRAKE : 54|1@1+ (1,0) [0|1] "" XXX
SG_ DASH_BTN_LIGHTS : 56|1@0+ (1,0) [0|1] "" XXX
SG_ LOWBEAM : 57|1@1+ (1,0) [0|1] "" XXX
SG_ HIGHBEAM : 58|1@1+ (1,0) [0|1] "" XXX
SG_ FOG_LIGHTS : 60|1@1+ (1,0) [0|1] "" XXX
SG_ WIPERS : 62|1@0+ (1,0) [0|1] "" XXX
BO_ 801 ES_DashStatus: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ PCB_Off : 12|1@1+ (1,0) [0|1] "" XXX
SG_ LDW_Off : 13|1@1+ (1,0) [0|1] "" XXX
SG_ Signal1 : 14|2@1+ (1,0) [0|3] "" XXX
SG_ Cruise_State_Msg : 16|4@1+ (1,0) [0|15] "" XXX
SG_ LKAS_State_Msg : 20|3@1+ (1,0) [0|7] "" XXX
SG_ Signal2 : 23|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Soft_Disable : 24|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Status_Msg : 25|2@1+ (1,0) [0|3] "" XXX
SG_ Signal3 : 27|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Distance : 28|3@1+ (1,0) [0|7] "" XXX
SG_ Signal4 : 31|1@1+ (1,0) [0|1] "" XXX
SG_ Conventional_Cruise : 32|1@1+ (1,0) [0|1] "" XXX
SG_ Signal5 : 33|2@1+ (1,0) [0|3] "" XXX
SG_ Cruise_Disengaged : 35|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Activated : 36|1@1+ (1,0) [0|1] "" XXX
SG_ Signal6 : 37|3@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Set_Speed : 40|8@1+ (1,0) [0|255] "" XXX
SG_ Cruise_Fault : 48|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_On : 49|1@1+ (1,0) [0|1] "" XXX
SG_ Display_Own_Car : 50|1@1+ (1,0) [0|1] "" XXX
SG_ Brake_Lights : 51|1@1+ (1,0) [0|1] "" XXX
SG_ Car_Follow : 52|1@1+ (1,0) [0|1] "" XXX
SG_ Signal7 : 53|3@1+ (1,0) [0|1] "" XXX
SG_ Far_Distance : 56|4@1+ (5,0) [0|75] "m" XXX
SG_ Cruise_State : 60|4@1+ (1,0) [0|15] "" XXX
BO_ 802 ES_LKAS_State: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ LKAS_Alert_Msg : 12|3@1+ (1,0) [0|7] "" XXX
SG_ Signal1 : 15|2@1+ (1,0) [0|3] "" XXX
SG_ LKAS_ACTIVE : 17|1@1+ (1,0) [0|1] "" XXX
SG_ LKAS_Dash_State : 18|2@1+ (1,0) [0|2] "" XXX
SG_ Signal2 : 20|3@1+ (1,0) [0|7] "" XXX
SG_ Backward_Speed_Limit_Menu : 23|1@1+ (1,0) [0|1] "" XXX
SG_ LKAS_Left_Line_Enable : 24|1@1+ (1,0) [0|1] "" XXX
SG_ LKAS_Left_Line_Light_Blink : 25|1@1+ (1,0) [0|1] "" XXX
SG_ LKAS_Right_Line_Enable : 26|1@1+ (1,0) [0|1] "" XXX
SG_ LKAS_Right_Line_Light_Blink : 27|1@1+ (1,0) [0|1] "" XXX
SG_ LKAS_Left_Line_Visible : 28|2@1+ (1,0) [0|3] "" XXX
SG_ LKAS_Right_Line_Visible : 30|2@1+ (1,0) [0|3] "" XXX
SG_ LKAS_Alert : 32|5@1+ (1,0) [0|31] "" XXX
SG_ Signal3 : 37|27@1+ (1,0) [0|1] "" XXX
BO_ 803 ES_Infotainment: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ LKAS_Blue_Lines : 15|4@0+ (1,0) [0|15] "" XXX
SG_ Signal1 : 19|4@0+ (1,0) [0|15] "" XXX
SG_ LKAS_State_Infotainment : 22|3@0+ (1,0) [0|7] "" XXX
SG_ Signal2 : 24|1@0+ (1,0) [0|1] "" XXX
BO_ 722 AC_State: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ AC_Mode : 37|3@1+ (1,0) [0|1] "" XXX
SG_ AC_ON : 24|2@1+ (1,0) [0|1] "" XXX
BO_ 1677 Dash_State: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Units : 29|3@1+ (1,0) [0|7] "" XXX
BO_ 554 ES_HighBeamAssist: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ HBA_Available : 13|1@0+ (1,0) [0|1] "" XXX
BO_ 805 ES_STATIC_1: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ SET_3 : 23|2@0+ (1,0) [0|3] "" XXX
BO_ 289 ES_STATIC_2: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ SET_3 : 15|2@1+ (1,0) [0|3] "" XXX
CM_ SG_ 64 Throttle_Combo "Throttle Cruise + Pedal";
CM_ SG_ 313 Brake_Lights "Driver or Cruise Brake on";
CM_ SG_ 544 Cruise_Brake_Lights "1 = switch on brake lights";
CM_ SG_ 544 Brake_Pressure "Winds down after cruise disabled. Also can be non-zero when likely preparing for AEB";
CM_ SG_ 544 Signal3 "Usually goes to 2 if AEB_Status is 4";
CM_ SG_ 544 AEB_Status "Occasionally is 4 instead of 8 while Brake_Pressure is non-zero, unsure why";
CM_ SG_ 801 PCB_Off "Pre-Collision Braking off";
CM_ SG_ 801 Brake_Lights "Driver or Cruise brake on";
CM_ SG_ 801 Cruise_State "0 = Normal, 1 = Hold+User Brake, 2 = Ready, 3 = Hold";
CM_ SG_ 801 Far_Distance "1=0-5m, 2=5-10m, 3=10-15m, 4=15-20m, 5=20-25m, 6=25-30m, 7=30-35m, 8=35-40m, 9=40-45m, 10=45-50m, 11=50-55m, 12=55-60m, 13=60-65m, 14=65-70m, 15=75m+";
CM_ SG_ 801 LKAS_State_Msg "1 = LKAS_Off_Sharp_Curve, 2 = Keep_Hands_On_Steering_wheel_disabled, 3 = LKAS_Off, 4 = LKAS_Off_Too_Slow, 5 = LKAS_Off_Too_Fast";
CM_ SG_ 801 Cruise_State_Msg "1 = Cruise_Off_Steep_Slope, 2 = Cruise_lvl1_eco, 3 = Cruise_lvl2_comfort, 4 = Cruise_off_empty_reason, 5 = Cruise_off, 6 = Cruise_Unable_to_set, 7 = Cruise_Unable_to_set_brakes_applied, 8 = Eyesight_not_ready, 9 = Cruise_lvl3_standard, 10 = Cruise_lvl4_dynamic, 11 = Cruise_Unable_to_set_steep_slope";
CM_ SG_ 801 Cruise_Soft_Disable "Eyesight soft disable (eg direct sunlight)";
CM_ SG_ 801 Cruise_Status_Msg "1 = Disabled_Bad_Visibility, 2 = Disabled_Check_Manual";
CM_ SG_ 802 LKAS_ACTIVE "Turns on the full LKAS dash display";
CM_ SG_ 802 LKAS_Alert_Msg "1 = Keep_Hands_On_Wheel, 6 = Pre_Collision_Braking, 7 = Keep_Hands_On_Wheel_Off";
CM_ SG_ 802 LKAS_Alert "1 = FCW_Cont_Beep, 2 = FCW_Repeated_Beep, 3 = Throttle_Management_Activated_Warning, 4 = Throttle_Management_Activated_Alert, 5 = Pre_Collision_Activated_Alert, 8 = Traffic_Light_Ahead, 9 = Apply_Brake_to_Hold Position, 11 = LDW_Right, 12 = LDW_Left, 13 = Stay_Alert, 14 = Lead_Vehicle_Start_Alert, 18 = Keep_Hands_On_Steering_Alert, 24 = Audio_Beep, 25 = Audio_Lead_Car_Change, 26 = Audio_ACC_Disengaged, 27 = Audio_LKAS_disabled, 28 = Audio_Ding_Ding, 30 = Audio_Repeated_Beep";
CM_ SG_ 802 LKAS_Left_Line_Visible "0 = Off, 1 = White, 2 = Green, 3 = Orange";
CM_ SG_ 802 LKAS_Dash_State "0 = Off, 1 = Ready, 2 = Active";
CM_ SG_ 802 LKAS_Right_Line_Visible "0 = Off, 1 = White, 2 = Green, 3 = Orange";
CM_ SG_ 912 UNITS "0 = Metric, 1 = Imperial";
CM_ SG_ 912 ICY_ROAD "1 = DASHLIGHT ON, 2 = WARNING, 3 = OFF";
VAL_ 544 AEB_Status 12 "AEB related" 8 "AEB actuation" 4 "AEB related" 0 "No AEB actuation";
CM_ "subaru_global_2020_hybrid.dbc starts here";
BO_ 39 Cruise_Status_2: 8 XXX
SG_ Cruise_Activated : 37|1@0+ (1,0) [0|1] "" XXX
BO_ 295 Transmission: 8 XXX
SG_ Gear : 44|4@1+ (1,0) [0|15] "" XXX
BO_ 360 Throttle_Hybrid: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Throttle_Pedal : 32|8@1+ (1,0) [0|255] "" XXX
BO_ 550 Brake_Hybrid: 8 XXX
SG_ Brake_Pedal : 24|8@1+ (1,0) [0|1] "" XXX
SG_ Brake : 37|1@1+ (1,0) [0|1] "" XXX
VAL_ 295 Gear 0 "P" 1 "R" 3 "D";

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

Loading…
Cancel
Save