mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-09-03 14:43:48 +08:00
Compare commits
465 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 08b519ca77 | |||
| 449cb11938 | |||
| 3d4c625deb | |||
| dff446fe5e | |||
| 75577ecfca | |||
| 41bca45bdd | |||
| 3ebc6b9903 | |||
| 5e13c2d61b | |||
| d646413db3 | |||
| d0fc9f9f46 | |||
| eef1d0513e | |||
| 401319431a | |||
| 6f49c1cfc9 | |||
| 9f2f79a652 | |||
| 4d9df8b147 | |||
| 138e4cca06 | |||
| 5d32cccaf1 | |||
| 764417845f | |||
| 3fb2bcdcee | |||
| d8ac4dc57a | |||
| 2620f9f9bd | |||
| 16e561c5b5 | |||
| 6420724913 | |||
| 388662ceb0 | |||
| b5286ec678 | |||
| aa9eeae40e | |||
| d426054dec | |||
| b22babb0b5 | |||
| 147b9df247 | |||
| 02a45f13a2 | |||
| 5f256e60d9 | |||
| b6964f0142 | |||
| 83c3ee8e26 | |||
| 7926c2183d | |||
| 7d39054b6c | |||
| 79fa8bd566 | |||
| ae82751776 | |||
| 0911d9c208 | |||
| 465ac2651a | |||
| 4486dc2f14 | |||
| f546a3e07a | |||
| 3acff1e3d7 | |||
| f198977141 | |||
| dc62d0e27a | |||
| 6b1ad03acf | |||
| ebb096a956 | |||
| 11b2987c50 | |||
| ec0ab9d300 | |||
| f501a4de37 | |||
| 63f8828c01 | |||
| aa1d691304 | |||
| ac95896551 | |||
| 443c35228d | |||
| 4d281c22d7 | |||
| 6c1ec6798f | |||
| 386a6f9216 | |||
| c02bb05113 | |||
| 695573c057 | |||
| f0d8de490c | |||
| 7bfe5ab830 | |||
| f07d588534 | |||
| a0aa48f82a | |||
| 3c852bdbb0 | |||
| f5ba6362ce | |||
| 2d93c29890 | |||
| c0b8f1cb01 | |||
| e19aed96da | |||
| f6d7442c05 | |||
| 8bcf4c7abf | |||
| f85bfb277b | |||
| b2602bc4e7 | |||
| 3e176f3884 | |||
| f79ab05fa5 | |||
| 5b47ff584a | |||
| af2e153e52 | |||
| b619371441 | |||
| e3bfb66ded | |||
| 328f2d9ff7 | |||
| 227b5cf82a | |||
| adb5058cb8 | |||
| 3c655e79a9 | |||
| 032f085500 | |||
| 5882bd23ba | |||
| 78aba03b4f | |||
| 2c002755c7 | |||
| b3c417ce05 | |||
| 00fc6d8158 | |||
| 81d20d304f | |||
| d683da24ea | |||
| 4509316877 | |||
| 47ccab65d9 | |||
| 979b297652 | |||
| 6a17743513 | |||
| e20ea5d0d1 | |||
| f20b256473 | |||
| a88da4071f | |||
| 9437efe93b | |||
| b7393ad04a | |||
| 1da3008676 | |||
| 7446b96939 | |||
| 145bf39587 | |||
| 31f00eaff7 | |||
| b381cc0c4a | |||
| 903631ee53 | |||
| f8d47139a3 | |||
| 89753b6194 | |||
| 0b9298e363 | |||
| fcf4d75c76 | |||
| 4db69dae3b | |||
| c82cc2ed9f | |||
| f30a8ea20e | |||
| 1a3b243233 | |||
| 68cef2d360 | |||
| 60aa4aad49 | |||
| 5c4f6ff353 | |||
| c1857824b7 | |||
| 468ba323fc | |||
| dfd9b54bf5 | |||
| b00888c858 | |||
| 0a89eaf255 | |||
| 931877feb9 | |||
| 71f35601d7 | |||
| 9eb5768d2a | |||
| 2ef545b987 | |||
| 83cec26dea | |||
| 0122e4069b | |||
| f857a55f59 | |||
| 05140149fb | |||
| 6a64493512 | |||
| 9c1d39b859 | |||
| ffab4a8321 | |||
| 71c1d79807 | |||
| 36d0c074f1 | |||
| 6dccb85b96 | |||
| d11ecaf457 | |||
| b302637e4d | |||
| e28f72c661 | |||
| 2db8d95905 | |||
| db5922db43 | |||
| 96f5819c6a | |||
| cfd221b89c | |||
| 013f8579d7 | |||
| 2b53b59bee | |||
| 33f6d69a32 | |||
| 58e919c264 | |||
| 17e5542b1b | |||
| e1458d4723 | |||
| 06f9e43e4e | |||
| f8e03a9fc5 | |||
| 7c6741a93e | |||
| 4b3372d006 | |||
| 9a9e7cd1e9 | |||
| 1d9fdc25ca | |||
| 05db925e93 | |||
| 2bd080821b | |||
| 651726bbb5 | |||
| 6eabec436d | |||
| 56d6a6ee47 | |||
| e9f4c6316c | |||
| 284dbddd8a | |||
| 0068d7a698 | |||
| f63ee3375a | |||
| 05e9dfd5d0 | |||
| 269562e73a | |||
| 3cefd789e5 | |||
| d477735c92 | |||
| 66893b27ae | |||
| e0d9e05f9f | |||
| 73f64ac754 | |||
| 5130168067 | |||
| 04a2530ace | |||
| 297358741a | |||
| 41b10d0184 | |||
| 49f061eee4 | |||
| d8090be19d | |||
| d78902d73b | |||
| a0cf285394 | |||
| a531309e4f | |||
| 459d7c4099 | |||
| d47be80928 | |||
| 25903a0d1a | |||
| 75bd7ea3a0 | |||
| 74a2d0119e | |||
| 4f0264d07e | |||
| c201bef873 | |||
| 8e10e6adc1 | |||
| 4078e6fcfa | |||
| 80c97d0e80 | |||
| 525e57a26e | |||
| def1979aca | |||
| 5d9b55adcb | |||
| 21805a5454 | |||
| 50e1c1d376 | |||
| ef956fb54e | |||
| 944f0f087d | |||
| 68c6a1f189 | |||
| c4ef78afc9 | |||
| 526f8e0075 | |||
| a62e7b50d7 | |||
| e33213187e | |||
| bbbb4d1cf6 | |||
| 17c1499100 | |||
| 00772a6aeb | |||
| 76c930e33b | |||
| 7177b312f4 | |||
| d3cfea6a8a | |||
| 6e7b197e8a | |||
| 3719f97866 | |||
| 161ecbc1ab | |||
| b567d9fc90 | |||
| 33744deb61 | |||
| 225dfb6678 | |||
| 0593e53b04 | |||
| 4c3b2e9206 | |||
| 230ed14ece | |||
| 5c00729cfe | |||
| f95dbf83c4 | |||
| f6ab7849e8 | |||
| 6d52355bdd | |||
| 757c82c1e7 | |||
| 1a56ccbd9e | |||
| f15e6f86c7 | |||
| 5e8e40c5c3 | |||
| 13d0973528 | |||
| b10afc8379 | |||
| 00fdbd9c6f | |||
| 17cef8f164 | |||
| 730ba6e14d | |||
| 604a5ec3d1 | |||
| f2e6fddee9 | |||
| cb4ebf85a6 | |||
| 60e1615553 | |||
| 83e8064044 | |||
| a143e6ee93 | |||
| 6f57861420 | |||
| 5ef9fbda99 | |||
| 1fe6a5011a | |||
| 14b2e4dbc8 | |||
| 42d164f285 | |||
| 032bf899e0 | |||
| 1f470c8da5 | |||
| 3f6ccd104e | |||
| 4ccfc1c00c | |||
| 7a54b630fc | |||
| 22ee337762 | |||
| d84a6a95c1 | |||
| ddf95f3e45 | |||
| 008958360c | |||
| c0e9507313 | |||
| d54b6b0794 | |||
| ec485d078a | |||
| d97a4fdd65 | |||
| 12e9e1982c | |||
| f73af2211d | |||
| 603f9b56f9 | |||
| 101c354f3e | |||
| c2e2c24e8c | |||
| 21ba6ab7cd | |||
| 23a8240688 | |||
| fa8616b7ce | |||
| d1b4bfe8e9 | |||
| 8526563cf6 | |||
| c3ad1ba7dc | |||
| e245ac8332 | |||
| 74ff7bdf97 | |||
| 096dbfb701 | |||
| ad2382da53 | |||
| 2118eb17e0 | |||
| 8a5cef0f86 | |||
| 6ed117a131 | |||
| e78537c4aa | |||
| cdfd5d1d66 | |||
| 8e1caf8fe4 | |||
| c3ee472b19 | |||
| 16521d354e | |||
| 5ffa73368a | |||
| b290167194 | |||
| ebdb85ff06 | |||
| ede63179c1 | |||
| ada0ce8855 | |||
| 682b4b5c92 | |||
| 1bf2717626 | |||
| cbf7f35c85 | |||
| 8c41d92e89 | |||
| 097c6e4eb1 | |||
| e1c3d1e929 | |||
| bd9d65e92c | |||
| decf859858 | |||
| dcde24f667 | |||
| 4f471fc38c | |||
| ca737c0d40 | |||
| f1f065a77a | |||
| f64d6e6a73 | |||
| c56f7d0c20 | |||
| a367ee458c | |||
| 187318b500 | |||
| acf32365be | |||
| d7ef213792 | |||
| 6bd48c28e8 | |||
| d938c9daa6 | |||
| 1d3cd32e56 | |||
| 61f5c9e7ef | |||
| 0315fe483a | |||
| 7f6adc7a7f | |||
| d4d06e5561 | |||
| 98f856a548 | |||
| d8528595b3 | |||
| 0e5a5c527e | |||
| 2c9b8a8a2f | |||
| 47ba1544d3 | |||
| 425ba0faf4 | |||
| 5485e275fc | |||
| 724e3b200c | |||
| a59f46c7b2 | |||
| 3fe7d9b90a | |||
| 9e3ab90bdd | |||
| 8e69eb32fd | |||
| 7ec6fa5c0e | |||
| 83444c3499 | |||
| 57ac82d148 | |||
| 89d8b1cb1b | |||
| 6eba716ff8 | |||
| 42d3cf42d8 | |||
| 06f6ff66a8 | |||
| cd1d13e456 | |||
| b02a10b4de | |||
| 518b0f0345 | |||
| 3c9721be9b | |||
| a9b20d2c32 | |||
| 01b606b92a | |||
| 32117d43bc | |||
| 332dfdf099 | |||
| f7634ec761 | |||
| 98a913693d | |||
| 2250920c8a | |||
| cdd8a0b2df | |||
| d326365ee4 | |||
| bc413a844f | |||
| 76e5806575 | |||
| a527614604 | |||
| 63817ce7db | |||
| eac56eea22 | |||
| 8f95c92891 | |||
| dd870ef29c | |||
| a149d2624a | |||
| 06adeb71fd | |||
| bbbfc46601 | |||
| 48d6adab46 | |||
| a611653837 | |||
| 8b3ce51325 | |||
| cee5cf4471 | |||
| d51bd65695 | |||
| 5d5a04416a | |||
| 9798511e2e | |||
| b5223b6e23 | |||
| 1f33a35c5b | |||
| 4c2acfc55c | |||
| 73eac7d282 | |||
| 2a38c61f10 | |||
| 38abe7704e | |||
| 474c4ff01e | |||
| d50e0ebd4f | |||
| dc8d47bb50 | |||
| 3e63820cc0 | |||
| d21e13ba8f | |||
| 6334045800 | |||
| c82952da4c | |||
| dad4f928cd | |||
| 0d3330c501 | |||
| ab447ef306 | |||
| 62afc81810 | |||
| 934c484896 | |||
| 290efba471 | |||
| 3aa1436ff4 | |||
| 034992a3e8 | |||
| 8de5f51971 | |||
| a8af7ad960 | |||
| 9affcc8378 | |||
| a6a7475e7a | |||
| 22463e8323 | |||
| ac56cce888 | |||
| 6dd4d74ca0 | |||
| 428d47c918 | |||
| 1b9d7c5cd7 | |||
| 2691ee89e5 | |||
| 2833fdc54d | |||
| dbe927c629 | |||
| 4ef68730a2 | |||
| 2175217e9b | |||
| d89371c518 | |||
| 6d4089feb7 | |||
| 686f09658e | |||
| 517a07d1de | |||
| 493f377d21 | |||
| 10c1e61ffc | |||
| 7b9b7461bc | |||
| 165c960e52 | |||
| a44635ea6b | |||
| e8959fa3b7 | |||
| 56a47318a0 | |||
| 7de5bdc557 | |||
| 7e9e6c9f67 | |||
| d304d14342 | |||
| b5753daa17 | |||
| b55a55e4b4 | |||
| c9184018de | |||
| 6e454d801b | |||
| 300bdcaf16 | |||
| fa02a2baa8 | |||
| 32e2f0bccc | |||
| 8436e41731 | |||
| 205e4b3a43 | |||
| 042cdeda03 | |||
| 6277ecee4e | |||
| 0078eb477c | |||
| c8a1fb3895 | |||
| f65be7b584 | |||
| 7fbab917fa | |||
| a4a1d98f14 | |||
| 122672cd45 | |||
| fb1bfd16eb | |||
| 2eb88f4b6e | |||
| 5b06fb4968 | |||
| f8c251001f | |||
| 28d03e95d3 | |||
| 762ced4157 | |||
| b9a83f5873 | |||
| e8f526f6b8 | |||
| a0dc562f9a | |||
| 07adabd70d | |||
| 34ca49517f | |||
| 749235cda2 | |||
| 515f28fcbd | |||
| eaa5a9ad83 | |||
| 640187f350 | |||
| 3932dd9fe2 | |||
| f0e3414d1f | |||
| ba9f216931 | |||
| 4e711173e0 | |||
| 8f945fb6fe | |||
| ec6bf08a65 | |||
| 0351e7d817 | |||
| 7eae0e9670 | |||
| 8ef7e55e74 | |||
| 0d2f0b6825 | |||
| 6370abd73a | |||
| 8640f06054 | |||
| 779b42d8ea | |||
| f5f846f5b6 | |||
| d8b6e43a0d | |||
| b72042042f | |||
| bd6dced538 | |||
| 66245a5a2e | |||
| d4a3bc0f5c | |||
| fcc5cc359e | |||
| aa381d4d97 | |||
| bc3f215764 | |||
| daf0f84bc9 | |||
| b945d4c021 | |||
| 9f1066ce83 | |||
| 370654637a | |||
| fb854cecd3 | |||
| 713ce294cc | |||
| 7450b9de9a | |||
| 5b2b053afd |
@@ -0,0 +1,6 @@
|
|||||||
|
github: firestar5683
|
||||||
|
patreon: firestar4430
|
||||||
|
custom:
|
||||||
|
- "https://cash.app/$domkthompson"
|
||||||
|
- "https://account.venmo.com/u/firestar4430"
|
||||||
|
- "https://www.paypal.com/paypalme/firestar4430"
|
||||||
@@ -34,7 +34,7 @@ runs:
|
|||||||
- name: setup github cache
|
- name: setup github cache
|
||||||
id: gha-cache
|
id: gha-cache
|
||||||
if: ${{ !contains(runner.name, 'nsc') && inputs.save != 'false' }}
|
if: ${{ !contains(runner.name, 'nsc') && inputs.save != 'false' }}
|
||||||
uses: 'actions/cache@v4'
|
uses: 'actions/cache@v5'
|
||||||
with:
|
with:
|
||||||
path: ${{ inputs.path }}
|
path: ${{ inputs.path }}
|
||||||
key: ${{ inputs.key }}
|
key: ${{ inputs.key }}
|
||||||
@@ -43,7 +43,7 @@ runs:
|
|||||||
- name: setup github cache
|
- name: setup github cache
|
||||||
id: gha-cache-ro
|
id: gha-cache-ro
|
||||||
if: ${{ !contains(runner.name, 'nsc') && inputs.save == 'false' }}
|
if: ${{ !contains(runner.name, 'nsc') && inputs.save == 'false' }}
|
||||||
uses: 'actions/cache/restore@v4'
|
uses: 'actions/cache/restore@v5'
|
||||||
with:
|
with:
|
||||||
path: ${{ inputs.path }}
|
path: ${{ inputs.path }}
|
||||||
key: ${{ inputs.key }}
|
key: ${{ inputs.key }}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ runs:
|
|||||||
${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \
|
${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \
|
||||||
scons -j$(nproc) --cache-populate"
|
scons -j$(nproc) --cache-populate"
|
||||||
- name: Save scons cache
|
- name: Save scons cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v5
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
with:
|
with:
|
||||||
path: .ci_cache/scons_cache
|
path: .ci_cache/scons_cache
|
||||||
|
|||||||
@@ -23,11 +23,6 @@ on:
|
|||||||
type: boolean
|
type: boolean
|
||||||
default: true
|
default: true
|
||||||
required: false
|
required: false
|
||||||
build_ui:
|
|
||||||
description: "Build UI (selfdrive/ui)"
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
required: false
|
|
||||||
build_params:
|
build_params:
|
||||||
description: "Build params Python extension"
|
description: "Build params Python extension"
|
||||||
type: boolean
|
type: boolean
|
||||||
@@ -88,7 +83,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Checkout target branch
|
- name: Checkout target branch
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ env.BUILD_BRANCH }}
|
ref: ${{ env.BUILD_BRANCH }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
@@ -156,7 +151,6 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
TARGETS=()
|
TARGETS=()
|
||||||
[[ "${{ inputs.build_ui }}" == "true" ]] && TARGETS+=("selfdrive/ui/ui")
|
|
||||||
[[ "${{ inputs.build_params }}" == "true" ]] && TARGETS+=("common/params_pyx.so")
|
[[ "${{ inputs.build_params }}" == "true" ]] && TARGETS+=("common/params_pyx.so")
|
||||||
[[ "${{ inputs.build_cereal }}" == "true" ]] && TARGETS+=("cereal/messaging/bridge")
|
[[ "${{ inputs.build_cereal }}" == "true" ]] && TARGETS+=("cereal/messaging/bridge")
|
||||||
if [[ "${{ inputs.build_panda }}" == "true" ]]; then
|
if [[ "${{ inputs.build_panda }}" == "true" ]]; then
|
||||||
@@ -184,8 +178,8 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${#TARGETS[@]} -eq 0 ]]; then
|
if [[ ${#TARGETS[@]} -eq 0 ]]; then
|
||||||
echo "No partial targets selected; defaulting to UI + panda"
|
echo "No partial targets selected; defaulting to panda"
|
||||||
TARGETS=("selfdrive/ui/ui" "panda/board/obj/panda.bin.signed")
|
TARGETS=("panda/board/obj/panda.bin.signed")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Running partial build for targets: ${TARGETS[*]}"
|
echo "Running partial build for targets: ${TARGETS[*]}"
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Checkout target branch
|
- name: Checkout target branch
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ env.BUILD_BRANCH }}
|
ref: ${{ env.BUILD_BRANCH }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|||||||
@@ -17,17 +17,17 @@ jobs:
|
|||||||
publish:
|
publish:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Log in to GHCR
|
- name: Log in to GHCR
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push runner image
|
- name: Build and push runner image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: tools/truenas_github_runner/Dockerfile
|
file: tools/truenas_github_runner/Dockerfile
|
||||||
|
|||||||
@@ -54,9 +54,6 @@ cereal/gen
|
|||||||
selfdrive/ui/translations/tmp
|
selfdrive/ui/translations/tmp
|
||||||
selfdrive/car/tests/cars_dump
|
selfdrive/car/tests/cars_dump
|
||||||
system/camerad/test/ae_gray_test
|
system/camerad/test/ae_gray_test
|
||||||
selfdrive/ui/ui.macos
|
|
||||||
selfdrive/ui/ui.larch64
|
|
||||||
|
|
||||||
.coverage*
|
.coverage*
|
||||||
coverage.xml
|
coverage.xml
|
||||||
htmlcov
|
htmlcov
|
||||||
|
|||||||
Vendored
+1
-16
@@ -11,14 +11,6 @@
|
|||||||
"tools/sim/run_bridge.py"
|
"tools/sim/run_bridge.py"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "cpp_process",
|
|
||||||
"type": "pickString",
|
|
||||||
"description": "Select the process to debug",
|
|
||||||
"options": [
|
|
||||||
"selfdrive/ui/ui"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "args",
|
"id": "args",
|
||||||
"description": "Arguments to pass to the process",
|
"description": "Arguments to pass to the process",
|
||||||
@@ -40,13 +32,6 @@
|
|||||||
"justMyCode": true,
|
"justMyCode": true,
|
||||||
"args": "${input:args}"
|
"args": "${input:args}"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "C++: openpilot Process",
|
|
||||||
"type": "cppdbg",
|
|
||||||
"request": "launch",
|
|
||||||
"program": "${workspaceFolder}/${input:cpp_process}",
|
|
||||||
"cwd": "${workspaceFolder}"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Attach LLDB to Replay drive",
|
"name": "Attach LLDB to Replay drive",
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
@@ -82,4 +67,4 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-118
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import importlib
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@@ -37,10 +38,6 @@ AddOption('--coverage',
|
|||||||
action='store_true',
|
action='store_true',
|
||||||
help='build with test coverage options')
|
help='build with test coverage options')
|
||||||
|
|
||||||
AddOption('--clazy',
|
|
||||||
action='store_true',
|
|
||||||
help='build with clazy')
|
|
||||||
|
|
||||||
AddOption('--ccflags',
|
AddOption('--ccflags',
|
||||||
action='store',
|
action='store',
|
||||||
type='string',
|
type='string',
|
||||||
@@ -132,6 +129,41 @@ elif arch == "aarch64" and AGNOS:
|
|||||||
arch = "larch64"
|
arch = "larch64"
|
||||||
assert arch in ["larch64", "aarch64", "x86_64", "Darwin"]
|
assert arch in ["larch64", "aarch64", "x86_64", "Darwin"]
|
||||||
|
|
||||||
|
# AGNOS 19.6 ships native dependencies as versioned Python packages. Link
|
||||||
|
# Cap'n Proto statically from that managed package so release binaries don't
|
||||||
|
# depend on the removed libcapnp-1.0.2.so system library.
|
||||||
|
try:
|
||||||
|
capnproto = importlib.import_module("capnproto")
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
capnproto = None
|
||||||
|
try:
|
||||||
|
ffmpeg = importlib.import_module("ffmpeg")
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
ffmpeg = None
|
||||||
|
|
||||||
|
capnproto_include_dirs = [capnproto.INCLUDE_DIR] if capnproto is not None else []
|
||||||
|
capnproto_lib_dirs = [capnproto.LIB_DIR] if capnproto is not None else []
|
||||||
|
ffmpeg_include_dirs = [ffmpeg.INCLUDE_DIR] if ffmpeg is not None else []
|
||||||
|
ffmpeg_lib_dirs = [ffmpeg.LIB_DIR] if ffmpeg is not None else []
|
||||||
|
|
||||||
|
# Cross-builds install managed dependencies in /work/.venv-linux-arm64, but
|
||||||
|
# comma devices expose the same packages from /usr/local/venv. Never embed the
|
||||||
|
# host/container mount path in release binaries.
|
||||||
|
ffmpeg_runtime_lib_dirs = ffmpeg_lib_dirs
|
||||||
|
if arch == "larch64" and ffmpeg is not None:
|
||||||
|
ffmpeg_runtime_lib_dirs = [os.path.join("/usr/local/venv", os.path.relpath(ffmpeg.LIB_DIR, sys.prefix))]
|
||||||
|
|
||||||
|
# The managed native-dependency packages keep their tools inside the package
|
||||||
|
# instead of installing them into /usr/local/venv/bin. cereal invokes capnpc
|
||||||
|
# directly while SConscript files are evaluated, so make the packaged tools
|
||||||
|
# discoverable to both SCons actions and configure-time subprocesses.
|
||||||
|
dependency_bin_dirs = [
|
||||||
|
package.BIN_DIR for package in (capnproto, ffmpeg)
|
||||||
|
if package is not None and os.path.isdir(package.BIN_DIR)
|
||||||
|
]
|
||||||
|
if dependency_bin_dirs:
|
||||||
|
os.environ["PATH"] = os.pathsep.join([*dependency_bin_dirs, os.environ["PATH"]])
|
||||||
|
|
||||||
# Homebrew llvm can shadow Apple clang and break macOS SDK header resolution.
|
# Homebrew llvm can shadow Apple clang and break macOS SDK header resolution.
|
||||||
# Use the system toolchain explicitly on macOS for reliable local builds.
|
# Use the system toolchain explicitly on macOS for reliable local builds.
|
||||||
cc = '/usr/bin/clang' if arch == "Darwin" else 'clang'
|
cc = '/usr/bin/clang' if arch == "Darwin" else 'clang'
|
||||||
@@ -273,7 +305,10 @@ env = Environment(
|
|||||||
"-Wno-vla-cxx-extension",
|
"-Wno-vla-cxx-extension",
|
||||||
] + cflags + ccflags,
|
] + cflags + ccflags,
|
||||||
|
|
||||||
CPPPATH=cpppath + [
|
# Managed dependencies must precede the compatibility sysroot. The sysroot
|
||||||
|
# can intentionally retain legacy libraries for C3 support, but new release
|
||||||
|
# binaries must link against the versions shipped in the managed venv.
|
||||||
|
CPPPATH=capnproto_include_dirs + ffmpeg_include_dirs + cpppath + [
|
||||||
"#",
|
"#",
|
||||||
"#third_party/acados/include",
|
"#third_party/acados/include",
|
||||||
"#third_party/acados/include/blasfeo/include",
|
"#third_party/acados/include/blasfeo/include",
|
||||||
@@ -292,11 +327,11 @@ env = Environment(
|
|||||||
RANLIB=ranlib,
|
RANLIB=ranlib,
|
||||||
LINKFLAGS=ldflags,
|
LINKFLAGS=ldflags,
|
||||||
|
|
||||||
RPATH=rpath,
|
RPATH=ffmpeg_runtime_lib_dirs + rpath,
|
||||||
|
|
||||||
CFLAGS=["-std=gnu11"] + cflags,
|
CFLAGS=["-std=gnu11"] + cflags,
|
||||||
CXXFLAGS=["-std=c++1z"] + cxxflags,
|
CXXFLAGS=["-std=c++1z"] + cxxflags,
|
||||||
LIBPATH=libpath + [
|
LIBPATH=capnproto_lib_dirs + ffmpeg_lib_dirs + libpath + [
|
||||||
"#msgq_repo",
|
"#msgq_repo",
|
||||||
"#third_party",
|
"#third_party",
|
||||||
"#selfdrive/pandad",
|
"#selfdrive/pandad",
|
||||||
@@ -354,116 +389,7 @@ else:
|
|||||||
np_version = SCons.Script.Value(np.__version__)
|
np_version = SCons.Script.Value(np.__version__)
|
||||||
Export('envCython', 'np_version')
|
Export('envCython', 'np_version')
|
||||||
|
|
||||||
# Qt build environment
|
Export('env', 'arch', 'real_arch')
|
||||||
qt_env = env.Clone()
|
|
||||||
qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "DBus", "Xml"]
|
|
||||||
|
|
||||||
qt_libs = []
|
|
||||||
if arch == "Darwin":
|
|
||||||
qt_env['QTDIR'] = f"{brew_prefix}/opt/qt@5"
|
|
||||||
qt_dirs = [
|
|
||||||
os.path.join(qt_env['QTDIR'], "include"),
|
|
||||||
]
|
|
||||||
qt_dirs += [f"{qt_env['QTDIR']}/include/Qt{m}" for m in qt_modules]
|
|
||||||
qt_env["LINKFLAGS"] += ["-F" + os.path.join(qt_env['QTDIR'], "lib")]
|
|
||||||
qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules] + ["OpenGL"]
|
|
||||||
qt_env.AppendENVPath('PATH', os.path.join(qt_env['QTDIR'], "bin"))
|
|
||||||
else:
|
|
||||||
if arch == "larch64":
|
|
||||||
qt_env.PrependENVPath('PATH', Dir("#third_party/qt5/larch64/bin/").abspath)
|
|
||||||
# For laptop/device builds that mount an AGNOS sysroot, always prefer Qt
|
|
||||||
# headers from that sysroot to keep headers/libs ABI-matched (Qt 5.12.x).
|
|
||||||
if arch == "larch64" and os.environ.get("SP_TICI_SYSROOT"):
|
|
||||||
qt_install_prefix = tici_libpath("/usr")
|
|
||||||
qt_install_headers = tici_libpath("/usr/include/aarch64-linux-gnu/qt5")
|
|
||||||
else:
|
|
||||||
qmake = os.environ.get("SP_QMAKE", "qmake")
|
|
||||||
qt_install_prefix = subprocess.check_output([qmake, '-query', 'QT_INSTALL_PREFIX'], encoding='utf8').strip()
|
|
||||||
qt_install_headers = subprocess.check_output([qmake, '-query', 'QT_INSTALL_HEADERS'], encoding='utf8').strip()
|
|
||||||
|
|
||||||
qt_env['QTDIR'] = qt_install_prefix
|
|
||||||
qt_dirs = [
|
|
||||||
f"{qt_install_headers}",
|
|
||||||
]
|
|
||||||
|
|
||||||
qt_gui_path = os.path.join(qt_install_headers, "QtGui")
|
|
||||||
qt_gui_dirs = [d for d in os.listdir(qt_gui_path) if os.path.isdir(os.path.join(qt_gui_path, d))]
|
|
||||||
qt_dirs += [f"{qt_install_headers}/QtGui/{qt_gui_dirs[0]}/QtGui", ] if qt_gui_dirs else []
|
|
||||||
qt_dirs += [f"{qt_install_headers}/Qt{m}" for m in qt_modules]
|
|
||||||
|
|
||||||
qt_libs = [f"Qt5{m}" for m in qt_modules]
|
|
||||||
if arch == "larch64":
|
|
||||||
qt_libs += ["GLESv2", "wayland-client"]
|
|
||||||
elif arch != "Darwin":
|
|
||||||
qt_libs += ["GL"]
|
|
||||||
qt_env['QT3DIR'] = qt_env['QTDIR']
|
|
||||||
qt_env.Tool('qt3')
|
|
||||||
if arch == "larch64" and os.environ.get("SP_TICI_SYSROOT"):
|
|
||||||
qt_tool_bin = tici_libpath("/usr/lib/qt5/bin")
|
|
||||||
qt_tool_root = tici_libpath("/")
|
|
||||||
qt_arm_moc = os.path.join(qt_tool_bin, "moc")
|
|
||||||
qt_arm_uic = os.path.join(qt_tool_bin, "uic")
|
|
||||||
qt_arm_rcc = os.path.join(qt_tool_bin, "rcc")
|
|
||||||
qt_host_bin = os.environ.get("SP_QT_HOST_BIN", "/usr/lib/qt5/bin")
|
|
||||||
qt_host_moc = os.environ.get("SP_QT_HOST_MOC", os.path.join(qt_host_bin, "moc"))
|
|
||||||
qt_host_uic = os.environ.get("SP_QT_HOST_UIC", os.path.join(qt_host_bin, "uic"))
|
|
||||||
qt_host_rcc = os.environ.get("SP_QT_HOST_RCC", "rcc")
|
|
||||||
if platform.machine() in ("aarch64", "arm64"):
|
|
||||||
if "SP_QT_HOST_MOC" in os.environ:
|
|
||||||
qt_env['QT3_MOC'] = qt_host_moc
|
|
||||||
elif os.path.isfile(qt_arm_moc):
|
|
||||||
qt_env['QT3_MOC'] = qt_arm_moc
|
|
||||||
if "SP_QT_HOST_UIC" in os.environ:
|
|
||||||
qt_env['QT3_UIC'] = qt_host_uic
|
|
||||||
elif os.path.isfile(qt_arm_uic):
|
|
||||||
qt_env['QT3_UIC'] = qt_arm_uic
|
|
||||||
if "SP_QT_HOST_RCC" in os.environ:
|
|
||||||
qt_env['SP_QT_RCC'] = qt_host_rcc
|
|
||||||
elif os.path.isfile(qt_arm_rcc):
|
|
||||||
qt_env['SP_QT_RCC'] = qt_arm_rcc
|
|
||||||
else:
|
|
||||||
qt_qemu = shutil.which("qemu-aarch64-static") or shutil.which("qemu-aarch64")
|
|
||||||
|
|
||||||
if qt_qemu and os.path.isfile(qt_arm_moc):
|
|
||||||
qt_env['QT3_MOC'] = f"{qt_qemu} -L {qt_tool_root} {qt_arm_moc}"
|
|
||||||
else:
|
|
||||||
qt_env['QT3_MOC'] = qt_host_moc
|
|
||||||
|
|
||||||
if qt_qemu and os.path.isfile(qt_arm_uic):
|
|
||||||
qt_env['QT3_UIC'] = f"{qt_qemu} -L {qt_tool_root} {qt_arm_uic}"
|
|
||||||
else:
|
|
||||||
qt_env['QT3_UIC'] = qt_host_uic
|
|
||||||
|
|
||||||
if qt_qemu and os.path.isfile(qt_arm_rcc):
|
|
||||||
qt_env['SP_QT_RCC'] = f"{qt_qemu} -L {qt_tool_root} {qt_arm_rcc}"
|
|
||||||
else:
|
|
||||||
qt_env['SP_QT_RCC'] = qt_host_rcc
|
|
||||||
|
|
||||||
qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"]
|
|
||||||
qt_flags = [
|
|
||||||
"-D_REENTRANT",
|
|
||||||
"-DQT_NO_DEBUG",
|
|
||||||
"-DQT_WIDGETS_LIB",
|
|
||||||
"-DQT_GUI_LIB",
|
|
||||||
"-DQT_CORE_LIB",
|
|
||||||
"-DQT_MESSAGELOGCONTEXT",
|
|
||||||
]
|
|
||||||
qt_env['CXXFLAGS'] += qt_flags
|
|
||||||
qt_env['LIBPATH'] += ['#selfdrive/ui', ]
|
|
||||||
qt_env['LIBS'] = qt_libs
|
|
||||||
|
|
||||||
if GetOption("clazy"):
|
|
||||||
checks = [
|
|
||||||
"level0",
|
|
||||||
"level1",
|
|
||||||
"no-range-loop",
|
|
||||||
"no-non-pod-global-static",
|
|
||||||
]
|
|
||||||
qt_env['CXX'] = 'clazy'
|
|
||||||
qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0]
|
|
||||||
qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks)
|
|
||||||
|
|
||||||
Export('env', 'qt_env', 'arch', 'real_arch')
|
|
||||||
|
|
||||||
# Build common module
|
# Build common module
|
||||||
SConscript(['common/SConscript'])
|
SConscript(['common/SConscript'])
|
||||||
@@ -484,7 +410,15 @@ SConscript(['opendbc_repo/SConscript'], exports={'env': env_swaglog})
|
|||||||
SConscript(['cereal/SConscript'])
|
SConscript(['cereal/SConscript'])
|
||||||
|
|
||||||
Import('socketmaster', 'msgq')
|
Import('socketmaster', 'msgq')
|
||||||
messaging = [socketmaster, msgq, 'capnp', 'kj',]
|
if capnproto is not None:
|
||||||
|
messaging = [
|
||||||
|
socketmaster,
|
||||||
|
msgq,
|
||||||
|
File(os.path.join(capnproto.LIB_DIR, "libcapnp.a")),
|
||||||
|
File(os.path.join(capnproto.LIB_DIR, "libkj.a")),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
messaging = [socketmaster, msgq, 'capnp', 'kj']
|
||||||
Export('messaging')
|
Export('messaging')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -46,9 +46,6 @@ while [[ $# -gt 0 ]]; do
|
|||||||
shortcut_includes_panda=1
|
shortcut_includes_panda=1
|
||||||
add_panda_targets
|
add_panda_targets
|
||||||
;;
|
;;
|
||||||
--ui|-ui)
|
|
||||||
shortcut_targets+=("selfdrive/ui/ui")
|
|
||||||
;;
|
|
||||||
--cereal|-cereal)
|
--cereal|-cereal)
|
||||||
shortcut_targets+=(
|
shortcut_targets+=(
|
||||||
"cereal/libcereal.a"
|
"cereal/libcereal.a"
|
||||||
|
|||||||
+11
-3
@@ -1,3 +1,5 @@
|
|||||||
|
import subprocess
|
||||||
|
|
||||||
Import('env', 'common', 'msgq')
|
Import('env', 'common', 'msgq')
|
||||||
|
|
||||||
cereal_dir = Dir('.')
|
cereal_dir = Dir('.')
|
||||||
@@ -5,9 +7,15 @@ gen_dir = Dir('gen')
|
|||||||
|
|
||||||
# Build cereal
|
# Build cereal
|
||||||
schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp']
|
schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp']
|
||||||
env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files],
|
schema_outputs = env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files],
|
||||||
schema_files,
|
schema_files,
|
||||||
f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/")
|
f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/")
|
||||||
|
|
||||||
|
# capnpc embeds an exact compiler-version guard in every generated C++ header.
|
||||||
|
# Include the tool version in the dependency signature so SCons cannot reuse
|
||||||
|
# generated headers from a cache populated by another AGNOS/toolchain version.
|
||||||
|
capnp_compiler_version = subprocess.check_output(['capnpc', '--version'], encoding='utf-8').strip()
|
||||||
|
env.Depends(schema_outputs, env.Value(capnp_compiler_version))
|
||||||
|
|
||||||
cereal = env.Library('cereal', [f'gen/cpp/{s}.c++' for s in schema_files])
|
cereal = env.Library('cereal', [f'gen/cpp/{s}.c++' for s in schema_files])
|
||||||
|
|
||||||
|
|||||||
+27
-1
@@ -98,6 +98,7 @@ struct StarPilotCarState @0xf35cc4560bbf6ec2 {
|
|||||||
teslaCCNotArmed @27 :Bool; # lateral engaged but DI_cruiseState != STANDBY/ENABLED
|
teslaCCNotArmed @27 :Bool; # lateral engaged but DI_cruiseState != STANDBY/ENABLED
|
||||||
accelHardCruise @28 :Bool; # current/releasing accel cruise button came from GM hard-press signal
|
accelHardCruise @28 :Bool; # current/releasing accel cruise button came from GM hard-press signal
|
||||||
decelHardCruise @29 :Bool; # current/releasing decel cruise button came from GM hard-press signal
|
decelHardCruise @29 :Bool; # current/releasing decel cruise button came from GM hard-press signal
|
||||||
|
pulseAndGlide @30 :Bool; # developer-only wheel-button pulse-and-glide mode is enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StarPilotDeviceState @0xda96579883444c35 {
|
struct StarPilotDeviceState @0xda96579883444c35 {
|
||||||
@@ -219,11 +220,27 @@ struct StarPilotPlan @0xf98d843bfd7004a3 {
|
|||||||
disableThrottle @35 :Bool;
|
disableThrottle @35 :Bool;
|
||||||
trackingLead @36 :Bool;
|
trackingLead @36 :Bool;
|
||||||
stopSignConfirmed @37 :Bool;
|
stopSignConfirmed @37 :Bool;
|
||||||
|
pulseGlideCoasting @38 :Bool; # developer-only P&G phase for on-road status UI
|
||||||
|
# Curve Speed Controller diagnostics, for tuning and rollout validation
|
||||||
|
cscOverridden @39 :Bool; # driver cancelled this curve with RES+
|
||||||
|
cscLearnedLatAccel @40 :Float32; # learned comfort at the current curvature, before margin
|
||||||
|
cscBindingDistance @41 :Float32; # distance to the horizon point setting the target, m
|
||||||
|
approachStopLength @42 :Float32; # pre-commit distance to a detected stop, m; 0 when off
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StarPilotRadarState @0xb86e6369214c01c8 {
|
struct StarPilotRadarState @0xb86e6369214c01c8 {
|
||||||
leadLeft @0 :LeadData;
|
leadLeft @0 :LeadData;
|
||||||
leadRight @1 :LeadData;
|
leadRight @1 :LeadData;
|
||||||
|
adjacentStopped @2 :AdjacentStopped;
|
||||||
|
|
||||||
|
# A vehicle in an adjacent lane that was observed MOVING and then came to rest.
|
||||||
|
# Distinct from leadLeft/leadRight, which are moving-target-only by design.
|
||||||
|
struct AdjacentStopped {
|
||||||
|
status @0 :Bool;
|
||||||
|
dRel @1 :Float32;
|
||||||
|
yRel @2 :Float32;
|
||||||
|
radarTrackId @3 :Int32 = -1;
|
||||||
|
}
|
||||||
|
|
||||||
struct LeadData {
|
struct LeadData {
|
||||||
dRel @0 :Float32;
|
dRel @0 :Float32;
|
||||||
@@ -253,6 +270,7 @@ struct StarPilotSelfdriveState @0xf416ec09499d9d19 {
|
|||||||
alertSize @3 :AlertSize;
|
alertSize @3 :AlertSize;
|
||||||
alertType @4 :Text;
|
alertType @4 :Text;
|
||||||
alertSound @5 :Car.CarControl.HUDControl.AudibleAlert;
|
alertSound @5 :Car.CarControl.HUDControl.AudibleAlert;
|
||||||
|
vEgo @6 :Float32;
|
||||||
|
|
||||||
enum AlertStatus {
|
enum AlertStatus {
|
||||||
normal @0;
|
normal @0;
|
||||||
@@ -282,7 +300,15 @@ struct StarPilotLateralManeuverPlanDEPRECATED @0xcb9fd56c7057593a {
|
|||||||
desiredCurvature @0 :Float32; # 1/m
|
desiredCurvature @0 :Float32; # 1/m
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CustomReserved11 @0xc2243c65e0340384 {
|
struct StarPilotLateralState @0xc2243c65e0340384 {
|
||||||
|
active @0 :Bool;
|
||||||
|
frictionThreshold @1 :Float32;
|
||||||
|
frictionScale @2 :Float32;
|
||||||
|
feedforward @3 :Float32;
|
||||||
|
frictionJerk @4 :Float32;
|
||||||
|
frictionJerkDeadzone @5 :Float32;
|
||||||
|
lowSpeedFactor @6 :Float32;
|
||||||
|
unwindDetected @7 :Bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CustomReserved12 @0x9ccdc8676701b412 {
|
struct CustomReserved12 @0x9ccdc8676701b412 {
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+58
-6
@@ -130,8 +130,13 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
|||||||
userBookmark @95;
|
userBookmark @95;
|
||||||
excessiveActuation @96;
|
excessiveActuation @96;
|
||||||
audioFeedback @97;
|
audioFeedback @97;
|
||||||
|
bigModelLoading @100;
|
||||||
|
bigModelFailed @102;
|
||||||
|
|
||||||
soundsUnavailableDEPRECATED @47;
|
soundsUnavailableDEPRECATED @47;
|
||||||
|
stockLkasDEPRECATED @98;
|
||||||
|
lateralManeuverDEPRECATED @99;
|
||||||
|
bigModelReadyDEPRECATED @101;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,6 +472,10 @@ struct CanData {
|
|||||||
struct DeviceState @0xa4d8b5af2aa492eb {
|
struct DeviceState @0xa4d8b5af2aa492eb {
|
||||||
deviceType @45 :InitData.DeviceType;
|
deviceType @45 :InitData.DeviceType;
|
||||||
|
|
||||||
|
# usb
|
||||||
|
chestnutPresent @51 :Bool;
|
||||||
|
usbState @52 :UsbState;
|
||||||
|
|
||||||
networkType @22 :NetworkType;
|
networkType @22 :NetworkType;
|
||||||
networkInfo @31 :NetworkInfo;
|
networkInfo @31 :NetworkInfo;
|
||||||
networkStrength @24 :NetworkStrength;
|
networkStrength @24 :NetworkStrength;
|
||||||
@@ -498,7 +507,8 @@ struct DeviceState @0xa4d8b5af2aa492eb {
|
|||||||
pmicTempC @39 :List(Float32);
|
pmicTempC @39 :List(Float32);
|
||||||
intakeTempC @46 :Float32;
|
intakeTempC @46 :Float32;
|
||||||
exhaustTempC @47 :Float32;
|
exhaustTempC @47 :Float32;
|
||||||
caseTempC @48 :Float32;
|
gnssTempC @48 :Float32;
|
||||||
|
bottomSocTempC @50 :Float32;
|
||||||
maxTempC @44 :Float32; # max of other temps, used to control fan
|
maxTempC @44 :Float32; # max of other temps, used to control fan
|
||||||
thermalZones @38 :List(ThermalZone);
|
thermalZones @38 :List(ThermalZone);
|
||||||
thermalStatus @14 :ThermalStatus;
|
thermalStatus @14 :ThermalStatus;
|
||||||
@@ -512,10 +522,10 @@ struct DeviceState @0xa4d8b5af2aa492eb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum ThermalStatus {
|
enum ThermalStatus {
|
||||||
green @0;
|
ok @0;
|
||||||
yellow @1;
|
warmDEPRECATED @1;
|
||||||
red @2;
|
overheated @2;
|
||||||
danger @3;
|
critical @3;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum NetworkType {
|
enum NetworkType {
|
||||||
@@ -731,6 +741,41 @@ struct PeripheralState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UsbState {
|
||||||
|
devices @0 :List(Device);
|
||||||
|
|
||||||
|
struct Device {
|
||||||
|
busnum @0 :UInt8;
|
||||||
|
devnum @1 :UInt8;
|
||||||
|
vendorId @2 :UInt16;
|
||||||
|
productId @3 :UInt16;
|
||||||
|
speedMbps @4 :UInt16;
|
||||||
|
manufacturer @6 :Text;
|
||||||
|
product @5 :Text;
|
||||||
|
linkErrorCount @7 :UInt16;
|
||||||
|
usb3Lane @8 :Usb3Lane;
|
||||||
|
|
||||||
|
enum Usb3Lane {
|
||||||
|
unknown @0;
|
||||||
|
a @1;
|
||||||
|
b @2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ChestnutState {
|
||||||
|
tempC @0 :Float32;
|
||||||
|
memoryTempC @1 :Float32;
|
||||||
|
powerDrawW @2 :Float32;
|
||||||
|
powerLimitW @3 :Float32;
|
||||||
|
gpuUsagePercent @4 :UInt8;
|
||||||
|
gpuClockMhz @5 :UInt16;
|
||||||
|
fanSpeedRpm @6 :UInt16;
|
||||||
|
pcieLtssm @7 :UInt8;
|
||||||
|
supplyVoltage @8 :UInt16; # mV
|
||||||
|
supplyCurrent @9 :Int16; # mA
|
||||||
|
}
|
||||||
|
|
||||||
struct RadarState @0x9a185389d6fdd05f {
|
struct RadarState @0x9a185389d6fdd05f {
|
||||||
mdMonoTime @6 :UInt64;
|
mdMonoTime @6 :UInt64;
|
||||||
carStateMonoTime @11 :UInt64;
|
carStateMonoTime @11 :UInt64;
|
||||||
@@ -1282,6 +1327,11 @@ struct LongitudinalPlan @0xe00b5b3eba12876c {
|
|||||||
|
|
||||||
solverExecutionTime @35 :Float32;
|
solverExecutionTime @35 :Float32;
|
||||||
|
|
||||||
|
leadTrajectoryX0 @40 :List(Float32);
|
||||||
|
leadTrajectoryV0 @41 :List(Float32);
|
||||||
|
leadTrajectoryX1 @42 :List(Float32);
|
||||||
|
leadTrajectoryV1 @43 :List(Float32);
|
||||||
|
|
||||||
enum LongitudinalPlanSource {
|
enum LongitudinalPlanSource {
|
||||||
cruise @0;
|
cruise @0;
|
||||||
lead0 @1;
|
lead0 @1;
|
||||||
@@ -2687,6 +2737,7 @@ struct Event {
|
|||||||
procLog @33 :ProcLog;
|
procLog @33 :ProcLog;
|
||||||
clocks @35 :Clocks;
|
clocks @35 :Clocks;
|
||||||
deviceState @6 :DeviceState;
|
deviceState @6 :DeviceState;
|
||||||
|
chestnutState @152 :ChestnutState;
|
||||||
logMessage @18 :Text;
|
logMessage @18 :Text;
|
||||||
errorLogMessage @85 :Text;
|
errorLogMessage @85 :Text;
|
||||||
|
|
||||||
@@ -2706,6 +2757,7 @@ struct Event {
|
|||||||
userBookmark @93 :UserBookmark;
|
userBookmark @93 :UserBookmark;
|
||||||
bookmarkButton @148 :UserBookmark;
|
bookmarkButton @148 :UserBookmark;
|
||||||
audioFeedback @149 :AudioFeedback;
|
audioFeedback @149 :AudioFeedback;
|
||||||
|
visionSpeedLimitBookmark @153 :UserBookmark;
|
||||||
|
|
||||||
lateralManeuverPlan @150 :LateralManeuverPlan;
|
lateralManeuverPlan @150 :LateralManeuverPlan;
|
||||||
# *********** debug ***********
|
# *********** debug ***********
|
||||||
@@ -2742,7 +2794,7 @@ struct Event {
|
|||||||
starpilotSelfdriveState @115 :Custom.StarPilotSelfdriveState;
|
starpilotSelfdriveState @115 :Custom.StarPilotSelfdriveState;
|
||||||
customReserved9 @116 :Custom.CustomReserved9;
|
customReserved9 @116 :Custom.CustomReserved9;
|
||||||
starpilotLateralManeuverPlanDEPRECATED @136 :Custom.StarPilotLateralManeuverPlanDEPRECATED;
|
starpilotLateralManeuverPlanDEPRECATED @136 :Custom.StarPilotLateralManeuverPlanDEPRECATED;
|
||||||
customReserved11 @137 :Custom.CustomReserved11;
|
starpilotLateralState @137 :Custom.StarPilotLateralState;
|
||||||
customReserved12 @138 :Custom.CustomReserved12;
|
customReserved12 @138 :Custom.CustomReserved12;
|
||||||
customReserved13 @139 :Custom.CustomReserved13;
|
customReserved13 @139 :Custom.CustomReserved13;
|
||||||
customReserved14 @140 :Custom.CustomReserved14;
|
customReserved14 @140 :Custom.CustomReserved14;
|
||||||
|
|||||||
@@ -268,6 +268,7 @@ class SubMaster:
|
|||||||
class PubMaster:
|
class PubMaster:
|
||||||
def __init__(self, services: List[str]):
|
def __init__(self, services: List[str]):
|
||||||
self.sock = {}
|
self.sock = {}
|
||||||
|
self._zmq_readers_settled = set()
|
||||||
for s in services:
|
for s in services:
|
||||||
self.sock[s] = pub_sock(s)
|
self.sock[s] = pub_sock(s)
|
||||||
|
|
||||||
@@ -277,6 +278,13 @@ class PubMaster:
|
|||||||
self.sock[s].send(dat)
|
self.sock[s].send(dat)
|
||||||
|
|
||||||
def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
|
def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
|
||||||
|
if "ZMQ" in os.environ:
|
||||||
|
if s not in self._zmq_readers_settled:
|
||||||
|
time.sleep(min(timeout, 1.0))
|
||||||
|
self._zmq_readers_settled.add(s)
|
||||||
|
elif dt >= 0.05:
|
||||||
|
time.sleep(min(timeout, 1.0))
|
||||||
|
return True
|
||||||
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
|
||||||
|
|||||||
Binary file not shown.
@@ -12,6 +12,7 @@ static std::map<std::string, service> services = {
|
|||||||
{ "temperatureSensor", {"temperatureSensor", true, 2.000000, 200, 256000}},
|
{ "temperatureSensor", {"temperatureSensor", true, 2.000000, 200, 256000}},
|
||||||
{ "gpsNMEA", {"gpsNMEA", true, 9.000000, -1, 256000}},
|
{ "gpsNMEA", {"gpsNMEA", true, 9.000000, -1, 256000}},
|
||||||
{ "deviceState", {"deviceState", true, 2.000000, 1, 256000}},
|
{ "deviceState", {"deviceState", true, 2.000000, 1, 256000}},
|
||||||
|
{ "chestnutState", {"chestnutState", true, 10.000000, 10, 256000}},
|
||||||
{ "touch", {"touch", true, 20.000000, 1, 256000}},
|
{ "touch", {"touch", true, 20.000000, 1, 256000}},
|
||||||
{ "can", {"can", true, 100.000000, 2053, 10485760}},
|
{ "can", {"can", true, 100.000000, 2053, 10485760}},
|
||||||
{ "controlsState", {"controlsState", true, 100.000000, 10, 2097152}},
|
{ "controlsState", {"controlsState", true, 100.000000, 10, 2097152}},
|
||||||
@@ -68,6 +69,7 @@ static std::map<std::string, service> services = {
|
|||||||
{ "rawAudioData", {"rawAudioData", false, 20.000000, -1, 256000}},
|
{ "rawAudioData", {"rawAudioData", false, 20.000000, -1, 256000}},
|
||||||
{ "bookmarkButton", {"bookmarkButton", true, 0.000000, 1, 256000}},
|
{ "bookmarkButton", {"bookmarkButton", true, 0.000000, 1, 256000}},
|
||||||
{ "audioFeedback", {"audioFeedback", true, 0.000000, 1, 256000}},
|
{ "audioFeedback", {"audioFeedback", true, 0.000000, 1, 256000}},
|
||||||
|
{ "visionSpeedLimitBookmark", {"visionSpeedLimitBookmark", false, 0.000000, 1, 256000}},
|
||||||
{ "roadEncodeData", {"roadEncodeData", false, 20.000000, -1, 10485760}},
|
{ "roadEncodeData", {"roadEncodeData", false, 20.000000, -1, 10485760}},
|
||||||
{ "driverEncodeData", {"driverEncodeData", false, 20.000000, -1, 10485760}},
|
{ "driverEncodeData", {"driverEncodeData", false, 20.000000, -1, 10485760}},
|
||||||
{ "wideRoadEncodeData", {"wideRoadEncodeData", false, 20.000000, -1, 10485760}},
|
{ "wideRoadEncodeData", {"wideRoadEncodeData", false, 20.000000, -1, 10485760}},
|
||||||
@@ -82,6 +84,7 @@ static std::map<std::string, service> services = {
|
|||||||
{ "livestreamRoadEncodeData", {"livestreamRoadEncodeData", false, 20.000000, -1, 2097152}},
|
{ "livestreamRoadEncodeData", {"livestreamRoadEncodeData", false, 20.000000, -1, 2097152}},
|
||||||
{ "livestreamDriverEncodeData", {"livestreamDriverEncodeData", false, 20.000000, -1, 2097152}},
|
{ "livestreamDriverEncodeData", {"livestreamDriverEncodeData", false, 20.000000, -1, 2097152}},
|
||||||
{ "customReserved9", {"customReserved9", true, 0.000000, 1, 256000}},
|
{ "customReserved9", {"customReserved9", true, 0.000000, 1, 256000}},
|
||||||
|
{ "starpilotLateralState", {"starpilotLateralState", true, 100.000000, 10, 256000}},
|
||||||
{ "customReservedRawData0", {"customReservedRawData0", true, 0.000000, -1, 256000}},
|
{ "customReservedRawData0", {"customReservedRawData0", true, 0.000000, -1, 256000}},
|
||||||
{ "customReservedRawData1", {"customReservedRawData1", true, 0.000000, -1, 256000}},
|
{ "customReservedRawData1", {"customReservedRawData1", true, 0.000000, -1, 256000}},
|
||||||
{ "customReservedRawData2", {"customReservedRawData2", true, 0.000000, -1, 256000}},
|
{ "customReservedRawData2", {"customReservedRawData2", true, 0.000000, -1, 256000}},
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ _services: dict[str, tuple] = {
|
|||||||
"temperatureSensor": (True, 2., 200),
|
"temperatureSensor": (True, 2., 200),
|
||||||
"gpsNMEA": (True, 9.),
|
"gpsNMEA": (True, 9.),
|
||||||
"deviceState": (True, 2., 1),
|
"deviceState": (True, 2., 1),
|
||||||
|
"chestnutState": (True, 10., 10),
|
||||||
"touch": (True, 20., 1),
|
"touch": (True, 20., 1),
|
||||||
"can": (True, 100., 2053, QueueSize.BIG), # decimation gives ~3 msgs in a full segment
|
"can": (True, 100., 2053, QueueSize.BIG), # decimation gives ~3 msgs in a full segment
|
||||||
"controlsState": (True, 100., 10, QueueSize.MEDIUM),
|
"controlsState": (True, 100., 10, QueueSize.MEDIUM),
|
||||||
@@ -85,6 +86,7 @@ _services: dict[str, tuple] = {
|
|||||||
"rawAudioData": (False, 20.),
|
"rawAudioData": (False, 20.),
|
||||||
"bookmarkButton": (True, 0., 1),
|
"bookmarkButton": (True, 0., 1),
|
||||||
"audioFeedback": (True, 0., 1),
|
"audioFeedback": (True, 0., 1),
|
||||||
|
"visionSpeedLimitBookmark": (False, 0., 1),
|
||||||
"roadEncodeData": (False, 20., None, QueueSize.BIG),
|
"roadEncodeData": (False, 20., None, QueueSize.BIG),
|
||||||
"driverEncodeData": (False, 20., None, QueueSize.BIG),
|
"driverEncodeData": (False, 20., None, QueueSize.BIG),
|
||||||
"wideRoadEncodeData": (False, 20., None, QueueSize.BIG),
|
"wideRoadEncodeData": (False, 20., None, QueueSize.BIG),
|
||||||
@@ -101,6 +103,7 @@ _services: dict[str, tuple] = {
|
|||||||
"livestreamRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
"livestreamRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
||||||
"livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
"livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
||||||
"customReserved9": (True, 0., 1),
|
"customReserved9": (True, 0., 1),
|
||||||
|
"starpilotLateralState": (True, 100., 10),
|
||||||
"customReservedRawData0": (True, 0.),
|
"customReservedRawData0": (True, 0.),
|
||||||
"customReservedRawData1": (True, 0.),
|
"customReservedRawData1": (True, 0.),
|
||||||
"customReservedRawData2": (True, 0.),
|
"customReservedRawData2": (True, 0.),
|
||||||
|
|||||||
+15
-7
@@ -58,26 +58,34 @@ def file_chunked_exists(path) -> bool:
|
|||||||
class ChunkStream(io.RawIOBase):
|
class ChunkStream(io.RawIOBase):
|
||||||
def __init__(self, paths):
|
def __init__(self, paths):
|
||||||
self._paths = iter(paths)
|
self._paths = iter(paths)
|
||||||
self._buffer = memoryview(b"")
|
self._file = None
|
||||||
|
|
||||||
def readable(self):
|
def readable(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def readinto(self, buffer):
|
def readinto(self, buffer):
|
||||||
count = 0
|
count = 0
|
||||||
|
view = memoryview(buffer)
|
||||||
while count < len(buffer):
|
while count < len(buffer):
|
||||||
if not self._buffer:
|
if self._file is None:
|
||||||
path = next(self._paths, None)
|
path = next(self._paths, None)
|
||||||
if path is None:
|
if path is None:
|
||||||
break
|
break
|
||||||
self._buffer = memoryview(Path(path).read_bytes())
|
self._file = open(path, "rb")
|
||||||
|
bytes_read = self._file.readinto(view[count:])
|
||||||
|
if not bytes_read:
|
||||||
|
self._file.close()
|
||||||
|
self._file = None
|
||||||
continue
|
continue
|
||||||
take = min(len(buffer) - count, len(self._buffer))
|
count += bytes_read
|
||||||
buffer[count:count + take] = self._buffer[:take]
|
|
||||||
self._buffer = self._buffer[take:]
|
|
||||||
count += take
|
|
||||||
return count
|
return count
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self._file is not None:
|
||||||
|
self._file.close()
|
||||||
|
self._file = None
|
||||||
|
super().close()
|
||||||
|
|
||||||
|
|
||||||
def open_file_chunked(path):
|
def open_file_chunked(path):
|
||||||
chunks = get_existing_chunks(path)
|
chunks = get_existing_chunks(path)
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ from openpilot.common.params import Params
|
|||||||
|
|
||||||
|
|
||||||
def get_gps_location_service(params: Params) -> str:
|
def get_gps_location_service(params: Params) -> str:
|
||||||
if params.get_bool("UbloxAvailable"):
|
if params.get_bool("UbloxAvailable") or params.get_bool("CarGpsAvailable"):
|
||||||
return "gpsLocationExternal"
|
return "gpsLocationExternal"
|
||||||
else:
|
else:
|
||||||
return "gpsLocation"
|
return "gpsLocation"
|
||||||
|
|||||||
Binary file not shown.
+88
-12
@@ -16,10 +16,14 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"AthenadUploadQueue", {PERSISTENT, JSON}},
|
{"AthenadUploadQueue", {PERSISTENT, JSON}},
|
||||||
{"AthenadRecentlyViewedRoutes", {PERSISTENT, STRING}},
|
{"AthenadRecentlyViewedRoutes", {PERSISTENT, STRING}},
|
||||||
{"BootCount", {PERSISTENT, INT}},
|
{"BootCount", {PERSISTENT, INT}},
|
||||||
|
{"BluetoothAudioAddress", {PERSISTENT, STRING}},
|
||||||
|
{"BluetoothAudioTestActive", {CLEAR_ON_MANAGER_START | DONT_LOG, BOOL}},
|
||||||
|
{"BluetoothEnabled", {PERSISTENT, BOOL, "0"}},
|
||||||
{"CalibrationParams", {PERSISTENT, BYTES}},
|
{"CalibrationParams", {PERSISTENT, BYTES}},
|
||||||
{"CameraDebugExpGain", {CLEAR_ON_MANAGER_START, STRING}},
|
{"CameraDebugExpGain", {CLEAR_ON_MANAGER_START, STRING}},
|
||||||
{"CameraDebugExpTime", {CLEAR_ON_MANAGER_START, STRING}},
|
{"CameraDebugExpTime", {CLEAR_ON_MANAGER_START, STRING}},
|
||||||
{"CarBatteryCapacity", {PERSISTENT, INT}},
|
{"CarBatteryCapacity", {PERSISTENT, INT}},
|
||||||
|
{"CarGpsAvailable", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"CarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}},
|
{"CarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}},
|
||||||
{"CarParamsCache", {CLEAR_ON_MANAGER_START, BYTES}},
|
{"CarParamsCache", {CLEAR_ON_MANAGER_START, BYTES}},
|
||||||
{"CarParamsPersistent", {PERSISTENT, BYTES}},
|
{"CarParamsPersistent", {PERSISTENT, BYTES}},
|
||||||
@@ -62,6 +66,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"GsmRoaming", {PERSISTENT, BOOL}},
|
{"GsmRoaming", {PERSISTENT, BOOL}},
|
||||||
{"HardwareSerial", {PERSISTENT, STRING}},
|
{"HardwareSerial", {PERSISTENT, STRING}},
|
||||||
{"HasAcceptedTerms", {PERSISTENT, STRING, "0"}},
|
{"HasAcceptedTerms", {PERSISTENT, STRING, "0"}},
|
||||||
|
// Internal kill switch; the platform verification allowlist remains the hard safety gate.
|
||||||
|
{"HondaBoschARadar", {PERSISTENT, BOOL, "1"}},
|
||||||
{"HondaGasFactorParams", {PERSISTENT, FLOAT}},
|
{"HondaGasFactorParams", {PERSISTENT, FLOAT}},
|
||||||
{"HondaLateralPidKiScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
|
{"HondaLateralPidKiScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
|
||||||
{"HondaLateralPidKpScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
|
{"HondaLateralPidKpScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
|
||||||
@@ -70,6 +76,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"IsEngaged", {PERSISTENT, BOOL}},
|
{"IsEngaged", {PERSISTENT, BOOL}},
|
||||||
{"IsLdwEnabled", {PERSISTENT, BOOL}},
|
{"IsLdwEnabled", {PERSISTENT, BOOL}},
|
||||||
|
{"IsLiveStreaming", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"IsMetric", {PERSISTENT, BOOL}},
|
{"IsMetric", {PERSISTENT, BOOL}},
|
||||||
{"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"IsOnroad", {PERSISTENT, BOOL}},
|
{"IsOnroad", {PERSISTENT, BOOL}},
|
||||||
@@ -80,6 +87,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
|
{"JoystickControlDevice", {PERSISTENT, STRING}},
|
||||||
{"LanguageSetting", {PERSISTENT, STRING, "main_en"}},
|
{"LanguageSetting", {PERSISTENT, STRING, "main_en"}},
|
||||||
{"LastAthenaPingTime", {CLEAR_ON_MANAGER_START, INT}},
|
{"LastAthenaPingTime", {CLEAR_ON_MANAGER_START, INT}},
|
||||||
{"LastGPSPosition", {PERSISTENT, STRING}},
|
{"LastGPSPosition", {PERSISTENT, STRING}},
|
||||||
@@ -94,6 +102,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"LiveDelay", {PERSISTENT, BYTES}},
|
{"LiveDelay", {PERSISTENT, BYTES}},
|
||||||
{"LiveParameters", {PERSISTENT, JSON}},
|
{"LiveParameters", {PERSISTENT, JSON}},
|
||||||
{"LiveParametersV2", {PERSISTENT, BYTES}},
|
{"LiveParametersV2", {PERSISTENT, BYTES}},
|
||||||
|
{"LivestreamEncoderBitrate", {CLEAR_ON_MANAGER_START | DONT_LOG, INT}},
|
||||||
|
{"LivestreamRequestKeyframe", {CLEAR_ON_MANAGER_START | DONT_LOG, BOOL}},
|
||||||
{"LiveTorqueParameters", {PERSISTENT | DONT_LOG, BYTES}},
|
{"LiveTorqueParameters", {PERSISTENT | DONT_LOG, BYTES}},
|
||||||
{"LateralManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"LateralManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
{"LocationFilterInitialState", {PERSISTENT, BYTES}},
|
{"LocationFilterInitialState", {PERSISTENT, BYTES}},
|
||||||
@@ -125,11 +135,17 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"RecordAudioFeedback", {PERSISTENT, BOOL, "0"}},
|
{"RecordAudioFeedback", {PERSISTENT, BOOL, "0"}},
|
||||||
{"RecordFront", {PERSISTENT, BOOL}},
|
{"RecordFront", {PERSISTENT, BOOL}},
|
||||||
{"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet
|
{"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet
|
||||||
|
{"SentryModeEnabled", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
||||||
|
{"SentryModeCapture", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
|
{"SentryModeLastEvent", {PERSISTENT, JSON, "{}", "{}"}},
|
||||||
|
{"SentryModeNtfyUrl", {PERSISTENT, STRING}},
|
||||||
|
{"SentryModeSensitivity", {PERSISTENT, FLOAT, "0.04", "0.04", 0, SETTINGS_SIMPLE}},
|
||||||
|
{"SentryModeStatus", {CLEAR_ON_MANAGER_START | DONT_LOG, JSON}},
|
||||||
|
{"SentryModeWarningTime", {PERSISTENT, FLOAT, "1.0", "1.0", 0, SETTINGS_SIMPLE}},
|
||||||
|
{"SentryModeWebhook", {PERSISTENT, STRING}},
|
||||||
{"SecOCKey", {PERSISTENT | DONT_LOG, STRING}},
|
{"SecOCKey", {PERSISTENT | DONT_LOG, STRING}},
|
||||||
{"ShowDebugInfo", {PERSISTENT, BOOL}},
|
{"ShowDebugInfo", {PERSISTENT, BOOL}},
|
||||||
{"ShowAllToggles", {PERSISTENT, BOOL, "0", "0", 3}},
|
{"ShowAllToggles", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||||
{"TryRaylibUI", {PERSISTENT, BOOL, "1"}},
|
|
||||||
{"UseOldUI", {PERSISTENT, BOOL, "0", std::nullopt, 0, SETTINGS_SIMPLE}},
|
|
||||||
{"UsePrebuilt", {PERSISTENT, BOOL, "1"}},
|
{"UsePrebuilt", {PERSISTENT, BOOL, "1"}},
|
||||||
{"RouteCount", {PERSISTENT, INT, "0"}},
|
{"RouteCount", {PERSISTENT, INT, "0"}},
|
||||||
{"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
@@ -152,6 +168,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
|
{"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
|
||||||
{"UsbGpuActive", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"UsbGpuActive", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
{"UsbGpuCompiled", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"UsbGpuCompiled", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
|
{"UsbGpuLoading", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
{"UsbGpuPresent", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"UsbGpuPresent", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
{"Version", {PERSISTENT, STRING}},
|
{"Version", {PERSISTENT, STRING}},
|
||||||
|
|
||||||
@@ -178,6 +195,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"ApiCache_DriveStats", {PERSISTENT, JSON, "{}", "{}"}},
|
{"ApiCache_DriveStats", {PERSISTENT, JSON, "{}", "{}"}},
|
||||||
{"AutomaticallyDownloadModels", {PERSISTENT, BOOL, "1", "0", 1}},
|
{"AutomaticallyDownloadModels", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||||
{"AutomaticUpdates", {PERSISTENT, BOOL, "1", "1", 0}},
|
{"AutomaticUpdates", {PERSISTENT, BOOL, "1", "1", 0}},
|
||||||
|
{"AllowGpuModelDownloadWithoutGpu", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||||
{"AvailableModelNames", {PERSISTENT, STRING, "", "", 1}},
|
{"AvailableModelNames", {PERSISTENT, STRING, "", "", 1}},
|
||||||
{"AvailableModelSeries", {PERSISTENT, STRING, "", "", 1}},
|
{"AvailableModelSeries", {PERSISTENT, STRING, "", "", 1}},
|
||||||
{"AvailableModels", {PERSISTENT, STRING, "", "", 1}},
|
{"AvailableModels", {PERSISTENT, STRING, "", "", 1}},
|
||||||
@@ -193,7 +211,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"CalibratedLateralAcceleration", {PERSISTENT, FLOAT, "2.0", "2.0", 2}},
|
{"CalibratedLateralAcceleration", {PERSISTENT, FLOAT, "2.0", "2.0", 2}},
|
||||||
{"CalibrationProgress", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
{"CalibrationProgress", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||||
{"CameraOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
{"CameraOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||||
{"CameraView", {PERSISTENT, INT, "3", "0", 2, SETTINGS_SIMPLE}},
|
{"CameraView", {PERSISTENT, INT, "2", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"CancelDownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
{"CancelDownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||||
{"DisableWideRoad", {PERSISTENT, BOOL, "0", "0", 3}},
|
{"DisableWideRoad", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||||
{"CancelModelDownload", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
{"CancelModelDownload", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||||
@@ -204,7 +222,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"CECurves", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
{"CECurves", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"CECurvesLead", {PERSISTENT, BOOL, "0", "0", 1}},
|
{"CECurvesLead", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||||
{"CELead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"CELead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"CEModelStopTime", {PERSISTENT, FLOAT, "7.0", "0.0", 2, SETTINGS_SIMPLE}},
|
{"CEModelStopTime", {PERSISTENT, FLOAT, "7.7", "0.0", 2, SETTINGS_SIMPLE}},
|
||||||
|
{"CEOpenRoad", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"CESignalLaneDetection", {PERSISTENT, BOOL, "1", "0", 2}},
|
{"CESignalLaneDetection", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||||
{"CESignalSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
|
{"CESignalSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
|
||||||
{"CESlowerLead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"CESlowerLead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
@@ -229,6 +248,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"ConditionalExperimental", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"ConditionalExperimental", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"CurvatureData", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
|
{"CurvatureData", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
|
||||||
{"CurveSpeedController", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"CurveSpeedController", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
|
{"CurveSpeedControllerNoLead", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"CustomAlerts", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
{"CustomAlerts", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
||||||
{"CustomAccelProfile", {PERSISTENT, BOOL, "0", "0", 3}},
|
{"CustomAccelProfile", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||||
{"CustomAccelProfileInitialized", {PERSISTENT, BOOL, "0", "0", 3}},
|
{"CustomAccelProfileInitialized", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||||
@@ -266,7 +286,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
{"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
||||||
{"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}},
|
{"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}},
|
||||||
{"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"DeviceShutdown", {PERSISTENT, INT, "9", "33", 1, SETTINGS_SIMPLE}},
|
{"DeviceShutdown", {PERSISTENT, INT, "6", "6", 1, SETTINGS_SIMPLE}},
|
||||||
{"DisableOnroadUploads", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"DisableOnroadUploads", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"DisableOpenpilotLongitudinal", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
{"DisableOpenpilotLongitudinal", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
||||||
{"DiscordUsername", {PERSISTENT, STRING, "", "", 0}},
|
{"DiscordUsername", {PERSISTENT, STRING, "", "", 0}},
|
||||||
@@ -284,11 +304,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"DownloadAllModels", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
{"DownloadAllModels", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||||
{"DownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
{"DownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||||
{"DriverCamera", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
{"DriverCamera", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"Model", {PERSISTENT, STRING, "sc2", "sc2", 1}},
|
{"Model", {PERSISTENT, STRING, "rdf43", "rdf43", 1}},
|
||||||
{"ModelVersion", {PERSISTENT, STRING, "v11", "v11", 1}},
|
{"ModelVersion", {PERSISTENT, STRING, "v15", "v15", 1}},
|
||||||
{"DrivingModel", {PERSISTENT, STRING, "sc2", "sc2", 1}},
|
{"DrivingModel", {PERSISTENT, STRING, "rdf43", "rdf43", 1}},
|
||||||
{"DrivingModelName", {PERSISTENT, STRING, "South Carolina", "South Carolina", 1}},
|
{"DrivingModelName", {PERSISTENT, STRING, "Regret Driven Framework V4", "Regret Driven Framework V4", 1}},
|
||||||
{"DrivingModelVersion", {PERSISTENT, STRING, "v11", "v11", 1}},
|
{"DrivingModelVersion", {PERSISTENT, STRING, "v15", "v15", 1}},
|
||||||
{"DynamicPathWidth", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"DynamicPathWidth", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"DynamicPedalsOnUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"DynamicPedalsOnUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"EngageVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
|
{"EngageVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
|
||||||
@@ -324,9 +344,22 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"ForceStops", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
|
{"ForceStops", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"ForceStopDistanceOffset", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"ForceStopDistanceOffset", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"ForceStandstill", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"ForceStandstill", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
|
{"FordLKASButtonControlMigrated", {PERSISTENT, BOOL, "0", "0"}},
|
||||||
{"ForceTorqueController", {PERSISTENT, BOOL, "0", "0", 3}},
|
{"ForceTorqueController", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||||
|
{"FordAngleBlend", {PERSISTENT, FLOAT, "0.5", "0.5", 2}},
|
||||||
|
{"FordAngleHighSpeedDamping", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
|
||||||
|
{"FordAngleHighSpeedFactor", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
|
||||||
|
{"FordAngleLaneChangeFactor", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
|
||||||
|
{"FordAngleLowSpeedFactor", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
|
||||||
|
{"FordCurvatureBlendHigh", {PERSISTENT, FLOAT, "0.4", "0.4", 2}},
|
||||||
|
{"FordCurvatureBlendLow", {PERSISTENT, FLOAT, "0.4", "0.4", 2}},
|
||||||
|
{"FordCurvatureLaneChangeFactor", {PERSISTENT, FLOAT, "0.85", "0.85", 2}},
|
||||||
|
{"FordHandsFreeCluster", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||||
|
{"FordHumanTurnDetection", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||||
|
{"FordLateralMode", {PERSISTENT, INT, "1", "1", 2}},
|
||||||
{"FLMActiveOverrides", {PERSISTENT, JSON, "{}", "{}", 2}},
|
{"FLMActiveOverrides", {PERSISTENT, JSON, "{}", "{}", 2}},
|
||||||
{"FLMActiveProfileId", {PERSISTENT, STRING, "", "", 2}},
|
{"FLMActiveProfileId", {PERSISTENT, STRING, "", "", 2}},
|
||||||
|
{"FLMSubmittedTune", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
|
||||||
{"FLMTrialBaseline", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
|
{"FLMTrialBaseline", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
|
||||||
{"FLMTrialApplied", {PERSISTENT, BOOL, "0", "0", 2}},
|
{"FLMTrialApplied", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||||
{"FPSCounter", {PERSISTENT, BOOL, "0", "0", 3}},
|
{"FPSCounter", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||||
@@ -336,9 +369,14 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"StarPilotCarParamsPersistent", {PERSISTENT, BYTES, "", ""}},
|
{"StarPilotCarParamsPersistent", {PERSISTENT, BYTES, "", ""}},
|
||||||
{"StarPilotDongleId", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
|
{"StarPilotDongleId", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
|
||||||
{"StarPilotFavoriteSlots", {PERSISTENT, JSON, "[]", "[]", 1}},
|
{"StarPilotFavoriteSlots", {PERSISTENT, JSON, "[]", "[]", 1}},
|
||||||
|
{"ControllerActionSlots", {PERSISTENT, JSON, "[]", "[]", 1}},
|
||||||
|
{"WheelControlLearnSlot", {CLEAR_ON_MANAGER_START | DONT_LOG, INT}},
|
||||||
|
{"WheelControlMappings", {PERSISTENT, JSON, "[]", "[]", 1}},
|
||||||
|
{"WheelControlStatus", {CLEAR_ON_MANAGER_START | DONT_LOG, JSON, "{}", "{}"}},
|
||||||
|
{"WheelControlTestActive", {CLEAR_ON_MANAGER_START | DONT_LOG, BOOL}},
|
||||||
|
{"WheelControlsEnabled", {PERSISTENT, BOOL, "0"}},
|
||||||
{"StarPilotStats", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
|
{"StarPilotStats", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
|
||||||
{"StarPilotTogglesUpdated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
{"StarPilotTogglesUpdated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||||
{"FrogsGoMoosTweak", {PERSISTENT, BOOL, "1", "0", 2}},
|
|
||||||
{"GoatScream", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
{"GoatScream", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"GoatScreamCriticalAlerts", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
{"GoatScreamCriticalAlerts", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"GreenLightAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
{"GreenLightAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
||||||
@@ -371,13 +409,21 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"IssueReported", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
|
{"IssueReported", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
|
||||||
{"KonikDongleId", {PERSISTENT, STRING, "", "", 0}},
|
{"KonikDongleId", {PERSISTENT, STRING, "", "", 0}},
|
||||||
{"KonikMinutes", {PERSISTENT, INT, "0", "0", 0}},
|
{"KonikMinutes", {PERSISTENT, INT, "0", "0", 0}},
|
||||||
|
{"LaneCentering", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||||
|
{"LaneCenteringPauseOnSignal", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||||
|
{"LaneCenteringE2EAuthority", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
|
||||||
|
{"LaneCenterOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||||
{"LaneChanges", {PERSISTENT, BOOL, "1", "1", 0, SETTINGS_SIMPLE}},
|
{"LaneChanges", {PERSISTENT, BOOL, "1", "1", 0, SETTINGS_SIMPLE}},
|
||||||
|
{"LaneChangeCloseGap", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
||||||
|
{"LaneChangeCloseGapSeconds", {PERSISTENT, FLOAT, "0.6", "0.6", 1, SETTINGS_SIMPLE}},
|
||||||
{"LaneChangeSmoothing", {PERSISTENT, INT, "5", "10", 1, SETTINGS_SIMPLE}},
|
{"LaneChangeSmoothing", {PERSISTENT, INT, "5", "10", 1, SETTINGS_SIMPLE}},
|
||||||
{"LaneChangeTime", {PERSISTENT, FLOAT, "1.0", "0.0", 1, SETTINGS_SIMPLE}},
|
{"LaneChangeTime", {PERSISTENT, FLOAT, "1.0", "0.0", 1, SETTINGS_SIMPLE}},
|
||||||
{"LaneDetectionWidth", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
|
{"LaneDetectionWidth", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
|
||||||
{"LaneLinesColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
|
{"LaneLinesColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
|
||||||
{"LaneLinesWidth", {PERSISTENT, FLOAT, "4.0", "2.0", 2, SETTINGS_SIMPLE}},
|
{"LaneLinesWidth", {PERSISTENT, FLOAT, "4.0", "2.0", 2, SETTINGS_SIMPLE}},
|
||||||
{"LastMapsUpdate", {PERSISTENT, STRING, "", ""}},
|
{"LastMapsUpdate", {PERSISTENT, STRING, "", ""}},
|
||||||
|
{"MapsDownloadProgress", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||||
|
{"MapsDownloadSizeCache", {PERSISTENT, STRING, "{}", "{}"}},
|
||||||
{"LateralTune", {PERSISTENT, BOOL, "1", "0", 1}},
|
{"LateralTune", {PERSISTENT, BOOL, "1", "0", 1}},
|
||||||
{"LeadDepartingAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
{"LeadDepartingAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
||||||
{"LeadDetectionThreshold", {PERSISTENT, INT, "35", "50", 3}},
|
{"LeadDetectionThreshold", {PERSISTENT, INT, "35", "50", 3}},
|
||||||
@@ -415,6 +461,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"MapsSelected", {PERSISTENT, STRING, "", "", 0}},
|
{"MapsSelected", {PERSISTENT, STRING, "", "", 0}},
|
||||||
{"MapSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
|
{"MapSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
|
||||||
{"NavDesiresAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
|
{"NavDesiresAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||||
|
{"NavLanePositioningAllowed", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||||
{"NavLongitudinalAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
|
{"NavLongitudinalAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||||
{"ClearNavOnOffroad", {PERSISTENT, BOOL, "1", "1", 2, SETTINGS_SIMPLE}},
|
{"ClearNavOnOffroad", {PERSISTENT, BOOL, "1", "1", 2, SETTINGS_SIMPLE}},
|
||||||
{"ClearNavOnOffroadTimeoutMinutes", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"ClearNavOnOffroadTimeoutMinutes", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
@@ -439,6 +486,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"ModelDrivesAndScores", {PERSISTENT, JSON, "{}", "{}"}},
|
{"ModelDrivesAndScores", {PERSISTENT, JSON, "{}", "{}"}},
|
||||||
{"ModelReleasedDates", {PERSISTENT, STRING, "", "", 1}},
|
{"ModelReleasedDates", {PERSISTENT, STRING, "", "", 1}},
|
||||||
{"ModelRandomizer", {PERSISTENT, BOOL, "0", "0", 2}},
|
{"ModelRandomizer", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||||
|
{"LatSmoothSeconds", {PERSISTENT, FLOAT, "0.1", "0.1", 3}},
|
||||||
|
{"LongSmoothSeconds", {PERSISTENT, FLOAT, "0.3", "0.3", 3}},
|
||||||
{"ModelSortMode", {PERSISTENT, STRING, "alphabetical", "alphabetical", 1}},
|
{"ModelSortMode", {PERSISTENT, STRING, "alphabetical", "alphabetical", 1}},
|
||||||
{"ModelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
{"ModelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||||
{"ModelUI", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
|
{"ModelUI", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
|
||||||
@@ -466,7 +515,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"OnroadDistanceButtonPressed", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
{"OnroadDistanceButtonPressed", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||||
{"FavoriteVirtualAccelCruiseCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
{"FavoriteVirtualAccelCruiseCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
{"FavoriteVirtualDecelCruiseCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
{"FavoriteVirtualDecelCruiseCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
|
{"FavoriteTrafficModeCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
{"WheelButtonBookmarkCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
{"WheelButtonBookmarkCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
|
{"WheelControlAOLCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
|
{"WheelControlForceCoastCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
|
{"WheelControlPulseGlideCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
{"openpilotMinutes", {PERSISTENT, INT, "0", "0", 0}},
|
{"openpilotMinutes", {PERSISTENT, INT, "0", "0", 0}},
|
||||||
{"OverpassRequests", {PERSISTENT, JSON, "{}", "{}"}},
|
{"OverpassRequests", {PERSISTENT, JSON, "{}", "{}"}},
|
||||||
{"PathColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
|
{"PathColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
|
||||||
@@ -478,12 +531,18 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"PauseLateralSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
|
{"PauseLateralSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
|
||||||
{"LateralResumeDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
|
{"LateralResumeDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
|
||||||
{"PedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
{"PedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
||||||
|
{"PIPPreviewEnabled", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||||
|
{"PIPPreviewMask", {PERSISTENT, JSON, "{\"width\":1928,\"height\":1208,\"center_left\":[315,548],\"center_right\":[1571,539],\"crop_size\":580}", "{\"width\":1928,\"height\":1208,\"center_left\":[315,548],\"center_right\":[1571,539],\"crop_size\":580}", 2}},
|
||||||
|
{"PIPPreviewShowOnBlinker", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||||
|
{"PIPPreviewShowOnBSM", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||||
|
{"PIPPreviewInvert", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||||
{"GalaxyPaired", {PERSISTENT, BOOL, "0", "0", 0}},
|
{"GalaxyPaired", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||||
{"GalaxyUploadPending", {PERSISTENT, BOOL, "0", "0", 0}},
|
{"GalaxyUploadPending", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||||
{"PreferredSchedule", {PERSISTENT, INT, "2", "0", 0}},
|
{"PreferredSchedule", {PERSISTENT, INT, "2", "0", 0}},
|
||||||
{"PreviousSpeedLimit", {PERSISTENT, FLOAT, "0.0", "0.0"}},
|
{"PreviousSpeedLimit", {PERSISTENT, FLOAT, "0.0", "0.0"}},
|
||||||
{"PromptDistractedVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
|
{"PromptDistractedVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
|
||||||
{"PromptVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
|
{"PromptVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
|
||||||
|
{"PulseGlideSpeedDelta", {PERSISTENT, FLOAT, "5.0", "5.0", 3}},
|
||||||
{"QOLLateral", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"QOLLateral", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"QOLLongitudinal", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"QOLLongitudinal", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"QOLVisuals", {PERSISTENT, BOOL, "1", "0", 0, SETTINGS_SIMPLE}},
|
{"QOLVisuals", {PERSISTENT, BOOL, "1", "0", 0, SETTINGS_SIMPLE}},
|
||||||
@@ -509,7 +568,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"RelaxedJerkDeceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
|
{"RelaxedJerkDeceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
|
||||||
{"RelaxedJerkSpeed", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
|
{"RelaxedJerkSpeed", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
|
||||||
{"RelaxedJerkSpeedDecrease", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
|
{"RelaxedJerkSpeedDecrease", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
|
||||||
{"ReverseCruise", {PERSISTENT, BOOL, "0", "0", 1}},
|
{"RivianAngleControl", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
|
{"RivianAngleSaturated", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL, "0", "0"}},
|
||||||
|
{"RivianToiRecoveryFailed", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL, "0", "0"}},
|
||||||
{"RecoveryPower", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
|
{"RecoveryPower", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
|
||||||
{"RoadEdgesWidth", {PERSISTENT, FLOAT, "2.0", "2.0", 2, SETTINGS_SIMPLE}},
|
{"RoadEdgesWidth", {PERSISTENT, FLOAT, "2.0", "2.0", 2, SETTINGS_SIMPLE}},
|
||||||
{"RoadNameUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"RoadNameUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
@@ -575,6 +636,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"VisionSpeedLimitAutoBookmark", {PERSISTENT, BOOL, "0", "0", 0}},
|
{"VisionSpeedLimitAutoBookmark", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||||
{"VisionSpeedLimitAutoPreserveSegment", {PERSISTENT, BOOL, "0", "0", 0}},
|
{"VisionSpeedLimitAutoPreserveSegment", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||||
{"VisionSpeedLimitDetection", {PERSISTENT, BOOL, "1", "0", 0}},
|
{"VisionSpeedLimitDetection", {PERSISTENT, BOOL, "1", "0", 0}},
|
||||||
|
{"VisionSpeedLimitLowLimitFilter", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||||
|
{"VisionSpeedLimitLowLimitThreshold", {PERSISTENT, INT, "25", "25", 0}},
|
||||||
{"VisionSpeedLimitTrainingCollector", {PERSISTENT, BOOL, "1", "1", 0}},
|
{"VisionSpeedLimitTrainingCollector", {PERSISTENT, BOOL, "1", "1", 0}},
|
||||||
{"StandardFollow", {PERSISTENT, FLOAT, "1.45", "1.45", 2}},
|
{"StandardFollow", {PERSISTENT, FLOAT, "1.45", "1.45", 2}},
|
||||||
{"StandardFollowHigh", {PERSISTENT, FLOAT, "1.2", "1.2", 2}},
|
{"StandardFollowHigh", {PERSISTENT, FLOAT, "1.2", "1.2", 2}},
|
||||||
@@ -615,6 +678,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"SwitchbackModeEnabled", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
|
{"SwitchbackModeEnabled", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
|
||||||
{"SubaruSNG", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
|
{"SubaruSNG", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"SubaruSNGManualParkingBrake", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"SubaruSNGManualParkingBrake", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
|
{"SubaruStopStartOff", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
|
{"SubaruAvhOnAtStartup", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"TacoTune", {PERSISTENT, BOOL, "0", "0", 2}},
|
{"TacoTune", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||||
{"TeslaCoopSteering", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"TeslaCoopSteering", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"TestAlert", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
{"TestAlert", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||||
@@ -635,6 +700,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"TuningLevel", {PERSISTENT, INT, "0", "0", 0}},
|
{"TuningLevel", {PERSISTENT, INT, "0", "0", 0}},
|
||||||
{"TuningLevelConfirmed", {PERSISTENT, BOOL, "0", "0", 0}},
|
{"TuningLevelConfirmed", {PERSISTENT, BOOL, "0", "0", 0}},
|
||||||
{"TurnDesires", {PERSISTENT, BOOL, "0", "0", 2}},
|
{"TurnDesires", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||||
|
{"TurnSteeringLimitMuteSpeed", {PERSISTENT, INT, "0", "0", 0}},
|
||||||
{"UnlockDoors", {PERSISTENT, BOOL, "1", "0", 0}},
|
{"UnlockDoors", {PERSISTENT, BOOL, "1", "0", 0}},
|
||||||
{"Updated", {PERSISTENT, STRING, "0", "0"}},
|
{"Updated", {PERSISTENT, STRING, "0", "0"}},
|
||||||
{"UpdateSpeedLimits", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
{"UpdateSpeedLimits", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||||
@@ -647,6 +713,16 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"UseSI", {PERSISTENT, BOOL, "1", "1", 3}},
|
{"UseSI", {PERSISTENT, BOOL, "1", "1", 3}},
|
||||||
{"UserFavorites", {PERSISTENT, STRING, "", "", 1}},
|
{"UserFavorites", {PERSISTENT, STRING, "", "", 1}},
|
||||||
{"UseVienna", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
{"UseVienna", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
||||||
|
{"VASMAnnotationConfig", {PERSISTENT, JSON, "{}", "{}", 2}},
|
||||||
|
{"VASMConfidenceThreshold", {PERSISTENT, FLOAT, "0.94", "0.94", 2}},
|
||||||
|
{"VASMEnabled", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||||
|
{"VASMLeftActive", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
|
||||||
|
{"VASMLeftConfidence", {CLEAR_ON_MANAGER_START, STRING, "0.0", "0.0", 2}},
|
||||||
|
{"VASMLastUpdateMonoTime", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
|
||||||
|
{"VASMRightActive", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
|
||||||
|
{"VASMRightConfidence", {CLEAR_ON_MANAGER_START, STRING, "0.0", "0.0", 2}},
|
||||||
|
{"VASMSmoothSeconds", {PERSISTENT, FLOAT, "0.2", "0.2", 2}},
|
||||||
|
{"VASMTimestampEof", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
|
||||||
{"VEgoStarting", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
{"VEgoStarting", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||||
{"VEgoStartingStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
{"VEgoStartingStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||||
{"VEgoStopping", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
{"VEgoStopping", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
|
||||||
|
|||||||
Binary file not shown.
+4
-1
@@ -50,7 +50,10 @@ class OpenpilotPrefix:
|
|||||||
symlink_path = Params().get_param_path()
|
symlink_path = Params().get_param_path()
|
||||||
if os.path.exists(symlink_path):
|
if os.path.exists(symlink_path):
|
||||||
shutil.rmtree(os.path.realpath(symlink_path), ignore_errors=True)
|
shutil.rmtree(os.path.realpath(symlink_path), ignore_errors=True)
|
||||||
os.remove(symlink_path)
|
# when the params path is a real directory rather than a symlink, rmtree above already
|
||||||
|
# removed it and there is no link left to unlink
|
||||||
|
if os.path.islink(symlink_path):
|
||||||
|
os.remove(symlink_path)
|
||||||
shutil.rmtree(self.msgq_path, ignore_errors=True)
|
shutil.rmtree(self.msgq_path, ignore_errors=True)
|
||||||
if PC:
|
if PC:
|
||||||
shutil.rmtree(Paths.log_root(), ignore_errors=True)
|
shutil.rmtree(Paths.log_root(), ignore_errors=True)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class Priority:
|
|||||||
# - modeld = 55
|
# - modeld = 55
|
||||||
# - camerad = 54
|
# - camerad = 54
|
||||||
CTRL_LOW = 51 # plannerd & radard
|
CTRL_LOW = 51 # plannerd & radard
|
||||||
|
UI = 50
|
||||||
|
|
||||||
# CORE 3
|
# CORE 3
|
||||||
# - pandad = 55
|
# - pandad = 55
|
||||||
|
|||||||
@@ -7,19 +7,6 @@ class Spinner:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.spinner_proc = None
|
self.spinner_proc = None
|
||||||
|
|
||||||
# Prefer the legacy compiled spinner on device.
|
|
||||||
legacy_spinner = os.path.join(BASEDIR, "selfdrive", "ui", "spinner")
|
|
||||||
if os.path.isfile("/TICI") and os.path.isfile(legacy_spinner) and os.access(legacy_spinner, os.X_OK):
|
|
||||||
try:
|
|
||||||
self.spinner_proc = subprocess.Popen([legacy_spinner],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
|
|
||||||
close_fds=True)
|
|
||||||
return
|
|
||||||
except OSError:
|
|
||||||
self.spinner_proc = None
|
|
||||||
|
|
||||||
# Raylib spinner requires Python deps from the repo virtualenv.
|
|
||||||
spinner_cwd = os.path.join(BASEDIR, "system", "ui")
|
spinner_cwd = os.path.join(BASEDIR, "system", "ui")
|
||||||
venv_python = os.path.join(BASEDIR, ".venv", "bin", "python")
|
venv_python = os.path.join(BASEDIR, ".venv", "bin", "python")
|
||||||
python_exec = venv_python if os.path.isfile(venv_python) else "python3"
|
python_exec = venv_python if os.path.isfile(venv_python) else "python3"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from openpilot.common import file_chunker
|
from openpilot.common import file_chunker
|
||||||
|
|
||||||
|
|
||||||
@@ -14,3 +16,19 @@ def test_chunked_stream_round_trip(tmp_path, monkeypatch):
|
|||||||
assert file_chunker.read_file_chunked(path) == payload
|
assert file_chunker.read_file_chunked(path) == payload
|
||||||
with file_chunker.open_file_chunked(path) as stream:
|
with file_chunker.open_file_chunked(path) as stream:
|
||||||
assert stream.read(9) + stream.read() == payload
|
assert stream.read(9) + stream.read() == payload
|
||||||
|
|
||||||
|
|
||||||
|
def test_unchunked_stream_does_not_materialize_file(tmp_path, monkeypatch):
|
||||||
|
path = tmp_path / "fat.onnx"
|
||||||
|
payload = b"large model read through bounded buffers"
|
||||||
|
path.write_bytes(payload)
|
||||||
|
original_read_bytes = Path.read_bytes
|
||||||
|
|
||||||
|
def reject_whole_file_read(candidate):
|
||||||
|
if candidate == path:
|
||||||
|
raise AssertionError("streaming must not call Path.read_bytes()")
|
||||||
|
return original_read_bytes(candidate)
|
||||||
|
|
||||||
|
monkeypatch.setattr(Path, "read_bytes", reject_whole_file_read)
|
||||||
|
with file_chunker.open_file_chunked(path) as stream:
|
||||||
|
assert stream.read() == payload
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
from opendbc.car.hyundai.values import CAR as HYUNDAI_CAR
|
||||||
|
|
||||||
|
from openpilot.starpilot.common.lateral_only_experimental import (
|
||||||
|
experimental_mode_available,
|
||||||
|
lateral_only_experimental_available,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_telluride_platform_allows_lateral_only_experimental_mode():
|
||||||
|
CP = SimpleNamespace(
|
||||||
|
carFingerprint=HYUNDAI_CAR.HYUNDAI_PALISADE_2023,
|
||||||
|
openpilotLongitudinalControl=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert lateral_only_experimental_available(CP)
|
||||||
|
assert experimental_mode_available(CP)
|
||||||
|
|
||||||
|
|
||||||
|
def test_lateral_only_mode_does_not_expand_other_stock_acc_cars():
|
||||||
|
CP = SimpleNamespace(
|
||||||
|
carFingerprint=HYUNDAI_CAR.HYUNDAI_SONATA,
|
||||||
|
openpilotLongitudinalControl=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not lateral_only_experimental_available(CP)
|
||||||
|
assert not experimental_mode_available(CP)
|
||||||
|
|
||||||
|
old_palisade = SimpleNamespace(
|
||||||
|
carFingerprint=HYUNDAI_CAR.HYUNDAI_PALISADE,
|
||||||
|
openpilotLongitudinalControl=False,
|
||||||
|
)
|
||||||
|
assert not lateral_only_experimental_available(old_palisade)
|
||||||
|
|
||||||
|
|
||||||
|
def test_normal_experimental_mode_remains_available_with_openpilot_long():
|
||||||
|
CP = SimpleNamespace(
|
||||||
|
carFingerprint=HYUNDAI_CAR.HYUNDAI_SONATA,
|
||||||
|
openpilotLongitudinalControl=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not lateral_only_experimental_available(CP)
|
||||||
|
assert experimental_mode_available(CP)
|
||||||
@@ -50,11 +50,8 @@ class TestParams:
|
|||||||
assert self.params.get("CarParams", block=True) == b"test"
|
assert self.params.get("CarParams", block=True) == b"test"
|
||||||
|
|
||||||
def test_params_unknown_key_fails(self):
|
def test_params_unknown_key_fails(self):
|
||||||
with pytest.raises(UnknownKeyName):
|
assert self.params.get("swag") is None
|
||||||
self.params.get("swag")
|
assert not self.params.get_bool("swag")
|
||||||
|
|
||||||
with pytest.raises(UnknownKeyName):
|
|
||||||
self.params.get_bool("swag")
|
|
||||||
|
|
||||||
with pytest.raises(UnknownKeyName):
|
with pytest.raises(UnknownKeyName):
|
||||||
self.params.put("swag", "abc")
|
self.params.put("swag", "abc")
|
||||||
|
|||||||
@@ -9,18 +9,6 @@ class TextWindow:
|
|||||||
def __init__(self, text):
|
def __init__(self, text):
|
||||||
self.text_proc = None
|
self.text_proc = None
|
||||||
|
|
||||||
# Prefer the legacy compiled text window on device.
|
|
||||||
legacy_text = os.path.join(BASEDIR, "selfdrive", "ui", "text")
|
|
||||||
if os.path.isfile("/TICI") and os.path.isfile(legacy_text) and os.access(legacy_text, os.X_OK):
|
|
||||||
try:
|
|
||||||
self.text_proc = subprocess.Popen([legacy_text, text],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
|
|
||||||
close_fds=True)
|
|
||||||
return
|
|
||||||
except OSError:
|
|
||||||
self.text_proc = None
|
|
||||||
|
|
||||||
text_cwd = os.path.join(BASEDIR, "system", "ui")
|
text_cwd = os.path.join(BASEDIR, "system", "ui")
|
||||||
venv_python = os.path.join(BASEDIR, ".venv", "bin", "python")
|
venv_python = os.path.join(BASEDIR, ".venv", "bin", "python")
|
||||||
python_exec = venv_python if os.path.isfile(venv_python) else "python3"
|
python_exec = venv_python if os.path.isfile(venv_python) else "python3"
|
||||||
|
|||||||
@@ -2,14 +2,18 @@ import datetime
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
MIN_DATE = datetime.datetime(year=2025, month=2, day=21)
|
MIN_DATE = datetime.datetime(year=2025, month=2, day=21)
|
||||||
|
MAX_DATE = datetime.datetime(year=2035, month=1, day=1)
|
||||||
|
|
||||||
|
def _utc_now_naive():
|
||||||
|
return datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
|
||||||
|
|
||||||
def min_date():
|
def min_date():
|
||||||
# on systemd systems, the default time is the systemd build time
|
# on systemd systems, the default time is the systemd build time
|
||||||
systemd_path = Path("/lib/systemd/systemd")
|
systemd_path = Path("/lib/systemd/systemd")
|
||||||
if systemd_path.exists():
|
if systemd_path.exists():
|
||||||
d = datetime.datetime.fromtimestamp(systemd_path.stat().st_mtime)
|
d = datetime.datetime.fromtimestamp(systemd_path.stat().st_mtime, datetime.UTC).replace(tzinfo=None)
|
||||||
return max(MIN_DATE, d + datetime.timedelta(days=1))
|
return max(MIN_DATE, d + datetime.timedelta(days=1))
|
||||||
return MIN_DATE
|
return MIN_DATE
|
||||||
|
|
||||||
def system_time_valid():
|
def system_time_valid():
|
||||||
return datetime.datetime.now() > min_date()
|
return min_date() < _utc_now_naive() < MAX_DATE
|
||||||
|
|||||||
Binary file not shown.
+14
-10
@@ -5,7 +5,7 @@ import contextlib
|
|||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
import functools
|
import functools
|
||||||
from subprocess import Popen, PIPE, TimeoutExpired
|
from subprocess import Popen, PIPE, STDOUT, TimeoutExpired
|
||||||
import zstandard as zstd
|
import zstandard as zstd
|
||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
|
|
||||||
@@ -87,16 +87,20 @@ def run_cmd_default(cmd: list[str], default: str = "", cwd=None, env=None) -> st
|
|||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def managed_proc(cmd: list[str], env: dict[str, str]):
|
def managed_proc(cmd: list[str], env: dict[str, str]):
|
||||||
proc = Popen(cmd, env=env, stdout=PIPE, stderr=PIPE)
|
# capture output to a temp file rather than a pipe. nothing drains the pipe while the process
|
||||||
try:
|
# runs, so a long lived, chatty child would eventually fill the pipe buffer and block forever.
|
||||||
yield proc
|
with tempfile.TemporaryFile() as log_file:
|
||||||
finally:
|
proc = Popen(cmd, env=env, stdout=log_file, stderr=STDOUT)
|
||||||
if proc.poll() is None:
|
proc.log_file = log_file
|
||||||
proc.terminate()
|
|
||||||
try:
|
try:
|
||||||
proc.wait(timeout=5)
|
yield proc
|
||||||
except TimeoutExpired:
|
finally:
|
||||||
proc.kill()
|
if proc.poll() is None:
|
||||||
|
proc.terminate()
|
||||||
|
try:
|
||||||
|
proc.wait(timeout=5)
|
||||||
|
except TimeoutExpired:
|
||||||
|
proc.kill()
|
||||||
|
|
||||||
|
|
||||||
def retry(attempts=3, delay=1.0, ignore_failure=False):
|
def retry(attempts=3, delay=1.0, ignore_failure=False):
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
#define COMMA_VERSION "0.10.3"
|
#define COMMA_VERSION "0.11.2"
|
||||||
|
|||||||
+22
-2
@@ -8,6 +8,15 @@ from pathlib import Path
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
int(os.environ.get("DEBUG", "0"))
|
||||||
|
except ValueError:
|
||||||
|
os.environ["DEBUG"] = "0"
|
||||||
|
|
||||||
|
if platform.system() == "Darwin":
|
||||||
|
os.environ["SP_HEADLESS_TEST"] = "1"
|
||||||
|
|
||||||
|
|
||||||
def _prepend_host_pytest_runtime() -> None:
|
def _prepend_host_pytest_runtime() -> None:
|
||||||
if platform.system() != "Darwin" or os.getenv("SP_DISABLE_HOST_PYTEST_REDIRECT") == "1":
|
if platform.system() != "Darwin" or os.getenv("SP_DISABLE_HOST_PYTEST_REDIRECT") == "1":
|
||||||
return
|
return
|
||||||
@@ -89,8 +98,7 @@ def openpilot_function_fixture(request):
|
|||||||
# ensure the test doesn't change the prefix
|
# ensure the test doesn't change the prefix
|
||||||
assert "OPENPILOT_PREFIX" in os.environ and prefix == os.environ["OPENPILOT_PREFIX"]
|
assert "OPENPILOT_PREFIX" in os.environ and prefix == os.environ["OPENPILOT_PREFIX"]
|
||||||
|
|
||||||
# cleanup any started processes
|
manager.manager_cleanup()
|
||||||
manager.manager_cleanup()
|
|
||||||
|
|
||||||
# some processes disable gc for performance, re-enable here
|
# some processes disable gc for performance, re-enable here
|
||||||
if not gc.isenabled():
|
if not gc.isenabled():
|
||||||
@@ -118,6 +126,9 @@ def tici_setup_fixture(request, openpilot_function_fixture):
|
|||||||
@pytest.hookimpl(tryfirst=True)
|
@pytest.hookimpl(tryfirst=True)
|
||||||
def pytest_collection_modifyitems(config, items):
|
def pytest_collection_modifyitems(config, items):
|
||||||
skipper = pytest.mark.skip(reason="Skipping tici test on PC")
|
skipper = pytest.mark.skip(reason="Skipping tici test on PC")
|
||||||
|
darwin_fake_event_skipper = pytest.mark.skip(reason="Fake socket events are unavailable on macOS")
|
||||||
|
darwin_tmpfs_skipper = pytest.mark.skip(reason="tmpfs mount tests require Linux")
|
||||||
|
darwin_proxy_skipper = pytest.mark.skip(reason="Athena local proxy socket test requires Linux select semantics")
|
||||||
for item in items:
|
for item in items:
|
||||||
if "tici" in item.keywords:
|
if "tici" in item.keywords:
|
||||||
if not TICI:
|
if not TICI:
|
||||||
@@ -130,6 +141,15 @@ def pytest_collection_modifyitems(config, items):
|
|||||||
class_property_value = getattr(item.cls, class_property_name)
|
class_property_value = getattr(item.cls, class_property_name)
|
||||||
item.add_marker(pytest.mark.xdist_group(class_property_value))
|
item.add_marker(pytest.mark.xdist_group(class_property_value))
|
||||||
|
|
||||||
|
if platform.system() == "Darwin" and item.path.name in ("test_fuzzy.py", "test_processes.py") and "process_replay" in item.path.parts:
|
||||||
|
item.add_marker(darwin_fake_event_skipper)
|
||||||
|
|
||||||
|
if platform.system() == "Darwin" and item.path.name == "test_git.py" and "updated" in item.path.parts:
|
||||||
|
item.add_marker(darwin_tmpfs_skipper)
|
||||||
|
|
||||||
|
if platform.system() == "Darwin" and item.name == "test_start_local_proxy" and "athena" in item.path.parts:
|
||||||
|
item.add_marker(darwin_proxy_skipper)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(trylast=True)
|
@pytest.hookimpl(trylast=True)
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
|
|||||||
+296
-146
@@ -4,108 +4,183 @@
|
|||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
# 326 Supported Cars
|
# 453 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> |Video|Setup 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> |Video|Setup Video|
|
||||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||||
|
|Acura|ADX 2025-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ADX 2025-26">Buy Here</a></sub></details>|||
|
||||||
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ILX 2016-18">Buy Here</a></sub></details>|||
|
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ILX 2016-18">Buy Here</a></sub></details>|||
|
||||||
|Acura|ILX 2019|All|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ILX 2019">Buy Here</a></sub></details>|||
|
|Acura|ILX 2019|All|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ILX 2019">Buy Here</a></sub></details>|||
|
||||||
|Acura|MDX 2025|All except Type S|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2025">Buy Here</a></sub></details>|||
|
|Acura|Integra 2023-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura Integra 2023-26">Buy Here</a></sub></details>|||
|
||||||
|
|Acura|MDX 2014-16|Advance Package|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2014-16">Buy Here</a></sub></details>|||
|
||||||
|
|Acura|MDX 2017-19|All|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2017-19">Buy Here</a></sub></details>|||
|
||||||
|
|Acura|MDX 2020|All|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2020">Buy Here</a></sub></details>|||
|
||||||
|
|Acura|MDX 2022-24|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|43 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2022-24">Buy Here</a></sub></details>|||
|
||||||
|
|Acura|MDX 2025|All except Type S|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2025">Buy Here</a></sub></details>|||
|
||||||
|
|Acura|MDX Hybrid 2017-19|All|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX Hybrid 2017-19">Buy Here</a></sub></details>|||
|
||||||
|
|Acura|MDX Hybrid 2020|All|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX Hybrid 2020">Buy Here</a></sub></details>|||
|
||||||
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2016-18">Buy Here</a></sub></details>|||
|
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2016-18">Buy Here</a></sub></details>|||
|
||||||
|Acura|RDX 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2019-21">Buy Here</a></sub></details>|||
|
|Acura|RDX 2019-21|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2019-21">Buy Here</a></sub></details>|||
|
||||||
|Acura|TLX 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura TLX 2021">Buy Here</a></sub></details>|||
|
|Acura|RDX 2022-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|43 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2022-26">Buy Here</a></sub></details>|||
|
||||||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi A3 2014-19">Buy Here</a></sub></details>|||
|
|Acura|TLX 2015-17|Advance Package|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura TLX 2015-17">Buy Here</a></sub></details>|||
|
||||||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>|||
|
|Acura|TLX 2018-20|All|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura TLX 2018-20">Buy Here</a></sub></details>|||
|
||||||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q2 2018">Buy Here</a></sub></details>|||
|
|Acura|TLX 2021|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura TLX 2021">Buy Here</a></sub></details>|||
|
||||||
|Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q3 2019-24">Buy Here</a></sub></details>|||
|
|Acura|TLX 2024-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura TLX 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi RS3 2018">Buy Here</a></sub></details>|||
|
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi A3 2014-19">Buy Here</a></sub></details>|||
|
||||||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi S3 2015-17">Buy Here</a></sub></details>|||
|
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi A3 Sportback e-tron 2017-18">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|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet 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>||
|
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q2 2018">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|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV 2022-23">Buy Here</a></sub></details>|||
|
|Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q3 2019-24">Buy Here</a></sub></details>|||
|
||||||
|
|Audi|Q4 e-tron 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q4 e-tron 2021-23">Buy Here</a></sub></details>|||
|
||||||
|
|Audi|Q4 e-tron 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q4 e-tron 2024-25">Buy Here</a></sub></details>|||
|
||||||
|
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi RS3 2018">Buy Here</a></sub></details>|||
|
||||||
|
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi S3 2015-17">Buy Here</a></sub></details>|||
|
||||||
|
|Buick|Baby Enclave 2020-23|Driver Assist Package|Stock|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Buick Baby Enclave 2020-23">Buy Here</a></sub></details>|||
|
||||||
|
|Buick[<sup>3</sup>](#footnotes)|LaCrosse 2017-19|Driver Confidence Package 2|openpilot|18 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Buick LaCrosse 2017-19">Buy Here</a></sub></details>|||
|
||||||
|
|Buick|LaCrosse ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|Stock|3 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Buick LaCrosse ASCM Harness 2017-19">Buy Here</a></sub></details>|||
|
||||||
|
|Buick|LaCrosse US ASCM Harness 2019|Adaptive Cruise Control (ACC)|Stock|3 mph|27 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Buick LaCrosse US ASCM Harness 2019">Buy Here</a></sub></details>|||
|
||||||
|
|Buick[<sup>3</sup>](#footnotes)|Regal Essence 2018|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Buick Regal Essence 2018">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac[<sup>3</sup>](#footnotes)|ATS Premium Performance 2018|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac ATS Premium Performance 2018">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac[<sup>3</sup>](#footnotes)|CT6 No-ACC 2016-20|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac CT6 No-ACC 2016-20">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac[<sup>3</sup>](#footnotes)|Escalade 2017|Driver Assist Package|openpilot|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac Escalade 2017">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac|Escalade ASCM Harness 2018|Driver Assist Package|Stock|3 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac Escalade ASCM Harness 2018">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac[<sup>3</sup>](#footnotes)|Escalade ESV 2016|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac Escalade ESV 2016">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac[<sup>3</sup>](#footnotes)|Escalade ESV 2019|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac Escalade ESV 2019">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac|Escalade ESV Platinum ASCM Harness 2019|Adaptive Cruise Control (ACC) & LKAS|Stock|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac Escalade ESV Platinum ASCM Harness 2019">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac|XT4 2023|Driver Assist Package|Stock|0 mph|30 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac XT4 2023">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac[<sup>3</sup>](#footnotes)|XT4 No-ACC 2023|Adaptive Cruise Control (ACC)|openpilot|24 mph|30 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac XT4 No-ACC 2023">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac|XT5 2022|Driver Assist Package|Stock|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac XT5 2022">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac[<sup>3</sup>](#footnotes)|XT5 No-ACC 2022|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac XT5 No-ACC 2022">Buy Here</a></sub></details>|||
|
||||||
|
|Cadillac|XT6 2020|Driver Assist Package|Stock|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac XT6 2020">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Blazer 2019-25|Driver Assist Package|Stock|3 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Blazer 2019-25">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Bolt EV & EUV ACC 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV & EUV ACC 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|Bolt EV & EUV ACC w Pedal 2022-23|Adaptive Cruise Control (ACC)|openpilot|24 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV & EUV ACC w Pedal 2022-23">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Bolt EV & EUV No-ACC 2022-23|Adaptive Cruise Control (ACC)|openpilot|24 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV & EUV No-ACC 2022-23">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Bolt EV No-ACC 2017|Adaptive Cruise Control (ACC)|openpilot|24 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV No-ACC 2017">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Bolt EV No-ACC 2018-21|Adaptive Cruise Control (ACC)|openpilot|24 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV No-ACC 2018-21">Buy Here</a></sub></details>|||
|
||||||
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Equinox 2019-22">Buy Here</a></sub></details>|||
|
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Equinox 2019-22">Buy Here</a></sub></details>|||
|
||||||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Silverado 1500 2020-21">Buy Here</a></sub></details>|||
|
|Chevrolet[<sup>3</sup>](#footnotes)|Equinox No-ACC 2019-22|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Equinox No-ACC 2019-22">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Malibu 2019|SDGM Harness (Optional SASCM)|Stock|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu 2019">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Malibu ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|Stock|3 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu ASCM Harness 2017-19">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Malibu Hybrid No-ACC 2017|Adaptive Cruise Control (ACC)|openpilot|24 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu Hybrid No-ACC 2017">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet[<sup>3</sup>](#footnotes)|Malibu No-ACC 2023|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu No-ACC 2023">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet[<sup>3</sup>](#footnotes)|Malibu Premier 2017|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu Premier 2017">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Silverado 1500 2020-21">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet[<sup>3</sup>](#footnotes)|Silverado 1500 No-ACC 2020-21|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Silverado 1500 No-ACC 2020-21">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet[<sup>3</sup>](#footnotes)|Suburban Premier 2016-20|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Suburban Premier 2016-20">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet[<sup>3</sup>](#footnotes)|Suburban Premier No-ACC 2016-20|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Suburban Premier No-ACC 2016-20">Buy Here</a></sub></details>|||
|
||||||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Trailblazer 2021-22">Buy Here</a></sub></details>|||
|
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Trailblazer 2021-22">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet[<sup>3</sup>](#footnotes)|Trailblazer No-ACC 2021-22|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Trailblazer No-ACC 2021-22">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Traverse 2022-23|RS, Premier, or High Country Trim|Stock|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Traverse 2022-23">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|TRAX 2024-25|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet TRAX 2024-25">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet[<sup>3</sup>](#footnotes)|Volt 2017-18|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet 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|Volt 2019|Adaptive Cruise Control (ACC) & LKAS|Stock|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Volt 2019">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Volt ASCM Harness 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Volt ASCM Harness 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|Volt Camera Harness 2017-18|Flashed camera-forward integration with ACC|openpilot available[<sup>1</sup>](#footnotes)|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Volt Camera Harness 2017-18">Buy Here</a></sub></details>|||
|
||||||
|
|Chevrolet|Volt No-ACC 2016-18 (OBD Harness)|Redneck ACC|openpilot|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Volt No-ACC 2016-18 (OBD Harness)">Buy Here</a></sub></details>|||
|
||||||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2017-18">Buy Here</a></sub></details>|||
|
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2017-18">Buy Here</a></sub></details>|||
|
||||||
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2019-20">Buy Here</a></sub></details>|||
|
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2019-20">Buy Here</a></sub></details>|||
|
||||||
|Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2021-23">Buy Here</a></sub></details>|||
|
|Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2021-23">Buy Here</a></sub></details>|||
|
||||||
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica Hybrid 2017-18">Buy Here</a></sub></details>|||
|
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica Hybrid 2017-18">Buy Here</a></sub></details>|||
|
||||||
|Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica Hybrid 2019-25">Buy Here</a></sub></details>|||
|
|Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica Hybrid 2019-25">Buy Here</a></sub></details>|||
|
||||||
|comma|body|All|openpilot|0 mph|0 mph|[](##)|[](##)|None|<a href="https://youtu.be/VT-i3yRsX2s?t=2736" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|comma|body|All|openpilot|0 mph|0 mph|[](##)|[](##)|None|<a href="https://youtu.be/VT-i3yRsX2s?t=2736" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||||
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=CUPRA Ateca 2018-23">Buy Here</a></sub></details>|||
|
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=CUPRA Ateca 2018-23">Buy Here</a></sub></details>|||
|
||||||
|
|CUPRA|Born 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=CUPRA Born 2021-23">Buy Here</a></sub></details>|||
|
||||||
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Dodge Durango 2020-21">Buy Here</a></sub></details>|||
|
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Dodge Durango 2020-21">Buy Here</a></sub></details>|||
|
||||||
|Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Bronco Sport 2021-24">Buy Here</a></sub></details>|||
|
|Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Bronco Sport 2021-24">Buy Here</a></sub></details>|||
|
||||||
|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape 2020-22">Buy Here</a></sub></details>|||
|
|Ford|Edge 2022|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Edge 2022">Buy Here</a></sub></details>|||
|
||||||
|
|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape 2020-22">Buy Here</a></sub></details>|||
|
||||||
|Ford|Escape 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Escape 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Hybrid 2020-22">Buy Here</a></sub></details>|||
|
|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Hybrid 2020-22">Buy Here</a></sub></details>|||
|
||||||
|Ford|Escape Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Hybrid 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Escape Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Hybrid 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|Escape Plug-in Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|||
|
|Ford|Escape Plug-in Hybrid 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|||
|
||||||
|Ford|Escape Plug-in Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Plug-in Hybrid 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Escape Plug-in Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Plug-in Hybrid 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|Expedition 2022-24|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Expedition 2022-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Expedition 2022-24|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Expedition 2022-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|Explorer 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Explorer 2020-24">Buy Here</a></sub></details>|||
|
|Ford|Explorer 2020-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Explorer 2020-24">Buy Here</a></sub></details>|||
|
||||||
|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Explorer Hybrid 2020-24">Buy Here</a></sub></details>|||
|
|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Explorer Hybrid 2020-24">Buy Here</a></sub></details>|||
|
||||||
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford F-150 2021-23">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford F-150 2021-23">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford F-150 Hybrid 2021-23">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford F-150 Hybrid 2021-23">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|Focus 2018[<sup>2</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Focus 2018">Buy Here</a></sub></details>|||
|
|Ford|F-150 Lightning 2022-25|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford F-150 Lightning 2022-25">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|Focus Hybrid 2018[<sup>2</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Focus Hybrid 2018">Buy Here</a></sub></details>|||
|
|Ford|Focus 2018-22[<sup>2</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Focus 2018-22">Buy Here</a></sub></details>|||
|
||||||
|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga 2020-23">Buy Here</a></sub></details>|||
|
|Ford|Focus Hybrid 2018-22[<sup>2</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Focus Hybrid 2018-22">Buy Here</a></sub></details>|||
|
||||||
|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Hybrid 2020-23">Buy Here</a></sub></details>|||
|
|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga 2020-23">Buy Here</a></sub></details>|||
|
||||||
|
|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Hybrid 2020-23">Buy Here</a></sub></details>|||
|
||||||
|Ford|Kuga Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Hybrid 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Kuga Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Hybrid 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|Kuga Plug-in Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Plug-in Hybrid 2020-23">Buy Here</a></sub></details>|||
|
|Ford|Kuga Plug-in Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Plug-in Hybrid 2020-23">Buy Here</a></sub></details>|||
|
||||||
|Ford|Kuga Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Plug-in Hybrid 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Kuga Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Plug-in Hybrid 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|Maverick 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick 2022">Buy Here</a></sub></details>|||
|
|Ford|Maverick 2022|LARIAT Luxury|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick 2022">Buy Here</a></sub></details>|||
|
||||||
|Ford|Maverick 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick 2023-24">Buy Here</a></sub></details>|||
|
|Ford|Maverick 2023-24|Co-Pilot360 Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick 2023-24">Buy Here</a></sub></details>|||
|
||||||
|Ford|Maverick Hybrid 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick Hybrid 2022">Buy Here</a></sub></details>|||
|
|Ford|Maverick Hybrid 2022|LARIAT Luxury|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick Hybrid 2022">Buy Here</a></sub></details>|||
|
||||||
|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick Hybrid 2023-24">Buy Here</a></sub></details>|||
|
|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick Hybrid 2023-24">Buy Here</a></sub></details>|||
|
||||||
|
|Ford|Mondeo 2014-22|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Mondeo 2014-22">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|Mustang Mach-E 2021-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Mustang Mach-E 2021-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Mustang Mach-E 2021-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Mustang Mach-E 2021-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Ranger 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Ranger 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|
|Ford|Transit 2025|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Transit 2025">Buy Here</a></sub></details>|||
|
||||||
|Genesis|G70 2018|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2018">Buy Here</a></sub></details>|||
|
|Genesis|G70 2018|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2018">Buy Here</a></sub></details>|||
|
||||||
|Genesis|G70 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2019-21">Buy Here</a></sub></details>|||
|
|Genesis|G70 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2019-21">Buy Here</a></sub></details>|||
|
||||||
|Genesis|G70 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2022-23">Buy Here</a></sub></details>|||
|
|Genesis|G70 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2022-23">Buy Here</a></sub></details>|||
|
||||||
|Genesis|G80 2017|All|Stock|19 mph|37 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 2017">Buy Here</a></sub></details>|||
|
|Genesis|G80 2017|All|Stock|19 mph|37 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 2017">Buy Here</a></sub></details>|||
|
||||||
|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 2018-19">Buy Here</a></sub></details>|||
|
|Genesis|G80 2018-19|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 2018-19">Buy Here</a></sub></details>|||
|
||||||
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 (2.5T Advanced Trim, with HDA II) 2024">Buy Here</a></sub></details>|||
|
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 (2.5T Advanced Trim, with HDA II) 2024">Buy Here</a></sub></details>|||
|
||||||
|Genesis|G90 2017-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G90 2017-20">Buy Here</a></sub></details>|||
|
|Genesis|G90 2017-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G90 2017-20">Buy Here</a></sub></details>|||
|
||||||
|Genesis|GV60 (Advanced Trim) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV60 (Advanced Trim) 2023">Buy Here</a></sub></details>|||
|
|Genesis|GV60 (Advanced Trim) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV60 (Advanced Trim) 2023">Buy Here</a></sub></details>|||
|
||||||
|Genesis|GV60 (Performance Trim) 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV60 (Performance Trim) 2022-23">Buy Here</a></sub></details>|||
|
|Genesis|GV60 (Performance Trim) 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV60 (Performance Trim) 2022-23">Buy Here</a></sub></details>|||
|
||||||
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 (2.5T Trim, without HDA II) 2022-24">Buy Here</a></sub></details>|||
|
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 (2.5T Trim, without HDA II) 2022-24">Buy Here</a></sub></details>|||
|
||||||
|
|Genesis|GV70 (3.5T Sport Prestige Trim, with HDA II & LFA2) 2026|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 (3.5T Sport Prestige Trim, with HDA II & LFA2) 2026">Buy Here</a></sub></details>|||
|
||||||
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 (3.5T Trim, without HDA II) 2022-23">Buy Here</a></sub></details>|||
|
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 (3.5T Trim, without HDA II) 2022-23">Buy Here</a></sub></details>|||
|
||||||
|
|Genesis|GV70 Electrified 2026|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 Electrified 2026">Buy Here</a></sub></details>|||
|
||||||
|Genesis|GV70 Electrified (Australia Only) 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 Electrified (Australia Only) 2022">Buy Here</a></sub></details>|||
|
|Genesis|GV70 Electrified (Australia Only) 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 Electrified (Australia Only) 2022">Buy Here</a></sub></details>|||
|
||||||
|Genesis|GV70 Electrified (with HDA II) 2023-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 Electrified (with HDA II) 2023-24">Buy Here</a></sub></details>|||
|
|Genesis|GV70 Electrified (with HDA II) 2023-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 Electrified (with HDA II) 2023-24">Buy Here</a></sub></details>|||
|
||||||
|Genesis|GV80 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV80 2023">Buy Here</a></sub></details>|||
|
|Genesis|GV80 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis 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|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC 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>||
|
|Genesis|GV80 (3.5T Prestige Trim, with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV80 (3.5T Prestige Trim, with HDA II & LFA2) 2025">Buy Here</a></sub></details>|||
|
||||||
|Honda|Accord 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda 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>||
|
|Genesis|GV80 Coupe (with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV80 Coupe (with HDA II & LFA2) 2025">Buy Here</a></sub></details>|||
|
||||||
|Honda|Accord 2023-25|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2023-25">Buy Here</a></sub></details>|||
|
|GMC[<sup>3</sup>](#footnotes)|Acadia 2018|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC 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 Hybrid 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2018-22">Buy Here</a></sub></details>|||
|
|GMC|Acadia ASCM Harness 2018|Adaptive Cruise Control (ACC)|Stock|3 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Acadia ASCM Harness 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 Hybrid 2023-25|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2023-25">Buy Here</a></sub></details>|||
|
|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC 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|City (Brazil only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|14 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda City (Brazil only) 2023">Buy Here</a></sub></details>|||
|
|GMC[<sup>3</sup>](#footnotes)|Sierra 1500 No-ACC 2020-21|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Sierra 1500 No-ACC 2020-21">Buy Here</a></sub></details>|||
|
||||||
|
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|Stock|0 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Yukon 2019-20">Buy Here</a></sub></details>|||
|
||||||
|
|GMC[<sup>3</sup>](#footnotes)|Yukon No-ACC 2019-20|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Yukon No-ACC 2019-20">Buy Here</a></sub></details>|||
|
||||||
|
|Holden[<sup>3</sup>](#footnotes)|Astra 2017|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Holden Astra 2017">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Accord 2016-17|Honda Sensing|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2016-17">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Accord 2018-22|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda 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|Accord 2023-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2023-25">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Accord Hybrid 2017|All|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2017">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Accord Hybrid 2018-22|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2018-22">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Accord Hybrid 2023-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2023-25">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|City (Brazil only) 2023|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|14 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda City (Brazil only) 2023">Buy Here</a></sub></details>|||
|
||||||
|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda 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 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda 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 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|2 mph[<sup>4</sup>](#footnotes)|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda 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 2019-21|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|2 mph[<sup>4</sup>](#footnotes)|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda 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 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2022-24">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 2022-24|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2022-24">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-18|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2017-18">Buy Here</a></sub></details>|||
|
|Honda|Civic Hatchback 2017-18|Honda Sensing|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2017-18">Buy Here</a></sub></details>|||
|
||||||
|Honda|Civic Hatchback 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2019-21">Buy Here</a></sub></details>|||
|
|Honda|Civic Hatchback 2019-21|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2019-21">Buy Here</a></sub></details>|||
|
||||||
|Honda|Civic Hatchback 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2022-24">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-24|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2022-24">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 Hybrid 2025-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid 2025-26">Buy Here</a></sub></details>|||
|
|Honda|Civic Hatchback Hybrid 2025-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid 2025-26">Buy Here</a></sub></details>|||
|
||||||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid (Europe only) 2023">Buy Here</a></sub></details>|||
|
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid (Europe only) 2023">Buy Here</a></sub></details>|||
|
||||||
|Honda|Civic Hybrid 2025-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hybrid 2025-26">Buy Here</a></sub></details>|||
|
|Honda|Civic Hybrid 2025-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hybrid 2025-26">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Clarity 2018-21|All|openpilot|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Clarity 2018-21">Buy Here</a></sub></details>|||
|
||||||
|Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2015-16">Buy Here</a></sub></details>|||
|
|Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2015-16">Buy Here</a></sub></details>|||
|
||||||
|Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|15 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2017-22">Buy Here</a></sub></details>|||
|
|Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|15 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2017-22">Buy Here</a></sub></details>|||
|
||||||
|Honda|CR-V 2023-26|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2023-26">Buy Here</a></sub></details>|||
|
|Honda|CR-V 2023-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2023-26">Buy Here</a></sub></details>|||
|
||||||
|Honda|CR-V Hybrid 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V Hybrid 2017-22">Buy Here</a></sub></details>|||
|
|Honda|CR-V Hybrid 2017-22|Honda Sensing|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V Hybrid 2017-22">Buy Here</a></sub></details>|||
|
||||||
|Honda|CR-V Hybrid 2023-25|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V Hybrid 2023-25">Buy Here</a></sub></details>|||
|
|Honda|CR-V Hybrid 2023-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V Hybrid 2023-25">Buy Here</a></sub></details>|||
|
||||||
|Honda|e 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda e 2020">Buy Here</a></sub></details>|||
|
|Honda|e 2020|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda e 2020">Buy Here</a></sub></details>|||
|
||||||
|Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Fit 2018-20">Buy Here</a></sub></details>|||
|
|Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Fit 2018-20">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Fit (Taiwan) 2021|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|14 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Fit (Taiwan) 2021">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Fit (Taiwan) 2024-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|14 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Fit (Taiwan) 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Honda|Freed 2020|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Freed 2020">Buy Here</a></sub></details>|||
|
|Honda|Freed 2020|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Freed 2020">Buy Here</a></sub></details>|||
|
||||||
|Honda|HR-V 2019-22|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda HR-V 2019-22">Buy Here</a></sub></details>|||
|
|Honda|HR-V 2019-22|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda HR-V 2019-22">Buy Here</a></sub></details>|||
|
||||||
|Honda|HR-V 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda HR-V 2023-25">Buy Here</a></sub></details>|||
|
|Honda|HR-V 2023-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda HR-V 2023-25">Buy Here</a></sub></details>|||
|
||||||
|Honda|Insight 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Insight 2019-22">Buy Here</a></sub></details>|||
|
|Honda|Insight 2019-22|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Insight 2019-22">Buy Here</a></sub></details>|||
|
||||||
|Honda|Inspire 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Inspire 2018">Buy Here</a></sub></details>|||
|
|Honda|Inspire 2018|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Inspire 2018">Buy Here</a></sub></details>|||
|
||||||
|Honda|N-Box 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|11 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda N-Box 2018">Buy Here</a></sub></details>|||
|
|Honda|N-Box 2018|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|11 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda N-Box 2018">Buy Here</a></sub></details>|||
|
||||||
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2018-20">Buy Here</a></sub></details>|||
|
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2018-20">Buy Here</a></sub></details>|||
|
||||||
|Honda|Odyssey 2021-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|43 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2021-26">Buy Here</a></sub></details>|||
|
|Honda|Odyssey 2021-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|43 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2021-26">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Odyssey (Singapore) 2021|Honda Sensing|openpilot|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey (Singapore) 2021">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Odyssey (Taiwan) 2018-19|Honda Sensing|openpilot|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey (Taiwan) 2018-19">Buy Here</a></sub></details>|||
|
||||||
|Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Passport 2019-25">Buy Here</a></sub></details>|||
|
|Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Passport 2019-25">Buy Here</a></sub></details>|||
|
||||||
|Honda|Passport 2026|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Passport 2026">Buy Here</a></sub></details>|||
|
|Honda|Passport 2026|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Passport 2026">Buy Here</a></sub></details>|||
|
||||||
|Honda|Pilot 2016-22|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2016-22">Buy Here</a></sub></details>|||
|
|Honda|Pilot 2016-22|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2016-22">Buy Here</a></sub></details>|||
|
||||||
|Honda|Pilot 2023-25|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2023-25">Buy Here</a></sub></details>|||
|
|Honda|Pilot 2023-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2023-25">Buy Here</a></sub></details>|||
|
||||||
|
|Honda|Prelude 2026|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Prelude 2026">Buy Here</a></sub></details>|||
|
||||||
|Honda|Ridgeline 2017-25|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Ridgeline 2017-25">Buy Here</a></sub></details>|||
|
|Honda|Ridgeline 2017-25|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Ridgeline 2017-25">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera 2022">Buy Here</a></sub></details>|||
|
|Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera 2022">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid 2019">Buy Here</a></sub></details>|||
|
|Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid 2019">Buy Here</a></sub></details>|||
|
||||||
@@ -115,14 +190,20 @@ A supported vehicle is one that just works when you install a comma device. All
|
|||||||
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2017-18">Buy Here</a></sub></details>|||
|
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2017-18">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2019">Buy Here</a></sub></details>|||
|
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2019">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Elantra 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra GT 2017-20">Buy Here</a></sub></details>|||
|
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra GT 2017-20">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Elantra Hybrid 2024-26|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Hybrid 2024-26">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Genesis 2015-16">Buy Here</a></sub></details>|||
|
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Genesis 2015-16">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai i30 2017-19">Buy Here</a></sub></details>|||
|
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai i30 2017-19">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|i30 Hybrid 2024|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai i30 Hybrid 2024">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (Southeast Asia and Europe only) 2022-24">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (Southeast Asia and Europe only) 2022-24">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Ioniq 5 (with HDA II) 2022-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq 5 (with HDA II) 2022-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Ioniq 5 (without HDA II) 2022-24|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq 5 (without HDA II) 2022-24|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Ioniq 6 (with HDA II) 2023-24|Highway Driving Assist II|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 6 (with HDA II) 2023-24">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq 5 N (with HDA II) 2024|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai S connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 N (with HDA II) 2024">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Ioniq 5 PE (with HDA II & LFA2) 2025-26|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 PE (with HDA II & LFA2) 2025-26">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Ioniq 6 (with HDA II) 2023-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 6 (with HDA II) 2023-24">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Ioniq 9 (with HDA II & LFA2) 2025-26|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 9 (with HDA II & LFA2) 2025-26">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Electric 2019">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Electric 2019">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Electric 2020">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Electric 2020">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Hybrid 2017-19">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Hybrid 2017-19">Buy Here</a></sub></details>|||
|
||||||
@@ -130,39 +211,62 @@ A supported vehicle is one that just works when you install a comma device. All
|
|||||||
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2019">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|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona 2020">Buy Here</a></sub></details>|||
|
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona 2020">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Kona (without HDA II) 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona (without HDA II) 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2018-21">Buy Here</a></sub></details>|||
|
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2018-21">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2022-23">Buy Here</a></sub></details>|||
|
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2022-23">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Kona Electric (without HDA II) 2024|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric (without HDA II) 2024">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Hybrid 2020">Buy Here</a></sub></details>|||
|
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Hybrid 2020">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Kona Hybrid (without HDA II) 2024|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Hybrid (without HDA II) 2024">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Nexo 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Nexo 2021">Buy Here</a></sub></details>|||
|
|Hyundai|Nexo 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Nexo 2021">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Palisade (with HDA II) 2023-25|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Palisade (with HDA II) 2023-25">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Palisade (without HDA II) 2023-25|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Palisade (without HDA II) 2023-25">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Cruz 2022-24">Buy Here</a></sub></details>|||
|
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Cruz 2022-24">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Santa Cruz (without HDA II) 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Cruz (without HDA II) 2025">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Santa Fe 2019-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe 2019-20">Buy Here</a></sub></details>|<a href="https://youtu.be/bjDR0YjM__s" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Hyundai|Santa Fe 2019-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe 2019-20">Buy Here</a></sub></details>|<a href="https://youtu.be/bjDR0YjM__s" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||||
|Hyundai|Santa Fe 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Santa Fe 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Santa Fe Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>|||
|
|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Santa Fe Hybrid (with HDA II & LFA2) 2024-25|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Hybrid (with HDA II & LFA2) 2024-25">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Santa Fe Hybrid (without HDA II, LFA2) 2025-26|Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Hybrid (without HDA II, LFA2) 2025-26">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>|||
|
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata 2018-19">Buy Here</a></sub></details>|||
|
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata 2018-19">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Sonata 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Sonata 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai 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|Sonata (without HDA II) 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata (without HDA II) 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Sonata Hybrid 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata Hybrid 2020-23">Buy Here</a></sub></details>|||
|
|Hyundai|Sonata Hybrid 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata Hybrid 2020-23">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Sonata Hybrid (without HDA II) 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata Hybrid (without HDA II) 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Staria 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Staria 2023">Buy Here</a></sub></details>|||
|
|Hyundai|Staria 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Staria 2023">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2021">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2021">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2022">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2022">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Tucson 2023-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2023-24">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson 2023-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2023-24">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Tucson (without HDA II) 2025-26|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson (without HDA II) 2025-26">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Diesel 2019">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Diesel 2019">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Tucson Hybrid 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Hybrid 2022-24">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson Hybrid 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Hybrid 2022-24">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Tucson Hybrid (without HDA II) 2025-26|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Hybrid (without HDA II) 2025-26">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Tucson Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Plug-in Hybrid 2024">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Plug-in Hybrid 2024">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Tucson Plug-in Hybrid (without HDA II) 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Plug-in Hybrid (without HDA II) 2025">Buy Here</a></sub></details>|||
|
||||||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Veloster 2019-20">Buy Here</a></sub></details>|||
|
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Veloster 2019-20">Buy Here</a></sub></details>|||
|
||||||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Jeep 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>||
|
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Jeep 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>||
|
||||||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Jeep 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>||
|
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Jeep 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|Carnival 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival 2022-24">Buy Here</a></sub></details>|||
|
|Kia|Carnival 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival 2022-24">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Carnival 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival 2025">Buy Here</a></sub></details>|||
|
||||||
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival (China only) 2023">Buy Here</a></sub></details>|||
|
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival (China only) 2023">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Carnival (with HDA II) 2025|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival (with HDA II) 2025">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Carnival Hybrid 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival Hybrid 2025">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Carnival Hybrid 2026|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival Hybrid 2026">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Carnival Hybrid (with HDA II) 2025-26|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival Hybrid (with HDA II) 2025-26">Buy Here</a></sub></details>|||
|
||||||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed 2019-21">Buy Here</a></sub></details>|||
|
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed 2019-21">Buy Here</a></sub></details>|||
|
||||||
|Kia|EV6 (Southeast Asia only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>|||
|
|Kia|EV6 (Southeast Asia only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|EV6 (with HDA I) 2025|Highway Driving Assist I|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (with HDA I) 2025">Buy Here</a></sub></details>|||
|
||||||
|Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|
|Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|
||||||
|Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
|
|Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|EV9 2025-26|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV9 2025-26">Buy Here</a></sub></details>|||
|
||||||
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2019-21">Buy Here</a></sub></details>|||
|
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2019-21">Buy Here</a></sub></details>|||
|
||||||
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2022-23">Buy Here</a></sub></details>|||
|
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2022-23">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|K4 (with HDA II) 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K4 (with HDA II) 2025">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|K4 (without HDA II) 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K4 (without HDA II) 2025">Buy Here</a></sub></details>|||
|
||||||
|Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 2021-24">Buy Here</a></sub></details>|||
|
|Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 2021-24">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|K5 (without HDA II) 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 (without HDA II) 2025">Buy Here</a></sub></details>|||
|
||||||
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 Hybrid 2020-22">Buy Here</a></sub></details>|||
|
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 Hybrid 2020-22">Buy Here</a></sub></details>|||
|
||||||
|Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K8 Hybrid (with HDA II) 2023">Buy Here</a></sub></details>|||
|
|Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K8 Hybrid (with HDA II) 2023">Buy Here</a></sub></details>|||
|
||||||
|Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia 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|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia 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>||
|
||||||
@@ -186,13 +290,20 @@ A supported vehicle is one that just works when you install a comma device. All
|
|||||||
|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia 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|Sorento 2018|Advanced Smart Cruise Control & LKAS|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia 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|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia 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|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia 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|Sorento 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento 2021-23">Buy Here</a></sub></details>|||
|
|Kia|Sorento 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento 2021-23">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Sorento (without HDA II) 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento (without HDA II) 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Kia|Sorento Hybrid 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento Hybrid 2021-23">Buy Here</a></sub></details>|||
|
|Kia|Sorento Hybrid 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento Hybrid 2021-23">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Sorento Hybrid 2026|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento Hybrid 2026">Buy Here</a></sub></details>|||
|
||||||
|Kia|Sorento Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>|||
|
|Kia|Sorento Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>|||
|
||||||
|Kia|Sportage 2023-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage 2023-24">Buy Here</a></sub></details>|||
|
|Kia|Sportage 2023-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage 2023-24">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Sportage (without HDA II) 2026|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage (without HDA II) 2026">Buy Here</a></sub></details>|||
|
||||||
|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage Hybrid 2023">Buy Here</a></sub></details>|||
|
|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage Hybrid 2023">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Sportage Hybrid 2026|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage Hybrid 2026">Buy Here</a></sub></details>|||
|
||||||
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia 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|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia 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|Stinger 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Stinger 2022-23">Buy Here</a></sub></details>|||
|
|Kia|Stinger 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Stinger 2022-23">Buy Here</a></sub></details>|||
|
||||||
|Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Telluride 2020-22">Buy Here</a></sub></details>|||
|
|Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Telluride 2020-22">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Telluride (with HDA II) 2023-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Telluride (with HDA II) 2023-24">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Telluride (without HDA II) 2023-25|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Telluride (without HDA II) 2023-25">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|XCeed Plug-in Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia XCeed Plug-in Hybrid 2021">Buy Here</a></sub></details>|||
|
||||||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus CT Hybrid 2017-18">Buy Here</a></sub></details>|||
|
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus CT Hybrid 2017-18">Buy Here</a></sub></details>|||
|
||||||
|Lexus|ES 2017-18|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus ES 2017-18">Buy Here</a></sub></details>|||
|
|Lexus|ES 2017-18|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus ES 2017-18">Buy Here</a></sub></details>|||
|
||||||
|Lexus|ES 2019-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus ES 2019-25">Buy Here</a></sub></details>|||
|
|Lexus|ES 2019-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus ES 2019-25">Buy Here</a></sub></details>|||
|
||||||
@@ -215,44 +326,54 @@ A supported vehicle is one that just works when you install a comma device. All
|
|||||||
|Lexus|RX Hybrid 2017-19|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus RX Hybrid 2017-19">Buy Here</a></sub></details>|||
|
|Lexus|RX Hybrid 2017-19|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus RX Hybrid 2017-19">Buy Here</a></sub></details>|||
|
||||||
|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus RX Hybrid 2020-22">Buy Here</a></sub></details>|||
|
|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus RX Hybrid 2020-22">Buy Here</a></sub></details>|||
|
||||||
|Lexus|UX Hybrid 2019-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus UX Hybrid 2019-24">Buy Here</a></sub></details>|||
|
|Lexus|UX Hybrid 2019-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus UX Hybrid 2019-24">Buy Here</a></sub></details>|||
|
||||||
|Lincoln|Aviator 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lincoln Aviator 2020-24">Buy Here</a></sub></details>|||
|
|Lincoln|Aviator 2020-24|Co-Pilot360 Plus|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lincoln Aviator 2020-24">Buy Here</a></sub></details>|||
|
||||||
|Lincoln|Aviator Plug-in Hybrid 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lincoln Aviator Plug-in Hybrid 2020-24">Buy Here</a></sub></details>|||
|
|Lincoln|Aviator Plug-in Hybrid 2020-24|Co-Pilot360 Plus|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lincoln Aviator Plug-in Hybrid 2020-24">Buy Here</a></sub></details>|||
|
||||||
|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=MAN eTGE 2020-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=MAN eTGE 2020-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||||
|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=MAN TGE 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=MAN TGE 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||||
|Mazda|CX-5 2022-25|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Mazda CX-5 2022-25">Buy Here</a></sub></details>|||
|
|Mazda|CX-5 2022-25|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Mazda CX-5 2022-25">Buy Here</a></sub></details>|||
|
||||||
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Mazda 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>||
|
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Mazda 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>||
|
||||||
|Nissan[<sup>5</sup>](#footnotes)|Altima 2019-20, 2024|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Altima 2019-20, 2024">Buy Here</a></sub></details>|||
|
|Nissan[<sup>6</sup>](#footnotes)|Altima 2019-20, 2024|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Altima 2019-20, 2024">Buy Here</a></sub></details>|||
|
||||||
|Nissan[<sup>5</sup>](#footnotes)|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan 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>||
|
|Nissan[<sup>6</sup>](#footnotes)|Leaf 2018-25|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Leaf 2018-25">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||||
|Nissan[<sup>5</sup>](#footnotes)|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Rogue 2018-20">Buy Here</a></sub></details>|||
|
|Nissan[<sup>6</sup>](#footnotes)|Leaf Instrument Cluster 2018-25|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Leaf Instrument Cluster 2018-25">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||||
|Nissan[<sup>5</sup>](#footnotes)|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan X-Trail 2017">Buy Here</a></sub></details>|||
|
|Nissan[<sup>6</sup>](#footnotes)|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Rogue 2018-20">Buy Here</a></sub></details>|||
|
||||||
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Ram connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ram 1500 2019-24">Buy Here</a></sub></details>|||
|
|Nissan[<sup>6</sup>](#footnotes)|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan X-Trail 2017">Buy Here</a></sub></details>|||
|
||||||
|Rivian|R1S 2022-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1S 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|32 mph|1 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Ram connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ram 1500 2019-24">Buy Here</a></sub></details>|||
|
||||||
|Rivian|R1T 2022-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1T 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Rivian|R1S 2022-24|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1S 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=SEAT Ateca 2016-23">Buy Here</a></sub></details>|||
|
|Rivian|R1S 2025|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1S 2025">Buy Here</a></sub></details>|||
|
||||||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=SEAT Leon 2014-20">Buy Here</a></sub></details>|||
|
|Rivian|R1T 2022-24|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1T 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||||
|Subaru|Ascent 2019-21|All[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
|Rivian|R1T 2025|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1T 2025">Buy Here</a></sub></details>|||
|
||||||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>||
|
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=SEAT Ateca 2016-23">Buy Here</a></sub></details>|||
|
||||||
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=SEAT Leon 2014-20">Buy Here</a></sub></details>|||
|
||||||
|Subaru|Forester 2019-21|All[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
|Subaru|Ascent 2019-21|All[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
||||||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
|Subaru|Ascent 2023-25|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Ascent 2023-25">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
||||||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>||
|
||||||
|Subaru|Legacy 2020-22|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru B connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
||||||
|Subaru|Outback 2020-22|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru B connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
|Subaru|Crosstrek 2025|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Crosstrek 2025">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
||||||
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>||
|
|Subaru|Forester 2019-21|All[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
||||||
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
|Subaru|Forester 2022-24|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru C connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Forester 2022-24">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|Fabia 2022-23[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Fabia 2022-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|
|Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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|Kamiq 2021-23[<sup>11,13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Kamiq 2021-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|
|Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
||||||
|Škoda|Karoq 2019-23[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Karoq 2019-23">Buy Here</a></sub></details>|||
|
|Subaru|Legacy 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru B connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
||||||
|Škoda|Kodiaq 2017-23[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Kodiaq 2017-23">Buy Here</a></sub></details>|||
|
|Subaru|Legacy 2025|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Legacy 2025">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 2015-19[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia 2015-19">Buy Here</a></sub></details>|||
|
|Subaru|Outback 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru B connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
||||||
|Škoda|Octavia RS 2016[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia RS 2016">Buy Here</a></sub></details>|||
|
|Subaru|Outback 2023-24|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 2023-24">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 Scout 2017-19[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia Scout 2017-19">Buy Here</a></sub></details>|||
|
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>||
|
||||||
|Škoda|Scala 2020-23[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Scala 2020-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru 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>|||
|
||||||
|Škoda|Superb 2015-22[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Superb 2015-22">Buy Here</a></sub></details>|||
|
|Škoda|Enyaq 2021-23[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Enyaq 2021-23">Buy Here</a></sub></details>|||
|
||||||
|Tesla[<sup>9</sup>](#footnotes)|Model 3 (with HW3) 2019-23[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model 3 (with HW3) 2019-23">Buy Here</a></sub></details>|||
|
|Škoda|Enyaq 2024-25[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Enyaq 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Tesla[<sup>9</sup>](#footnotes)|Model 3 (with HW4) 2024-25[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model 3 (with HW4) 2024-25">Buy Here</a></sub></details>|||
|
|Škoda|Fabia 2022-23[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Fabia 2022-23">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)|||
|
||||||
|Tesla[<sup>9</sup>](#footnotes)|Model Y (with HW3) 2020-23[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW3) 2020-23">Buy Here</a></sub></details>|||
|
|Škoda|Kamiq 2021-23[<sup>12,14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Kamiq 2021-23">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)|||
|
||||||
|Tesla[<sup>9</sup>](#footnotes)|Model Y (with HW4) 2024-25[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW4) 2024-25">Buy Here</a></sub></details>|||
|
|Škoda|Karoq 2019-23[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Karoq 2019-23">Buy Here</a></sub></details>|||
|
||||||
|
|Škoda|Kodiaq 2017-23[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Kodiaq 2017-23">Buy Here</a></sub></details>|||
|
||||||
|
|Škoda|Octavia 2015-19[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia 2015-19">Buy Here</a></sub></details>|||
|
||||||
|
|Škoda|Octavia RS 2016[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia RS 2016">Buy Here</a></sub></details>|||
|
||||||
|
|Škoda|Octavia Scout 2017-19[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia Scout 2017-19">Buy Here</a></sub></details>|||
|
||||||
|
|Škoda|Scala 2020-23[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Scala 2020-23">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)|||
|
||||||
|
|Škoda|Superb 2015-22[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Superb 2015-22">Buy Here</a></sub></details>|||
|
||||||
|
|Tesla[<sup>10</sup>](#footnotes)|Model 3 (with HW3) 2019-23[<sup>9</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model 3 (with HW3) 2019-23">Buy Here</a></sub></details>|||
|
||||||
|
|Tesla[<sup>10</sup>](#footnotes)|Model 3 (with HW4) 2024-26[<sup>9</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model 3 (with HW4) 2024-26">Buy Here</a></sub></details>|||
|
||||||
|
|Tesla[<sup>10</sup>](#footnotes)|Model Y (with HW3) 2020-23[<sup>9</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW3) 2020-23">Buy Here</a></sub></details>|||
|
||||||
|
|Tesla[<sup>10</sup>](#footnotes)|Model Y (with HW4) 2024-25[<sup>9</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW4) 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Alphard 2019-20">Buy Here</a></sub></details>|||
|
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Alphard 2019-20">Buy Here</a></sub></details>|||
|
||||||
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Alphard Hybrid 2021">Buy Here</a></sub></details>|||
|
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Alphard Hybrid 2021">Buy Here</a></sub></details>|||
|
||||||
|Toyota|Avalon 2016|Toyota Safety Sense P|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Avalon 2016">Buy Here</a></sub></details>|||
|
|Toyota|Avalon 2016|Toyota Safety Sense P|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Avalon 2016">Buy Here</a></sub></details>|||
|
||||||
@@ -265,8 +386,8 @@ A supported vehicle is one that just works when you install a comma device. All
|
|||||||
|Toyota|C-HR 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR 2021">Buy Here</a></sub></details>|||
|
|Toyota|C-HR 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR 2021">Buy Here</a></sub></details>|||
|
||||||
|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR Hybrid 2017-20">Buy Here</a></sub></details>|||
|
|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR Hybrid 2017-20">Buy Here</a></sub></details>|||
|
||||||
|Toyota|C-HR Hybrid 2021-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR Hybrid 2021-22">Buy Here</a></sub></details>|||
|
|Toyota|C-HR Hybrid 2021-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR Hybrid 2021-22">Buy Here</a></sub></details>|||
|
||||||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>10</sup>](#footnotes)|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota 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|Camry 2018-20|All|Stock|0 mph[<sup>11</sup>](#footnotes)|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota 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|Camry 2021-24|All|openpilot|0 mph[<sup>10</sup>](#footnotes)|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry 2021-24">Buy Here</a></sub></details>|||
|
|Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>11</sup>](#footnotes)|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry 2021-24">Buy Here</a></sub></details>|||
|
||||||
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota 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|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota 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|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry Hybrid 2021-24">Buy Here</a></sub></details>|||
|
|Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry Hybrid 2021-24">Buy Here</a></sub></details>|||
|
||||||
|Toyota|Corolla 2017-19|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Corolla 2017-19">Buy Here</a></sub></details>|||
|
|Toyota|Corolla 2017-19|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Corolla 2017-19">Buy Here</a></sub></details>|||
|
||||||
@@ -298,62 +419,91 @@ A supported vehicle is one that just works when you install a comma device. All
|
|||||||
|Toyota|RAV4 Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota 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|RAV4 Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota 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|RAV4 Hybrid 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Hybrid 2023-25">Buy Here</a></sub></details>|<a href="https://youtu.be/4eIsEq4L4Ng" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Toyota|RAV4 Hybrid 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Hybrid 2023-25">Buy Here</a></sub></details>|<a href="https://youtu.be/4eIsEq4L4Ng" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||||
|Toyota|Sienna 2018-20|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota 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|Sienna 2018-20|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota 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|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen 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|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen 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|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen 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|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen 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|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen 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|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen 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|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon Shooting Brake 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|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon Shooting Brake 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|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Atlas 2018-23">Buy Here</a></sub></details>|||
|
|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Atlas 2018-23">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Atlas Cross Sport 2020-22">Buy Here</a></sub></details>|||
|
|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Atlas Cross Sport 2020-22">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen California 2021-23">Buy Here</a></sub></details>|||
|
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen California 2021-23">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Caravelle 2020">Buy Here</a></sub></details>|||
|
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Caravelle 2020">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen 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|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen 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|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Crafter 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Crafter 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||||
|Volkswagen|e-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen e-Crafter 2018-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|e-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen e-Crafter 2018-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||||
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen e-Golf 2014-20">Buy Here</a></sub></details>|||
|
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen e-Golf 2014-20">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf 2015-20">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf 2015-20">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf Alltrack 2015-19">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf Alltrack 2015-19">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTD 2015-20">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTD 2015-20">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTE 2015-20">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTE 2015-20">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTI 2015-21">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTI 2015-21">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf R 2015-19">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf R 2015-19">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf SportsVan 2015-20">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf SportsVan 2015-20">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Grand California 2019-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Grand California 2019-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||||
|Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Jetta 2018-23">Buy Here</a></sub></details>|||
|
|Volkswagen|ID.3 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen ID.3 2020-23">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Jetta GLI 2021-23">Buy Here</a></sub></details>|||
|
|Volkswagen|ID.3 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen ID.3 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Passat 2015-22[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat 2015-22">Buy Here</a></sub></details>|||
|
|Volkswagen|ID.4 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen ID.4 2021-23">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat Alltrack 2015-22">Buy Here</a></sub></details>|||
|
|Volkswagen|ID.4 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen ID.4 2024-25">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat GTE 2015-22">Buy Here</a></sub></details>|||
|
|Volkswagen|ID.5 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen ID.5 2022-23">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Polo 2018-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|
|Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Jetta 2018-23">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Jetta GLI 2021-23">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen T-Cross 2021">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|
|Volkswagen|Passat 2015-22[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat 2015-22">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen T-Roc 2018-23">Buy Here</a></sub></details>|||
|
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat Alltrack 2015-22">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Taos 2022-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Taos 2022-24">Buy Here</a></sub></details>|||
|
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat GTE 2015-22">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont 2018-22">Buy Here</a></sub></details>|||
|
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Polo 2018-23">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)|||
|
||||||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont Cross Sport 2021-22">Buy Here</a></sub></details>|||
|
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)|||
|
||||||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont X 2021-22">Buy Here</a></sub></details>|||
|
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen T-Cross 2021">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)|||
|
||||||
|Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Tiguan 2018-24">Buy Here</a></sub></details>|||
|
|Volkswagen|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen T-Roc 2018-23">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Tiguan eHybrid 2021-23">Buy Here</a></sub></details>|||
|
|Volkswagen|Taos 2022-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Taos 2022-24">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Touran 2016-23">Buy Here</a></sub></details>|||
|
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont 2018-22">Buy Here</a></sub></details>|||
|
||||||
|
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen 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,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont X 2021-22">Buy Here</a></sub></details>|||
|
||||||
|
|Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Tiguan 2018-24">Buy Here</a></sub></details>|||
|
||||||
|
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Tiguan eHybrid 2021-23">Buy Here</a></sub></details>|||
|
||||||
|
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Touran 2016-23">Buy Here</a></sub></details>|||
|
||||||
|
|
||||||
|
## StarPilot Community Cars
|
||||||
|
|
||||||
|
These additional vehicle ports are maintained by StarPilot rather than upstream openpilot.
|
||||||
|
|
||||||
|
# 17 Community 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> |Video|Setup Video|
|
||||||
|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||||
|
|Genesis|G70 Non-SCC 2021|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 Non-SCC 2021">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Bayon Non-SCC 2021|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Bayon Non-SCC 2021">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Elantra Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Hybrid Non-SCC 2022">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Non-SCC 2022">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric Non-SCC 2019">Buy Here</a></sub></details>|||
|
||||||
|
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Non-SCC 2019">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed Plug-in Hybrid Non-SCC 2022">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte Non-SCC 2019">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Forte Non-SCC 2021|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte Non-SCC 2021">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Ray EV 2025|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ray EV 2025">Buy Here</a></sub></details>|||
|
||||||
|
|Kia|Seltos Non-SCC 2023-24|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Seltos Non-SCC 2023-24">Buy Here</a></sub></details>|||
|
||||||
|
|Tesla|Model S (Pre-AP) 2012-14|All|Stock|0 mph|0 mph|[](##)|[](##)|None|||
|
||||||
|
|Toyota|Matrix Retrofit 2005|Custom retrofit|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Matrix Retrofit 2005">Buy Here</a></sub></details>|||
|
||||||
|
|Toyota|Prius 2016-20 with TSS2 EPS retrofit|Custom retrofit|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Prius 2016-20 with TSS2 EPS retrofit">Buy Here</a></sub></details>|||
|
||||||
|
|Toyota|RAV4 Prime 2021-23|All|openpilot|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Prime 2021-23">Buy Here</a></sub></details>|||
|
||||||
|
|Toyota|Sienna 2021-25|All|openpilot|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Sienna 2021-25">Buy Here</a></sub></details>|||
|
||||||
|
|Toyota|Yaris (Non-US only) 2020, 2023|All|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Yaris (Non-US only) 2020, 2023">Buy Here</a></sub></details>|||
|
||||||
|
|
||||||
### Footnotes
|
### Footnotes
|
||||||
<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 `nightly-dev`. <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 `nightly-dev`. <br />
|
||||||
<sup>2</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>2</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>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/gm" target="_blank">GM</a>. <br />
|
<sup>3</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/gm" target="_blank">GM</a>. <br />
|
||||||
<sup>4</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
|
<sup>4</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
|
||||||
<sup>5</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/nissan" target="_blank">Nissan</a>. <br />
|
<sup>5</sup>Enabling longitudinal control (alpha) will disable all CMBS functionality, including AEB and FCW. <br />
|
||||||
<sup>6</sup>In the non-US market, openpilot requires the car to come equipped with EyeSight with Lane Keep Assistance. <br />
|
<sup>6</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/nissan" target="_blank">Nissan</a>. <br />
|
||||||
<sup>7</sup>Enabling longitudinal control (alpha) will disable all EyeSight functionality, including AEB, LDW, and RAB. <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>Some 2023 model years have HW4. To check which hardware type your vehicle has, look for <b>Autopilot computer</b> under <b>Software -> Additional Vehicle Information</b> on your vehicle's touchscreen. See <a href="https://www.notateslaapp.com/news/2173/how-to-check-if-your-tesla-has-hardware-4-ai4-or-hardware-3">this page</a> for more information. <br />
|
<sup>8</sup>Enabling longitudinal control (alpha) will disable all EyeSight functionality, including AEB, LDW, and RAB. <br />
|
||||||
<sup>9</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/tesla" target="_blank">Tesla</a>. <br />
|
<sup>9</sup>Some 2023 model years have HW4. To check which hardware type your vehicle has, look for <b>Autopilot computer</b> under <b>Software -> Additional Vehicle Information</b> on your vehicle's touchscreen. See <a href="https://www.notateslaapp.com/news/2173/how-to-check-if-your-tesla-has-hardware-4-ai4-or-hardware-3">this page</a> for more information. <br />
|
||||||
<sup>10</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>10</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/tesla" target="_blank">Tesla</a>. <br />
|
||||||
<sup>11</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
|
<sup>11</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>12</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
|
<sup>12</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
|
||||||
<sup>13</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma four functionality. <br />
|
<sup>13</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
|
||||||
<sup>14</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>14</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma four functionality. <br />
|
||||||
<sup>15</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>15</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>16</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br />
|
||||||
## Community Maintained Cars
|
|
||||||
Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/).
|
|
||||||
|
|
||||||
# Don't see your car here?
|
# Don't see your car here?
|
||||||
|
|
||||||
|
|||||||
+56
-10
@@ -4,8 +4,8 @@ This workflow rebuilds StarPilot driving and driver-monitoring artifacts for the
|
|||||||
|
|
||||||
## Safety
|
## Safety
|
||||||
|
|
||||||
- The supported build device is `comma@192.168.3.110`.
|
- The supported build device is `comma@192.168.3.109`.
|
||||||
- Never run these commands against `192.168.3.109`.
|
- Never run these commands against `192.168.3.110`.
|
||||||
- Normal artifacts target QCOM. External-GPU artifacts must be compiled explicitly and tagged in the manifest.
|
- Normal artifacts target QCOM. External-GPU artifacts must be compiled explicitly and tagged in the manifest.
|
||||||
- Keep source ONNX files and compiled PKLs on the T5 workspace, not the comma.
|
- Keep source ONNX files and compiled PKLs on the T5 workspace, not the comma.
|
||||||
|
|
||||||
@@ -26,7 +26,8 @@ Important directories:
|
|||||||
- Oversized models are represented by repository-safe `.p00`, `.p01`, and `.sha256` files in `ready-for-resources/`.
|
- Oversized models are represented by repository-safe `.p00`, `.p01`, and `.sha256` files in `ready-for-resources/`.
|
||||||
- `logs/`: one remote compilation log per model.
|
- `logs/`: one remote compilation log per model.
|
||||||
- `results/`: source and artifact checksum records.
|
- `results/`: source and artifact checksum records.
|
||||||
- `manifests/`: generated `model_names_v22.json`.
|
- `manifests/`: source `model_names_v22.json` and namespaced release `model_names_v23.json`.
|
||||||
|
- The v23 manifest and compiled artifacts are published together in the resource repository's `Models` branch.
|
||||||
|
|
||||||
## Initialize And Extract
|
## Initialize And Extract
|
||||||
|
|
||||||
@@ -46,7 +47,10 @@ python3 scripts/model_rebuild_pipeline.py extract \
|
|||||||
--base-manifest /path/to/model_names_v21.json
|
--base-manifest /path/to/model_names_v21.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Source commits are defined in `scripts/model_source_map_v22.json`.
|
The original catalog sources are defined in `scripts/model_source_map_v22.json`.
|
||||||
|
Recovered late-model and supercombo sources, including RDF2, are defined in
|
||||||
|
`scripts/model_source_map_v23.json`. The v23 map is intentionally separate so
|
||||||
|
adding a recovered iteration cannot alter the older model source history.
|
||||||
|
|
||||||
## Compile
|
## Compile
|
||||||
|
|
||||||
@@ -65,7 +69,7 @@ python3 scripts/model_rebuild_pipeline.py compile \
|
|||||||
--base-manifest /path/to/model_names_v21.json
|
--base-manifest /path/to/model_names_v21.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Existing artifacts are skipped unless `--force` is passed. Each model is staged in its own remote input directory, compiled on `.110`, copied back to the T5, hashed, and copied into `ready-for-resources/`. Failures are written to `results/<id>_failure.json`; rerunning the same command resumes incomplete models.
|
Existing artifacts are skipped unless `--force` is passed. Each model is staged in its own remote input directory, compiled on `.109`, copied back to the T5, hashed, and copied into `ready-for-resources/`. Failures are written to `results/<id>_failure.json`; rerunning the same command resumes incomplete models.
|
||||||
|
|
||||||
Validate one or all completed artifacts with synthetic camera inputs on QCOM:
|
Validate one or all completed artifacts with synthetic camera inputs on QCOM:
|
||||||
|
|
||||||
@@ -88,6 +92,12 @@ For a model that cannot run on the device GPU, compile with the USB AMD GPU atta
|
|||||||
./models --lebowski --gpu
|
./models --lebowski --gpu
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The ASM2464PD bridge must run the current tinygrad custom firmware from
|
||||||
|
https://github.com/tinygrad/asm2464pd-firmware. Its USB product string starts
|
||||||
|
with `custom`; the legacy `USB 3.2 PCIe TinyEnclosure` patch is not compatible
|
||||||
|
with comma's current external-GPU runtime. Firmware flashing is a separate,
|
||||||
|
explicit hardware setup step and StarPilot never performs it automatically.
|
||||||
|
|
||||||
The dynamic flag (`--lebowski` above) sets the output and manifest model ID;
|
The dynamic flag (`--lebowski` above) sets the output and manifest model ID;
|
||||||
when only one source model is staged, its ONNX filename does not need to match
|
when only one source model is staged, its ONNX filename does not need to match
|
||||||
that ID. Input format and behavior version are inferred. `--external-gpu`
|
that ID. Input format and behavior version are inferred. `--external-gpu`
|
||||||
@@ -149,15 +159,51 @@ All four files must be updated together.
|
|||||||
|
|
||||||
## Manifest
|
## Manifest
|
||||||
|
|
||||||
Generate v22 after compilation:
|
The current test branch uses manifest v25 and requests v25 only. Seed the new
|
||||||
|
manifest from the previous catalog, then replace entries as artifacts are
|
||||||
|
rebuilt with the pinned runtime:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp /path/to/model_names_v24.json /path/to/model_names_v25.json
|
||||||
|
```
|
||||||
|
|
||||||
|
The current tinygrad pin is `f6fc4e3f2c3db5fae1e19cbfbc3ad9fc579a12ae`, from
|
||||||
|
`openpilot` `origin/master` (`bump tg + TC_MIN_GLOBALS`). StarPilot's
|
||||||
|
multi-model `modeld` remains in place; do not replace it with upstream's
|
||||||
|
single-model `modeld`.
|
||||||
|
|
||||||
|
For the older namespace migration workflow, generate the base manifest after
|
||||||
|
compilation and namespace the release artifacts as v23:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 scripts/model_rebuild_pipeline.py manifest \
|
python3 scripts/model_rebuild_pipeline.py manifest \
|
||||||
--base-manifest /path/to/model_names_v21.json
|
--base-manifest /path/to/model_names_v21.json
|
||||||
```
|
```
|
||||||
|
|
||||||
The generator preserves existing IDs and behavioral metadata and adds
|
```bash
|
||||||
`deeprl3v2`. Manifest v22 implies the unified single-PKL runtime layout.
|
python3 scripts/namespace_model_artifacts.py \
|
||||||
|
--workspace /Volumes/T5/StarPilot-Model-Rebuild-2026-06-22 \
|
||||||
|
--base-manifest /Volumes/T5/StarPilot-Model-Rebuild-2026-06-22/manifests/model_names_v22.json \
|
||||||
|
--manifest-version v23 --suffix 3
|
||||||
|
```
|
||||||
|
|
||||||
|
The namespace command changes IDs such as `tr1422` to `tr14223`, renames the
|
||||||
|
compiled and upload-ready files, and writes an ID map. It preserves display
|
||||||
|
names and behavioral versions. The current model manager requests v25 only; the
|
||||||
|
manifest is fetched from `Models/model_names_v25.json`. Devices still running
|
||||||
|
the prior branch continue to request their existing manifest version.
|
||||||
|
|
||||||
|
After importing newly compiled sources, normalize the release namespace before
|
||||||
|
copying files into either resource repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/reconcile_v23_artifacts.py \
|
||||||
|
--workspace /Volumes/T5/StarPilot-Model-Rebuild-2026-06-22
|
||||||
|
```
|
||||||
|
|
||||||
|
This maps recovered source IDs to their v23 release IDs, removes duplicate
|
||||||
|
macOS metadata files, and adds `rdf23` for Regret Driven Framework V2. It does
|
||||||
|
not overwrite a conflicting artifact.
|
||||||
Repository-hosted multipart files are discovered by naming convention, so no
|
Repository-hosted multipart files are discovered by naming convention, so no
|
||||||
size, hash, format, or part-count metadata is required.
|
size, hash, format, or part-count metadata is required.
|
||||||
|
|
||||||
@@ -171,6 +217,6 @@ Compilation validates JIT capture/replay, pickle round-trip, finite outputs, met
|
|||||||
2. Confirm `modeld` stays running.
|
2. Confirm `modeld` stays running.
|
||||||
3. Confirm finite `modelV2` path, lane-line, lead, pose, and action data.
|
3. Confirm finite `modelV2` path, lane-line, lead, pose, and action data.
|
||||||
4. Confirm `driverStateV2` on both supported camera resolutions.
|
4. Confirm `driverStateV2` on both supported camera resolutions.
|
||||||
5. Test download, selection, deletion, randomization, migration, and fallback in QT, raylib/mici, and Galaxy.
|
5. Test download, selection, deletion, randomization, migration, and fallback in both device UIs and Galaxy.
|
||||||
|
|
||||||
The built-in South Carolina artifact is `selfdrive/modeld/models/driving_tinygrad.pkl`. If migration cannot download the selected v22 artifact, StarPilot switches to that built-in model.
|
The built-in RDF artifact is `selfdrive/modeld/models/driving_tinygrad.pkl`. If migration cannot download the selected v25 artifact, StarPilot switches to that built-in model.
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ Use `./dev` for host-native tools. It creates and reuses an isolated environment
|
|||||||
./dev shell
|
./dev shell
|
||||||
```
|
```
|
||||||
|
|
||||||
For desktop UI work, use `./c3`, `./c4`, or `./raybig`. These commands use the same isolated host environment.
|
For desktop UI work, use `./c3` or `./c4`. These commands use the same isolated host environment.
|
||||||
|
|
||||||
Use `./build` when you need comma-compatible device artifacts. This is the expected validation for changes that affect compiled device code or runtime behavior:
|
Use `./build` when you need comma-compatible device artifacts. This is the expected validation for changes that affect compiled device code or runtime behavior:
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
This flow builds **device-target (`larch64`) binaries on your laptop** using a Linux/aarch64 container and a synced comma sysroot.
|
This flow builds **device-target (`larch64`) binaries on your laptop** using a Linux/aarch64 container and a synced comma sysroot.
|
||||||
|
|
||||||
For the full StarPilot branch workflow, including host-native shorthand tools such as `./dev`, `./c3`, `./c4`, and `./raybig`, see the [StarPilot development guide](https://github.com/firestar5683/StarPilot/blob/Dom/tools/STARPILOT_DEVELOPMENT.md).
|
For the full StarPilot branch workflow, including host-native shorthand tools such as `./dev`, `./c3`, and `./c4`, see the [StarPilot development guide](https://github.com/firestar5683/StarPilot/blob/Dom/tools/STARPILOT_DEVELOPMENT.md).
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -71,10 +71,10 @@ This runs:
|
|||||||
- `SP_TICI_SYSROOT=/opt/tici-sysroot`
|
- `SP_TICI_SYSROOT=/opt/tici-sysroot`
|
||||||
- `touch prebuilt`
|
- `touch prebuilt`
|
||||||
|
|
||||||
To run `scons` targets explicitly in the same device-compatible environment:
|
To run SCons targets explicitly in the same device-compatible environment:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
scripts/laptop_device_build.sh scons selfdrive/ui/ui
|
scripts/laptop_device_build.sh scons common/params_pyx.so
|
||||||
```
|
```
|
||||||
|
|
||||||
On macOS, once `.comma_sysroot` is present, plain `scons ...` auto-routes to this containerized device build.
|
On macOS, once `.comma_sysroot` is present, plain `scons ...` auto-routes to this containerized device build.
|
||||||
@@ -112,7 +112,6 @@ Preferred host-side shorthand commands on this branch:
|
|||||||
```bash
|
```bash
|
||||||
./c3
|
./c3
|
||||||
./c4
|
./c4
|
||||||
./raybig
|
|
||||||
./dev replay
|
./dev replay
|
||||||
./dev cabana
|
./dev cabana
|
||||||
./dev plotjuggler
|
./dev plotjuggler
|
||||||
@@ -120,10 +119,9 @@ Preferred host-side shorthand commands on this branch:
|
|||||||
|
|
||||||
These commands use the isolated `.host_runtime` cache so host-native artifacts do not churn the main tree.
|
These commands use the isolated `.host_runtime` cache so host-native artifacts do not churn the main tree.
|
||||||
|
|
||||||
Legacy direct script entrypoints still exist if needed:
|
Direct script entrypoints are also available:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
scripts/launch_ui_desktop.sh
|
scripts/launch_ui_c3_desktop.sh
|
||||||
scripts/launch_ui_c4_desktop.sh
|
scripts/launch_ui_c4_desktop.sh
|
||||||
scripts/launch_ui_raybig_desktop.sh
|
|
||||||
```
|
```
|
||||||
|
|||||||
+3
-81
@@ -51,8 +51,6 @@ function agnos_init {
|
|||||||
# StarPilot variables
|
# StarPilot variables
|
||||||
sudo chmod 0777 /cache
|
sudo chmod 0777 /cache
|
||||||
|
|
||||||
sudo rm -f /data/misc/display/color_cal/color_cal /data/misc/display/color_cal/source.sha256
|
|
||||||
|
|
||||||
# Check if AGNOS update is required
|
# Check if AGNOS update is required
|
||||||
AGNOS_CURRENT_VERSION="$(< /VERSION)"
|
AGNOS_CURRENT_VERSION="$(< /VERSION)"
|
||||||
AGNOS_UPDATE_REQUIRED=1
|
AGNOS_UPDATE_REQUIRED=1
|
||||||
@@ -149,86 +147,10 @@ function launch {
|
|||||||
while true; do sleep 1; done
|
while true; do sleep 1; done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
function prebuilt_runtime_compatible {
|
|
||||||
python3 - <<'PY'
|
|
||||||
import importlib
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
start = time.monotonic()
|
|
||||||
last = start
|
|
||||||
log_path = os.environ.get("SP_BOOT_TIMING_LOG")
|
|
||||||
|
|
||||||
def emit(line):
|
|
||||||
print(line, flush=True)
|
|
||||||
if log_path:
|
|
||||||
try:
|
|
||||||
with open(log_path, "a") as f:
|
|
||||||
f.write(line + "\n")
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def log_step(label):
|
|
||||||
global last
|
|
||||||
now = time.monotonic()
|
|
||||||
emit(f"SP_BOOT_TIMING prebuilt_compat {label} +{now - last:.3f}s total={now - start:.3f}s")
|
|
||||||
last = now
|
|
||||||
|
|
||||||
mods = [
|
|
||||||
"openpilot.common.params_pyx",
|
|
||||||
"msgq.ipc_pyx",
|
|
||||||
"msgq.visionipc.visionipc_pyx",
|
|
||||||
"openpilot.common.transformations.transformations",
|
|
||||||
"openpilot.selfdrive.pandad.pandad_api_impl",
|
|
||||||
"openpilot.selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx",
|
|
||||||
"openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx",
|
|
||||||
]
|
|
||||||
|
|
||||||
for mod in mods:
|
|
||||||
try:
|
|
||||||
importlib.import_module(mod)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Prebuilt compatibility failure in {mod}: {e}", file=sys.stderr)
|
|
||||||
raise
|
|
||||||
log_step(f"import:{mod}")
|
|
||||||
|
|
||||||
repo_root = Path.cwd().parents[1]
|
|
||||||
required_files = [
|
|
||||||
repo_root / "selfdrive/modeld/models/driving_tinygrad.pkl",
|
|
||||||
repo_root / "selfdrive/modeld/models/dmonitoring_model_metadata.pkl",
|
|
||||||
repo_root / "selfdrive/modeld/models/dmonitoring_model_tinygrad.pkl",
|
|
||||||
repo_root / "selfdrive/modeld/models/dm_warp_1928x1208_tinygrad.pkl",
|
|
||||||
repo_root / "selfdrive/modeld/models/dm_warp_1344x760_tinygrad.pkl",
|
|
||||||
repo_root / "selfdrive/pandad/pandad_api_impl.so",
|
|
||||||
repo_root / "selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/acados_ocp_solver_pyx.so",
|
|
||||||
repo_root / "selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/libacados_ocp_solver_lat.so",
|
|
||||||
repo_root / "selfdrive/controls/lib/longitudinal_mpc_lib/c_generated_code/acados_ocp_solver_pyx.so",
|
|
||||||
repo_root / "selfdrive/controls/lib/longitudinal_mpc_lib/c_generated_code/libacados_ocp_solver_long.so",
|
|
||||||
repo_root / "opendbc_repo/opendbc/dbc/gm_global_a_powertrain_generated.dbc",
|
|
||||||
]
|
|
||||||
|
|
||||||
for path in required_files:
|
|
||||||
if not path.is_file():
|
|
||||||
raise FileNotFoundError(f"Missing prebuilt runtime artifact: {path}")
|
|
||||||
log_step("required_files")
|
|
||||||
PY
|
|
||||||
}
|
|
||||||
|
|
||||||
USE_PREBUILT=1
|
|
||||||
if [ -f /data/params/d/UsePrebuilt ]; then
|
|
||||||
USE_PREBUILT=$(tr -d '\n' < /data/params/d/UsePrebuilt)
|
|
||||||
fi
|
|
||||||
|
|
||||||
sp_launch_timing "prebuilt_decision_done"
|
sp_launch_timing "prebuilt_decision_done"
|
||||||
if [ "$USE_PREBUILT" = "1" ] && [ -f $DIR/prebuilt ] && ! prebuilt_runtime_compatible; then
|
# Published trees carry this marker and must never compile on-device.
|
||||||
echo "Prebuilt runtime artifacts are incompatible on this device; rebuilding locally."
|
# Developers can remove it explicitly when working from a source tree.
|
||||||
USE_PREBUILT=0
|
if [ ! -f "$DIR/prebuilt" ]; then
|
||||||
fi
|
|
||||||
sp_launch_timing "prebuilt_compat_done"
|
|
||||||
|
|
||||||
if [ "$USE_PREBUILT" != "1" ] || [ ! -f $DIR/prebuilt ]; then
|
|
||||||
sp_launch_timing "build_start"
|
sp_launch_timing "build_start"
|
||||||
./build.py
|
./build.py
|
||||||
sp_launch_timing "build_done"
|
sp_launch_timing "build_done"
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ fi
|
|||||||
export QCOM_PRIORITY=12
|
export QCOM_PRIORITY=12
|
||||||
|
|
||||||
if [ -z "$AGNOS_VERSION" ]; then
|
if [ -z "$AGNOS_VERSION" ]; then
|
||||||
export AGNOS_VERSION="12.8.28"
|
export AGNOS_VERSION="19.6.16"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$AGNOS_ACCEPTED_VERSIONS" ]; then
|
if [ -z "$AGNOS_ACCEPTED_VERSIONS" ]; then
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
exec python3 "$DIR/scripts/model_release.py" "$@"
|
||||||
@@ -21,6 +21,9 @@ static size_t fnv1a_hash(const std::string &str) {
|
|||||||
|
|
||||||
static std::string namespaced_endpoint(std::string endpoint) {
|
static std::string namespaced_endpoint(std::string endpoint) {
|
||||||
const char *namespace_env = std::getenv("OPENPILOT_ZMQ_NAMESPACE");
|
const char *namespace_env = std::getenv("OPENPILOT_ZMQ_NAMESPACE");
|
||||||
|
if (namespace_env == nullptr || namespace_env[0] == '\0') {
|
||||||
|
namespace_env = std::getenv("OPENPILOT_PREFIX");
|
||||||
|
}
|
||||||
if (namespace_env != nullptr && namespace_env[0] != '\0') {
|
if (namespace_env != nullptr && namespace_env[0] != '\0') {
|
||||||
endpoint = std::string(namespace_env) + ":" + endpoint;
|
endpoint = std::string(namespace_env) + ":" + endpoint;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ const bool MUST_USE_ZMQ = false;
|
|||||||
|
|
||||||
bool messaging_use_zmq(){
|
bool messaging_use_zmq(){
|
||||||
if (std::getenv("ZMQ") || MUST_USE_ZMQ) {
|
if (std::getenv("ZMQ") || MUST_USE_ZMQ) {
|
||||||
if (std::getenv("OPENPILOT_PREFIX")) {
|
|
||||||
std::cerr << "OPENPILOT_PREFIX not supported with ZMQ backend\n";
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+148
-14
@@ -1,24 +1,36 @@
|
|||||||
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
|
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
|
||||||
|
|
||||||
# Support Information for 384 Known Cars
|
# Support Information for 518 Known Cars
|
||||||
|
|
||||||
|Make|Model|Package|Support Level|
|
|Make|Model|Package|Support Level|
|
||||||
|---|---|---|:---:|
|
|---|---|---|:---:|
|
||||||
|
|Acura|ADX 2025-26|All|[Upstream](#upstream)|
|
||||||
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|[Upstream](#upstream)|
|
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|[Upstream](#upstream)|
|
||||||
|Acura|ILX 2019|All|[Upstream](#upstream)|
|
|Acura|ILX 2019|All|[Upstream](#upstream)|
|
||||||
|Acura|Integra 2023-25|All|[Community](#community)|
|
|Acura|Integra 2023-25|All|[Community](#community)|
|
||||||
|
|Acura|Integra 2023-26|All|[Upstream](#upstream)|
|
||||||
|
|Acura|MDX 2014-16|Advance Package|[Upstream](#upstream)|
|
||||||
|Acura|MDX 2015-16|Advance Package|[Community](#community)|
|
|Acura|MDX 2015-16|Advance Package|[Community](#community)|
|
||||||
|
|Acura|MDX 2017-19|All|[Upstream](#upstream)|
|
||||||
|Acura|MDX 2017-20|All|[Community](#community)|
|
|Acura|MDX 2017-20|All|[Community](#community)|
|
||||||
|
|Acura|MDX 2020|All|[Upstream](#upstream)|
|
||||||
|
|Acura|MDX 2022-24|All|[Upstream](#upstream)|
|
||||||
|Acura|MDX 2022-24|All|[Community](#community)|
|
|Acura|MDX 2022-24|All|[Community](#community)|
|
||||||
|Acura|MDX 2025|All except Type S|[Upstream](#upstream)|
|
|Acura|MDX 2025|All except Type S|[Upstream](#upstream)|
|
||||||
|
|Acura|MDX Hybrid 2017-19|All|[Upstream](#upstream)|
|
||||||
|
|Acura|MDX Hybrid 2020|All|[Upstream](#upstream)|
|
||||||
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|[Upstream](#upstream)|
|
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|[Upstream](#upstream)|
|
||||||
|Acura|RDX 2019-21|All|[Upstream](#upstream)|
|
|Acura|RDX 2019-21|All|[Upstream](#upstream)|
|
||||||
|Acura|RDX 2022-25|All|[Community](#community)|
|
|Acura|RDX 2022-25|All|[Community](#community)|
|
||||||
|
|Acura|RDX 2022-26|All|[Upstream](#upstream)|
|
||||||
|Acura|RLX 2017|Advance Package or Technology Package|[Community](#community)|
|
|Acura|RLX 2017|Advance Package or Technology Package|[Community](#community)|
|
||||||
|
|Acura|TLX 2015-17|Advance Package|[Upstream](#upstream)|
|
||||||
|Acura|TLX 2015-17|Advance Package|[Community](#community)|
|
|Acura|TLX 2015-17|Advance Package|[Community](#community)|
|
||||||
|
|Acura|TLX 2018-20|All|[Upstream](#upstream)|
|
||||||
|Acura|TLX 2018-20|All|[Community](#community)|
|
|Acura|TLX 2018-20|All|[Community](#community)|
|
||||||
|Acura|TLX 2021|All|[Upstream](#upstream)|
|
|Acura|TLX 2021|All|[Upstream](#upstream)|
|
||||||
|Acura|TLX 2022-23|All|[Community](#community)|
|
|Acura|TLX 2022-23|All|[Community](#community)|
|
||||||
|
|Acura|TLX 2024-25|All|[Upstream](#upstream)|
|
||||||
|Acura|ZDX 2024|All|[Not compatible](#can-bus-security)|
|
|Acura|ZDX 2024|All|[Not compatible](#can-bus-security)|
|
||||||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
@@ -26,14 +38,54 @@
|
|||||||
|Audi|A5 2016-24|All|[Not compatible](#flexray)|
|
|Audi|A5 2016-24|All|[Not compatible](#flexray)|
|
||||||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|
|Audi|Q4 e-tron 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|
|Audi|Q4 e-tron 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Audi|Q5 2017-24|All|[Not compatible](#flexray)|
|
|Audi|Q5 2017-24|All|[Not compatible](#flexray)|
|
||||||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|[Upstream](#upstream)|
|
|Buick|Baby Enclave 2020-23|Driver Assist Package|[Upstream](#upstream)|
|
||||||
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|[Upstream](#upstream)|
|
|Buick|LaCrosse 2017-19|Driver Confidence Package 2|[Upstream](#upstream)|
|
||||||
|
|Buick|LaCrosse ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Buick|LaCrosse US ASCM Harness 2019|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Buick|Regal Essence 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Cadillac|ATS Premium Performance 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Cadillac|CT6 No-ACC 2016-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Cadillac|Escalade 2017|Driver Assist Package|[Upstream](#upstream)|
|
||||||
|
|Cadillac|Escalade ASCM Harness 2018|Driver Assist Package|[Upstream](#upstream)|
|
||||||
|
|Cadillac|Escalade ESV 2016|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|
||||||
|
|Cadillac|Escalade ESV 2019|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|
||||||
|
|Cadillac|Escalade ESV Platinum ASCM Harness 2019|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|
||||||
|
|Cadillac|XT4 2023|Driver Assist Package|[Upstream](#upstream)|
|
||||||
|
|Cadillac|XT4 No-ACC 2023|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Cadillac|XT5 2022|Driver Assist Package|[Upstream](#upstream)|
|
||||||
|
|Cadillac|XT5 No-ACC 2022|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Cadillac|XT6 2020|Driver Assist Package|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Blazer 2019-25|Driver Assist Package|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Bolt EV & EUV ACC 2022-23|Premier or Premier Redline Trim without Super Cruise Package|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Bolt EV & EUV ACC w Pedal 2022-23|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Bolt EV & EUV No-ACC 2022-23|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Bolt EV No-ACC 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Bolt EV No-ACC 2018-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Equinox No-ACC 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Malibu 2019|SDGM Harness (Optional SASCM)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Malibu ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Malibu Hybrid No-ACC 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Malibu No-ACC 2023|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Malibu Premier 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|[Upstream](#upstream)|
|
|Chevrolet|Silverado 1500 2020-21|Safety Package II|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Silverado 1500 No-ACC 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Suburban Premier 2016-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Suburban Premier No-ACC 2016-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Trailblazer No-ACC 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Traverse 2022-23|RS, Premier, or High Country Trim|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|TRAX 2024-25|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Volt 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Volt 2019|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Volt ASCM Harness 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Volt Camera Harness 2017-18|Flashed camera-forward integration with ACC|[Upstream](#upstream)|
|
||||||
|
|Chevrolet|Volt No-ACC 2016-18 (OBD Harness)|Redneck ACC|[Upstream](#upstream)|
|
||||||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|Chrysler|Pacifica 2021-23|All|[Upstream](#upstream)|
|
|Chrysler|Pacifica 2021-23|All|[Upstream](#upstream)|
|
||||||
@@ -41,8 +93,10 @@
|
|||||||
|Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
|Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|comma|body|All|[Upstream](#upstream)|
|
|comma|body|All|[Upstream](#upstream)|
|
||||||
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|
|CUPRA|Born 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
|Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||||
|
|Ford|Edge 2022|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||||
|Ford|Escape 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
|Ford|Escape 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||||
|Ford|Escape 2023-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
|Ford|Escape 2023-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||||
|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||||
@@ -54,8 +108,9 @@
|
|||||||
|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||||
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|
||||||
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|
||||||
|Ford|Focus 2018|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
|Ford|F-150 Lightning 2022-25|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|
||||||
|Ford|Focus Hybrid 2018|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
|Ford|Focus 2018-22|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||||
|
|Ford|Focus Hybrid 2018-22|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||||
|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||||
|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||||
|Ford|Kuga Hybrid 2024|All|[Upstream](#upstream)|
|
|Ford|Kuga Hybrid 2024|All|[Upstream](#upstream)|
|
||||||
@@ -65,11 +120,14 @@
|
|||||||
|Ford|Maverick 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
|
|Ford|Maverick 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
|
||||||
|Ford|Maverick Hybrid 2022|LARIAT Luxury|[Upstream](#upstream)|
|
|Ford|Maverick Hybrid 2022|LARIAT Luxury|[Upstream](#upstream)|
|
||||||
|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
|
|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
|
||||||
|
|Ford|Mondeo 2014-22|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||||
|Ford|Mustang Mach-E 2021-24|All|[Upstream](#upstream)|
|
|Ford|Mustang Mach-E 2021-24|All|[Upstream](#upstream)|
|
||||||
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||||
|
|Ford|Transit 2025|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||||
|Genesis|G70 2018|All|[Upstream](#upstream)|
|
|Genesis|G70 2018|All|[Upstream](#upstream)|
|
||||||
|Genesis|G70 2019-21|All|[Upstream](#upstream)|
|
|Genesis|G70 2019-21|All|[Upstream](#upstream)|
|
||||||
|Genesis|G70 2022-23|All|[Upstream](#upstream)|
|
|Genesis|G70 2022-23|All|[Upstream](#upstream)|
|
||||||
|
|Genesis|G70 Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||||
|Genesis|G80 2017|All|[Upstream](#upstream)|
|
|Genesis|G80 2017|All|[Upstream](#upstream)|
|
||||||
|Genesis|G80 2018-19|All|[Upstream](#upstream)|
|
|Genesis|G80 2018-19|All|[Upstream](#upstream)|
|
||||||
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|[Upstream](#upstream)|
|
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|[Upstream](#upstream)|
|
||||||
@@ -78,14 +136,24 @@
|
|||||||
|Genesis|GV60 (Performance Trim) 2022-23|All|[Upstream](#upstream)|
|
|Genesis|GV60 (Performance Trim) 2022-23|All|[Upstream](#upstream)|
|
||||||
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24|All|[Upstream](#upstream)|
|
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24|All|[Upstream](#upstream)|
|
||||||
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23|All|[Upstream](#upstream)|
|
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23|All|[Upstream](#upstream)|
|
||||||
|
|Genesis|GV70 Electrified 2026|All|[Upstream](#upstream)|
|
||||||
|Genesis|GV70 Electrified (Australia Only) 2022|All|[Upstream](#upstream)|
|
|Genesis|GV70 Electrified (Australia Only) 2022|All|[Upstream](#upstream)|
|
||||||
|Genesis|GV70 Electrified (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
|Genesis|GV70 Electrified (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||||
|Genesis|GV80 2023|All|[Upstream](#upstream)|
|
|Genesis|GV80 2023|All|[Upstream](#upstream)|
|
||||||
|
|Genesis|GV80 (3.5T Prestige Trim, with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||||
|
|Genesis|GV80 Coupe (with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||||
|
|GMC|Acadia 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|GMC|Acadia ASCM Harness 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|GMC|Sierra 1500 2020-21|Driver Alert Package II|[Upstream](#upstream)|
|
|GMC|Sierra 1500 2020-21|Driver Alert Package II|[Upstream](#upstream)|
|
||||||
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|[Dashcam mode](#dashcam)|
|
|GMC|Sierra 1500 No-ACC 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|
||||||
|
|GMC|Yukon No-ACC 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Holden|Astra 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|
|Honda|Accord 2016-17|Honda Sensing|[Upstream](#upstream)|
|
||||||
|Honda|Accord 2016-17|Honda Sensing|[Community](#community)|
|
|Honda|Accord 2016-17|Honda Sensing|[Community](#community)|
|
||||||
|Honda|Accord 2018-22|All|[Upstream](#upstream)|
|
|Honda|Accord 2018-22|All|[Upstream](#upstream)|
|
||||||
|Honda|Accord 2023-25|All|[Upstream](#upstream)|
|
|Honda|Accord 2023-25|All|[Upstream](#upstream)|
|
||||||
|
|Honda|Accord Hybrid 2017|All|[Upstream](#upstream)|
|
||||||
|Honda|Accord Hybrid 2018-22|All|[Upstream](#upstream)|
|
|Honda|Accord Hybrid 2018-22|All|[Upstream](#upstream)|
|
||||||
|Honda|Accord Hybrid 2023-25|All|[Upstream](#upstream)|
|
|Honda|Accord Hybrid 2023-25|All|[Upstream](#upstream)|
|
||||||
|Honda|City (Brazil only) 2023|All|[Upstream](#upstream)|
|
|Honda|City (Brazil only) 2023|All|[Upstream](#upstream)|
|
||||||
@@ -98,6 +166,7 @@
|
|||||||
|Honda|Civic Hatchback Hybrid 2025-26|All|[Upstream](#upstream)|
|
|Honda|Civic Hatchback Hybrid 2025-26|All|[Upstream](#upstream)|
|
||||||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|[Upstream](#upstream)|
|
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|[Upstream](#upstream)|
|
||||||
|Honda|Civic Hybrid 2025-26|All|[Upstream](#upstream)|
|
|Honda|Civic Hybrid 2025-26|All|[Upstream](#upstream)|
|
||||||
|
|Honda|Clarity 2018-21|All|[Upstream](#upstream)|
|
||||||
|Honda|Clarity 2018-21|All|[Community](#community)|
|
|Honda|Clarity 2018-21|All|[Community](#community)|
|
||||||
|Honda|CR-V 2015-16|Touring Trim|[Upstream](#upstream)|
|
|Honda|CR-V 2015-16|Touring Trim|[Upstream](#upstream)|
|
||||||
|Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)|
|
|Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)|
|
||||||
@@ -106,6 +175,8 @@
|
|||||||
|Honda|CR-V Hybrid 2023-25|All|[Upstream](#upstream)|
|
|Honda|CR-V Hybrid 2023-25|All|[Upstream](#upstream)|
|
||||||
|Honda|e 2020|All|[Upstream](#upstream)|
|
|Honda|e 2020|All|[Upstream](#upstream)|
|
||||||
|Honda|Fit 2018-20|Honda Sensing|[Upstream](#upstream)|
|
|Honda|Fit 2018-20|Honda Sensing|[Upstream](#upstream)|
|
||||||
|
|Honda|Fit (Taiwan) 2021|All|[Upstream](#upstream)|
|
||||||
|
|Honda|Fit (Taiwan) 2024-25|All|[Upstream](#upstream)|
|
||||||
|Honda|Freed 2020|Honda Sensing|[Upstream](#upstream)|
|
|Honda|Freed 2020|Honda Sensing|[Upstream](#upstream)|
|
||||||
|Honda|HR-V 2019-22|Honda Sensing|[Upstream](#upstream)|
|
|Honda|HR-V 2019-22|Honda Sensing|[Upstream](#upstream)|
|
||||||
|Honda|HR-V 2023-25|All|[Upstream](#upstream)|
|
|Honda|HR-V 2023-25|All|[Upstream](#upstream)|
|
||||||
@@ -114,27 +185,40 @@
|
|||||||
|Honda|N-Box 2018|All|[Upstream](#upstream)|
|
|Honda|N-Box 2018|All|[Upstream](#upstream)|
|
||||||
|Honda|Odyssey 2018-20|Honda Sensing|[Upstream](#upstream)|
|
|Honda|Odyssey 2018-20|Honda Sensing|[Upstream](#upstream)|
|
||||||
|Honda|Odyssey 2021-26|All|[Upstream](#upstream)|
|
|Honda|Odyssey 2021-26|All|[Upstream](#upstream)|
|
||||||
|
|Honda|Odyssey (Singapore) 2021|Honda Sensing|[Upstream](#upstream)|
|
||||||
|
|Honda|Odyssey (Taiwan) 2018-19|Honda Sensing|[Upstream](#upstream)|
|
||||||
|Honda|Passport 2019-25|All|[Upstream](#upstream)|
|
|Honda|Passport 2019-25|All|[Upstream](#upstream)|
|
||||||
|Honda|Passport 2026|All|[Upstream](#upstream)|
|
|Honda|Passport 2026|All|[Upstream](#upstream)|
|
||||||
|Honda|Pilot 2016-22|Honda Sensing|[Upstream](#upstream)|
|
|Honda|Pilot 2016-22|Honda Sensing|[Upstream](#upstream)|
|
||||||
|Honda|Pilot 2023-25|All|[Upstream](#upstream)|
|
|Honda|Pilot 2023-25|All|[Upstream](#upstream)|
|
||||||
|
|Honda|Prelude 2026|All|[Upstream](#upstream)|
|
||||||
|Honda|Prologue 2024-25|All|[Not compatible](#can-bus-security)|
|
|Honda|Prologue 2024-25|All|[Not compatible](#can-bus-security)|
|
||||||
|Honda|Ridgeline 2017-25|Honda Sensing|[Upstream](#upstream)|
|
|Honda|Ridgeline 2017-25|Honda Sensing|[Upstream](#upstream)|
|
||||||
|Hyundai|Azera 2022|All|[Upstream](#upstream)|
|
|Hyundai|Azera 2022|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Azera Hybrid 2019|All|[Upstream](#upstream)|
|
|Hyundai|Azera Hybrid 2019|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Azera Hybrid 2020|All|[Upstream](#upstream)|
|
|Hyundai|Azera Hybrid 2020|All|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Azera Hybrid (with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Bayon Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||||
|Hyundai|Custin 2023|All|[Upstream](#upstream)|
|
|Hyundai|Custin 2023|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Elantra 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Elantra Hybrid 2024-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Elantra Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||||
|
|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Hyundai|i30 Hybrid 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|[Upstream](#upstream)|
|
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Ioniq 5 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|
|Hyundai|Ioniq 5 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||||
|Hyundai|Ioniq 5 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|
|Hyundai|Ioniq 5 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Ioniq 5 N (with HDA II) 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Ioniq 5 PE (with HDA II & LFA2) 2025-26|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||||
|Hyundai|Ioniq 6 (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
|Hyundai|Ioniq 6 (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Ioniq 9 (with HDA II & LFA2) 2025-26|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Ioniq Electric 2020|All|[Upstream](#upstream)|
|
|Hyundai|Ioniq Electric 2020|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
@@ -143,40 +227,68 @@
|
|||||||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|[Upstream](#upstream)|
|
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Dashcam mode](#dashcam)|
|
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Dashcam mode](#dashcam)|
|
||||||
|
|Hyundai|Kona (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Kona Electric (without HDA II) 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Kona Hybrid (without HDA II) 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||||
|Hyundai|Nexo 2021|All|[Upstream](#upstream)|
|
|Hyundai|Nexo 2021|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Palisade 2020-22|All|[Upstream](#upstream)|
|
|Hyundai|Palisade 2020-22|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Palisade 2023-24|HDA2|[Community](#community)|
|
|Hyundai|Palisade 2023-25|HDA2|[Community](#community)|
|
||||||
|
|Hyundai|Palisade (with HDA II) 2023-25|Highway Driving Assist II|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Palisade (without HDA II) 2023-25|Highway Driving Assist|[Upstream](#upstream)|
|
||||||
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Santa Cruz (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Santa Fe 2019-20|All|[Upstream](#upstream)|
|
|Hyundai|Santa Fe 2019-20|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Santa Fe 2021-23|All|[Upstream](#upstream)|
|
|Hyundai|Santa Fe 2021-23|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Santa Fe Hybrid 2022-23|All|[Upstream](#upstream)|
|
|Hyundai|Santa Fe Hybrid 2022-23|All|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Santa Fe Hybrid (with HDA II & LFA2) 2024-25|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Santa Fe Hybrid (without HDA II, LFA2) 2025-26|Lane Follow Assist 2|[Upstream](#upstream)|
|
||||||
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|[Upstream](#upstream)|
|
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Sonata 2020-23|All|[Upstream](#upstream)|
|
|Hyundai|Sonata 2020-23|All|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Sonata (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Sonata Hybrid 2020-23|All|[Upstream](#upstream)|
|
|Hyundai|Sonata Hybrid 2020-23|All|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Sonata Hybrid (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Staria 2023|All|[Upstream](#upstream)|
|
|Hyundai|Staria 2023|All|[Upstream](#upstream)|
|
||||||
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Tucson 2023-24|All|[Upstream](#upstream)|
|
|Hyundai|Tucson 2023-24|All|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Tucson (without HDA II) 2025-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Tucson Hybrid 2022-24|All|[Upstream](#upstream)|
|
|Hyundai|Tucson Hybrid 2022-24|All|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Tucson Hybrid (without HDA II) 2025-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Tucson Plug-in Hybrid 2024|All|[Upstream](#upstream)|
|
|Hyundai|Tucson Plug-in Hybrid 2024|All|[Upstream](#upstream)|
|
||||||
|
|Hyundai|Tucson Plug-in Hybrid (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||||
|Kia|Carnival 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Carnival 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|Carnival 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|Carnival (with HDA II) 2025|Highway Driving Assist II|[Upstream](#upstream)|
|
||||||
|
|Kia|Carnival Hybrid 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|Carnival Hybrid 2026|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|Carnival Hybrid (with HDA II) 2025-26|Highway Driving Assist II|[Upstream](#upstream)|
|
||||||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||||
|Kia|EV6 (Southeast Asia only) 2022-24|All|[Upstream](#upstream)|
|
|Kia|EV6 (Southeast Asia only) 2022-24|All|[Upstream](#upstream)|
|
||||||
|
|Kia|EV6 (with HDA I) 2025|Highway Driving Assist I|[Upstream](#upstream)|
|
||||||
|Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|
|Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||||
|Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|
|Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|
||||||
|
|Kia|EV9 2025-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||||
|
|Kia|Forte Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||||
|
|Kia|K4 (with HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|K4 (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|K5 2021-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|K5 2021-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|K5 (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|[Upstream](#upstream)|
|
|Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|[Upstream](#upstream)|
|
||||||
|Kia|Niro EV 2019|All|[Upstream](#upstream)|
|
|Kia|Niro EV 2019|All|[Upstream](#upstream)|
|
||||||
@@ -198,17 +310,25 @@
|
|||||||
|Kia|Optima Hybrid 2017|Advanced Smart Cruise Control|[Dashcam mode](#dashcam)|
|
|Kia|Optima Hybrid 2017|Advanced Smart Cruise Control|[Dashcam mode](#dashcam)|
|
||||||
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|Seltos 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Seltos 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|Seltos Non-SCC 2023-24|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||||
|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|[Upstream](#upstream)|
|
|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|[Upstream](#upstream)|
|
||||||
|Kia|Sorento 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Sorento 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|Sorento 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Sorento 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|Sorento (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|Sorento Hybrid 2021-23|All|[Upstream](#upstream)|
|
|Kia|Sorento Hybrid 2021-23|All|[Upstream](#upstream)|
|
||||||
|
|Kia|Sorento Hybrid 2026|All|[Upstream](#upstream)|
|
||||||
|Kia|Sorento Plug-in Hybrid 2022-23|All|[Upstream](#upstream)|
|
|Kia|Sorento Plug-in Hybrid 2022-23|All|[Upstream](#upstream)|
|
||||||
|Kia|Sportage 2023-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Sportage 2023-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|Sportage (without HDA II) 2026|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|
|Kia|Sportage Hybrid 2026|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Kia|Stinger 2022-23|All|[Upstream](#upstream)|
|
|Kia|Stinger 2022-23|All|[Upstream](#upstream)|
|
||||||
|Kia|Telluride 2020-22|All|[Upstream](#upstream)|
|
|Kia|Telluride 2020-22|All|[Upstream](#upstream)|
|
||||||
|Kia|Telluride 2023-24|HDA2|[Community](#community)|
|
|Kia|Telluride 2023-24|HDA2|[Community](#community)|
|
||||||
|
|Kia|Telluride (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||||
|
|Kia|Telluride (without HDA II) 2023-25|Highway Driving Assist|[Upstream](#upstream)|
|
||||||
|
|Kia|XCeed Plug-in Hybrid 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|[Upstream](#upstream)|
|
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|[Upstream](#upstream)|
|
||||||
|Lexus|ES 2017-18|All|[Upstream](#upstream)|
|
|Lexus|ES 2017-18|All|[Upstream](#upstream)|
|
||||||
|Lexus|ES 2019-25|All|[Upstream](#upstream)|
|
|Lexus|ES 2019-25|All|[Upstream](#upstream)|
|
||||||
@@ -243,7 +363,8 @@
|
|||||||
|Mazda|CX-9 2016-20|All|[Dashcam mode](#dashcam)|
|
|Mazda|CX-9 2016-20|All|[Dashcam mode](#dashcam)|
|
||||||
|Mazda|CX-9 2021-23|All|[Upstream](#upstream)|
|
|Mazda|CX-9 2021-23|All|[Upstream](#upstream)|
|
||||||
|Nissan|Altima 2019-20, 2024|ProPILOT Assist|[Upstream](#upstream)|
|
|Nissan|Altima 2019-20, 2024|ProPILOT Assist|[Upstream](#upstream)|
|
||||||
|Nissan|Leaf 2018-23|ProPILOT Assist|[Upstream](#upstream)|
|
|Nissan|Leaf 2018-25|ProPILOT Assist|[Upstream](#upstream)|
|
||||||
|
|Nissan|Leaf Instrument Cluster 2018-25|ProPILOT Assist|[Upstream](#upstream)|
|
||||||
|Nissan|Rogue 2018-20|ProPILOT Assist|[Upstream](#upstream)|
|
|Nissan|Rogue 2018-20|ProPILOT Assist|[Upstream](#upstream)|
|
||||||
|Nissan|X-Trail 2017|ProPILOT Assist|[Upstream](#upstream)|
|
|Nissan|X-Trail 2017|ProPILOT Assist|[Upstream](#upstream)|
|
||||||
|Peugeot|208 2019-25|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
|Peugeot|208 2019-25|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||||
@@ -252,30 +373,36 @@
|
|||||||
|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)|
|
|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)|
|
||||||
|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)|
|
|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)|
|
||||||
|Rivian|R1S 2022-24|All|[Upstream](#upstream)|
|
|Rivian|R1S 2022-24|All|[Upstream](#upstream)|
|
||||||
|
|Rivian|R1S 2025|All|[Upstream](#upstream)|
|
||||||
|Rivian|R1T 2022-24|All|[Upstream](#upstream)|
|
|Rivian|R1T 2022-24|All|[Upstream](#upstream)|
|
||||||
|
|Rivian|R1T 2025|All|[Upstream](#upstream)|
|
||||||
|SEAT|Alhambra 2018-20|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
|SEAT|Alhambra 2018-20|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||||
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Subaru|Ascent 2019-21|All|[Upstream](#upstream)|
|
|Subaru|Ascent 2019-21|All|[Upstream](#upstream)|
|
||||||
|Subaru|Ascent 2023|All|[Dashcam mode](#dashcam)|
|
|Subaru|Ascent 2023-25|All|[Upstream](#upstream)|
|
||||||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||||
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|[Upstream](#upstream)|
|
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||||
|
|Subaru|Crosstrek 2025|All|[Upstream](#upstream)|
|
||||||
|Subaru|Crosstrek Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
|Subaru|Crosstrek Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||||
|Subaru|Forester 2017-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
|Subaru|Forester 2017-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||||
|Subaru|Forester 2019-21|All|[Upstream](#upstream)|
|
|Subaru|Forester 2019-21|All|[Upstream](#upstream)|
|
||||||
|Subaru|Forester 2022-24|All|[Dashcam mode](#dashcam)|
|
|Subaru|Forester 2022-24|All|[Upstream](#upstream)|
|
||||||
|Subaru|Forester Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
|Subaru|Forester Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
|Subaru|Impreza 2017-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance|[Upstream](#upstream)|
|
|Subaru|Impreza 2020-22|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||||
|Subaru|Legacy 2015-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
|Subaru|Legacy 2015-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||||
|Subaru|Legacy 2020-22|All|[Upstream](#upstream)|
|
|Subaru|Legacy 2020-22|All|[Upstream](#upstream)|
|
||||||
|
|Subaru|Legacy 2025|All|[Upstream](#upstream)|
|
||||||
|Subaru|Outback 2015-17|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
|Subaru|Outback 2015-17|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||||
|Subaru|Outback 2018-19|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
|Subaru|Outback 2018-19|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||||
|Subaru|Outback 2020-22|All|[Upstream](#upstream)|
|
|Subaru|Outback 2020-22|All|[Upstream](#upstream)|
|
||||||
|Subaru|Outback 2023|All|[Dashcam mode](#dashcam)|
|
|Subaru|Outback 2023-24|All|[Upstream](#upstream)|
|
||||||
|Subaru|Solterra 2023-25|Any|[Not compatible](#can-bus-security)|
|
|Subaru|Solterra 2023-25|Any|[Not compatible](#can-bus-security)|
|
||||||
|Subaru|XV 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
|Subaru|XV 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||||
|Subaru|XV 2020-21|EyeSight Driver Assistance|[Upstream](#upstream)|
|
|Subaru|XV 2020-21|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||||
|
|Škoda|Enyaq 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|
|Škoda|Enyaq 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Škoda|Kamiq 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Škoda|Kamiq 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Škoda|Karoq 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Škoda|Karoq 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
@@ -286,7 +413,8 @@
|
|||||||
|Škoda|Scala 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Škoda|Scala 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Tesla|Model 3 (with HW3) 2019-23|All|[Upstream](#upstream)|
|
|Tesla|Model 3 (with HW3) 2019-23|All|[Upstream](#upstream)|
|
||||||
|Tesla|Model 3 (with HW4) 2024-25|All|[Upstream](#upstream)|
|
|Tesla|Model 3 (with HW4) 2024-26|All|[Upstream](#upstream)|
|
||||||
|
|Tesla|Model S (Pre-AP) 2012-14|All|[Community](#community)|
|
||||||
|Tesla|Model X (with HW4) 2024|All|[Dashcam mode](#dashcam)|
|
|Tesla|Model X (with HW4) 2024|All|[Dashcam mode](#dashcam)|
|
||||||
|Tesla|Model Y (with HW3) 2020-23|All|[Upstream](#upstream)|
|
|Tesla|Model Y (with HW3) 2020-23|All|[Upstream](#upstream)|
|
||||||
|Tesla|Model Y (with HW4) 2024-25|All|[Upstream](#upstream)|
|
|Tesla|Model Y (with HW4) 2024-25|All|[Upstream](#upstream)|
|
||||||
@@ -321,6 +449,7 @@
|
|||||||
|Toyota|Highlander 2025|Any|[Not compatible](#can-bus-security)|
|
|Toyota|Highlander 2025|Any|[Not compatible](#can-bus-security)|
|
||||||
|Toyota|Highlander Hybrid 2017-19|All|[Upstream](#upstream)|
|
|Toyota|Highlander Hybrid 2017-19|All|[Upstream](#upstream)|
|
||||||
|Toyota|Highlander Hybrid 2020-23|All|[Upstream](#upstream)|
|
|Toyota|Highlander Hybrid 2020-23|All|[Upstream](#upstream)|
|
||||||
|
|Toyota|Matrix Retrofit 2005|Custom retrofit|[Community](#community)|
|
||||||
|Toyota|Mirai 2021|All|[Upstream](#upstream)|
|
|Toyota|Mirai 2021|All|[Upstream](#upstream)|
|
||||||
|Toyota|Prius 2016|Toyota Safety Sense P|[Upstream](#upstream)|
|
|Toyota|Prius 2016|Toyota Safety Sense P|[Upstream](#upstream)|
|
||||||
|Toyota|Prius 2017-20|All|[Upstream](#upstream)|
|
|Toyota|Prius 2017-20|All|[Upstream](#upstream)|
|
||||||
@@ -342,7 +471,7 @@
|
|||||||
|Toyota|RAV4 Prime 2024-25|Any|[Not compatible](#can-bus-security)|
|
|Toyota|RAV4 Prime 2024-25|Any|[Not compatible](#can-bus-security)|
|
||||||
|Toyota|Sequoia 2023-25|Any|[Not compatible](#can-bus-security)|
|
|Toyota|Sequoia 2023-25|Any|[Not compatible](#can-bus-security)|
|
||||||
|Toyota|Sienna 2018-20|All|[Upstream](#upstream)|
|
|Toyota|Sienna 2018-20|All|[Upstream](#upstream)|
|
||||||
|Toyota|Sienna 2021-23|All|[Community](#community)|
|
|Toyota|Sienna 2021-25|All|[Community](#community)|
|
||||||
|Toyota|Sienna 2024-25|Any|[Not compatible](#can-bus-security)|
|
|Toyota|Sienna 2024-25|Any|[Not compatible](#can-bus-security)|
|
||||||
|Toyota|Tundra 2022-25|Any|[Not compatible](#can-bus-security)|
|
|Toyota|Tundra 2022-25|Any|[Not compatible](#can-bus-security)|
|
||||||
|Toyota|Venza 2021-25|Any|[Not compatible](#can-bus-security)|
|
|Toyota|Venza 2021-25|Any|[Not compatible](#can-bus-security)|
|
||||||
@@ -369,6 +498,11 @@
|
|||||||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|
|Volkswagen|ID.3 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|
|Volkswagen|ID.3 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|
|Volkswagen|ID.4 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|
|Volkswagen|ID.4 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|
|Volkswagen|ID.5 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Volkswagen|Jetta 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
|Volkswagen|Jetta 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||||
|Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||||
@@ -444,4 +578,4 @@ Toyota, and the GM Global B platform.
|
|||||||
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
|
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
|
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
|
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.
|
may one day be supported, but we have no immediate plans to support FlexRay.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ test:
|
|||||||
run: codespell {files} -L tge,stdio -S *.dbc
|
run: codespell {files} -L tge,stdio -S *.dbc
|
||||||
files: git ls-tree -r HEAD --name-only
|
files: git ls-tree -r HEAD --name-only
|
||||||
cpplint:
|
cpplint:
|
||||||
run: cpplint --exclude=opendbc/safety/tests/misra/cppcheck/ --exclude=opendbc/can/*_pyx.cpp --recursive --quiet --counting=detailed --linelength=240 --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces opendbc/
|
run: cpplint --exclude=opendbc/safety/tests/misra/cppcheck/ --exclude=opendbc/safety/tests/.venv/ --exclude=opendbc/can/*_pyx.cpp --recursive --quiet --counting=detailed --linelength=240 --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces opendbc/
|
||||||
misra:
|
misra:
|
||||||
run: opendbc/safety/tests/misra/test_misra.sh
|
run: opendbc/safety/tests/misra/test_misra.sh
|
||||||
|
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ class CANParser:
|
|||||||
self.dbc: DBC = DBC(dbc_name)
|
self.dbc: DBC = DBC(dbc_name)
|
||||||
|
|
||||||
self.vl: dict[int | str, dict[str, float]] = VLDict(self)
|
self.vl: dict[int | str, dict[str, float]] = VLDict(self)
|
||||||
|
self.vl_raw: dict[int | str, bytes] = {}
|
||||||
self.vl_all: dict[int | str, dict[str, list[float]]] = {}
|
self.vl_all: dict[int | str, dict[str, list[float]]] = {}
|
||||||
self.ts_nanos: dict[int | str, dict[str, int]] = {}
|
self.ts_nanos: dict[int | str, dict[str, int]] = {}
|
||||||
self.addresses: set[int] = set()
|
self.addresses: set[int] = set()
|
||||||
@@ -166,6 +167,8 @@ class CANParser:
|
|||||||
signals_dict = {s: 0.0 for s in signal_names}
|
signals_dict = {s: 0.0 for s in signal_names}
|
||||||
dict.__setitem__(self.vl, msg.address, signals_dict)
|
dict.__setitem__(self.vl, msg.address, signals_dict)
|
||||||
dict.__setitem__(self.vl, msg.name, signals_dict)
|
dict.__setitem__(self.vl, msg.name, signals_dict)
|
||||||
|
self.vl_raw[msg.address] = bytes(msg.size)
|
||||||
|
self.vl_raw[msg.name] = bytes(msg.size)
|
||||||
self.vl_all[msg.address] = defaultdict(list)
|
self.vl_all[msg.address] = defaultdict(list)
|
||||||
self.vl_all[msg.name] = self.vl_all[msg.address]
|
self.vl_all[msg.name] = self.vl_all[msg.address]
|
||||||
self.ts_nanos[msg.address] = {s: 0 for s in signal_names}
|
self.ts_nanos[msg.address] = {s: 0 for s in signal_names}
|
||||||
@@ -247,6 +250,8 @@ class CANParser:
|
|||||||
vl_addr[sig.name] = state.vals[i]
|
vl_addr[sig.name] = state.vals[i]
|
||||||
vl_all_addr[sig.name] = state.all_vals[i]
|
vl_all_addr[sig.name] = state.all_vals[i]
|
||||||
ts_addr[sig.name] = state.timestamps[-1]
|
ts_addr[sig.name] = state.timestamps[-1]
|
||||||
|
self.vl_raw[address] = bytes(dat)
|
||||||
|
self.vl_raw[state.name] = bytes(dat)
|
||||||
|
|
||||||
if not bus_empty:
|
if not bus_empty:
|
||||||
self.last_nonempty_nanos = t
|
self.last_nonempty_nanos = t
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import copy
|
import copy
|
||||||
from opendbc.can import CANPacker, CANParser
|
from opendbc.can import CANPacker, CANParser
|
||||||
|
from opendbc.car.honda.hondacan import honda_checksum
|
||||||
|
|
||||||
|
|
||||||
class TestCanChecksums:
|
class TestCanChecksums:
|
||||||
@@ -90,6 +91,13 @@ class TestCanChecksums:
|
|||||||
assert parser.vl['LKAS_HUD']['CHECKSUM'] == std
|
assert parser.vl['LKAS_HUD']['CHECKSUM'] == std
|
||||||
assert parser.vl['LKAS_HUD_A']['CHECKSUM'] == ext
|
assert parser.vl['LKAS_HUD_A']['CHECKSUM'] == ext
|
||||||
|
|
||||||
|
def test_honda_canfd_checksum_offset_is_scoped_to_mvl_messages(self):
|
||||||
|
# Existing high-ID Honda messages retain the legacy extended-ID offset;
|
||||||
|
# only the Accord MVL replacement-radar IDs use the CAN-FD offset.
|
||||||
|
payload = bytearray(8)
|
||||||
|
assert honda_checksum(0xF31AA54, None, payload) == 11 # existing radarless LKAS_HUD_2
|
||||||
|
assert honda_checksum(0xF31AA52, None, payload) == 4 # Accord MVL RADAR_LEAD2
|
||||||
|
|
||||||
def verify_volkswagen_mqb_crc(self, subtests, msg_name: str, msg_addr: int, test_messages: list[bytes], counter_field: str = 'COUNTER'):
|
def verify_volkswagen_mqb_crc(self, subtests, msg_name: str, msg_addr: int, test_messages: list[bytes], counter_field: str = 'COUNTER'):
|
||||||
"""Test AUTOSAR E2E Profile 2 CRCs"""
|
"""Test AUTOSAR E2E Profile 2 CRCs"""
|
||||||
assert len(test_messages) == 16 # All counter values must be tested
|
assert len(test_messages) == 16 # All counter values must be tested
|
||||||
|
|||||||
@@ -374,6 +374,7 @@ struct CarControl {
|
|||||||
brake @1: Float32; # [0.0, 1.0]
|
brake @1: Float32; # [0.0, 1.0]
|
||||||
torqueOutputCan @8: Float32; # value sent over can to the car
|
torqueOutputCan @8: Float32; # value sent over can to the car
|
||||||
speed @6: Float32; # m/s
|
speed @6: Float32; # m/s
|
||||||
|
lateralControlMode @9: LateralControlMode;
|
||||||
|
|
||||||
enum LongControlState @0xe40f3a917d908282{
|
enum LongControlState @0xe40f3a917d908282{
|
||||||
off @0;
|
off @0;
|
||||||
@@ -381,6 +382,13 @@ struct CarControl {
|
|||||||
stopping @2;
|
stopping @2;
|
||||||
starting @3;
|
starting @3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum LateralControlMode {
|
||||||
|
inactive @0;
|
||||||
|
torque @1;
|
||||||
|
angle @2;
|
||||||
|
torqueRecovering @3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CruiseControl {
|
struct CruiseControl {
|
||||||
@@ -510,6 +518,7 @@ struct CarParams {
|
|||||||
startingState @70 :Bool; # Does this car make use of special starting state
|
startingState @70 :Bool; # Does this car make use of special starting state
|
||||||
|
|
||||||
steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds
|
steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds
|
||||||
|
lateralSmoothSeconds @78 :Float32; # Speed-scheduled curvature smoothing used by select angle-control platforms
|
||||||
longitudinalActuatorDelay @58 :Float32; # Gas/Brake actuator delay in seconds
|
longitudinalActuatorDelay @58 :Float32; # Gas/Brake actuator delay in seconds
|
||||||
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
|
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
|
||||||
carVin @38 :Text; # VIN number queried during fingerprinting
|
carVin @38 :Text; # VIN number queried during fingerprinting
|
||||||
@@ -635,6 +644,8 @@ struct CarParams {
|
|||||||
fcaGiorgio @32;
|
fcaGiorgio @32;
|
||||||
rivian @33;
|
rivian @33;
|
||||||
volkswagenMeb @34;
|
volkswagenMeb @34;
|
||||||
|
teslaPreAP @35;
|
||||||
|
volvo @36;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SteerControlType {
|
enum SteerControlType {
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ def _normalize_forced_candidate(candidate: str | None) -> str | None:
|
|||||||
return LEGACY_FORCED_CANDIDATE_MAP.get(candidate, candidate)
|
return LEGACY_FORCED_CANDIDATE_MAP.get(candidate, candidate)
|
||||||
|
|
||||||
|
|
||||||
def _normalize_gm_bolt_candidate(candidate: str | None, fingerprints: dict[int, dict]) -> str | None:
|
def _normalize_gm_bolt_candidate(candidate: str | None, fingerprints: dict[int, dict], vin: str | None = None) -> str | None:
|
||||||
"""
|
"""
|
||||||
Normalize ambiguous/mismatched Bolt candidates using robust PT message signatures.
|
Normalize ambiguous/mismatched Bolt candidates using robust PT message signatures.
|
||||||
This guards against occasional wrong variant selection causing persistent canError.
|
This guards against occasional wrong variant selection causing persistent canError.
|
||||||
@@ -79,7 +79,22 @@ def _normalize_gm_bolt_candidate(candidate: str | None, fingerprints: dict[int,
|
|||||||
msg_304_len = pt.get(304) # 8 on 2017 Gen1, 1 on 2018-2021 Gen1
|
msg_304_len = pt.get(304) # 8 on 2017 Gen1, 1 on 2018-2021 Gen1
|
||||||
has_pedal = 513 in pt
|
has_pedal = 513 in pt
|
||||||
|
|
||||||
|
# The 2022-23 Bolt ACC, pedal, and CC variants share the same FPv1
|
||||||
|
# fingerprint. Recover an ambiguous match when the observed traffic
|
||||||
|
# matches the Bolt family and the VIN confirms model year 2022/2023.
|
||||||
|
bolt_2022_2023_signature = (
|
||||||
|
pt.get(190) == 7 and
|
||||||
|
msg_211_len == 3 and
|
||||||
|
pt.get(566) == 8 and
|
||||||
|
pt.get(458) == 5
|
||||||
|
)
|
||||||
|
vin_year = vin[9] if isinstance(vin, str) and len(vin) > 9 else None
|
||||||
|
|
||||||
|
# VIN model-year codes: N=2022, P=2023.
|
||||||
|
if candidate is None and bolt_2022_2023_signature and vin_year in ("N", "P"):
|
||||||
|
return "CHEVROLET_BOLT_ACC_2022_2023_PEDAL" if has_pedal else "CHEVROLET_BOLT_ACC_2022_2023"
|
||||||
# If detection failed entirely but the signature is clearly Bolt, recover to a sane default.
|
# If detection failed entirely but the signature is clearly Bolt, recover to a sane default.
|
||||||
|
|
||||||
if candidate is None and 170 in pt and 188 in pt and msg_211_len in (2, 3):
|
if candidate is None and 170 in pt and 188 in pt and msg_211_len in (2, 3):
|
||||||
if msg_211_len == 3:
|
if msg_211_len == 3:
|
||||||
return "CHEVROLET_BOLT_ACC_2022_2023_PEDAL" if has_pedal else "CHEVROLET_BOLT_ACC_2022_2023"
|
return "CHEVROLET_BOLT_ACC_2022_2023_PEDAL" if has_pedal else "CHEVROLET_BOLT_ACC_2022_2023"
|
||||||
@@ -279,7 +294,7 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
|
|||||||
def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, alpha_long_allowed: bool,
|
def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, alpha_long_allowed: bool,
|
||||||
is_release: bool, params: Params, num_pandas: int = 1, cached_params: CarParamsT | None = None, starpilot_toggles: SimpleNamespace = None):
|
is_release: bool, params: Params, num_pandas: int = 1, cached_params: CarParamsT | None = None, starpilot_toggles: SimpleNamespace = None):
|
||||||
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params)
|
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params)
|
||||||
candidate = _normalize_gm_bolt_candidate(candidate, fingerprints)
|
candidate = _normalize_gm_bolt_candidate(candidate, fingerprints, vin)
|
||||||
candidate = _normalize_gm_volt_candidate(candidate, fingerprints)
|
candidate = _normalize_gm_volt_candidate(candidate, fingerprints)
|
||||||
candidate = _normalize_forced_candidate(candidate)
|
candidate = _normalize_forced_candidate(candidate)
|
||||||
fingerprinted_candidate = candidate
|
fingerprinted_candidate = candidate
|
||||||
|
|||||||
@@ -23,9 +23,11 @@ def ecu_log(msg):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_req=b'\x28\x83\x01', timeout=0.1, retry=10, reset=False):
|
def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_req=b'\x28\x83\x01', timeout=0.1, retry=10, reset=False,
|
||||||
|
require_response=False, diag_request=EXT_DIAG_REQUEST, diag_response=EXT_DIAG_RESPONSE, response_offset=0x8):
|
||||||
"""Silence an ECU by disabling sending and receiving messages using UDS 0x28.
|
"""Silence an ECU by disabling sending and receiving messages using UDS 0x28.
|
||||||
The ECU will stay silent as long as openpilot keeps sending Tester Present.
|
The ECU will stay silent as long as openpilot keeps sending Tester Present.
|
||||||
|
Set require_response for takeovers that must fail closed unless the ECU confirms communication control.
|
||||||
|
|
||||||
This is used to disable the radar in some cars. Openpilot will emulate the radar.
|
This is used to disable the radar in some cars. Openpilot will emulate the radar.
|
||||||
WARNING: THIS DISABLES AEB!"""
|
WARNING: THIS DISABLES AEB!"""
|
||||||
@@ -34,7 +36,8 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
|
|||||||
if reset:
|
if reset:
|
||||||
try:
|
try:
|
||||||
ecu_log("sending ECU reset before communication control...")
|
ecu_log("sending ECU reset before communication control...")
|
||||||
reset_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [RESET_REQUEST], [RESET_RESPONSE])
|
reset_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [RESET_REQUEST], [RESET_RESPONSE],
|
||||||
|
response_offset=response_offset)
|
||||||
reset_query.get_data(timeout=timeout)
|
reset_query.get_data(timeout=timeout)
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -45,7 +48,8 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
|
|||||||
try:
|
try:
|
||||||
# Enter extended diagnostic session
|
# Enter extended diagnostic session
|
||||||
ecu_log(f"attempt {i+1}/{retry}: diag session...")
|
ecu_log(f"attempt {i+1}/{retry}: diag session...")
|
||||||
query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [EXT_DIAG_REQUEST], [EXT_DIAG_RESPONSE])
|
query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [diag_request], [diag_response],
|
||||||
|
response_offset=response_offset)
|
||||||
|
|
||||||
for _, _ in query.get_data(timeout).items():
|
for _, _ in query.get_data(timeout).items():
|
||||||
ecu_log("diag session OK")
|
ecu_log("diag session OK")
|
||||||
@@ -55,14 +59,15 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
|
|||||||
|
|
||||||
# Send CC command and log the response
|
# Send CC command and log the response
|
||||||
ecu_log("sending CC...")
|
ecu_log("sending CC...")
|
||||||
cc_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [com_cont_req], [b''])
|
cc_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [com_cont_req], [b''],
|
||||||
|
response_offset=response_offset)
|
||||||
cc_response = cc_query.get_data(timeout)
|
cc_response = cc_query.get_data(timeout)
|
||||||
|
|
||||||
# Log what we got back
|
# Log what we got back
|
||||||
cc_success = False
|
cc_success = False
|
||||||
cc_rejected = False
|
cc_rejected = False
|
||||||
cc_nrc = None
|
cc_nrc = None
|
||||||
for (rx_addr, _), data in cc_response.items():
|
for (_rx_addr, _), data in cc_response.items():
|
||||||
ecu_log(f"CC response: {data.hex() if data else 'empty'}")
|
ecu_log(f"CC response: {data.hex() if data else 'empty'}")
|
||||||
# Check for positive response (0x68 = 0x28 + 0x40)
|
# Check for positive response (0x68 = 0x28 + 0x40)
|
||||||
if len(data) >= 1 and data[0] == 0x68:
|
if len(data) >= 1 and data[0] == 0x68:
|
||||||
@@ -93,6 +98,9 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
|
|||||||
# ECU explicitly rejected - don't retry, it won't work
|
# ECU explicitly rejected - don't retry, it won't work
|
||||||
ecu_log("=== ECU DISABLE REJECTED ===")
|
ecu_log("=== ECU DISABLE REJECTED ===")
|
||||||
return False
|
return False
|
||||||
|
elif require_response:
|
||||||
|
ecu_log("CC response required but none received; retrying...")
|
||||||
|
continue
|
||||||
else:
|
else:
|
||||||
# No response - consider it sent (ECU might have stopped responding)
|
# No response - consider it sent (ECU might have stopped responding)
|
||||||
ecu_log("=== ECU DISABLE SENT (no response) ===")
|
ecu_log("=== ECU DISABLE SENT (no response) ===")
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ class CarHarness(EnumBase):
|
|||||||
ford_q3 = BaseCarHarness("Ford Q3 connector")
|
ford_q3 = BaseCarHarness("Ford Q3 connector")
|
||||||
ford_q4 = BaseCarHarness("Ford Q4 connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
|
ford_q4 = BaseCarHarness("Ford Q4 connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
|
||||||
rivian = BaseCarHarness("Rivian A connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
|
rivian = BaseCarHarness("Rivian A connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
|
||||||
|
rivian_b = BaseCarHarness("Rivian B connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
|
||||||
tesla_a = BaseCarHarness("Tesla A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
|
tesla_a = BaseCarHarness("Tesla A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
|
||||||
tesla_b = BaseCarHarness("Tesla B connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
|
tesla_b = BaseCarHarness("Tesla B connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
|
||||||
psa_a = BaseCarHarness("PSA A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
|
psa_a = BaseCarHarness("PSA A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class CAR(Platforms):
|
|||||||
|
|
||||||
EXTRA_HYUNDAI = ExtraPlatformConfig(
|
EXTRA_HYUNDAI = ExtraPlatformConfig(
|
||||||
[
|
[
|
||||||
CommunityCarDocs("Hyundai Palisade 2023-24", package="HDA2"),
|
CommunityCarDocs("Hyundai Palisade 2023-25", package="HDA2"),
|
||||||
CommunityCarDocs("Kia Telluride 2023-24", package="HDA2"),
|
CommunityCarDocs("Kia Telluride 2023-24", package="HDA2"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -245,7 +245,6 @@ MIGRATION = {
|
|||||||
"KIA SELTOS 2021": HYUNDAI.KIA_SELTOS,
|
"KIA SELTOS 2021": HYUNDAI.KIA_SELTOS,
|
||||||
"KIA SPORTAGE 5TH GEN": HYUNDAI.KIA_SPORTAGE_5TH_GEN,
|
"KIA SPORTAGE 5TH GEN": HYUNDAI.KIA_SPORTAGE_5TH_GEN,
|
||||||
"KIA SPORTAGE 2026": HYUNDAI.KIA_SPORTAGE_2026,
|
"KIA SPORTAGE 2026": HYUNDAI.KIA_SPORTAGE_2026,
|
||||||
"KIA SPORTAGE HYBRID 2026": HYUNDAI.KIA_SPORTAGE_HEV_2026,
|
|
||||||
"KIA SORENTO GT LINE 2018": HYUNDAI.KIA_SORENTO,
|
"KIA SORENTO GT LINE 2018": HYUNDAI.KIA_SORENTO,
|
||||||
"KIA SORENTO 4TH GEN": HYUNDAI.KIA_SORENTO_4TH_GEN,
|
"KIA SORENTO 4TH GEN": HYUNDAI.KIA_SORENTO_4TH_GEN,
|
||||||
"KIA SORENTO 2024": HYUNDAI.KIA_SORENTO_2024,
|
"KIA SORENTO 2024": HYUNDAI.KIA_SORENTO_2024,
|
||||||
@@ -265,6 +264,7 @@ MIGRATION = {
|
|||||||
"GENESIS G70 2020": HYUNDAI.GENESIS_G70_2020,
|
"GENESIS G70 2020": HYUNDAI.GENESIS_G70_2020,
|
||||||
"GENESIS GV70 1ST GEN": HYUNDAI.GENESIS_GV70_1ST_GEN,
|
"GENESIS GV70 1ST GEN": HYUNDAI.GENESIS_GV70_1ST_GEN,
|
||||||
"GENESIS GV70 ELECTRIFIED 2026": HYUNDAI.GENESIS_GV70_ELECTRIFIED_2ND_GEN,
|
"GENESIS GV70 ELECTRIFIED 2026": HYUNDAI.GENESIS_GV70_ELECTRIFIED_2ND_GEN,
|
||||||
|
"GENESIS GV70 2026": HYUNDAI.GENESIS_GV70_2026,
|
||||||
"GENESIS G80 2017": HYUNDAI.GENESIS_G80,
|
"GENESIS G80 2017": HYUNDAI.GENESIS_G80,
|
||||||
"GENESIS G90 2017": HYUNDAI.GENESIS_G90,
|
"GENESIS G90 2017": HYUNDAI.GENESIS_G90,
|
||||||
"GENESIS GV80 2023": HYUNDAI.GENESIS_GV80,
|
"GENESIS GV80 2023": HYUNDAI.GENESIS_GV80,
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ from opendbc.car.lateral import ISO_LATERAL_ACCEL, apply_std_steer_angle_limits
|
|||||||
from opendbc.car.ford import fordcan
|
from opendbc.car.ford import fordcan
|
||||||
from opendbc.car.ford.values import CarControllerParams, FordFlags, CAR
|
from opendbc.car.ford.values import CarControllerParams, FordFlags, CAR
|
||||||
from opendbc.car.interfaces import CarControllerBase, V_CRUISE_MAX
|
from opendbc.car.interfaces import CarControllerBase, V_CRUISE_MAX
|
||||||
|
from openpilot.starpilot.car.ford import fordcan as starpilot_fordcan
|
||||||
|
from openpilot.starpilot.car.ford.lateral import FordLateralController, FordLateralMode, FordLateralResult
|
||||||
|
|
||||||
LongCtrlState = structs.CarControl.Actuators.LongControlState
|
LongCtrlState = structs.CarControl.Actuators.LongControlState
|
||||||
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
||||||
@@ -80,6 +82,9 @@ class CarController(CarControllerBase):
|
|||||||
self.steer_alert_last = False
|
self.steer_alert_last = False
|
||||||
self.lead_distance_bars_last = None
|
self.lead_distance_bars_last = None
|
||||||
self.distance_bar_frame = 0
|
self.distance_bar_frame = 0
|
||||||
|
self.ford_lateral = None if CP.flags & FordFlags.LKA_STEERING else FordLateralController(CP)
|
||||||
|
self.ford_shadow_curvature = 0.0
|
||||||
|
self.ford_lateral_announced_mode = FordLateralMode.native
|
||||||
|
|
||||||
def update(self, CC, CS, now_nanos, starpilot_toggles):
|
def update(self, CC, CS, now_nanos, starpilot_toggles):
|
||||||
can_sends = []
|
can_sends = []
|
||||||
@@ -91,6 +96,9 @@ class CarController(CarControllerBase):
|
|||||||
steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw)
|
steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw)
|
||||||
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
|
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
|
||||||
|
|
||||||
|
if self.ford_lateral is not None:
|
||||||
|
self.ford_lateral.update_inputs()
|
||||||
|
|
||||||
### acc buttons ###
|
### acc buttons ###
|
||||||
if CC.cruiseControl.cancel:
|
if CC.cruiseControl.cancel:
|
||||||
can_sends.append(fordcan.create_button_msg(self.packer, self.CAN.camera, CS.buttons_stock_values, cancel=True))
|
can_sends.append(fordcan.create_button_msg(self.packer, self.CAN.camera, CS.buttons_stock_values, cancel=True))
|
||||||
@@ -128,38 +136,70 @@ class CarController(CarControllerBase):
|
|||||||
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN, active=lka_active, apply_angle=self.apply_angle_last,
|
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN, active=lka_active, apply_angle=self.apply_angle_last,
|
||||||
direction=direction, ramp_type=ramp_type, curvature=-self.apply_curvature_last))
|
direction=direction, ramp_type=ramp_type, curvature=-self.apply_curvature_last))
|
||||||
else:
|
else:
|
||||||
# send steer msg at 20Hz
|
lateral_mode = self.ford_lateral.mode
|
||||||
if (self.frame % CarControllerParams.STEER_STEP) == 0:
|
lateral_mode_ready = lateral_mode == self.ford_lateral_announced_mode
|
||||||
# Bronco and some other cars consistently overshoot curv requests
|
|
||||||
# Apply some deadzone + smoothing convergence to avoid oscillations
|
# Keep the original Ford path available without changing its command behavior.
|
||||||
if self.CP.carFingerprint in (CAR.FORD_BRONCO_SPORT_MK1, CAR.FORD_F_150_MK14):
|
if lateral_mode == FordLateralMode.native:
|
||||||
self.anti_overshoot_curvature_last = anti_overshoot(actuators.curvature, self.anti_overshoot_curvature_last, CS.out.vEgoRaw)
|
if (self.frame % CarControllerParams.STEER_STEP) == 0:
|
||||||
apply_curvature = self.anti_overshoot_curvature_last
|
if not lateral_mode_ready:
|
||||||
|
self.apply_curvature_last = 0.0
|
||||||
|
apply_curvature = 0.0
|
||||||
|
elif self.CP.carFingerprint in (CAR.FORD_BRONCO_SPORT_MK1, CAR.FORD_F_150_MK14):
|
||||||
|
self.anti_overshoot_curvature_last = anti_overshoot(
|
||||||
|
actuators.curvature, self.anti_overshoot_curvature_last, CS.out.vEgoRaw)
|
||||||
|
apply_curvature = self.anti_overshoot_curvature_last
|
||||||
|
else:
|
||||||
|
apply_curvature = actuators.curvature
|
||||||
|
|
||||||
|
current_curvature = -CS.out.yawRate / max(CS.out.vEgoRaw, 0.1)
|
||||||
|
self.apply_curvature_last = apply_ford_curvature_limits(
|
||||||
|
apply_curvature, self.apply_curvature_last, current_curvature,
|
||||||
|
CS.out.vEgoRaw, 0., CC.latActive and lateral_mode_ready, self.CP)
|
||||||
|
|
||||||
|
if self.CP.flags & FordFlags.CANFD:
|
||||||
|
mode = 1 if CC.latActive and lateral_mode_ready else 0
|
||||||
|
counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10
|
||||||
|
can_sends.append(fordcan.create_lat_ctl2_msg(
|
||||||
|
self.packer, self.CAN, mode, 0., 0., -self.apply_curvature_last, 0., counter))
|
||||||
|
else:
|
||||||
|
can_sends.append(fordcan.create_lat_ctl_msg(
|
||||||
|
self.packer, self.CAN, CC.latActive and lateral_mode_ready, 0., 0., -self.apply_curvature_last, 0.))
|
||||||
|
elif (self.frame % CarControllerParams.STEER_STEP) == 0:
|
||||||
|
if not lateral_mode_ready:
|
||||||
|
lateral = FordLateralResult(shadow_curvature=self.ford_lateral._current_curvature(CS))
|
||||||
|
elif lateral_mode == FordLateralMode.angle:
|
||||||
|
lateral = self.ford_lateral.update_angle(CC, CS, actuators)
|
||||||
else:
|
else:
|
||||||
apply_curvature = actuators.curvature
|
lateral = self.ford_lateral.update_curvature(CC, CS, actuators)
|
||||||
|
|
||||||
# apply rate limits, curvature error limit, and clip to signal range
|
|
||||||
current_curvature = -CS.out.yawRate / max(CS.out.vEgoRaw, 0.1)
|
|
||||||
|
|
||||||
self.apply_curvature_last = apply_ford_curvature_limits(apply_curvature, self.apply_curvature_last, current_curvature,
|
|
||||||
CS.out.vEgoRaw, 0., CC.latActive, self.CP)
|
|
||||||
|
|
||||||
|
self.apply_curvature_last = lateral.curvature
|
||||||
|
self.ford_shadow_curvature = lateral.shadow_curvature
|
||||||
if self.CP.flags & FordFlags.CANFD:
|
if self.CP.flags & FordFlags.CANFD:
|
||||||
# TODO: extended mode
|
|
||||||
# Ford uses four individual signals to dictate how to drive to the car. Curvature alone (limited to 0.02m/s^2)
|
|
||||||
# can actuate the steering for a large portion of any lateral movements. However, in order to get further control on
|
|
||||||
# steer actuation, the other three signals are necessary. Ford controls vehicles differently than most other makes.
|
|
||||||
# A detailed explanation on ford control can be found here:
|
|
||||||
# https://www.f150gen14.com/forum/threads/introducing-bluepilot-a-ford-specific-fork-for-comma3x-openpilot.24241/#post-457706
|
|
||||||
mode = 1 if CC.latActive else 0
|
|
||||||
counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10
|
counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10
|
||||||
can_sends.append(fordcan.create_lat_ctl2_msg(self.packer, self.CAN, mode, 0., 0., -self.apply_curvature_last, 0., counter))
|
can_sends.append(starpilot_fordcan.create_lat_ctl2_msg(
|
||||||
|
self.packer, self.CAN, 1 if lateral.active else 0,
|
||||||
|
lateral.ramp_type, lateral.precision_type,
|
||||||
|
-lateral.path_offset, -lateral.path_angle,
|
||||||
|
-lateral.curvature, -lateral.curvature_rate, counter))
|
||||||
else:
|
else:
|
||||||
can_sends.append(fordcan.create_lat_ctl_msg(self.packer, self.CAN, CC.latActive, 0., 0., -self.apply_curvature_last, 0.))
|
can_sends.append(starpilot_fordcan.create_lat_ctl_msg(
|
||||||
|
self.packer, self.CAN, lateral.active,
|
||||||
|
lateral.ramp_type, lateral.precision_type,
|
||||||
|
-lateral.path_offset, -lateral.path_angle,
|
||||||
|
-lateral.curvature, -lateral.curvature_rate))
|
||||||
|
|
||||||
# send lka msg at 33Hz
|
|
||||||
if (self.frame % CarControllerParams.LKA_STEP) == 0:
|
if (self.frame % CarControllerParams.LKA_STEP) == 0:
|
||||||
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN))
|
if lateral_mode == FordLateralMode.native:
|
||||||
|
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN))
|
||||||
|
else:
|
||||||
|
angle_mode = lateral_mode == FordLateralMode.angle
|
||||||
|
shadow_curvature = -self.ford_lateral._current_curvature(CS)
|
||||||
|
if angle_mode:
|
||||||
|
shadow_curvature = -self.ford_shadow_curvature
|
||||||
|
can_sends.append(starpilot_fordcan.create_lka_msg(
|
||||||
|
self.packer, self.CAN, angle_mode=angle_mode, shadow_curvature=shadow_curvature))
|
||||||
|
self.ford_lateral_announced_mode = lateral_mode
|
||||||
|
|
||||||
### longitudinal control ###
|
### longitudinal control ###
|
||||||
# send acc msg at 50Hz
|
# send acc msg at 50Hz
|
||||||
@@ -215,9 +255,15 @@ class CarController(CarControllerBase):
|
|||||||
|
|
||||||
if (self.frame % CarControllerParams.ACC_UI_STEP) == 0 or send_ui:
|
if (self.frame % CarControllerParams.ACC_UI_STEP) == 0 or send_ui:
|
||||||
show_distance_bars = self.frame - self.distance_bar_frame < 400
|
show_distance_bars = self.frame - self.distance_bar_frame < 400
|
||||||
|
hands_free_cluster = bool(
|
||||||
|
self.ford_lateral is not None
|
||||||
|
and self.ford_lateral.mode != FordLateralMode.native
|
||||||
|
and self.ford_lateral.mode == self.ford_lateral_announced_mode
|
||||||
|
and self.ford_lateral.hands_free_cluster_enabled)
|
||||||
can_sends.append(fordcan.create_acc_ui_msg(self.packer, self.CAN, self.CP, main_on, CC.latActive,
|
can_sends.append(fordcan.create_acc_ui_msg(self.packer, self.CAN, self.CP, main_on, CC.latActive,
|
||||||
fcw_alert, CS.out.cruiseState.standstill, show_distance_bars,
|
fcw_alert, CS.out.cruiseState.standstill, show_distance_bars,
|
||||||
hud_control, CS.acc_tja_status_stock_values))
|
hud_control, CS.acc_tja_status_stock_values,
|
||||||
|
hands_free_cluster))
|
||||||
|
|
||||||
self.main_on_last = main_on
|
self.main_on_last = main_on
|
||||||
self.lkas_enabled_last = CC.latActive
|
self.lkas_enabled_last = CC.latActive
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from opendbc.car import Bus, create_button_events, structs
|
|||||||
from opendbc.car.common.conversions import Conversions as CV
|
from opendbc.car.common.conversions import Conversions as CV
|
||||||
from opendbc.car.ford.fordcan import CanBus
|
from opendbc.car.ford.fordcan import CanBus
|
||||||
from opendbc.car.ford.values import DBC, CarControllerParams, FordFlags
|
from opendbc.car.ford.values import DBC, CarControllerParams, FordFlags
|
||||||
|
from opendbc.car.gps import get_car_gps_config
|
||||||
from opendbc.car.interfaces import CarStateBase
|
from opendbc.car.interfaces import CarStateBase
|
||||||
|
|
||||||
ButtonType = structs.CarState.ButtonEvent.Type
|
ButtonType = structs.CarState.ButtonEvent.Type
|
||||||
@@ -16,26 +17,71 @@ class CarState(CarStateBase):
|
|||||||
super().__init__(CP, FPCP)
|
super().__init__(CP, FPCP)
|
||||||
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
|
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
|
||||||
if CP.transmissionType == TransmissionType.automatic:
|
if CP.transmissionType == TransmissionType.automatic:
|
||||||
self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"]
|
if CP.flags & FordFlags.CANFD:
|
||||||
|
self.shifter_values = can_define.dv["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"]
|
||||||
|
elif CP.flags & FordFlags.ALT_STEER_ANGLE:
|
||||||
|
self.shifter_values = can_define.dv["TransGearData"]["GearLvrPos_D_Actl"]
|
||||||
|
else:
|
||||||
|
self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"]
|
||||||
|
|
||||||
self.distance_button = 0
|
self.distance_button = 0
|
||||||
self.lc_button = 0
|
self.lc_button = 0
|
||||||
self.lkas_available = False
|
self.lkas_available = False
|
||||||
self.lateral_motion_control = None
|
self.lateral_motion_control = None
|
||||||
|
self.lateral_control_status = None
|
||||||
|
self.steering_angle_offset_deg = 0.0
|
||||||
|
self.car_gps_config = get_car_gps_config(CP)
|
||||||
|
self.car_gps_supported = self.car_gps_config is not None
|
||||||
|
self.car_gps = None
|
||||||
|
self._car_gps_timestamp_nanos = 0
|
||||||
|
|
||||||
|
def _update_car_gps(self, cp) -> None:
|
||||||
|
if self.car_gps_config is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
timestamps = [max(cp.ts_nanos[name].values(), default=0) for name in self.car_gps_config.messages]
|
||||||
|
if not all(timestamps) or max(timestamps) - min(timestamps) > 2_000_000_000:
|
||||||
|
return
|
||||||
|
|
||||||
|
timestamp_nanos = max(timestamps)
|
||||||
|
if timestamp_nanos <= self._car_gps_timestamp_nanos:
|
||||||
|
return
|
||||||
|
|
||||||
|
gps = self.car_gps_config.decoder(*(cp.vl[name] for name in self.car_gps_config.messages))
|
||||||
|
if gps is not None:
|
||||||
|
gps["timestamp_nanos"] = timestamp_nanos
|
||||||
|
self.car_gps = gps
|
||||||
|
self._car_gps_timestamp_nanos = timestamp_nanos
|
||||||
|
|
||||||
|
def get_car_gps(self):
|
||||||
|
return self.car_gps
|
||||||
|
|
||||||
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
|
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
|
||||||
cp = can_parsers[Bus.pt]
|
cp = can_parsers[Bus.pt]
|
||||||
cp_cam = can_parsers[Bus.cam]
|
cp_cam = can_parsers[Bus.cam]
|
||||||
|
|
||||||
|
self._update_car_gps(cp)
|
||||||
|
|
||||||
ret = structs.CarState()
|
ret = structs.CarState()
|
||||||
|
|
||||||
# Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement
|
if self.CP.flags & FordFlags.ALT_STEER_ANGLE:
|
||||||
# The vehicle usually recovers out of this state within a minute of normal driving
|
sensors_valid = (
|
||||||
ret.vehicleSensorsInvalid = cp.vl["SteeringPinion_Data"]["StePinCompAnEst_D_Qf"] != 3
|
int((cp.vl["ParkAid_Data"]["ExtSteeringAngleReq2"] + 1000) * 10) not in (32766, 32767)
|
||||||
|
and cp.vl["ParkAid_Data"]["EPASExtAngleStatReq"] == 0
|
||||||
|
and cp.vl["ParkAid_Data"]["ApaSys_D_Stat"] in (0, 1)
|
||||||
|
)
|
||||||
|
ret.vehicleSensorsInvalid = not sensors_valid
|
||||||
|
else:
|
||||||
|
# The ABS can recalibrate the steering pinion offset briefly after startup.
|
||||||
|
ret.vehicleSensorsInvalid = cp.vl["SteeringPinion_Data"]["StePinCompAnEst_D_Qf"] != 3
|
||||||
|
|
||||||
# car speed
|
# car speed
|
||||||
ret.vEgoRaw = cp.vl["BrakeSysFeatures"]["Veh_V_ActlBrk"] * CV.KPH_TO_MS
|
ret.vEgoRaw = cp.vl["BrakeSysFeatures"]["Veh_V_ActlBrk"] * CV.KPH_TO_MS
|
||||||
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
||||||
|
if self.CP.flags & FordFlags.CANFD:
|
||||||
|
ret.vEgoCluster = ((cp.vl["Cluster_Info_3_FD1"]["DISPLAY_SPEED_SCALING"] / 100) *
|
||||||
|
cp.vl["EngVehicleSpThrottle2"]["Veh_V_ActlEng"] +
|
||||||
|
cp.vl["Cluster_Info_3_FD1"]["DISPLAY_SPEED_OFFSET"]) * CV.KPH_TO_MS
|
||||||
ret.yawRate = cp.vl["Yaw_Data_FD1"]["VehYaw_W_Actl"]
|
ret.yawRate = cp.vl["Yaw_Data_FD1"]["VehYaw_W_Actl"]
|
||||||
ret.standstill = cp.vl["DesiredTorqBrk"]["VehStop_D_Stat"] == 1
|
ret.standstill = cp.vl["DesiredTorqBrk"]["VehStop_D_Stat"] == 1
|
||||||
|
|
||||||
@@ -48,7 +94,14 @@ class CarState(CarStateBase):
|
|||||||
ret.parkingBrake = cp.vl["DesiredTorqBrk"]["PrkBrkStatus"] in (1, 2)
|
ret.parkingBrake = cp.vl["DesiredTorqBrk"]["PrkBrkStatus"] in (1, 2)
|
||||||
|
|
||||||
# steering wheel
|
# steering wheel
|
||||||
ret.steeringAngleDeg = cp.vl["SteeringPinion_Data"]["StePinComp_An_Est"]
|
if self.CP.flags & FordFlags.ALT_STEER_ANGLE:
|
||||||
|
steering_angle_init = cp.vl["SteeringPinion_Data_Alt"]["StePinRelInit_An_Sns"]
|
||||||
|
if not ret.vehicleSensorsInvalid:
|
||||||
|
steering_angle_est = cp.vl["ParkAid_Data"]["ExtSteeringAngleReq2"]
|
||||||
|
self.steering_angle_offset_deg = steering_angle_est - steering_angle_init
|
||||||
|
ret.steeringAngleDeg = steering_angle_init + self.steering_angle_offset_deg
|
||||||
|
else:
|
||||||
|
ret.steeringAngleDeg = cp.vl["SteeringPinion_Data"]["StePinComp_An_Est"]
|
||||||
ret.steeringTorque = cp.vl["EPAS_INFO"]["SteeringColumnTorque"]
|
ret.steeringTorque = cp.vl["EPAS_INFO"]["SteeringColumnTorque"]
|
||||||
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE, 5)
|
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE, 5)
|
||||||
ret.steerFaultTemporary = cp.vl["EPAS_INFO"]["EPAS_Failure"] == 1
|
ret.steerFaultTemporary = cp.vl["EPAS_INFO"]["EPAS_Failure"] == 1
|
||||||
@@ -57,10 +110,12 @@ class CarState(CarStateBase):
|
|||||||
|
|
||||||
if self.CP.flags & FordFlags.CANFD:
|
if self.CP.flags & FordFlags.CANFD:
|
||||||
# this signal is always 0 on non-CAN FD cars
|
# this signal is always 0 on non-CAN FD cars
|
||||||
ret.steerFaultTemporary |= cp.vl["Lane_Assist_Data3_FD1"]["LatCtlSte_D_Stat"] not in (1, 2, 3)
|
self.lateral_control_status = int(cp.vl["Lane_Assist_Data3_FD1"]["LatCtlSte_D_Stat"])
|
||||||
|
ret.steerFaultTemporary |= self.lateral_control_status not in (1, 2, 3)
|
||||||
|
|
||||||
# cruise state
|
# cruise state
|
||||||
is_metric = cp.vl["INSTRUMENT_PANEL"]["METRIC_UNITS"] == 1 if not self.CP.flags & FordFlags.CANFD else False
|
is_metric = cp.vl["INSTRUMENT_PANEL"]["METRIC_UNITS"] == 1 if not self.CP.flags & FordFlags.CANFD else \
|
||||||
|
cp_cam.vl["IPMA_Data2"]["IsaVLimUnit_D_Rq"] == 1
|
||||||
ret.cruiseState.speed = cp.vl["EngBrakeData"]["Veh_V_DsplyCcSet"] * (CV.KPH_TO_MS if is_metric else CV.MPH_TO_MS)
|
ret.cruiseState.speed = cp.vl["EngBrakeData"]["Veh_V_DsplyCcSet"] * (CV.KPH_TO_MS if is_metric else CV.MPH_TO_MS)
|
||||||
ret.cruiseState.enabled = cp.vl["EngBrakeData"]["CcStat_D_Actl"] in (4, 5)
|
ret.cruiseState.enabled = cp.vl["EngBrakeData"]["CcStat_D_Actl"] in (4, 5)
|
||||||
ret.cruiseState.available = cp.vl["EngBrakeData"]["CcStat_D_Actl"] in (3, 4, 5)
|
ret.cruiseState.available = cp.vl["EngBrakeData"]["CcStat_D_Actl"] in (3, 4, 5)
|
||||||
@@ -72,7 +127,12 @@ class CarState(CarStateBase):
|
|||||||
|
|
||||||
# gear
|
# gear
|
||||||
if self.CP.transmissionType == TransmissionType.automatic:
|
if self.CP.transmissionType == TransmissionType.automatic:
|
||||||
gear = self.shifter_values.get(cp.vl["PowertrainData_10"]["TrnRng_D_Rq"])
|
if self.CP.flags & FordFlags.CANFD:
|
||||||
|
gear = self.shifter_values.get(cp.vl["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"])
|
||||||
|
elif self.CP.flags & FordFlags.ALT_STEER_ANGLE:
|
||||||
|
gear = self.shifter_values.get(cp.vl["TransGearData"]["GearLvrPos_D_Actl"])
|
||||||
|
else:
|
||||||
|
gear = self.shifter_values.get(cp.vl["PowertrainData_10"]["TrnRng_D_Rq"])
|
||||||
ret.gearShifter = self.parse_gear_shifter(gear)
|
ret.gearShifter = self.parse_gear_shifter(gear)
|
||||||
elif self.CP.transmissionType == TransmissionType.manual:
|
elif self.CP.transmissionType == TransmissionType.manual:
|
||||||
if bool(cp.vl["BCM_Lamp_Stat_FD1"]["RvrseLghtOn_B_Stat"]):
|
if bool(cp.vl["BCM_Lamp_Stat_FD1"]["RvrseLghtOn_B_Stat"]):
|
||||||
@@ -126,12 +186,102 @@ class CarState(CarStateBase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
fp_ret = custom.StarPilotCarState.new_message()
|
fp_ret = custom.StarPilotCarState.new_message()
|
||||||
|
fp_ret.brakeLights = ret.brakePressed
|
||||||
|
try:
|
||||||
|
fp_ret.brakeLights = bool(cp.vl["BCM_Lamp_Stat_FD1"]["StopLghtOn_B_Stat"])
|
||||||
|
except (KeyError, AttributeError):
|
||||||
|
try:
|
||||||
|
fp_ret.brakeLights = cp.vl["BrakeSysFeatures_2"]["BrkLamp_B_Rq"] == 1
|
||||||
|
except (KeyError, AttributeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
speed_limit = cp_cam.vl["Traffic_RecognitnData"]["TsrVLim1MsgTxt_D_Rq"]
|
||||||
|
speed_limit_unit = cp_cam.vl["Traffic_RecognitnData"]["TsrVlUnitMsgTxt_D_Rq"]
|
||||||
|
speed_factor = CV.MPH_TO_MS if speed_limit_unit == 2 else CV.KPH_TO_MS if speed_limit_unit == 1 else 0.0
|
||||||
|
fp_ret.dashboardSpeedLimit = speed_limit * speed_factor if speed_limit not in (0, 255) else 0.0
|
||||||
|
except (KeyError, AttributeError):
|
||||||
|
fp_ret.dashboardSpeedLimit = 0.0
|
||||||
|
|
||||||
return ret, fp_ret
|
return ret, fp_ret
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_can_parsers(CP):
|
def get_can_parsers(CP):
|
||||||
|
gps_config = get_car_gps_config(CP)
|
||||||
|
gps_messages = [(name, 0) for name in gps_config.messages] if gps_config is not None else []
|
||||||
|
|
||||||
|
pt_messages = [
|
||||||
|
("BrakeSysFeatures", 50),
|
||||||
|
("Yaw_Data_FD1", 100),
|
||||||
|
("DesiredTorqBrk", 50),
|
||||||
|
("EngVehicleSpThrottle", 100),
|
||||||
|
("EngVehicleSpThrottle2", 50),
|
||||||
|
("BrakeSnData_4", 50),
|
||||||
|
("EngBrakeData", 10),
|
||||||
|
("EPAS_INFO", 50),
|
||||||
|
("Cluster_Info1_FD1", 10),
|
||||||
|
("Steering_Data_FD1", 10),
|
||||||
|
("BodyInfo_3_FD1", 2),
|
||||||
|
("RCMStatusMessage2_FD1", 10),
|
||||||
|
("BCM_Lamp_Stat_FD1", 0),
|
||||||
|
*gps_messages,
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.flags & FordFlags.ALT_STEER_ANGLE:
|
||||||
|
pt_messages += [
|
||||||
|
("SteeringPinion_Data_Alt", 100),
|
||||||
|
("ParkAid_Data", 50),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
pt_messages += [("SteeringPinion_Data", 100)]
|
||||||
|
|
||||||
|
if CP.flags & FordFlags.CANFD:
|
||||||
|
pt_messages += [
|
||||||
|
("Lane_Assist_Data3_FD1", 33),
|
||||||
|
("Cluster_Info_3_FD1", 10),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
pt_messages += [("INSTRUMENT_PANEL", 1)]
|
||||||
|
|
||||||
|
if CP.transmissionType == TransmissionType.automatic:
|
||||||
|
if CP.flags & FordFlags.CANFD:
|
||||||
|
pt_messages += [("Gear_Shift_by_Wire_FD1", 10)]
|
||||||
|
elif CP.flags & FordFlags.ALT_STEER_ANGLE:
|
||||||
|
pt_messages += [("TransGearData", 10)]
|
||||||
|
else:
|
||||||
|
pt_messages += [("PowertrainData_10", 10)]
|
||||||
|
|
||||||
|
if CP.enableBsm and not (CP.flags & FordFlags.CANFD):
|
||||||
|
pt_messages += [
|
||||||
|
("Side_Detect_L_Stat", 5),
|
||||||
|
("Side_Detect_R_Stat", 5),
|
||||||
|
]
|
||||||
|
|
||||||
|
cam_messages = [
|
||||||
|
("ACCDATA", 50),
|
||||||
|
("ACCDATA_2", 50),
|
||||||
|
("ACCDATA_3", 5),
|
||||||
|
("IPMA_Data", 1),
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.flags & FordFlags.CANFD:
|
||||||
|
cam_messages += [
|
||||||
|
("Traffic_RecognitnData", 1),
|
||||||
|
("IPMA_Data2", 1),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
cam_messages += [("Traffic_RecognitnData", 0)]
|
||||||
|
|
||||||
|
if CP.enableBsm and CP.flags & FordFlags.CANFD:
|
||||||
|
cam_messages += [
|
||||||
|
("Side_Detect_L_Stat", 5),
|
||||||
|
("Side_Detect_R_Stat", 5),
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.flags & FordFlags.LKA_STEERING:
|
||||||
|
cam_messages += [("LateralMotionControl", 20)]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).main),
|
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CanBus(CP).main),
|
||||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).camera),
|
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, CanBus(CP).camera),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ FW_VERSIONS = {
|
|||||||
b'LX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'LX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.abs, 0x760, None): [
|
(Ecu.abs, 0x760, None): [
|
||||||
|
b'LX6C-2D053-KF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'LX6C-2D053-KG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'LX6C-2D053-RD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'LX6C-2D053-RD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'LX6C-2D053-RE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'LX6C-2D053-RE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'LX6C-2D053-RF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'LX6C-2D053-RF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
@@ -24,6 +26,21 @@ FW_VERSIONS = {
|
|||||||
b'M1PT-14F397-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'M1PT-14F397-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
CAR.FORD_EDGE_MK2: {
|
||||||
|
(Ecu.eps, 0x730, None): [
|
||||||
|
b'M2GC-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
],
|
||||||
|
(Ecu.abs, 0x760, None): [
|
||||||
|
b'M2GC-2D053-CB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'M2GC-2D053-EA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
],
|
||||||
|
(Ecu.fwdRadar, 0x764, None): [
|
||||||
|
b'JX7T-14D049-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
],
|
||||||
|
(Ecu.fwdCamera, 0x706, None): [
|
||||||
|
b'KT4T-14F397-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
],
|
||||||
|
},
|
||||||
CAR.FORD_ESCAPE_MK4: {
|
CAR.FORD_ESCAPE_MK4: {
|
||||||
(Ecu.eps, 0x730, None): [
|
(Ecu.eps, 0x730, None): [
|
||||||
b'LX6C-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'LX6C-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
@@ -49,7 +66,9 @@ FW_VERSIONS = {
|
|||||||
},
|
},
|
||||||
CAR.FORD_ESCAPE_MK4_5: {
|
CAR.FORD_ESCAPE_MK4_5: {
|
||||||
(Ecu.eps, 0x730, None): [
|
(Ecu.eps, 0x730, None): [
|
||||||
|
b'PZ11-14D003-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'PZ11-14D003-EA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'PZ11-14D003-EA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'PZ11-14D003-FA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.abs, 0x760, None): [
|
(Ecu.abs, 0x760, None): [
|
||||||
b'PZ1C-2D053-EJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'PZ1C-2D053-EJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
@@ -58,11 +77,20 @@ FW_VERSIONS = {
|
|||||||
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.fwdCamera, 0x706, None): [
|
(Ecu.fwdCamera, 0x706, None): [
|
||||||
|
b'PJ6T-14H102-ABE\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'PJ6T-14H102-ABL\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'PJ6T-14H102-ABL\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'PJ6T-14H102-MDC\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'PJ6T-14H102-MDF\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'PJ6T-14H102-SCD\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'PJ6T-14H102-SCG\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
CAR.FORD_EXPLORER_MK6: {
|
CAR.FORD_EXPLORER_MK6: {
|
||||||
(Ecu.eps, 0x730, None): [
|
(Ecu.eps, 0x730, None): [
|
||||||
|
b'R1MC-14D003-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'R1MC-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'R1MC-14D003-AG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'R1MC-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'L1MC-14D003-AJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'L1MC-14D003-AJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'L1MC-14D003-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'L1MC-14D003-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'L1MC-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'L1MC-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
@@ -96,6 +124,7 @@ FW_VERSIONS = {
|
|||||||
],
|
],
|
||||||
(Ecu.abs, 0x760, None): [
|
(Ecu.abs, 0x760, None): [
|
||||||
b'RL14-2D053-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'RL14-2D053-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'PL14-2D053-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.fwdRadar, 0x764, None): [
|
(Ecu.fwdRadar, 0x764, None): [
|
||||||
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
@@ -106,6 +135,7 @@ FW_VERSIONS = {
|
|||||||
},
|
},
|
||||||
CAR.FORD_F_150_MK14: {
|
CAR.FORD_F_150_MK14: {
|
||||||
(Ecu.eps, 0x730, None): [
|
(Ecu.eps, 0x730, None): [
|
||||||
|
b'MB3C-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'ML3V-14D003-BA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'ML3V-14D003-BA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'ML3V-14D003-BC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'ML3V-14D003-BC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'ML3V-14D003-BD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'ML3V-14D003-BD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
@@ -136,8 +166,11 @@ FW_VERSIONS = {
|
|||||||
},
|
},
|
||||||
CAR.FORD_F_150_LIGHTNING_MK1: {
|
CAR.FORD_F_150_LIGHTNING_MK1: {
|
||||||
(Ecu.abs, 0x760, None): [
|
(Ecu.abs, 0x760, None): [
|
||||||
|
b'NL38-2D053-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'PL38-2D053-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'PL38-2D053-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'RL38-2D053-BC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'RL38-2D053-BD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'RL38-2D053-BD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'TL38-2D053-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.fwdCamera, 0x706, None): [
|
(Ecu.fwdCamera, 0x706, None): [
|
||||||
b'ML3T-14H102-ABT\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'ML3T-14H102-ABT\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
@@ -145,9 +178,13 @@ FW_VERSIONS = {
|
|||||||
b'RJ6T-14H102-BBC\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'RJ6T-14H102-BBC\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.fwdRadar, 0x764, None): [
|
(Ecu.fwdRadar, 0x764, None): [
|
||||||
|
b'ML3T-14D049-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'RB5T-14D049-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.eps, 0x730, None): [
|
(Ecu.eps, 0x730, None): [
|
||||||
|
b'NL38-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'NL38-14D003-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'RL38-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'RL38-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -164,6 +201,8 @@ FW_VERSIONS = {
|
|||||||
b'LK9C-2D053-CN\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'LK9C-2D053-CN\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.fwdRadar, 0x764, None): [
|
(Ecu.fwdRadar, 0x764, None): [
|
||||||
|
b'ML3T-14D049-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'ML3T-14D049-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.fwdCamera, 0x706, None): [
|
(Ecu.fwdCamera, 0x706, None): [
|
||||||
@@ -174,15 +213,42 @@ FW_VERSIONS = {
|
|||||||
CAR.FORD_FOCUS_MK4: {
|
CAR.FORD_FOCUS_MK4: {
|
||||||
(Ecu.eps, 0x730, None): [
|
(Ecu.eps, 0x730, None): [
|
||||||
b'JX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'JX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'JX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'JX6C-14D003-BB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'NX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.abs, 0x760, None): [
|
(Ecu.abs, 0x760, None): [
|
||||||
b'JX61-2D053-CJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'JX61-2D053-CJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'LX61-2D053-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'NX61-2D053-MD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.fwdRadar, 0x764, None): [
|
(Ecu.fwdRadar, 0x764, None): [
|
||||||
b'JX7T-14D049-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'JX7T-14D049-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'JX7T-14D049-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.fwdCamera, 0x706, None): [
|
(Ecu.fwdCamera, 0x706, None): [
|
||||||
b'JX7T-14F397-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'JX7T-14F397-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'N1BT-14F397-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
CAR.FORD_MONDEO_MK5: {
|
||||||
|
(Ecu.fwdCamera, 0x706, None): [
|
||||||
|
b'KT4T-14F397-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
],
|
||||||
|
(Ecu.abs, 0x760, None): [
|
||||||
|
b'KG9C-2D053-DF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
],
|
||||||
|
(Ecu.eps, 0x730, None): [
|
||||||
|
b'K2GC-14D003-AJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
],
|
||||||
|
(Ecu.fwdRadar, 0x764, None): [
|
||||||
|
b'JX7T-14D049-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
],
|
||||||
|
(Ecu.engine, 0x7e0, None): [
|
||||||
|
b'HS7A-14C204-CJD\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
],
|
||||||
|
(Ecu.debug, 0x7d0, None): [
|
||||||
|
b'1U5T-14G374-DA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
CAR.FORD_MAVERICK_MK1: {
|
CAR.FORD_MAVERICK_MK1: {
|
||||||
@@ -207,17 +273,25 @@ FW_VERSIONS = {
|
|||||||
},
|
},
|
||||||
CAR.FORD_RANGER_MK2: {
|
CAR.FORD_RANGER_MK2: {
|
||||||
(Ecu.eps, 0x730, None): [
|
(Ecu.eps, 0x730, None): [
|
||||||
|
b'JR3C-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'NB3C-14D003-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'NB3C-14D003-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'NL14-14D003-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'NL14-14D003-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'NL14-14D003-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'RB3C-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'RB3C-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.abs, 0x760, None): [
|
(Ecu.abs, 0x760, None): [
|
||||||
|
b'MB3C-2D053-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'MB3C-2D053-ZJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'PB3C-2D053-ZB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'PB3C-2D053-ZC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'PB3C-2D053-ZD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'PB3C-2D053-ZD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'PB3C-2D053-ZG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'PB3C-2D053-ZG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'PB3C-2D053-ZJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'PB3C-2D053-ZJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
|
b'PB9C-2D053-ZG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'RB3C-2D053-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'RB3C-2D053-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.fwdRadar, 0x764, None): [
|
(Ecu.fwdRadar, 0x764, None): [
|
||||||
|
b'JX7T-14D049-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.fwdCamera, 0x706, None): [
|
(Ecu.fwdCamera, 0x706, None): [
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ def create_acc_msg(packer, CAN: CanBus, long_active: bool, gas: float, accel: fl
|
|||||||
|
|
||||||
|
|
||||||
def create_acc_ui_msg(packer, CAN: CanBus, CP, main_on: bool, enabled: bool, fcw_alert: bool, standstill: bool,
|
def create_acc_ui_msg(packer, CAN: CanBus, CP, main_on: bool, enabled: bool, fcw_alert: bool, standstill: bool,
|
||||||
show_distance_bars: bool, hud_control, stock_values: dict):
|
show_distance_bars: bool, hud_control, stock_values: dict, hands_free_cluster: bool = False):
|
||||||
"""
|
"""
|
||||||
Creates a CAN message for the Ford IPC adaptive cruise, forward collision warning and traffic jam
|
Creates a CAN message for the Ford IPC adaptive cruise, forward collision warning and traffic jam
|
||||||
assist status.
|
assist status.
|
||||||
@@ -197,6 +197,8 @@ def create_acc_ui_msg(packer, CAN: CanBus, CP, main_on: bool, enabled: bool, fcw
|
|||||||
status = 3 # ActiveInterventionLeft
|
status = 3 # ActiveInterventionLeft
|
||||||
elif hud_control.rightLaneDepart:
|
elif hud_control.rightLaneDepart:
|
||||||
status = 4 # ActiveInterventionRight
|
status = 4 # ActiveInterventionRight
|
||||||
|
elif hands_free_cluster:
|
||||||
|
status = 7 # Hands-free assistance display
|
||||||
else:
|
else:
|
||||||
status = 2 # Active
|
status = 2 # Active
|
||||||
elif main_on:
|
elif main_on:
|
||||||
|
|||||||
@@ -31,12 +31,13 @@ class CarInterface(CarInterfaceBase):
|
|||||||
|
|
||||||
ret.radarUnavailable = Bus.radar not in DBC[candidate]
|
ret.radarUnavailable = Bus.radar not in DBC[candidate]
|
||||||
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
||||||
ret.steerActuatorDelay = 0.05 if ret.flags & FordFlags.LKA_STEERING else 0.2
|
ret.steerActuatorDelay = 0.05 if ret.flags & FordFlags.LKA_STEERING else 0.22
|
||||||
ret.steerLimitTimer = 1.0
|
ret.steerLimitTimer = 1.0
|
||||||
ret.steerAtStandstill = True
|
ret.steerAtStandstill = True
|
||||||
|
|
||||||
ret.longitudinalTuning.kiBP = [0.]
|
ret.longitudinalTuning.kiBP = [0.]
|
||||||
ret.longitudinalTuning.kiV = [0.5]
|
ret.longitudinalTuning.kiV = [0.5]
|
||||||
|
ret.longitudinalTuning.kpV = [0.]
|
||||||
|
|
||||||
if not ret.radarUnavailable and DBC[candidate][Bus.radar] == RADAR.DELPHI_MRR:
|
if not ret.radarUnavailable and DBC[candidate][Bus.radar] == RADAR.DELPHI_MRR:
|
||||||
# average of 33.3 Hz radar timestep / 4 scan modes = 60 ms
|
# average of 33.3 Hz radar timestep / 4 scan modes = 60 ms
|
||||||
@@ -44,15 +45,19 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.radarDelay = 0.06
|
ret.radarDelay = 0.06
|
||||||
|
|
||||||
CAN = CanBus(fingerprint=fingerprint)
|
CAN = CanBus(fingerprint=fingerprint)
|
||||||
|
if 0x365 in fingerprint[CAN.main]:
|
||||||
|
ret.flags |= int(FordFlags.HEV_CLUSTER_DATA)
|
||||||
|
if all(address in fingerprint[CAN.main] for address in (0x07A, 0x24B, 0x24C)):
|
||||||
|
ret.flags |= int(FordFlags.HEV_BATTERY_DATA)
|
||||||
cfgs = [get_safety_config(structs.CarParams.SafetyModel.ford)]
|
cfgs = [get_safety_config(structs.CarParams.SafetyModel.ford)]
|
||||||
if CAN.main >= 4:
|
if CAN.main >= 4:
|
||||||
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
|
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
|
||||||
ret.safetyConfigs = cfgs
|
ret.safetyConfigs = cfgs
|
||||||
|
|
||||||
ret.alphaLongitudinalAvailable = ret.radarUnavailable
|
ret.alphaLongitudinalAvailable = True
|
||||||
if alpha_long or not ret.radarUnavailable:
|
ret.openpilotLongitudinalControl = bool(alpha_long)
|
||||||
|
if ret.openpilotLongitudinalControl:
|
||||||
ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.LONG_CONTROL.value
|
ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.LONG_CONTROL.value
|
||||||
ret.openpilotLongitudinalControl = True
|
|
||||||
|
|
||||||
if ret.flags & FordFlags.CANFD:
|
if ret.flags & FordFlags.CANFD:
|
||||||
ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.CANFD.value
|
ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.CANFD.value
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
from collections import deque
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from math import cos, sin
|
from math import cos, sin
|
||||||
@@ -19,6 +20,7 @@ DELPHI_MRR_RADAR_MSG_COUNT = 64
|
|||||||
DELPHI_MRR_RADAR_RANGE_COVERAGE = {0: 42, 1: 164, 2: 45, 3: 175} # scan index to detection range (m)
|
DELPHI_MRR_RADAR_RANGE_COVERAGE = {0: 42, 1: 164, 2: 45, 3: 175} # scan index to detection range (m)
|
||||||
DELPHI_MRR_MIN_LONG_RANGE_DIST = 30 # meters
|
DELPHI_MRR_MIN_LONG_RANGE_DIST = 30 # meters
|
||||||
DELPHI_MRR_CLUSTER_THRESHOLD = 5 # meters, lateral distance and relative velocity are weighted
|
DELPHI_MRR_CLUSTER_THRESHOLD = 5 # meters, lateral distance and relative velocity are weighted
|
||||||
|
STEER_ASSIST_DATA_ADDR = 0x3D7
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -89,12 +91,17 @@ def _create_delphi_mrr_radar_can_parser(CP) -> CANParser:
|
|||||||
return CANParser(RADAR.DELPHI_MRR, messages, CanBus(CP).radar)
|
return CANParser(RADAR.DELPHI_MRR, messages, CanBus(CP).radar)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_steer_assist_radar_can_parser(CP) -> CANParser:
|
||||||
|
return CANParser(RADAR.STEER_ASSIST_DATA, [("Steer_Assist_Data", 20)], CanBus(CP).camera)
|
||||||
|
|
||||||
|
|
||||||
class RadarInterface(RadarInterfaceBase):
|
class RadarInterface(RadarInterfaceBase):
|
||||||
def __init__(self, CP):
|
def __init__(self, CP):
|
||||||
super().__init__(CP)
|
super().__init__(CP)
|
||||||
|
|
||||||
self.points: list[list[float]] = []
|
self.points: list[list[float]] = []
|
||||||
self.clusters: list[Cluster] = []
|
self.clusters: list[Cluster] = []
|
||||||
|
self.v_rel_history = deque(maxlen=20)
|
||||||
|
|
||||||
self.updated_messages = set()
|
self.updated_messages = set()
|
||||||
self.track_id = 0
|
self.track_id = 0
|
||||||
@@ -111,6 +118,9 @@ class RadarInterface(RadarInterfaceBase):
|
|||||||
elif self.radar == RADAR.DELPHI_MRR:
|
elif self.radar == RADAR.DELPHI_MRR:
|
||||||
self.rcp = _create_delphi_mrr_radar_can_parser(CP)
|
self.rcp = _create_delphi_mrr_radar_can_parser(CP)
|
||||||
self.trigger_msg = DELPHI_MRR_RADAR_HEADER_ADDR
|
self.trigger_msg = DELPHI_MRR_RADAR_HEADER_ADDR
|
||||||
|
elif self.radar == RADAR.STEER_ASSIST_DATA:
|
||||||
|
self.rcp = _create_steer_assist_radar_can_parser(CP)
|
||||||
|
self.trigger_msg = STEER_ASSIST_DATA_ADDR
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unsupported radar: {self.radar}")
|
raise ValueError(f"Unsupported radar: {self.radar}")
|
||||||
|
|
||||||
@@ -135,10 +145,45 @@ class RadarInterface(RadarInterfaceBase):
|
|||||||
_update = self._update_delphi_mrr(ret)
|
_update = self._update_delphi_mrr(ret)
|
||||||
if not _update:
|
if not _update:
|
||||||
return None
|
return None
|
||||||
|
elif self.radar == RADAR.STEER_ASSIST_DATA:
|
||||||
|
self._update_steer_assist()
|
||||||
|
|
||||||
ret.points = list(self.pts.values())
|
ret.points = list(self.pts.values())
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def _update_steer_assist(self):
|
||||||
|
msg = self.rcp.vl["Steer_Assist_Data"]
|
||||||
|
confidence = msg["CmbbObjConfdnc_D_Stat"]
|
||||||
|
if confidence <= 0:
|
||||||
|
self.pts.pop(0, None)
|
||||||
|
self.v_rel_history.clear()
|
||||||
|
return
|
||||||
|
|
||||||
|
d_rel = msg["CmbbObjDistLong_L_Actl"]
|
||||||
|
v_rel = msg["CmbbObjRelLong_V_Actl"]
|
||||||
|
new_track = 0 not in self.pts
|
||||||
|
if new_track:
|
||||||
|
self.pts[0] = structs.RadarData.RadarPoint()
|
||||||
|
self.pts[0].trackId = self.track_id
|
||||||
|
self.track_id += 1
|
||||||
|
elif abs(v_rel) < 1e-2:
|
||||||
|
self.v_rel_history.append(d_rel - self.pts[0].dRel)
|
||||||
|
v_rel = sum(self.v_rel_history)
|
||||||
|
else:
|
||||||
|
self.v_rel_history.clear()
|
||||||
|
|
||||||
|
if not new_track and (abs(self.pts[0].vRel - v_rel) > 2.0 or abs(self.pts[0].dRel - d_rel) > 5.0):
|
||||||
|
self.pts[0].trackId = self.track_id
|
||||||
|
self.track_id += 1
|
||||||
|
self.v_rel_history.clear()
|
||||||
|
|
||||||
|
self.pts[0].dRel = d_rel
|
||||||
|
self.pts[0].yRel = msg["CmbbObjDistLat_L_Actl"]
|
||||||
|
self.pts[0].vRel = v_rel
|
||||||
|
self.pts[0].aRel = float('nan')
|
||||||
|
self.pts[0].yvRel = msg["CmbbObjRelLat_V_Actl"]
|
||||||
|
self.pts[0].measured = True
|
||||||
|
|
||||||
def _update_delphi_esr(self):
|
def _update_delphi_esr(self):
|
||||||
for ii in sorted(self.updated_messages):
|
for ii in sorted(self.updated_messages):
|
||||||
cpt = self.rcp.vl[ii]
|
cpt = self.rcp.vl[ii]
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
import random
|
import random
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
from hypothesis import settings, given, strategies as st
|
from hypothesis import settings, given, strategies as st
|
||||||
from parameterized import parameterized
|
from parameterized import parameterized
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from opendbc.car import Bus, gen_empty_fingerprint
|
||||||
|
from opendbc.can import CANPacker
|
||||||
|
from opendbc.car.ford import fordcan
|
||||||
|
from opendbc.car.gps import FORD_MACH_E_GPS_MESSAGES, get_car_gps_config, parse_ford_can_gps
|
||||||
from opendbc.car.structs import CarParams
|
from opendbc.car.structs import CarParams
|
||||||
from opendbc.car.fw_versions import build_fw_dict
|
from opendbc.car.fw_versions import build_fw_dict
|
||||||
from opendbc.car.ford.values import CAR, FW_QUERY_CONFIG, FW_PATTERN, get_platform_codes
|
from opendbc.car.ford.interface import CarInterface
|
||||||
|
from opendbc.car.ford.values import CAR, FW_QUERY_CONFIG, FW_PATTERN, FordSafetyFlags, get_platform_codes, match_vin_to_car
|
||||||
from opendbc.car.ford.fingerprints import FW_VERSIONS
|
from opendbc.car.ford.fingerprints import FW_VERSIONS
|
||||||
|
|
||||||
Ecu = CarParams.Ecu
|
Ecu = CarParams.Ecu
|
||||||
@@ -20,6 +27,7 @@ ECU_ADDRESSES = {
|
|||||||
Ecu.engine: 0x7E0, # Powertrain Control Module (PCM)
|
Ecu.engine: 0x7E0, # Powertrain Control Module (PCM)
|
||||||
Ecu.shiftByWire: 0x732, # Gear Shift Module (GSM)
|
Ecu.shiftByWire: 0x732, # Gear Shift Module (GSM)
|
||||||
Ecu.debug: 0x7D0, # Accessory Protocol Interface Module (APIM)
|
Ecu.debug: 0x7D0, # Accessory Protocol Interface Module (APIM)
|
||||||
|
Ecu.hud: 0x720, # Instrument Cluster Module (ICM)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -41,6 +49,16 @@ ECU_PART_NUMBER = {
|
|||||||
|
|
||||||
|
|
||||||
class TestFordFW:
|
class TestFordFW:
|
||||||
|
def test_vin_fallback(self):
|
||||||
|
def vin(wmi, vds, powertrain, year):
|
||||||
|
return f"{wmi}{vds}{powertrain}0{year}1234567"
|
||||||
|
|
||||||
|
assert match_vin_to_car(vin("2FM", "PK4A", "A", "N")) == {str(CAR.FORD_EDGE_MK2)}
|
||||||
|
assert match_vin_to_car(vin("3FM", "K1RA", "A", "M")) == {str(CAR.FORD_MUSTANG_MACH_E_MK1)}
|
||||||
|
assert match_vin_to_car(vin("1FT", "F1CA", "A", "M")) == {str(CAR.FORD_F_150_MK14)}
|
||||||
|
assert match_vin_to_car(vin("1FT", "F1CA", "L", "N")) == {str(CAR.FORD_F_150_LIGHTNING_MK1)}
|
||||||
|
assert match_vin_to_car("0" * 17) == set()
|
||||||
|
|
||||||
def test_fw_query_config(self):
|
def test_fw_query_config(self):
|
||||||
for (ecu, addr, subaddr) in FW_QUERY_CONFIG.extra_ecus:
|
for (ecu, addr, subaddr) in FW_QUERY_CONFIG.extra_ecus:
|
||||||
assert ecu in ECU_ADDRESSES, "Unknown ECU"
|
assert ecu in ECU_ADDRESSES, "Unknown ECU"
|
||||||
@@ -50,10 +68,13 @@ class TestFordFW:
|
|||||||
@parameterized.expand(FW_VERSIONS.items())
|
@parameterized.expand(FW_VERSIONS.items())
|
||||||
def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[int, int, int | None], Iterable[bytes]]):
|
def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[int, int, int | None], Iterable[bytes]]):
|
||||||
for (ecu, addr, subaddr), fws in fw_versions.items():
|
for (ecu, addr, subaddr), fws in fw_versions.items():
|
||||||
assert ecu in ECU_PART_NUMBER, "Unexpected ECU"
|
assert ecu in ECU_ADDRESSES, "Unknown ECU"
|
||||||
assert addr == ECU_ADDRESSES[ecu], "ECU address mismatch"
|
assert addr == ECU_ADDRESSES[ecu], "ECU address mismatch"
|
||||||
assert subaddr is None, "Unexpected ECU subaddress"
|
assert subaddr is None, "Unexpected ECU subaddress"
|
||||||
|
|
||||||
|
if ecu not in ECU_PART_NUMBER:
|
||||||
|
continue
|
||||||
|
|
||||||
for fw in fws:
|
for fw in fws:
|
||||||
assert len(fw) == 24, "Expected ECU response to be 24 bytes"
|
assert len(fw) == 24, "Expected ECU response to be 24 bytes"
|
||||||
|
|
||||||
@@ -140,3 +161,158 @@ class TestFordFW:
|
|||||||
live_fw[(0x760, None)] = {b"M1MC-2D053-XX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}
|
live_fw[(0x760, None)] = {b"M1MC-2D053-XX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}
|
||||||
candidates = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fw, '', {expected_fingerprint: offline_fw})
|
candidates = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fw, '', {expected_fingerprint: offline_fw})
|
||||||
assert len(candidates) == 0, "Should not match new model year hint"
|
assert len(candidates) == 0, "Should not match new model year hint"
|
||||||
|
|
||||||
|
|
||||||
|
def test_mach_e_longitudinal_toggle_controls_stock_acc_selection():
|
||||||
|
stock = CarInterface.get_params(
|
||||||
|
CAR.FORD_MUSTANG_MACH_E_MK1, gen_empty_fingerprint(), [], False, False, False, None)
|
||||||
|
enhanced = CarInterface.get_params(
|
||||||
|
CAR.FORD_MUSTANG_MACH_E_MK1, gen_empty_fingerprint(), [], True, False, False, None)
|
||||||
|
|
||||||
|
assert stock.alphaLongitudinalAvailable
|
||||||
|
assert not stock.openpilotLongitudinalControl
|
||||||
|
assert stock.pcmCruise
|
||||||
|
assert not (stock.safetyConfigs[-1].safetyParam & FordSafetyFlags.LONG_CONTROL)
|
||||||
|
|
||||||
|
assert enhanced.alphaLongitudinalAvailable
|
||||||
|
assert enhanced.openpilotLongitudinalControl
|
||||||
|
assert enhanced.safetyConfigs[-1].safetyParam & FordSafetyFlags.LONG_CONTROL
|
||||||
|
|
||||||
|
|
||||||
|
def test_mach_e_can_gps_decode():
|
||||||
|
nav1 = {
|
||||||
|
"GpsHsphLattSth_D_Actl": 2,
|
||||||
|
"GpsHsphLongEast_D_Actl": 2,
|
||||||
|
"GPS_Latitude_Degrees": 37,
|
||||||
|
"GPS_Latitude_Minutes": 57,
|
||||||
|
"GPS_Latitude_Min_dec": 0.8864,
|
||||||
|
"GPS_Longitude_Degrees": -121,
|
||||||
|
"GPS_Longitude_Minutes": 44,
|
||||||
|
"GPS_Longitude_Min_dec": 0.22,
|
||||||
|
}
|
||||||
|
nav2 = {
|
||||||
|
"GpsUtcYr_No_Actl": 2026,
|
||||||
|
"GpsUtcMnth_No_Actl": 8,
|
||||||
|
"GpsUtcDay_No_Actl": 26,
|
||||||
|
"GPS_UTC_hours": 0,
|
||||||
|
"GPS_UTC_minutes": 24,
|
||||||
|
"GPS_UTC_seconds": 38,
|
||||||
|
"Gps_B_Falt": 0,
|
||||||
|
}
|
||||||
|
nav3 = {
|
||||||
|
"GPS_dimension": 2,
|
||||||
|
"GPS_Hdop": 0.6,
|
||||||
|
"GPS_Vdop": 0.8,
|
||||||
|
"GPS_Sat_num_in_view": 31,
|
||||||
|
"GPS_MSL_altitude": 90,
|
||||||
|
"GPS_Speed": 10,
|
||||||
|
"GPS_Heading": 180,
|
||||||
|
}
|
||||||
|
|
||||||
|
gps = parse_ford_can_gps(nav1, nav2, nav3)
|
||||||
|
|
||||||
|
assert gps is not None
|
||||||
|
assert gps["latitude"] == 37.96477333333333
|
||||||
|
assert gps["longitude"] == -121.737
|
||||||
|
assert abs(gps["altitude"] - 27.432) < 1e-9
|
||||||
|
assert abs(gps["speed"] - 10 * 0.44704) < 1e-9
|
||||||
|
assert gps["hasFix"]
|
||||||
|
assert gps["satelliteCount"] == 0 # 31 is Ford's invalid sentinel.
|
||||||
|
|
||||||
|
|
||||||
|
def test_mach_e_can_gps_fault_invalidates_fix():
|
||||||
|
nav1 = {
|
||||||
|
"GpsHsphLattSth_D_Actl": 2,
|
||||||
|
"GpsHsphLongEast_D_Actl": 2,
|
||||||
|
"GPS_Latitude_Degrees": 37,
|
||||||
|
"GPS_Latitude_Minutes": 57,
|
||||||
|
"GPS_Latitude_Min_dec": 0.8864,
|
||||||
|
"GPS_Longitude_Degrees": -121,
|
||||||
|
"GPS_Longitude_Minutes": 44,
|
||||||
|
"GPS_Longitude_Min_dec": 0.22,
|
||||||
|
}
|
||||||
|
nav2 = {
|
||||||
|
"GpsUtcYr_No_Actl": 2026,
|
||||||
|
"GpsUtcMnth_No_Actl": 8,
|
||||||
|
"GpsUtcDay_No_Actl": 26,
|
||||||
|
"GPS_UTC_hours": 0,
|
||||||
|
"GPS_UTC_minutes": 24,
|
||||||
|
"GPS_UTC_seconds": 38,
|
||||||
|
"Gps_B_Falt": 1,
|
||||||
|
}
|
||||||
|
nav3 = {
|
||||||
|
"GPS_dimension": 2,
|
||||||
|
"GPS_Hdop": 0.6,
|
||||||
|
"GPS_Vdop": 0.8,
|
||||||
|
"GPS_Sat_num_in_view": 31,
|
||||||
|
"GPS_MSL_altitude": 90,
|
||||||
|
"GPS_Speed": 0,
|
||||||
|
"GPS_Heading": 180,
|
||||||
|
}
|
||||||
|
|
||||||
|
gps = parse_ford_can_gps(nav1, nav2, nav3)
|
||||||
|
|
||||||
|
assert gps is not None
|
||||||
|
assert not gps["hasFix"]
|
||||||
|
assert gps["latitude"] == 37.96477333333333
|
||||||
|
assert gps["altitude"] == 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_mach_e_can_gps_messages_are_optional_main_bus_inputs():
|
||||||
|
cp = CarInterface.get_params(CAR.FORD_MUSTANG_MACH_E_MK1, gen_empty_fingerprint(), [], False, False, False, None)
|
||||||
|
parser = CarInterface.CarState.get_can_parsers(cp)[Bus.pt]
|
||||||
|
gps_config = get_car_gps_config(cp)
|
||||||
|
|
||||||
|
assert gps_config is not None
|
||||||
|
assert gps_config.messages == FORD_MACH_E_GPS_MESSAGES
|
||||||
|
assert gps_config.decoder is parse_ford_can_gps
|
||||||
|
assert set(parser.addresses) >= {0x462, 0x463, 0x464}
|
||||||
|
assert set(FORD_MACH_E_GPS_MESSAGES) == set(gps_config.messages) == {
|
||||||
|
parser.dbc.addr_to_msg[0x462].name,
|
||||||
|
parser.dbc.addr_to_msg[0x463].name,
|
||||||
|
parser.dbc.addr_to_msg[0x464].name,
|
||||||
|
}
|
||||||
|
assert all(parser.message_states[address].ignore_alive for address in (0x462, 0x463, 0x464))
|
||||||
|
|
||||||
|
|
||||||
|
def test_lightning_low_rate_camera_messages_use_declared_frequencies():
|
||||||
|
cp = CarInterface.get_params(CAR.FORD_F_150_LIGHTNING_MK1, gen_empty_fingerprint(), [], True, False, False, None)
|
||||||
|
cp.enableBsm = True
|
||||||
|
parser = CarInterface.CarState.get_can_parsers(cp)[Bus.cam]
|
||||||
|
|
||||||
|
expected_frequencies = {
|
||||||
|
"IPMA_Data": 1,
|
||||||
|
"Traffic_RecognitnData": 1,
|
||||||
|
"Side_Detect_L_Stat": 5,
|
||||||
|
"Side_Detect_R_Stat": 5,
|
||||||
|
}
|
||||||
|
for message, frequency in expected_frequencies.items():
|
||||||
|
state = parser.message_states[parser.dbc.name_to_msg[message].address]
|
||||||
|
assert state.frequency == frequency
|
||||||
|
assert state.timeout_threshold == pytest.approx(10e9 / frequency)
|
||||||
|
|
||||||
|
|
||||||
|
def test_hands_free_cluster_status_is_opt_in():
|
||||||
|
packer = CANPacker("ford_lincoln_base_pt")
|
||||||
|
CAN = SimpleNamespace(main=0)
|
||||||
|
CP = SimpleNamespace(openpilotLongitudinalControl=False)
|
||||||
|
hud = SimpleNamespace(leftLaneDepart=False, rightLaneDepart=False)
|
||||||
|
stock_values = dict.fromkeys([
|
||||||
|
"HaDsply_No_Cs", "HaDsply_No_Cnt", "AccStopStat_D_Dsply", "AccTrgDist2_D_Dsply",
|
||||||
|
"AccStopRes_B_Dsply", "TjaWarn_D_Rq", "TjaMsgTxt_D_Dsply", "IaccLamp_D_Rq",
|
||||||
|
"AccMsgTxt_D2_Rq", "FcwDeny_B_Dsply", "FcwMemStat_B_Actl", "AccTGap_B_Dsply",
|
||||||
|
"CadsAlignIncplt_B_Actl", "AccFllwMde_B_Dsply", "CadsRadrBlck_B_Actl",
|
||||||
|
"CmbbPostEvnt_B_Dsply", "AccStopMde_B_Dsply", "FcwMemSens_D_Actl",
|
||||||
|
"FcwMsgTxt_D_Rq", "AccWarn_D_Dsply", "FcwVisblWarn_B_Rq", "FcwAudioWarn_B_Rq",
|
||||||
|
"AccTGap_D_Dsply", "AccMemEnbl_B_RqDrv", "FdaMem_B_Stat",
|
||||||
|
], 0)
|
||||||
|
|
||||||
|
regular = fordcan.create_acc_ui_msg(
|
||||||
|
packer, CAN, CP, True, True, False, False, False, hud, stock_values)
|
||||||
|
hands_free = fordcan.create_acc_ui_msg(
|
||||||
|
packer, CAN, CP, True, True, False, False, False, hud, stock_values, True)
|
||||||
|
expected_regular = packer.make_can_msg("ACCDATA_3", 0, {"Tja_D_Stat": 2})
|
||||||
|
expected_hands_free = packer.make_can_msg("ACCDATA_3", 0, {"Tja_D_Stat": 7})
|
||||||
|
|
||||||
|
assert regular == expected_regular
|
||||||
|
assert hands_free == expected_hands_free
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from opendbc.car.lateral import AngleSteeringLimits
|
|||||||
from opendbc.car.structs import CarParams
|
from opendbc.car.structs import CarParams
|
||||||
from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
|
from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
|
||||||
from opendbc.car.fw_query_definitions import FwQueryConfig, LiveFwVersions, OfflineFwVersions, Request, StdQueries, p16
|
from opendbc.car.fw_query_definitions import FwQueryConfig, LiveFwVersions, OfflineFwVersions, Request, StdQueries, p16
|
||||||
|
from opendbc.car.vin import Vin, is_valid_vin
|
||||||
|
|
||||||
Ecu = CarParams.Ecu
|
Ecu = CarParams.Ecu
|
||||||
|
|
||||||
@@ -53,11 +54,15 @@ class FordFlags(IntFlag):
|
|||||||
# Static flags
|
# Static flags
|
||||||
CANFD = 1
|
CANFD = 1
|
||||||
LKA_STEERING = 2
|
LKA_STEERING = 2
|
||||||
|
ALT_STEER_ANGLE = 4
|
||||||
|
HEV_CLUSTER_DATA = 8
|
||||||
|
HEV_BATTERY_DATA = 16
|
||||||
|
|
||||||
|
|
||||||
class RADAR:
|
class RADAR:
|
||||||
DELPHI_ESR = 'ford_fusion_2018_adas'
|
DELPHI_ESR = 'ford_fusion_2018_adas'
|
||||||
DELPHI_MRR = 'FORD_CADS'
|
DELPHI_MRR = 'FORD_CADS'
|
||||||
|
STEER_ASSIST_DATA = 'ford_lincoln_base_pt'
|
||||||
|
|
||||||
|
|
||||||
class Footnote(Enum):
|
class Footnote(Enum):
|
||||||
@@ -87,6 +92,10 @@ class FordCarDocs(CarDocs):
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FordPlatformConfig(PlatformConfig):
|
class FordPlatformConfig(PlatformConfig):
|
||||||
|
wmis: set[str] = field(default_factory=set)
|
||||||
|
vds_codes: set[str] = field(default_factory=set)
|
||||||
|
years: set[str] = field(default_factory=set)
|
||||||
|
|
||||||
dbc_dict: DbcDict = field(default_factory=lambda: {
|
dbc_dict: DbcDict = field(default_factory=lambda: {
|
||||||
Bus.pt: 'ford_lincoln_base_pt',
|
Bus.pt: 'ford_lincoln_base_pt',
|
||||||
Bus.radar: RADAR.DELPHI_MRR,
|
Bus.radar: RADAR.DELPHI_MRR,
|
||||||
@@ -106,6 +115,7 @@ class FordPlatformConfig(PlatformConfig):
|
|||||||
class FordCANFDPlatformConfig(FordPlatformConfig):
|
class FordCANFDPlatformConfig(FordPlatformConfig):
|
||||||
dbc_dict: DbcDict = field(default_factory=lambda: {
|
dbc_dict: DbcDict = field(default_factory=lambda: {
|
||||||
Bus.pt: 'ford_lincoln_base_pt',
|
Bus.pt: 'ford_lincoln_base_pt',
|
||||||
|
Bus.radar: RADAR.STEER_ASSIST_DATA,
|
||||||
})
|
})
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
@@ -122,17 +132,26 @@ class FordLKASteeringPlatformConfig(FordPlatformConfig):
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FordF150LightningPlatform(FordCANFDPlatformConfig):
|
class FordF150LightningPlatform(FordCANFDPlatformConfig):
|
||||||
def init(self):
|
pass
|
||||||
super().init()
|
|
||||||
|
|
||||||
# Don't show in docs until this issue is resolved. See https://github.com/commaai/openpilot/issues/30302
|
|
||||||
self.car_docs = []
|
MY_2020, MY_2021, MY_2022, MY_2023, MY_2024, MY_2025 = 'L', 'M', 'N', 'P', 'R', 'S'
|
||||||
|
F150_VDS_CODES = {'F1C', 'F1E', 'W1C', 'W1E', 'X1C', 'X1E', 'W1R', 'W1P', 'W1S', 'W1T'}
|
||||||
|
F150_ELECTRIC_CODES = {'L', 'V'}
|
||||||
|
MACH_E_VDS_CODES = {'K1R', 'K1S', 'K2S', 'K3R', 'K3S', 'K4S'}
|
||||||
|
|
||||||
|
|
||||||
class CAR(Platforms):
|
class CAR(Platforms):
|
||||||
FORD_BRONCO_SPORT_MK1 = FordPlatformConfig(
|
FORD_BRONCO_SPORT_MK1 = FordPlatformConfig(
|
||||||
[FordCarDocs("Ford Bronco Sport 2021-24")],
|
[FordCarDocs("Ford Bronco Sport 2021-24")],
|
||||||
CarSpecs(mass=1625, wheelbase=2.67, steerRatio=17.7),
|
CarSpecs(mass=1625, wheelbase=2.67, steerRatio=17.7),
|
||||||
|
wmis={'3FM'}, vds_codes={'CR9'}, years={MY_2021, MY_2022, MY_2023, MY_2024},
|
||||||
|
)
|
||||||
|
FORD_EDGE_MK2 = FordPlatformConfig(
|
||||||
|
[FordCarDocs("Ford Edge 2022")],
|
||||||
|
CarSpecs(mass=1933, wheelbase=2.824, steerRatio=15.3),
|
||||||
|
flags=FordFlags.ALT_STEER_ANGLE,
|
||||||
|
wmis={'2FM'}, vds_codes={'PK4'}, years={MY_2022},
|
||||||
)
|
)
|
||||||
FORD_ESCAPE_MK4 = FordPlatformConfig(
|
FORD_ESCAPE_MK4 = FordPlatformConfig(
|
||||||
[
|
[
|
||||||
@@ -140,6 +159,7 @@ class CAR(Platforms):
|
|||||||
FordCarDocs("Ford Kuga 2020-23", "Adaptive Cruise Control with Lane Centering", hybrid=True, plug_in_hybrid=True),
|
FordCarDocs("Ford Kuga 2020-23", "Adaptive Cruise Control with Lane Centering", hybrid=True, plug_in_hybrid=True),
|
||||||
],
|
],
|
||||||
CarSpecs(mass=1750, wheelbase=2.71, steerRatio=16.7),
|
CarSpecs(mass=1750, wheelbase=2.71, steerRatio=16.7),
|
||||||
|
wmis={'1FM'}, vds_codes={'CU0', 'CU9'}, years={MY_2020, MY_2021, MY_2022},
|
||||||
)
|
)
|
||||||
FORD_ESCAPE_MK4_5 = FordCANFDPlatformConfig(
|
FORD_ESCAPE_MK4_5 = FordCANFDPlatformConfig(
|
||||||
[
|
[
|
||||||
@@ -148,6 +168,7 @@ class CAR(Platforms):
|
|||||||
FordCarDocs("Ford Kuga Plug-in Hybrid 2024", "All"),
|
FordCarDocs("Ford Kuga Plug-in Hybrid 2024", "All"),
|
||||||
],
|
],
|
||||||
CarSpecs(mass=1750, wheelbase=2.71, steerRatio=16.7),
|
CarSpecs(mass=1750, wheelbase=2.71, steerRatio=16.7),
|
||||||
|
wmis={'1FM'}, vds_codes={'CU0', 'CU9'}, years={MY_2023, MY_2024},
|
||||||
)
|
)
|
||||||
FORD_EXPLORER_MK6 = FordPlatformConfig(
|
FORD_EXPLORER_MK6 = FordPlatformConfig(
|
||||||
[
|
[
|
||||||
@@ -155,37 +176,49 @@ class CAR(Platforms):
|
|||||||
FordCarDocs("Lincoln Aviator 2020-24", "Co-Pilot360 Plus", plug_in_hybrid=True), # Hybrid: Grand Touring only
|
FordCarDocs("Lincoln Aviator 2020-24", "Co-Pilot360 Plus", plug_in_hybrid=True), # Hybrid: Grand Touring only
|
||||||
],
|
],
|
||||||
CarSpecs(mass=2050, wheelbase=3.025, steerRatio=16.8),
|
CarSpecs(mass=2050, wheelbase=3.025, steerRatio=16.8),
|
||||||
|
wmis={'1FM', '5LM'}, vds_codes={'5K7', '5K8', '5J7'},
|
||||||
|
years={MY_2020, MY_2021, MY_2022, MY_2023, MY_2024},
|
||||||
)
|
)
|
||||||
FORD_EXPEDITION_MK4 = FordCANFDPlatformConfig(
|
FORD_EXPEDITION_MK4 = FordCANFDPlatformConfig(
|
||||||
[FordCarDocs("Ford Expedition 2022-24", "Co-Pilot360 Assist 2.0", hybrid=False)],
|
[FordCarDocs("Ford Expedition 2022-24", "Co-Pilot360 Assist 2.0", hybrid=False)],
|
||||||
CarSpecs(mass=2000, wheelbase=3.69, steerRatio=17.0),
|
CarSpecs(mass=2000, wheelbase=3.69, steerRatio=17.0),
|
||||||
|
wmis={'1FM'}, vds_codes={'JU1', 'JU2', 'JK1'}, years={MY_2022, MY_2023, MY_2024},
|
||||||
)
|
)
|
||||||
FORD_F_150_MK14 = FordCANFDPlatformConfig(
|
FORD_F_150_MK14 = FordCANFDPlatformConfig(
|
||||||
[FordCarDocs("Ford F-150 2021-23", "Co-Pilot360 Assist 2.0", hybrid=True)],
|
[FordCarDocs("Ford F-150 2021-23", "Co-Pilot360 Assist 2.0", hybrid=True)],
|
||||||
CarSpecs(mass=2000, wheelbase=3.69, steerRatio=17.0),
|
CarSpecs(mass=3334, wheelbase=3.99, steerRatio=17.0),
|
||||||
|
wmis={'1FT'}, vds_codes=F150_VDS_CODES, years={MY_2021, MY_2022, MY_2023},
|
||||||
)
|
)
|
||||||
FORD_F_150_LIGHTNING_MK1 = FordF150LightningPlatform(
|
FORD_F_150_LIGHTNING_MK1 = FordF150LightningPlatform(
|
||||||
[FordCarDocs("Ford F-150 Lightning 2022-23", "Co-Pilot360 Assist 2.0")],
|
[FordCarDocs("Ford F-150 Lightning 2022-25", "Co-Pilot360 Assist 2.0")],
|
||||||
CarSpecs(mass=2948, wheelbase=3.70, steerRatio=16.9),
|
CarSpecs(mass=2948, wheelbase=3.70, steerRatio=16.9),
|
||||||
|
wmis={'1FT'}, vds_codes=F150_VDS_CODES, years={MY_2022, MY_2023, MY_2024, MY_2025},
|
||||||
)
|
)
|
||||||
FORD_FOCUS_MK4 = FordPlatformConfig(
|
FORD_FOCUS_MK4 = FordPlatformConfig(
|
||||||
[FordCarDocs("Ford Focus 2018", "Adaptive Cruise Control with Lane Centering", footnotes=[Footnote.FOCUS], hybrid=True)], # mHEV only
|
[FordCarDocs("Ford Focus 2018-22", "Adaptive Cruise Control with Lane Centering", footnotes=[Footnote.FOCUS], hybrid=True)], # mHEV only
|
||||||
CarSpecs(mass=1350, wheelbase=2.7, steerRatio=15.0),
|
CarSpecs(mass=1350, wheelbase=2.7, steerRatio=15.0),
|
||||||
)
|
)
|
||||||
|
FORD_MONDEO_MK5 = FordCANFDPlatformConfig(
|
||||||
|
[FordCarDocs("Ford Mondeo 2014-22", "Adaptive Cruise Control with Lane Centering")],
|
||||||
|
CarSpecs(mass=1550, wheelbase=2.85, steerRatio=14.8),
|
||||||
|
)
|
||||||
FORD_MAVERICK_MK1 = FordPlatformConfig(
|
FORD_MAVERICK_MK1 = FordPlatformConfig(
|
||||||
[
|
[
|
||||||
FordCarDocs("Ford Maverick 2022", "LARIAT Luxury", hybrid=True),
|
FordCarDocs("Ford Maverick 2022", "LARIAT Luxury", hybrid=True),
|
||||||
FordCarDocs("Ford Maverick 2023-24", "Co-Pilot360 Assist", hybrid=True),
|
FordCarDocs("Ford Maverick 2023-24", "Co-Pilot360 Assist", hybrid=True),
|
||||||
],
|
],
|
||||||
CarSpecs(mass=1650, wheelbase=3.076, steerRatio=17.0),
|
CarSpecs(mass=1650, wheelbase=3.076, steerRatio=17.0),
|
||||||
|
wmis={'3FT'}, vds_codes={'TW8'}, years={MY_2022, MY_2023, MY_2024},
|
||||||
)
|
)
|
||||||
FORD_MUSTANG_MACH_E_MK1 = FordCANFDPlatformConfig(
|
FORD_MUSTANG_MACH_E_MK1 = FordCANFDPlatformConfig(
|
||||||
[FordCarDocs("Ford Mustang Mach-E 2021-24", "All", setup_video="https://www.youtube.com/watch?v=AR4_eTF3b_A")],
|
[FordCarDocs("Ford Mustang Mach-E 2021-24", "All", setup_video="https://www.youtube.com/watch?v=AR4_eTF3b_A")],
|
||||||
CarSpecs(mass=2200, wheelbase=2.984, steerRatio=17.0), # TODO: check steer ratio
|
CarSpecs(mass=2200, wheelbase=2.984, steerRatio=17.0), # TODO: check steer ratio
|
||||||
|
wmis={'3FM'}, vds_codes=MACH_E_VDS_CODES, years={MY_2021, MY_2022, MY_2023, MY_2024},
|
||||||
)
|
)
|
||||||
FORD_RANGER_MK2 = FordCANFDPlatformConfig(
|
FORD_RANGER_MK2 = FordCANFDPlatformConfig(
|
||||||
[FordCarDocs("Ford Ranger 2024", "Adaptive Cruise Control with Lane Centering", setup_video="https://www.youtube.com/watch?v=2oJlXCKYOy0")],
|
[FordCarDocs("Ford Ranger 2024", "Adaptive Cruise Control with Lane Centering", setup_video="https://www.youtube.com/watch?v=2oJlXCKYOy0")],
|
||||||
CarSpecs(mass=2000, wheelbase=3.27, steerRatio=17.0),
|
CarSpecs(mass=2000, wheelbase=3.27, steerRatio=17.0),
|
||||||
|
wmis={'1FT'}, vds_codes={'ER4'}, years={MY_2024},
|
||||||
)
|
)
|
||||||
FORD_TRANSIT_MK5 = FordLKASteeringPlatformConfig(
|
FORD_TRANSIT_MK5 = FordLKASteeringPlatformConfig(
|
||||||
[FordCarDocs("Ford Transit 2025", "Co-Pilot360 Assist+")],
|
[FordCarDocs("Ford Transit 2025", "Co-Pilot360 Assist+")],
|
||||||
@@ -257,7 +290,25 @@ def match_fw_to_car_fuzzy(live_fw_versions: LiveFwVersions, vin: str, offline_fw
|
|||||||
if valid_expected_ecus.issubset(valid_found_ecus):
|
if valid_expected_ecus.issubset(valid_found_ecus):
|
||||||
candidates.add(candidate)
|
candidates.add(candidate)
|
||||||
|
|
||||||
return candidates
|
return candidates or match_vin_to_car(vin)
|
||||||
|
|
||||||
|
|
||||||
|
def match_vin_to_car(vin: str) -> set[str]:
|
||||||
|
if not is_valid_vin(vin):
|
||||||
|
return set()
|
||||||
|
|
||||||
|
vin_obj = Vin(vin)
|
||||||
|
vds = vin[3:7]
|
||||||
|
model_year = vin[9]
|
||||||
|
candidates = {platform for platform in CAR if vin_obj.wmi in platform.config.wmis and
|
||||||
|
model_year in platform.config.years and
|
||||||
|
any(code in vds for code in platform.config.vds_codes)}
|
||||||
|
|
||||||
|
if {CAR.FORD_F_150_MK14, CAR.FORD_F_150_LIGHTNING_MK1} & candidates:
|
||||||
|
electric = vin[7] in F150_ELECTRIC_CODES
|
||||||
|
candidates.discard(CAR.FORD_F_150_MK14 if electric else CAR.FORD_F_150_LIGHTNING_MK1)
|
||||||
|
|
||||||
|
return {str(candidate) for candidate in candidates}
|
||||||
|
|
||||||
|
|
||||||
# All of these ECUs must be present and are expected to have platform codes we can match
|
# All of these ECUs must be present and are expected to have platform codes we can match
|
||||||
@@ -266,10 +317,10 @@ PLATFORM_CODE_ECUS = (Ecu.abs, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.eps)
|
|||||||
DATA_IDENTIFIER_FORD_ASBUILT = 0xDE00
|
DATA_IDENTIFIER_FORD_ASBUILT = 0xDE00
|
||||||
|
|
||||||
ASBUILT_BLOCKS: list[tuple[int, list]] = [
|
ASBUILT_BLOCKS: list[tuple[int, list]] = [
|
||||||
(1, [Ecu.debug, Ecu.fwdCamera, Ecu.eps]),
|
(1, [Ecu.debug, Ecu.fwdCamera, Ecu.eps, Ecu.hud]),
|
||||||
(2, [Ecu.abs, Ecu.debug, Ecu.eps]),
|
(2, [Ecu.abs, Ecu.debug, Ecu.eps, Ecu.hud]),
|
||||||
(3, [Ecu.abs, Ecu.debug, Ecu.eps]),
|
(3, [Ecu.abs, Ecu.debug, Ecu.eps, Ecu.hud]),
|
||||||
(4, [Ecu.debug, Ecu.fwdCamera]),
|
(4, [Ecu.debug, Ecu.fwdCamera, Ecu.hud]),
|
||||||
(5, [Ecu.debug]),
|
(5, [Ecu.debug]),
|
||||||
(6, [Ecu.debug]),
|
(6, [Ecu.debug]),
|
||||||
(7, [Ecu.debug]),
|
(7, [Ecu.debug]),
|
||||||
@@ -297,13 +348,13 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
|||||||
Request(
|
Request(
|
||||||
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST],
|
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST],
|
||||||
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE],
|
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE],
|
||||||
whitelist_ecus=[Ecu.abs, Ecu.debug, Ecu.engine, Ecu.eps, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.shiftByWire],
|
whitelist_ecus=[Ecu.abs, Ecu.debug, Ecu.engine, Ecu.eps, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.shiftByWire, Ecu.hud],
|
||||||
logging=True,
|
logging=True,
|
||||||
),
|
),
|
||||||
Request(
|
Request(
|
||||||
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST],
|
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST],
|
||||||
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE],
|
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE],
|
||||||
whitelist_ecus=[Ecu.abs, Ecu.debug, Ecu.engine, Ecu.eps, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.shiftByWire],
|
whitelist_ecus=[Ecu.abs, Ecu.debug, Ecu.engine, Ecu.eps, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.shiftByWire, Ecu.hud],
|
||||||
bus=0,
|
bus=0,
|
||||||
auxiliary=True,
|
auxiliary=True,
|
||||||
),
|
),
|
||||||
@@ -320,7 +371,9 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
|||||||
# Note: We are unlikely to get a response from behind the gateway
|
# Note: We are unlikely to get a response from behind the gateway
|
||||||
(Ecu.shiftByWire, 0x732, None), # Gear Shift Module
|
(Ecu.shiftByWire, 0x732, None), # Gear Shift Module
|
||||||
(Ecu.debug, 0x7d0, None), # Accessory Protocol Interface Module
|
(Ecu.debug, 0x7d0, None), # Accessory Protocol Interface Module
|
||||||
|
(Ecu.hud, 0x720, None), # Instrument Cluster Module
|
||||||
],
|
],
|
||||||
|
non_essential_ecus={Ecu.eps: [CAR.FORD_F_150_LIGHTNING_MK1, CAR.FORD_EXPEDITION_MK4]},
|
||||||
# Custom fuzzy fingerprinting function using platform and model year hints
|
# Custom fuzzy fingerprinting function using platform and model year hints
|
||||||
match_fw_to_car_fuzzy=match_fw_to_car_fuzzy,
|
match_fw_to_car_fuzzy=match_fw_to_car_fuzzy,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ class Request:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class FwQueryConfig:
|
class FwQueryConfig:
|
||||||
requests: list[Request]
|
requests: list[Request]
|
||||||
|
non_tester_present_ecus: list[Ecu] = field(default_factory=list)
|
||||||
# TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus
|
# TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus
|
||||||
# Overrides and removes from essential ecus for specific models and ecus (exact matching)
|
# Overrides and removes from essential ecus for specific models and ecus (exact matching)
|
||||||
non_essential_ecus: dict[Ecu, list[str]] = field(default_factory=dict)
|
non_essential_ecus: dict[Ecu, list[str]] = field(default_factory=dict)
|
||||||
@@ -109,8 +110,13 @@ class FwQueryConfig:
|
|||||||
# Function a brand can implement to provide better fuzzy matching. Takes in FW versions and VIN,
|
# Function a brand can implement to provide better fuzzy matching. Takes in FW versions and VIN,
|
||||||
# returns set of candidates. Only will match if one candidate is returned
|
# returns set of candidates. Only will match if one candidate is returned
|
||||||
match_fw_to_car_fuzzy: Callable[[LiveFwVersions, str, OfflineFwVersions], set[str]] | None = None
|
match_fw_to_car_fuzzy: Callable[[LiveFwVersions, str, OfflineFwVersions], set[str]] | None = None
|
||||||
|
# Platforms whose shared firmware must be disambiguated by the brand fuzzy matcher.
|
||||||
|
fuzzy_only_platforms: set[str] = field(default_factory=set)
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
|
assert not self.fuzzy_only_platforms or self.match_fw_to_car_fuzzy is not None, \
|
||||||
|
"Fuzzy-only platforms require a brand fuzzy matcher"
|
||||||
|
|
||||||
# Asserts that a request exists if extra ecus are used
|
# Asserts that a request exists if extra ecus are used
|
||||||
if len(self.extra_ecus):
|
if len(self.extra_ecus):
|
||||||
assert len(self.requests), "Must define a request with extra ecus"
|
assert len(self.requests), "Must define a request with extra ecus"
|
||||||
|
|||||||
@@ -111,7 +111,8 @@ def match_fw_to_car_exact(live_fw_versions: LiveFwVersions, match_brand: str = N
|
|||||||
|
|
||||||
invalid = set()
|
invalid = set()
|
||||||
candidates = {c: f for c, f in FW_VERSIONS.items() if
|
candidates = {c: f for c, f in FW_VERSIONS.items() if
|
||||||
is_brand(MODEL_TO_BRAND[c], match_brand)}
|
is_brand(MODEL_TO_BRAND[c], match_brand) and
|
||||||
|
c not in FW_QUERY_CONFIGS[MODEL_TO_BRAND[c]].fuzzy_only_platforms}
|
||||||
|
|
||||||
for candidate, fws in candidates.items():
|
for candidate, fws in candidates.items():
|
||||||
config = FW_QUERY_CONFIGS[MODEL_TO_BRAND[candidate]]
|
config = FW_QUERY_CONFIGS[MODEL_TO_BRAND[candidate]]
|
||||||
@@ -181,6 +182,9 @@ def get_present_ecus(can_recv: CanRecvCallable, can_send: CanSendCallable, set_o
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for ecu_type, addr, sub_addr in config.get_all_ecus(VERSIONS[brand]):
|
for ecu_type, addr, sub_addr in config.get_all_ecus(VERSIONS[brand]):
|
||||||
|
if ecu_type in config.non_tester_present_ecus:
|
||||||
|
continue
|
||||||
|
|
||||||
# Only query ecus in whitelist if whitelist is not empty
|
# Only query ecus in whitelist if whitelist is not empty
|
||||||
if len(r.whitelist_ecus) == 0 or ecu_type in r.whitelist_ecus:
|
if len(r.whitelist_ecus) == 0 or ecu_type in r.whitelist_ecus:
|
||||||
a = (addr, sub_addr, r.bus)
|
a = (addr, sub_addr, r.bus)
|
||||||
@@ -216,6 +220,9 @@ def get_brand_ecu_matches(ecu_rx_addrs: set[EcuAddrBusType]) -> dict[str, list[b
|
|||||||
# Since we can't know what request an ecu responded to, add matches for all possible rx offsets
|
# Since we can't know what request an ecu responded to, add matches for all possible rx offsets
|
||||||
for brand, config, r in REQUESTS:
|
for brand, config, r in REQUESTS:
|
||||||
for ecu in config.get_all_ecus(VERSIONS[brand]):
|
for ecu in config.get_all_ecus(VERSIONS[brand]):
|
||||||
|
if ecu[0] in config.non_tester_present_ecus:
|
||||||
|
continue
|
||||||
|
|
||||||
if len(r.whitelist_ecus) == 0 or ecu[0] in r.whitelist_ecus:
|
if len(r.whitelist_ecus) == 0 or ecu[0] in r.whitelist_ecus:
|
||||||
brand_rx_addrs[brand].add((uds.get_rx_addr_for_tx_addr(ecu[1], r.rx_offset), ecu[2]))
|
brand_rx_addrs[brand].add((uds.get_rx_addr_for_tx_addr(ecu[1], r.rx_offset), ecu[2]))
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ TRUCK_LONG_SMOOTH_CARS = {
|
|||||||
TRUCK_FRICTION_BRAKE_ENGAGE = 40
|
TRUCK_FRICTION_BRAKE_ENGAGE = 40
|
||||||
TRUCK_FRICTION_BRAKE_RELEASE = 8
|
TRUCK_FRICTION_BRAKE_RELEASE = 8
|
||||||
TRUCK_FRICTION_BRAKE_IMMEDIATE_ACCEL = -0.85
|
TRUCK_FRICTION_BRAKE_IMMEDIATE_ACCEL = -0.85
|
||||||
|
TRUCK_FOLLOW_MICRO_ACCEL_MAX = 0.55
|
||||||
|
TRUCK_FOLLOW_MICRO_ACCEL_MIN = -0.10
|
||||||
|
TRUCK_FOLLOW_MICRO_ACCEL_SLEW = 1.5
|
||||||
ACC_DASHBOARD_ZERO_RESERVED_CARS = {
|
ACC_DASHBOARD_ZERO_RESERVED_CARS = {
|
||||||
CAR.CHEVROLET_BLAZER,
|
CAR.CHEVROLET_BLAZER,
|
||||||
CAR.CHEVROLET_EQUINOX,
|
CAR.CHEVROLET_EQUINOX,
|
||||||
@@ -215,11 +218,11 @@ def shape_truck_positive_accel(accel: float, v_ego: float, enabled: bool,
|
|||||||
if not enabled or accel <= 0.0 or v_ego < 12.0:
|
if not enabled or accel <= 0.0 or v_ego < 12.0:
|
||||||
return accel
|
return accel
|
||||||
|
|
||||||
low_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.93, 0.84, 0.76, 0.70]))
|
low_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.93, 0.84, 0.76, 0.76]))
|
||||||
mid_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.97, 0.91, 0.85, 0.79]))
|
mid_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.97, 0.91, 0.85, 0.85]))
|
||||||
|
|
||||||
if lead_visible and set_speed_error > 0.0:
|
if lead_visible and set_speed_error > 0.0:
|
||||||
follow_relief = float(np.interp(set_speed_error, [0.0, 1.0, 2.5, 4.0, 6.0], [0.0, 0.04, 0.10, 0.18, 0.30]))
|
follow_relief = float(np.interp(set_speed_error, [0.0, 1.0, 2.5, 4.0, 6.0], [0.0, 0.04, 0.10, 0.24, 0.42]))
|
||||||
low_scale += (1.0 - low_scale) * follow_relief
|
low_scale += (1.0 - low_scale) * follow_relief
|
||||||
mid_scale += (1.0 - mid_scale) * follow_relief
|
mid_scale += (1.0 - mid_scale) * follow_relief
|
||||||
|
|
||||||
@@ -232,6 +235,27 @@ def shape_truck_positive_accel(accel: float, v_ego: float, enabled: bool,
|
|||||||
return accel
|
return accel
|
||||||
|
|
||||||
|
|
||||||
|
def smooth_truck_follow_accel(accel: float, previous_accel: float, v_ego: float,
|
||||||
|
enabled: bool, lead_visible: bool, stopping: bool) -> float:
|
||||||
|
if (
|
||||||
|
not enabled or not lead_visible or stopping or v_ego < 25.0 or
|
||||||
|
accel > TRUCK_FOLLOW_MICRO_ACCEL_MAX or accel < TRUCK_FOLLOW_MICRO_ACCEL_MIN or
|
||||||
|
previous_accel > TRUCK_FOLLOW_MICRO_ACCEL_MAX or previous_accel < TRUCK_FOLLOW_MICRO_ACCEL_MIN
|
||||||
|
):
|
||||||
|
return accel
|
||||||
|
|
||||||
|
max_delta = TRUCK_FOLLOW_MICRO_ACCEL_SLEW * DT_CTRL * 4
|
||||||
|
return previous_accel + float(np.clip(accel - previous_accel, -max_delta, max_delta))
|
||||||
|
|
||||||
|
|
||||||
|
def shape_truck_pitch_accel(pitch_accel: float, v_ego: float, enabled: bool) -> float:
|
||||||
|
if not enabled:
|
||||||
|
return pitch_accel
|
||||||
|
|
||||||
|
scale = float(np.interp(v_ego, [8.0, 15.0, 25.0, 35.0], [0.60, 0.45, 0.30, 0.25]))
|
||||||
|
return pitch_accel * scale
|
||||||
|
|
||||||
|
|
||||||
def shape_truck_friction_brake(apply_brake: int, accel_cmd: float, stopping: bool, active: bool) -> tuple[int, bool]:
|
def shape_truck_friction_brake(apply_brake: int, accel_cmd: float, stopping: bool, active: bool) -> tuple[int, bool]:
|
||||||
if apply_brake <= 0:
|
if apply_brake <= 0:
|
||||||
return 0, False
|
return 0, False
|
||||||
@@ -484,6 +508,10 @@ class CarController(CarControllerBase):
|
|||||||
self.xt4_cc_button_burst_last_counter = -1
|
self.xt4_cc_button_burst_last_counter = -1
|
||||||
self.xt4_cc_button_observed_counter = -1
|
self.xt4_cc_button_observed_counter = -1
|
||||||
self.xt4_cc_button_counter_frame = 0
|
self.xt4_cc_button_counter_frame = 0
|
||||||
|
self.gm_cc_last_direction_button = CruiseButtons.INIT
|
||||||
|
self.gm_cc_last_direction_frame = 0
|
||||||
|
self.gm_cc_pending_reverse_button = CruiseButtons.INIT
|
||||||
|
self.gm_cc_pending_reverse_frame = 0
|
||||||
|
|
||||||
self.lka_steering_cmd_counter = 0
|
self.lka_steering_cmd_counter = 0
|
||||||
self.lka_icon_status_last = (False, False)
|
self.lka_icon_status_last = (False, False)
|
||||||
@@ -545,6 +573,7 @@ class CarController(CarControllerBase):
|
|||||||
self.bolt_acc_pedal_friction_release_frames = 0
|
self.bolt_acc_pedal_friction_release_frames = 0
|
||||||
self.bolt_acc_pedal_friction_low_speed_active = False
|
self.bolt_acc_pedal_friction_low_speed_active = False
|
||||||
self.truck_friction_brake_active = False
|
self.truck_friction_brake_active = False
|
||||||
|
self.truck_follow_accel = 0.0
|
||||||
|
|
||||||
def _reset_volt_one_pedal(self):
|
def _reset_volt_one_pedal(self):
|
||||||
self.volt_one_pedal_pid.reset()
|
self.volt_one_pedal_pid.reset()
|
||||||
@@ -966,10 +995,12 @@ class CarController(CarControllerBase):
|
|||||||
self.regen_release_counter = 0
|
self.regen_release_counter = 0
|
||||||
self.regen_min_on_frames = 0
|
self.regen_min_on_frames = 0
|
||||||
self.regen_min_off_frames = 0
|
self.regen_min_off_frames = 0
|
||||||
|
self.truck_follow_accel = 0.0
|
||||||
elif should_use_fixed_stopping_brake(self.CP, near_stop, stopping, CC.cruiseControl.resume):
|
elif should_use_fixed_stopping_brake(self.CP, near_stop, stopping, CC.cruiseControl.resume):
|
||||||
stop_accel = getattr(starpilot_toggles, "stopAccel", self.CP.stopAccel)
|
stop_accel = getattr(starpilot_toggles, "stopAccel", self.CP.stopAccel)
|
||||||
self.apply_gas = self.params.INACTIVE_REGEN
|
self.apply_gas = self.params.INACTIVE_REGEN
|
||||||
self.apply_brake = int(min(-100 * stop_accel, self.params.MAX_BRAKE))
|
self.apply_brake = int(min(-100 * stop_accel, self.params.MAX_BRAKE))
|
||||||
|
self.truck_follow_accel = 0.0
|
||||||
else:
|
else:
|
||||||
long_pitch_enabled = bool(getattr(starpilot_toggles, "long_pitch", True))
|
long_pitch_enabled = bool(getattr(starpilot_toggles, "long_pitch", True))
|
||||||
pedal_long_path = bool(self.CP.enableGasInterceptorDEPRECATED and (self.CP.flags & GMFlags.PEDAL_LONG.value))
|
pedal_long_path = bool(self.CP.enableGasInterceptorDEPRECATED and (self.CP.flags & GMFlags.PEDAL_LONG.value))
|
||||||
@@ -1016,6 +1047,7 @@ class CarController(CarControllerBase):
|
|||||||
getattr(self.CP, "transmissionType", None) == TransmissionType.automatic and
|
getattr(self.CP, "transmissionType", None) == TransmissionType.automatic and
|
||||||
not self.CP.enableGasInterceptorDEPRECATED
|
not self.CP.enableGasInterceptorDEPRECATED
|
||||||
)
|
)
|
||||||
|
accel_due_to_pitch = shape_truck_pitch_accel(accel_due_to_pitch, CS.out.vEgo, truck_long_smoothing)
|
||||||
accel_input = actuators.accel + accel_due_to_pitch
|
accel_input = actuators.accel + accel_due_to_pitch
|
||||||
if truck_long_smoothing:
|
if truck_long_smoothing:
|
||||||
accel_input = shape_truck_positive_accel(
|
accel_input = shape_truck_positive_accel(
|
||||||
@@ -1027,6 +1059,16 @@ class CarController(CarControllerBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
accel_cmd = float(np.clip(accel_input, self.params.ACCEL_MIN, accel_max))
|
accel_cmd = float(np.clip(accel_input, self.params.ACCEL_MIN, accel_max))
|
||||||
|
if truck_long_smoothing:
|
||||||
|
accel_cmd = smooth_truck_follow_accel(
|
||||||
|
accel_cmd,
|
||||||
|
self.truck_follow_accel,
|
||||||
|
CS.out.vEgo,
|
||||||
|
True,
|
||||||
|
CC.hudControl.leadVisible,
|
||||||
|
stopping,
|
||||||
|
)
|
||||||
|
self.truck_follow_accel = accel_cmd
|
||||||
torque = self.tireRadius * ((self.mass * accel_cmd) + (0.5 * self.coeffDrag * self.frontalArea * self.airDensity * CS.out.vEgo ** 2))
|
torque = self.tireRadius * ((self.mass * accel_cmd) + (0.5 * self.coeffDrag * self.frontalArea * self.airDensity * CS.out.vEgo ** 2))
|
||||||
scaled_torque = torque + self.params.ZERO_GAS
|
scaled_torque = torque + self.params.ZERO_GAS
|
||||||
apply_gas_torque = np.clip(scaled_torque, self.params.MAX_ACC_REGEN, gas_max)
|
apply_gas_torque = np.clip(scaled_torque, self.params.MAX_ACC_REGEN, gas_max)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from opendbc.can import CANDefine, CANParser
|
|||||||
from opendbc.car import Bus, create_button_events, structs
|
from opendbc.car import Bus, create_button_events, structs
|
||||||
from opendbc.car import DT_CTRL
|
from opendbc.car import DT_CTRL
|
||||||
from opendbc.car.common.conversions import Conversions as CV
|
from opendbc.car.common.conversions import Conversions as CV
|
||||||
|
from opendbc.car.gps import get_car_gps_config
|
||||||
from opendbc.car.interfaces import CarStateBase
|
from opendbc.car.interfaces import CarStateBase
|
||||||
from opendbc.car.gm.values import (
|
from opendbc.car.gm.values import (
|
||||||
ALT_ACCS,
|
ALT_ACCS,
|
||||||
@@ -104,6 +105,31 @@ class CarState(CarStateBase):
|
|||||||
self.lkas_enabled = 0
|
self.lkas_enabled = 0
|
||||||
self.pcm_acc_status = AccState.OFF
|
self.pcm_acc_status = AccState.OFF
|
||||||
self.stock_fcw_alert = 0
|
self.stock_fcw_alert = 0
|
||||||
|
self.car_gps_config = get_car_gps_config(CP)
|
||||||
|
self.car_gps_supported = self.car_gps_config is not None
|
||||||
|
self.car_gps = None
|
||||||
|
self._car_gps_timestamp_nanos = 0
|
||||||
|
|
||||||
|
def _update_car_gps(self, cp) -> None:
|
||||||
|
if self.car_gps_config is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
timestamps = [max(cp.ts_nanos[name].values(), default=0) for name in self.car_gps_config.messages]
|
||||||
|
if not all(timestamps) or max(timestamps) - min(timestamps) > 2_000_000_000:
|
||||||
|
return
|
||||||
|
|
||||||
|
timestamp_nanos = max(timestamps)
|
||||||
|
if timestamp_nanos <= self._car_gps_timestamp_nanos:
|
||||||
|
return
|
||||||
|
|
||||||
|
gps = self.car_gps_config.decoder(*(cp.vl[name] for name in self.car_gps_config.messages))
|
||||||
|
if gps is not None:
|
||||||
|
gps["timestamp_nanos"] = timestamp_nanos
|
||||||
|
self.car_gps = gps
|
||||||
|
self._car_gps_timestamp_nanos = timestamp_nanos
|
||||||
|
|
||||||
|
def get_car_gps(self):
|
||||||
|
return self.car_gps
|
||||||
|
|
||||||
def update_button_enable(self, buttonEvents: list[structs.CarState.ButtonEvent]):
|
def update_button_enable(self, buttonEvents: list[structs.CarState.ButtonEvent]):
|
||||||
if not self.CP.pcmCruise:
|
if not self.CP.pcmCruise:
|
||||||
@@ -119,6 +145,8 @@ class CarState(CarStateBase):
|
|||||||
cam_cp = can_parsers[Bus.cam]
|
cam_cp = can_parsers[Bus.cam]
|
||||||
loopback_cp = can_parsers[Bus.loopback]
|
loopback_cp = can_parsers[Bus.loopback]
|
||||||
|
|
||||||
|
self._update_car_gps(pt_cp)
|
||||||
|
|
||||||
ret = structs.CarState()
|
ret = structs.CarState()
|
||||||
|
|
||||||
volt_like = {
|
volt_like = {
|
||||||
@@ -428,6 +456,9 @@ class CarState(CarStateBase):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_can_parsers(CP):
|
def get_can_parsers(CP):
|
||||||
|
gps_config = get_car_gps_config(CP)
|
||||||
|
gps_messages = [(name, 0) for name in gps_config.messages] if gps_config is not None else []
|
||||||
|
|
||||||
volt_like = {
|
volt_like = {
|
||||||
CAR.CHEVROLET_VOLT,
|
CAR.CHEVROLET_VOLT,
|
||||||
CAR.CHEVROLET_VOLT_2019,
|
CAR.CHEVROLET_VOLT_2019,
|
||||||
@@ -451,6 +482,7 @@ class CarState(CarStateBase):
|
|||||||
("PSCMSteeringAngle", 100),
|
("PSCMSteeringAngle", 100),
|
||||||
("ECMAcceleratorPos", 80),
|
("ECMAcceleratorPos", 80),
|
||||||
("SportMode", 0),
|
("SportMode", 0),
|
||||||
|
*gps_messages,
|
||||||
]
|
]
|
||||||
|
|
||||||
prndl2_rate = 10 if CP.carFingerprint in kaofui_state_cars else 40
|
prndl2_rate = 10 if CP.carFingerprint in kaofui_state_cars else 40
|
||||||
|
|||||||
@@ -30,20 +30,20 @@ FINGERPRINTS = {
|
|||||||
CAR.BUICK_LACROSSE: [{
|
CAR.BUICK_LACROSSE: [{
|
||||||
190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 510: 8, 528: 5, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 5, 707: 8, 753: 5, 761: 7, 801: 8, 804: 3, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 872: 1, 882: 8, 890: 1, 892: 2, 893: 1, 894: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1904: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1914: 7, 1916: 7, 1918: 7, 1919: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8
|
190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 510: 8, 528: 5, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 5, 707: 8, 753: 5, 761: 7, 801: 8, 804: 3, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 872: 1, 882: 8, 890: 1, 892: 2, 893: 1, 894: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1904: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1914: 7, 1916: 7, 1918: 7, 1919: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8
|
||||||
}],
|
}],
|
||||||
# CAR.CHEVROLET_VOLT_CC: [
|
CAR.CHEVROLET_VOLT_CC: [
|
||||||
# FIXME: Need a message to distinguish flashed from non-flashed
|
# Captured no-ACC Volt fingerprints for OBD-C/L&P harness installations
|
||||||
# Volt Premier w/o acc 2016
|
# Volt Premier w/o ACC 2016
|
||||||
# {
|
{
|
||||||
# 170: 8, 171: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 209: 7, 211: 2, 241: 6, 288: 5, 289: 1, 290: 1, 298: 2, 304: 8, 308: 4, 309: 8, 311: 8, 313: 8, 320: 8, 328: 1, 352: 5, 368: 8, 381: 6, 384: 8, 386: 5, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 3, 508: 8, 512: 3, 528: 4, 530: 8, 532: 6, 537: 4, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 8, 563: 5, 564: 5, 565: 8, 566: 5, 567: 3, 568: 1, 577: 8, 578: 8, 594: 8, 647: 3, 707: 8, 711: 6, 717: 5, 761: 7, 800: 6, 810: 8, 821: 4, 823: 7, 832: 8, 840: 5, 842: 6, 844: 8, 866: 4, 869: 4, 961: 8, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1602: 8, 1618: 8, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1928: 7, 1930: 7, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2024: 8, 2025: 8, 2028: 8
|
170: 8, 171: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 209: 7, 211: 2, 241: 6, 288: 5, 289: 1, 290: 1, 298: 2, 304: 8, 308: 4, 309: 8, 311: 8, 313: 8, 320: 8, 328: 1, 352: 5, 368: 8, 381: 6, 384: 8, 386: 5, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 3, 508: 8, 512: 3, 528: 4, 530: 8, 532: 6, 537: 4, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 8, 563: 5, 564: 5, 565: 8, 566: 5, 567: 3, 568: 1, 577: 8, 578: 8, 594: 8, 647: 3, 707: 8, 711: 6, 717: 5, 761: 7, 800: 6, 810: 8, 821: 4, 823: 7, 832: 8, 840: 5, 842: 6, 844: 8, 866: 4, 869: 4, 961: 8, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1602: 8, 1618: 8, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1928: 7, 1930: 7, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2024: 8, 2025: 8, 2028: 8
|
||||||
# },
|
},
|
||||||
# {
|
{
|
||||||
# 201: 8, 493: 8, 495: 4, 193: 8, 197: 8, 209: 7, 171: 8, 456: 8, 199: 4, 489: 8, 211: 2, 499: 3, 390: 7, 532: 6, 568: 1, 761: 7, 381: 6, 485: 8, 189: 7, 479: 3, 711: 6, 501: 8, 241: 6, 717: 5, 869: 4, 389: 2, 454: 8, 170: 8, 190: 6, 497: 8, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 500: 6, 508: 8, 528: 4, 647: 3, 1105: 6, 1005: 6, 481: 7, 844: 8, 866: 4, 564: 5, 969: 8, 388: 8, 352: 5, 562: 8, 961: 8, 386: 8, 707: 8, 977: 8, 979: 7, 298: 8, 840: 5, 842: 5, 988: 6, 1001: 8, 560: 8, 546: 7, 558: 8, 309: 8, 995: 7, 311: 8, 566: 5, 567:3, 989: 8, 384: 4, 800: 6, 1033: 7, 1034: 7, 313: 8, 554: 3, 810: 8, 1017: 8, 1019: 2, 1020: 8, 1217: 8, 1223: 3, 1233: 8, 1227: 4, 1417: 8, 1009: 8, 1221: 5, 1275: 3, 1225: 7, 289: 8, 550: 8, 1273: 3, 1928: 7, 1187: 4, 1265: 8, 1927: 7, 1267: 1, 1906: 7, 288: 5, 304: 1, 328: 1, 1912: 7, 320: 3, 1910: 7, 563: 5, 1249: 8, 1930: 7, 1257: 6, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 565: 5, 1280: 4, 1907: 7
|
201: 8, 493: 8, 495: 4, 193: 8, 197: 8, 209: 7, 171: 8, 456: 8, 199: 4, 489: 8, 211: 2, 499: 3, 390: 7, 532: 6, 568: 1, 761: 7, 381: 6, 485: 8, 189: 7, 479: 3, 711: 6, 501: 8, 241: 6, 717: 5, 869: 4, 389: 2, 454: 8, 170: 8, 190: 6, 497: 8, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 500: 6, 508: 8, 528: 4, 647: 3, 1105: 6, 1005: 6, 481: 7, 844: 8, 866: 4, 564: 5, 969: 8, 388: 8, 352: 5, 562: 8, 961: 8, 386: 8, 707: 8, 977: 8, 979: 7, 298: 8, 840: 5, 842: 5, 988: 6, 1001: 8, 560: 8, 546: 7, 558: 8, 309: 8, 995: 7, 311: 8, 566: 5, 567:3, 989: 8, 384: 4, 800: 6, 1033: 7, 1034: 7, 313: 8, 554: 3, 810: 8, 1017: 8, 1019: 2, 1020: 8, 1217: 8, 1223: 3, 1233: 8, 1227: 4, 1417: 8, 1009: 8, 1221: 5, 1275: 3, 1225: 7, 289: 8, 550: 8, 1273: 3, 1928: 7, 1187: 4, 1265: 8, 1927: 7, 1267: 1, 1906: 7, 288: 5, 304: 1, 328: 1, 1912: 7, 320: 3, 1910: 7, 563: 5, 1249: 8, 1930: 7, 1257: 6, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 565: 5, 1280: 4, 1907: 7
|
||||||
# },
|
},
|
||||||
# # Volt Premier w/o ACC 2018 + Pedal
|
# Volt Premier w/o ACC 2018 + Pedal
|
||||||
# {
|
{
|
||||||
# 189: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 497: 8, 500: 6, 501: 8, 513: 6, 528: 4, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 566: 5, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 717: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1922: 7, 1930: 7
|
189: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 497: 8, 500: 6, 501: 8, 513: 6, 528: 4, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 566: 5, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 717: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1922: 7, 1930: 7
|
||||||
# }
|
}
|
||||||
# ],
|
],
|
||||||
CAR.BUICK_REGAL: [{
|
CAR.BUICK_REGAL: [{
|
||||||
190: 8, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 8, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 8, 419: 8, 422: 4, 426: 8, 431: 8, 442: 8, 451: 8, 452: 8, 453: 8, 455: 7, 456: 8, 463: 3, 479: 8, 481: 7, 485: 8, 487: 8, 489: 8, 495: 8, 497: 8, 499: 3, 500: 8, 501: 8, 508: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 569: 3, 573: 1, 577: 8, 578: 8, 579: 8, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 882: 8, 884: 8, 890: 1, 892: 2, 893: 2, 894: 1, 961: 8, 967: 8, 969: 8, 977: 8, 979: 8, 985: 8, 1001: 8, 1005: 6, 1009: 8, 1011: 8, 1013: 3, 1017: 8, 1020: 8, 1024: 8, 1025: 8, 1026: 8, 1027: 8, 1028: 8, 1029: 8, 1030: 8, 1031: 8, 1032: 2, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 8, 1225: 7, 1233: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 8, 1263: 8, 1265: 8, 1267: 8, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1601: 8, 1602: 8, 1603: 7, 1611: 8, 1618: 8, 1906: 8, 1907: 7, 1912: 7, 1914: 7, 1916: 7, 1919: 7, 1930: 7, 2016: 8, 2018: 8, 2019: 8, 2024: 8, 2026: 8
|
190: 8, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 8, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 8, 419: 8, 422: 4, 426: 8, 431: 8, 442: 8, 451: 8, 452: 8, 453: 8, 455: 7, 456: 8, 463: 3, 479: 8, 481: 7, 485: 8, 487: 8, 489: 8, 495: 8, 497: 8, 499: 3, 500: 8, 501: 8, 508: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 569: 3, 573: 1, 577: 8, 578: 8, 579: 8, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 882: 8, 884: 8, 890: 1, 892: 2, 893: 2, 894: 1, 961: 8, 967: 8, 969: 8, 977: 8, 979: 8, 985: 8, 1001: 8, 1005: 6, 1009: 8, 1011: 8, 1013: 3, 1017: 8, 1020: 8, 1024: 8, 1025: 8, 1026: 8, 1027: 8, 1028: 8, 1029: 8, 1030: 8, 1031: 8, 1032: 2, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 8, 1225: 7, 1233: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 8, 1263: 8, 1265: 8, 1267: 8, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1601: 8, 1602: 8, 1603: 7, 1611: 8, 1618: 8, 1906: 8, 1907: 7, 1912: 7, 1914: 7, 1916: 7, 1919: 7, 1930: 7, 2016: 8, 2018: 8, 2019: 8, 2024: 8, 2026: 8
|
||||||
}],
|
}],
|
||||||
@@ -207,7 +207,6 @@ FINGERPRINTS = {
|
|||||||
FINGERPRINTS.update({
|
FINGERPRINTS.update({
|
||||||
CAR.CHEVROLET_VOLT_ASCM: FINGERPRINTS[CAR.CHEVROLET_VOLT],
|
CAR.CHEVROLET_VOLT_ASCM: FINGERPRINTS[CAR.CHEVROLET_VOLT],
|
||||||
CAR.CHEVROLET_VOLT_CAMERA: [{**fp, CAMERA_DIAGNOSTIC_ADDRESS: 8, CAMERA_DIAGNOSTIC_RX_ADDRESS: 8} for fp in FINGERPRINTS[CAR.CHEVROLET_VOLT]],
|
CAR.CHEVROLET_VOLT_CAMERA: [{**fp, CAMERA_DIAGNOSTIC_ADDRESS: 8, CAMERA_DIAGNOSTIC_RX_ADDRESS: 8} for fp in FINGERPRINTS[CAR.CHEVROLET_VOLT]],
|
||||||
CAR.CHEVROLET_VOLT_CC: FINGERPRINTS[CAR.CHEVROLET_VOLT],
|
|
||||||
CAR.GMC_ACADIA_ASCM: FINGERPRINTS[CAR.GMC_ACADIA],
|
CAR.GMC_ACADIA_ASCM: FINGERPRINTS[CAR.GMC_ACADIA],
|
||||||
CAR.CHEVROLET_MALIBU_ASCM: FINGERPRINTS[CAR.CHEVROLET_MALIBU],
|
CAR.CHEVROLET_MALIBU_ASCM: FINGERPRINTS[CAR.CHEVROLET_MALIBU],
|
||||||
CAR.CADILLAC_ESCALADE_ASCM: FINGERPRINTS[CAR.CADILLAC_ESCALADE],
|
CAR.CADILLAC_ESCALADE_ASCM: FINGERPRINTS[CAR.CADILLAC_ESCALADE],
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from opendbc.car import DT_CTRL
|
from opendbc.car import DT_CTRL, structs
|
||||||
from opendbc.car.can_definitions import CanData
|
from opendbc.car.can_definitions import CanData
|
||||||
from opendbc.car.common.conversions import Conversions as CV
|
from opendbc.car.common.conversions import Conversions as CV
|
||||||
from opendbc.car.gm.values import CAR, CanBus, CruiseButtons, GMFlags
|
from opendbc.car.gm.values import CAR, CanBus, CruiseButtons, GMFlags
|
||||||
@@ -20,6 +20,14 @@ MALIBU_BUTTON_MAP = {
|
|||||||
ACC_CRUISE_STATE_ADAPTIVE = 2
|
ACC_CRUISE_STATE_ADAPTIVE = 2
|
||||||
XT4_CC_BUTTON_BURST_FRAMES = 6
|
XT4_CC_BUTTON_BURST_FRAMES = 6
|
||||||
XT4_CC_BUTTON_COUNTER_DELAY_FRAMES = 1
|
XT4_CC_BUTTON_COUNTER_DELAY_FRAMES = 1
|
||||||
|
BOLT_CC_BUTTON_CARS = {
|
||||||
|
CAR.CHEVROLET_BOLT_CC_2017,
|
||||||
|
CAR.CHEVROLET_BOLT_CC_2018_2021,
|
||||||
|
CAR.CHEVROLET_BOLT_CC_2022_2023,
|
||||||
|
}
|
||||||
|
BOLT_CC_TARGET_DEADBAND_MPH = 0.75
|
||||||
|
BOLT_CC_REVERSE_CONFIRM_S = 0.6
|
||||||
|
BOLT_CC_DIRECTION_MEMORY_S = 1.5
|
||||||
|
|
||||||
|
|
||||||
def malibu_phase_map_for_button(button):
|
def malibu_phase_map_for_button(button):
|
||||||
@@ -298,26 +306,65 @@ def create_lka_icon_command(bus, active, critical, steer):
|
|||||||
return CanData(0x104c006c, dat, bus)
|
return CanData(0x104c006c, dat, bus)
|
||||||
|
|
||||||
|
|
||||||
|
def stabilize_bolt_cc_button(controller, CP, requested_button):
|
||||||
|
if CP.carFingerprint not in BOLT_CC_BUTTON_CARS:
|
||||||
|
return requested_button
|
||||||
|
|
||||||
|
direction_buttons = (CruiseButtons.RES_ACCEL, CruiseButtons.DECEL_SET)
|
||||||
|
if requested_button not in direction_buttons:
|
||||||
|
controller.gm_cc_pending_reverse_button = CruiseButtons.INIT
|
||||||
|
return requested_button
|
||||||
|
|
||||||
|
last_button = getattr(controller, "gm_cc_last_direction_button", CruiseButtons.INIT)
|
||||||
|
last_frame = getattr(controller, "gm_cc_last_direction_frame", -int(BOLT_CC_DIRECTION_MEMORY_S / DT_CTRL) - 1)
|
||||||
|
recently_sent = (controller.frame - last_frame) * DT_CTRL <= BOLT_CC_DIRECTION_MEMORY_S
|
||||||
|
reversing_to_accel = (last_button == CruiseButtons.DECEL_SET and
|
||||||
|
requested_button == CruiseButtons.RES_ACCEL and recently_sent)
|
||||||
|
|
||||||
|
if reversing_to_accel:
|
||||||
|
pending_button = getattr(controller, "gm_cc_pending_reverse_button", CruiseButtons.INIT)
|
||||||
|
if pending_button != requested_button:
|
||||||
|
controller.gm_cc_pending_reverse_button = requested_button
|
||||||
|
controller.gm_cc_pending_reverse_frame = controller.frame
|
||||||
|
return CruiseButtons.INIT
|
||||||
|
|
||||||
|
pending_frame = getattr(controller, "gm_cc_pending_reverse_frame", controller.frame)
|
||||||
|
if (controller.frame - pending_frame) * DT_CTRL < BOLT_CC_REVERSE_CONFIRM_S:
|
||||||
|
return CruiseButtons.INIT
|
||||||
|
|
||||||
|
controller.gm_cc_pending_reverse_button = CruiseButtons.INIT
|
||||||
|
return requested_button
|
||||||
|
|
||||||
|
|
||||||
def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggles):
|
def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggles):
|
||||||
accel = actuators.accel
|
accel = actuators.accel
|
||||||
v_ego = CS.out.vEgo
|
v_ego = CS.out.vEgo
|
||||||
cruise_btn = CruiseButtons.INIT
|
cruise_btn = CruiseButtons.INIT
|
||||||
rate = 1 if abs(accel) <= 0.15 else 0.2
|
rate = 1 if abs(accel) <= 0.15 else 0.2
|
||||||
ms_convert = CV.MS_TO_KPH if getattr(starpilot_toggles, "is_metric", False) else CV.MS_TO_MPH
|
is_metric = getattr(starpilot_toggles, "is_metric", False)
|
||||||
|
ms_convert = CV.MS_TO_KPH if is_metric else CV.MS_TO_MPH
|
||||||
speed_setpoint = int(round(CS.out.cruiseState.speed * ms_convert))
|
speed_setpoint = int(round(CS.out.cruiseState.speed * ms_convert))
|
||||||
desired_setpoint = int(round((v_ego * 1.01 + 3 * accel) * ms_convert))
|
projected_setpoint = (v_ego * 1.01 + 3 * accel) * ms_convert
|
||||||
|
desired_setpoint = int(round(projected_setpoint))
|
||||||
|
bolt_cc = CS.CP.carFingerprint in BOLT_CC_BUTTON_CARS
|
||||||
|
target_deadband = BOLT_CC_TARGET_DEADBAND_MPH * (CV.MPH_TO_KPH if is_metric else 1.0) if bolt_cc else 0.0
|
||||||
|
comparison_setpoint = projected_setpoint if bolt_cc else desired_setpoint
|
||||||
|
|
||||||
if CS.CP.minEnableSpeed - (desired_setpoint / ms_convert) > 3.25:
|
if CS.CP.minEnableSpeed - (desired_setpoint / ms_convert) > 3.25:
|
||||||
cruise_btn = CruiseButtons.CANCEL
|
cruise_btn = CruiseButtons.CANCEL
|
||||||
controller.apply_speed = 0
|
elif comparison_setpoint < speed_setpoint - target_deadband and speed_setpoint > CS.CP.minEnableSpeed * ms_convert + 1:
|
||||||
elif desired_setpoint < speed_setpoint and speed_setpoint > CS.CP.minEnableSpeed * ms_convert + 1:
|
|
||||||
cruise_btn = CruiseButtons.DECEL_SET
|
cruise_btn = CruiseButtons.DECEL_SET
|
||||||
controller.apply_speed = speed_setpoint - 1
|
elif comparison_setpoint > speed_setpoint + target_deadband:
|
||||||
elif desired_setpoint > speed_setpoint:
|
|
||||||
cruise_btn = CruiseButtons.RES_ACCEL
|
cruise_btn = CruiseButtons.RES_ACCEL
|
||||||
|
|
||||||
|
cruise_btn = stabilize_bolt_cc_button(controller, CS.CP, cruise_btn)
|
||||||
|
if cruise_btn == CruiseButtons.CANCEL:
|
||||||
|
controller.apply_speed = 0
|
||||||
|
elif cruise_btn == CruiseButtons.DECEL_SET:
|
||||||
|
controller.apply_speed = speed_setpoint - 1
|
||||||
|
elif cruise_btn == CruiseButtons.RES_ACCEL:
|
||||||
controller.apply_speed = speed_setpoint + 1
|
controller.apply_speed = speed_setpoint + 1
|
||||||
else:
|
else:
|
||||||
cruise_btn = CruiseButtons.INIT
|
|
||||||
controller.apply_speed = speed_setpoint
|
controller.apply_speed = speed_setpoint
|
||||||
|
|
||||||
if CS.CP.carFingerprint == CAR.CADILLAC_XT4_CC:
|
if CS.CP.carFingerprint == CAR.CADILLAC_XT4_CC:
|
||||||
@@ -360,6 +407,9 @@ def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggl
|
|||||||
# Or bus 2, since we're forwarding... but I think it does
|
# Or bus 2, since we're forwarding... but I think it does
|
||||||
if (cruise_btn != CruiseButtons.INIT) and ((controller.frame - controller.last_button_frame) * DT_CTRL > rate):
|
if (cruise_btn != CruiseButtons.INIT) and ((controller.frame - controller.last_button_frame) * DT_CTRL > rate):
|
||||||
controller.last_button_frame = controller.frame
|
controller.last_button_frame = controller.frame
|
||||||
|
if bolt_cc and cruise_btn in (CruiseButtons.RES_ACCEL, CruiseButtons.DECEL_SET):
|
||||||
|
controller.gm_cc_last_direction_button = cruise_btn
|
||||||
|
controller.gm_cc_last_direction_frame = controller.frame
|
||||||
if CS.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
|
if CS.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
|
||||||
phase_map = malibu_phase_map_for_button(cruise_btn)
|
phase_map = malibu_phase_map_for_button(cruise_btn)
|
||||||
if phase_map:
|
if phase_map:
|
||||||
@@ -370,9 +420,11 @@ def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggl
|
|||||||
idx = (CS.buttons_counter + 1) % 4 # Need to predict the next idx for '22-23 EUV
|
idx = (CS.buttons_counter + 1) % 4 # Need to predict the next idx for '22-23 EUV
|
||||||
msgs = [create_buttons(packer, CanBus.POWERTRAIN, idx, cruise_btn)]
|
msgs = [create_buttons(packer, CanBus.POWERTRAIN, idx, cruise_btn)]
|
||||||
|
|
||||||
# Flashed camera-forward Volt CC installs also need the button spoof on the
|
# A camera-forward Volt CC install needs the button spoof on both sides.
|
||||||
# camera side. Removed-camera installs set NO_CAMERA and keep this PT-only.
|
# The OBD-C/L&P gateway variant has no camera bus and remains PT-only.
|
||||||
if CS.CP.carFingerprint == CAR.CHEVROLET_VOLT_CC and not (CS.CP.flags & GMFlags.NO_CAMERA.value):
|
if (CS.CP.carFingerprint == CAR.CHEVROLET_VOLT_CC and
|
||||||
|
getattr(CS.CP, "networkLocation", None) == structs.CarParams.NetworkLocation.fwdCamera and
|
||||||
|
not (CS.CP.flags & GMFlags.NO_CAMERA.value)):
|
||||||
msgs.append(create_buttons(packer, CanBus.CAMERA, idx, cruise_btn))
|
msgs.append(create_buttons(packer, CanBus.CAMERA, idx, cruise_btn))
|
||||||
return msgs
|
return msgs
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ NON_LINEAR_TORQUE_PARAMS = {
|
|||||||
"left": [1.525, 1.05, 0.155, 0.0],
|
"left": [1.525, 1.05, 0.155, 0.0],
|
||||||
"right": [1.525, 0.95, 0.150, 0.0],
|
"right": [1.525, 0.95, 0.150, 0.0],
|
||||||
},
|
},
|
||||||
|
CAR.CHEVROLET_TRAX: {
|
||||||
|
"left": [3.8060, 0.8282, 0.1702, 0],
|
||||||
|
"right": [3.8060, 0.8282, 0.1702, 0],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
NON_LINEAR_TORQUE_PARAM_ALIASES = {
|
NON_LINEAR_TORQUE_PARAM_ALIASES = {
|
||||||
@@ -269,7 +273,6 @@ class CarInterface(CarInterfaceBase):
|
|||||||
|
|
||||||
kaofui_camera_cars = {
|
kaofui_camera_cars = {
|
||||||
CAR.CHEVROLET_VOLT_CAMERA,
|
CAR.CHEVROLET_VOLT_CAMERA,
|
||||||
CAR.CHEVROLET_VOLT_CC,
|
|
||||||
CAR.CHEVROLET_MALIBU_HYBRID_CC,
|
CAR.CHEVROLET_MALIBU_HYBRID_CC,
|
||||||
}
|
}
|
||||||
bolt_cc_camera_cars = {
|
bolt_cc_camera_cars = {
|
||||||
@@ -603,6 +606,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.longitudinalTuning.kpV = [0.095, 0.085, 0.065, 0.050]
|
ret.longitudinalTuning.kpV = [0.095, 0.085, 0.065, 0.050]
|
||||||
ret.longitudinalTuning.kiV = [0.07, 0.10, 0.15, 0.24]
|
ret.longitudinalTuning.kiV = [0.07, 0.10, 0.15, 0.24]
|
||||||
ret.longitudinalTuning.kfDEPRECATED = 0.20
|
ret.longitudinalTuning.kfDEPRECATED = 0.20
|
||||||
|
ret.longitudinalActuatorDelay = 0.6
|
||||||
else:
|
else:
|
||||||
ret.longitudinalTuning.kfDEPRECATED = 0.25
|
ret.longitudinalTuning.kfDEPRECATED = 0.25
|
||||||
|
|
||||||
@@ -680,6 +684,8 @@ class CarInterface(CarInterfaceBase):
|
|||||||
|
|
||||||
if candidate in CC_ONLY_CAR:
|
if candidate in CC_ONLY_CAR:
|
||||||
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_ACC.value
|
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_ACC.value
|
||||||
|
if candidate == CAR.CHEVROLET_VOLT_CC and ret.networkLocation == NetworkLocation.gateway:
|
||||||
|
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_VOLT_CC_GATEWAY.value
|
||||||
|
|
||||||
if candidate in SDGM_CAR and ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]:
|
if candidate in SDGM_CAR and ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]:
|
||||||
ret.flags |= GMFlags.FORCE_BRAKE_C9.value
|
ret.flags |= GMFlags.FORCE_BRAKE_C9.value
|
||||||
@@ -693,7 +699,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
|
|
||||||
if ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]:
|
if ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]:
|
||||||
ret.flags |= GMFlags.NO_ACCELERATOR_POS_MSG.value
|
ret.flags |= GMFlags.NO_ACCELERATOR_POS_MSG.value
|
||||||
if candidate == CAR.CHEVROLET_VOLT and ret.networkLocation == NetworkLocation.gateway:
|
if candidate in (CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_CC) and ret.networkLocation == NetworkLocation.gateway:
|
||||||
# Reuse the no-camera safety bit as an ASCM Volt selector for the alternate EBCM brake path.
|
# Reuse the no-camera safety bit as an ASCM Volt selector for the alternate EBCM brake path.
|
||||||
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_CAMERA.value
|
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_CAMERA.value
|
||||||
|
|
||||||
@@ -779,6 +785,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.alternativeExperience |= ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE
|
ret.alternativeExperience |= ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE
|
||||||
|
|
||||||
if candidate == CAR.CHEVROLET_TRAX:
|
if candidate == CAR.CHEVROLET_TRAX:
|
||||||
|
ret.steerActuatorDelay = 0.46
|
||||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ from opendbc.car.gm.carcontroller import (
|
|||||||
get_stock_cc_active_for_cancel,
|
get_stock_cc_active_for_cancel,
|
||||||
shape_bolt_acc_pedal_low_speed_friction,
|
shape_bolt_acc_pedal_low_speed_friction,
|
||||||
shape_truck_friction_brake,
|
shape_truck_friction_brake,
|
||||||
|
shape_truck_pitch_accel,
|
||||||
shape_truck_positive_accel,
|
shape_truck_positive_accel,
|
||||||
|
smooth_truck_follow_accel,
|
||||||
should_use_fixed_stopping_brake,
|
should_use_fixed_stopping_brake,
|
||||||
should_activate_auto_hold,
|
should_activate_auto_hold,
|
||||||
should_activate_volt_one_pedal,
|
should_activate_volt_one_pedal,
|
||||||
@@ -361,6 +363,8 @@ def test_live_camera_path_does_not_send_pt_keepalive():
|
|||||||
def test_acc_2cd_replacement_only_used_with_live_camera_path():
|
def test_acc_2cd_replacement_only_used_with_live_camera_path():
|
||||||
assert should_send_acc_2cd(SimpleNamespace(
|
assert should_send_acc_2cd(SimpleNamespace(
|
||||||
carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=0))
|
carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=0))
|
||||||
|
assert should_send_acc_2cd(SimpleNamespace(
|
||||||
|
carFingerprint=CAR.CHEVROLET_SILVERADO, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=0))
|
||||||
assert not should_send_acc_2cd(SimpleNamespace(
|
assert not should_send_acc_2cd(SimpleNamespace(
|
||||||
carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=GMFlags.NO_CAMERA.value))
|
carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=GMFlags.NO_CAMERA.value))
|
||||||
assert not should_send_acc_2cd(SimpleNamespace(
|
assert not should_send_acc_2cd(SimpleNamespace(
|
||||||
@@ -861,6 +865,36 @@ def test_shape_truck_positive_accel_does_not_relax_without_speed_error():
|
|||||||
assert no_error == base
|
assert no_error == base
|
||||||
|
|
||||||
|
|
||||||
|
def test_shape_truck_positive_accel_keeps_more_highway_follow_authority():
|
||||||
|
city = shape_truck_positive_accel(0.28, 26.0, True)
|
||||||
|
highway = shape_truck_positive_accel(0.28, 34.0, True)
|
||||||
|
|
||||||
|
assert highway >= city
|
||||||
|
|
||||||
|
|
||||||
|
def test_smooth_truck_follow_accel_slews_small_highway_commands():
|
||||||
|
shaped = smooth_truck_follow_accel(0.50, 0.0, 30.0, True, True, False)
|
||||||
|
|
||||||
|
assert shaped == pytest.approx(0.06)
|
||||||
|
|
||||||
|
|
||||||
|
def test_smooth_truck_follow_accel_does_not_delay_safety_requests():
|
||||||
|
assert smooth_truck_follow_accel(-0.40, 0.20, 30.0, True, True, False) == -0.40
|
||||||
|
assert smooth_truck_follow_accel(0.20, -0.40, 30.0, True, True, False) == 0.20
|
||||||
|
assert smooth_truck_follow_accel(-0.20, 0.20, 30.0, True, True, True) == -0.20
|
||||||
|
assert smooth_truck_follow_accel(-0.20, 0.20, 20.0, True, True, False) == -0.20
|
||||||
|
assert smooth_truck_follow_accel(-0.20, 0.20, 30.0, True, False, False) == -0.20
|
||||||
|
|
||||||
|
|
||||||
|
def test_shape_truck_pitch_accel_attenuates_highway_grade_feedforward():
|
||||||
|
assert shape_truck_pitch_accel(-0.30, 30.0, True) == pytest.approx(-0.0825)
|
||||||
|
assert shape_truck_pitch_accel(0.30, 30.0, True) == pytest.approx(0.0825)
|
||||||
|
|
||||||
|
|
||||||
|
def test_shape_truck_pitch_accel_is_inactive_without_truck_tuning():
|
||||||
|
assert shape_truck_pitch_accel(-0.30, 30.0, False) == pytest.approx(-0.30)
|
||||||
|
|
||||||
|
|
||||||
def test_shape_truck_friction_brake_suppresses_boundary_chatter():
|
def test_shape_truck_friction_brake_suppresses_boundary_chatter():
|
||||||
assert shape_truck_friction_brake(14, -0.3, False, False) == (0, False)
|
assert shape_truck_friction_brake(14, -0.3, False, False) == (0, False)
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ from opendbc.car.gm.carcontroller import (
|
|||||||
)
|
)
|
||||||
import opendbc.car.gm.interface as gm_interface
|
import opendbc.car.gm.interface as gm_interface
|
||||||
from opendbc.car.common.conversions import Conversions as CV
|
from opendbc.car.common.conversions import Conversions as CV
|
||||||
|
from opendbc.car.gps import CHEVROLET_BOLT_GPS_CARS, CHEVROLET_BOLT_GPS_MESSAGES, get_car_gps_config, parse_chevrolet_bolt_can_gps
|
||||||
from opendbc.car.gm.fingerprints import FINGERPRINTS
|
from opendbc.car.gm.fingerprints import FINGERPRINTS
|
||||||
from opendbc.car.gm.values import ASCM_INT, CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, DBC, GM_RX_OFFSET, CarControllerParams, CruiseButtons, GMFlags, GMSafetyFlags
|
from opendbc.car.gm.values import ASCM_INT, CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, DBC, GM_RX_OFFSET, CarControllerParams, CruiseButtons, GMFlags, GMSafetyFlags
|
||||||
from opendbc.safety import ALTERNATIVE_EXPERIENCE
|
from opendbc.safety import ALTERNATIVE_EXPERIENCE
|
||||||
@@ -65,7 +66,76 @@ class TestGMFingerprint:
|
|||||||
assert finger.get(required_addr) == 8, required_addr
|
assert finger.get(required_addr) == 8, required_addr
|
||||||
|
|
||||||
|
|
||||||
|
class TestBoltGps:
|
||||||
|
@parameterized.expand(CHEVROLET_BOLT_GPS_CARS)
|
||||||
|
def test_all_bolt_generations_are_registered(self, car_model):
|
||||||
|
config = get_car_gps_config(SimpleNamespace(carFingerprint=car_model, brand="gm"))
|
||||||
|
assert config is not None
|
||||||
|
assert config.messages == CHEVROLET_BOLT_GPS_MESSAGES
|
||||||
|
gps = parse_chevrolet_bolt_can_gps({
|
||||||
|
"GPSLatitude": 145292743.0,
|
||||||
|
"GPSLongitude": -267520892.0,
|
||||||
|
})
|
||||||
|
assert gps is not None
|
||||||
|
assert gps["hasFix"]
|
||||||
|
assert gps["latitude"] == pytest.approx(40.3590953)
|
||||||
|
assert gps["longitude"] == pytest.approx(-74.3113589)
|
||||||
|
|
||||||
|
def test_invalid_bolt_position_does_not_become_a_fix(self):
|
||||||
|
gps = parse_chevrolet_bolt_can_gps({"GPSLatitude": 0.0, "GPSLongitude": -2147483648.0})
|
||||||
|
assert gps is not None
|
||||||
|
assert not gps["hasFix"]
|
||||||
|
assert gps["latitude"] == 0.0
|
||||||
|
assert gps["longitude"] == 0.0
|
||||||
|
|
||||||
|
@parameterized.expand(CHEVROLET_BOLT_GPS_CARS)
|
||||||
|
def test_gps_message_is_added_to_powertrain_parser(self, car_model):
|
||||||
|
cp = SimpleNamespace(
|
||||||
|
brand="gm",
|
||||||
|
carFingerprint=car_model,
|
||||||
|
flags=0,
|
||||||
|
networkLocation=structs.CarParams.NetworkLocation.gateway,
|
||||||
|
transmissionType=structs.CarParams.TransmissionType.direct,
|
||||||
|
enableBsm=False,
|
||||||
|
enableGasInterceptorDEPRECATED=False,
|
||||||
|
)
|
||||||
|
parsers = GMCarState.get_can_parsers(cp)
|
||||||
|
assert all(message in parsers[Bus.pt].vl for message in CHEVROLET_BOLT_GPS_MESSAGES)
|
||||||
|
|
||||||
|
|
||||||
class TestGMInterface:
|
class TestGMInterface:
|
||||||
|
@parameterized.expand([
|
||||||
|
CAR.CHEVROLET_BOLT_CC_2017,
|
||||||
|
CAR.CHEVROLET_BOLT_CC_2018_2021,
|
||||||
|
CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
|
||||||
|
CAR.CHEVROLET_BOLT_CC_2022_2023,
|
||||||
|
CAR.CHEVROLET_MALIBU_HYBRID_CC,
|
||||||
|
])
|
||||||
|
def test_bolt_pedal_long_uses_shared_planning_delay_without_retuning_pid(self, car_model):
|
||||||
|
CarInterface = interfaces[car_model]
|
||||||
|
fingerprint = _empty_fingerprint()
|
||||||
|
fingerprint[0][0x201] = 8
|
||||||
|
params = Params()
|
||||||
|
|
||||||
|
try:
|
||||||
|
params.put_bool("GMPedalLongitudinal", True)
|
||||||
|
car_params = CarInterface.get_params(
|
||||||
|
car_model,
|
||||||
|
fingerprint,
|
||||||
|
[],
|
||||||
|
alpha_long=False,
|
||||||
|
is_release=False,
|
||||||
|
docs=False,
|
||||||
|
starpilot_toggles=_test_starpilot_toggles(),
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
params.remove("GMPedalLongitudinal")
|
||||||
|
|
||||||
|
assert car_params.longitudinalActuatorDelay == pytest.approx(0.6)
|
||||||
|
assert list(car_params.longitudinalTuning.kpV) == pytest.approx([0.095, 0.085, 0.065, 0.050])
|
||||||
|
assert list(car_params.longitudinalTuning.kiV) == pytest.approx([0.07, 0.10, 0.15, 0.24])
|
||||||
|
assert car_params.longitudinalTuning.kfDEPRECATED == pytest.approx(0.20)
|
||||||
|
|
||||||
def test_bolt_acc_pedal_pid_accel_limits_keep_full_negative_authority(self):
|
def test_bolt_acc_pedal_pid_accel_limits_keep_full_negative_authority(self):
|
||||||
cp = SimpleNamespace(
|
cp = SimpleNamespace(
|
||||||
enableGasInterceptorDEPRECATED=True,
|
enableGasInterceptorDEPRECATED=True,
|
||||||
@@ -169,6 +239,45 @@ class TestGMInterface:
|
|||||||
assert car_params.flags & GMFlags.NO_CAMERA.value
|
assert car_params.flags & GMFlags.NO_CAMERA.value
|
||||||
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_CAMERA.value
|
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_CAMERA.value
|
||||||
|
|
||||||
|
def test_volt_cc_obd_gateway_uses_cc_long_no_camera_path(self):
|
||||||
|
CarInterface = interfaces[CAR.CHEVROLET_VOLT_CC]
|
||||||
|
car_params = CarInterface.get_params(
|
||||||
|
CAR.CHEVROLET_VOLT_CC,
|
||||||
|
_empty_fingerprint(),
|
||||||
|
[],
|
||||||
|
alpha_long=False,
|
||||||
|
is_release=False,
|
||||||
|
docs=False,
|
||||||
|
starpilot_toggles=_test_starpilot_toggles(),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert car_params.networkLocation == structs.CarParams.NetworkLocation.gateway
|
||||||
|
assert car_params.flags & GMFlags.CC_LONG.value
|
||||||
|
assert car_params.flags & GMFlags.NO_CAMERA.value
|
||||||
|
assert not (car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_CAM.value)
|
||||||
|
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_CC_LONG.value
|
||||||
|
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_ACC.value
|
||||||
|
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_CAMERA.value
|
||||||
|
|
||||||
|
parsers = CarInterface.CarState.get_can_parsers(car_params)
|
||||||
|
assert "ECMCruiseControl" in parsers[Bus.pt].vl
|
||||||
|
assert not parsers[Bus.cam].vl
|
||||||
|
|
||||||
|
def test_other_cc_only_gateway_does_not_use_volt_cc_safety_path(self):
|
||||||
|
CarInterface = interfaces[CAR.CHEVROLET_SILVERADO_CC]
|
||||||
|
car_params = CarInterface.get_params(
|
||||||
|
CAR.CHEVROLET_SILVERADO_CC,
|
||||||
|
_empty_fingerprint(),
|
||||||
|
[],
|
||||||
|
alpha_long=False,
|
||||||
|
is_release=False,
|
||||||
|
docs=False,
|
||||||
|
starpilot_toggles=_test_starpilot_toggles(),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert car_params.networkLocation == structs.CarParams.NetworkLocation.gateway
|
||||||
|
assert not (car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_VOLT_CC_GATEWAY.value)
|
||||||
|
|
||||||
def test_volt_ascm_sparse_fingerprint_without_camera_does_not_set_no_camera(self):
|
def test_volt_ascm_sparse_fingerprint_without_camera_does_not_set_no_camera(self):
|
||||||
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
|
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
|
||||||
fingerprint = {
|
fingerprint = {
|
||||||
@@ -501,6 +610,7 @@ class TestGMCarController:
|
|||||||
CP=SimpleNamespace(
|
CP=SimpleNamespace(
|
||||||
carFingerprint=CAR.CHEVROLET_VOLT_CC,
|
carFingerprint=CAR.CHEVROLET_VOLT_CC,
|
||||||
flags=0,
|
flags=0,
|
||||||
|
networkLocation=structs.CarParams.NetworkLocation.fwdCamera,
|
||||||
minEnableSpeed=24 * CV.MPH_TO_MS,
|
minEnableSpeed=24 * CV.MPH_TO_MS,
|
||||||
),
|
),
|
||||||
buttons_counter=2,
|
buttons_counter=2,
|
||||||
@@ -522,6 +632,7 @@ class TestGMCarController:
|
|||||||
CP=SimpleNamespace(
|
CP=SimpleNamespace(
|
||||||
carFingerprint=CAR.CHEVROLET_VOLT_CC,
|
carFingerprint=CAR.CHEVROLET_VOLT_CC,
|
||||||
flags=GMFlags.NO_CAMERA.value,
|
flags=GMFlags.NO_CAMERA.value,
|
||||||
|
networkLocation=structs.CarParams.NetworkLocation.gateway,
|
||||||
minEnableSpeed=24 * CV.MPH_TO_MS,
|
minEnableSpeed=24 * CV.MPH_TO_MS,
|
||||||
),
|
),
|
||||||
buttons_counter=2,
|
buttons_counter=2,
|
||||||
@@ -557,6 +668,80 @@ class TestGMCarController:
|
|||||||
|
|
||||||
assert [msg[2] for msg in msgs] == [0]
|
assert [msg[2] for msg in msgs] == [0]
|
||||||
|
|
||||||
|
@parameterized.expand([
|
||||||
|
CAR.CHEVROLET_BOLT_CC_2017,
|
||||||
|
CAR.CHEVROLET_BOLT_CC_2018_2021,
|
||||||
|
CAR.CHEVROLET_BOLT_CC_2022_2023,
|
||||||
|
])
|
||||||
|
def test_bolt_cc_redneck_ignores_small_setpoint_error(self, car_model):
|
||||||
|
packer = CANPacker(DBC[car_model][Bus.pt])
|
||||||
|
controller = SimpleNamespace(frame=int(2.0 / DT_CTRL), last_button_frame=0, apply_speed=0)
|
||||||
|
cs = SimpleNamespace(
|
||||||
|
CP=SimpleNamespace(
|
||||||
|
carFingerprint=car_model,
|
||||||
|
minEnableSpeed=24 * CV.MPH_TO_MS,
|
||||||
|
),
|
||||||
|
buttons_counter=2,
|
||||||
|
out=SimpleNamespace(
|
||||||
|
vEgo=(60.6 * CV.MPH_TO_MS) / 1.01,
|
||||||
|
cruiseState=SimpleNamespace(speed=60 * CV.MPH_TO_MS),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
msgs = gmcan.create_gm_cc_spam_command(packer, controller, cs, SimpleNamespace(accel=0.0), SimpleNamespace(is_metric=False))
|
||||||
|
|
||||||
|
assert msgs == []
|
||||||
|
assert controller.apply_speed == 60
|
||||||
|
|
||||||
|
def test_non_bolt_cc_redneck_keeps_existing_setpoint_selector(self):
|
||||||
|
packer = CANPacker(DBC[CAR.CHEVROLET_EQUINOX_CC][Bus.pt])
|
||||||
|
controller = SimpleNamespace(frame=int(2.0 / DT_CTRL), last_button_frame=0, apply_speed=0)
|
||||||
|
cs = SimpleNamespace(
|
||||||
|
CP=SimpleNamespace(
|
||||||
|
carFingerprint=CAR.CHEVROLET_EQUINOX_CC,
|
||||||
|
flags=GMFlags.CC_LONG.value,
|
||||||
|
minEnableSpeed=24 * CV.MPH_TO_MS,
|
||||||
|
),
|
||||||
|
buttons_counter=2,
|
||||||
|
out=SimpleNamespace(
|
||||||
|
vEgo=(60.6 * CV.MPH_TO_MS) / 1.01,
|
||||||
|
cruiseState=SimpleNamespace(speed=60 * CV.MPH_TO_MS),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
msgs = gmcan.create_gm_cc_spam_command(packer, controller, cs, SimpleNamespace(accel=0.0), SimpleNamespace(is_metric=False))
|
||||||
|
|
||||||
|
assert len(msgs) == 1
|
||||||
|
assert controller.apply_speed == 61
|
||||||
|
|
||||||
|
def test_bolt_cc_redneck_requires_persistent_acceleration_after_deceleration(self):
|
||||||
|
cp = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021)
|
||||||
|
controller = SimpleNamespace(
|
||||||
|
frame=100,
|
||||||
|
gm_cc_last_direction_button=CruiseButtons.DECEL_SET,
|
||||||
|
gm_cc_last_direction_frame=100,
|
||||||
|
gm_cc_pending_reverse_button=CruiseButtons.INIT,
|
||||||
|
gm_cc_pending_reverse_frame=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.RES_ACCEL) == CruiseButtons.INIT
|
||||||
|
controller.frame += int(0.5 / DT_CTRL)
|
||||||
|
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.RES_ACCEL) == CruiseButtons.INIT
|
||||||
|
controller.frame += int(0.11 / DT_CTRL)
|
||||||
|
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.RES_ACCEL) == CruiseButtons.RES_ACCEL
|
||||||
|
|
||||||
|
def test_bolt_cc_redneck_deceleration_is_not_debounced(self):
|
||||||
|
cp = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021)
|
||||||
|
controller = SimpleNamespace(
|
||||||
|
frame=100,
|
||||||
|
gm_cc_last_direction_button=CruiseButtons.RES_ACCEL,
|
||||||
|
gm_cc_last_direction_frame=100,
|
||||||
|
gm_cc_pending_reverse_button=CruiseButtons.INIT,
|
||||||
|
gm_cc_pending_reverse_frame=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.DECEL_SET) == CruiseButtons.DECEL_SET
|
||||||
|
|
||||||
def test_xt4_cc_redneck_spam_matches_physical_button_burst(self):
|
def test_xt4_cc_redneck_spam_matches_physical_button_burst(self):
|
||||||
packer = CANPacker(DBC[CAR.CADILLAC_XT4_CC][Bus.pt])
|
packer = CANPacker(DBC[CAR.CADILLAC_XT4_CC][Bus.pt])
|
||||||
controller = SimpleNamespace(
|
controller = SimpleNamespace(
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ class TestGMCan:
|
|||||||
assert bus == 0
|
assert bus == 0
|
||||||
assert dat.hex() == "20000000000000"
|
assert dat.hex() == "20000000000000"
|
||||||
|
|
||||||
|
|
||||||
def test_gas_regen_command_matches_starpilot_volt_2019(self):
|
def test_gas_regen_command_matches_starpilot_volt_2019(self):
|
||||||
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_2019]["pt"])
|
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_2019]["pt"])
|
||||||
addr, dat, bus = gmcan.create_gas_regen_command(packer, 0, 5000, 1, True, False, include_always_one3=True, use_volt_layout=True)
|
addr, dat, bus = gmcan.create_gas_regen_command(packer, 0, 5000, 1, True, False, include_always_one3=True, use_volt_layout=True)
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ class GMSafetyFlags(IntFlag):
|
|||||||
FLAG_GM_REMOTE_START_BOOTS_COMMA = 8192
|
FLAG_GM_REMOTE_START_BOOTS_COMMA = 8192
|
||||||
FLAG_GM_PANDA_3D1_SCHED = 16384
|
FLAG_GM_PANDA_3D1_SCHED = 16384
|
||||||
FLAG_GM_PANDA_PADDLE_SCHED = 32768
|
FLAG_GM_PANDA_PADDLE_SCHED = 32768
|
||||||
|
FLAG_GM_VOLT_CC_GATEWAY = 16384
|
||||||
|
|
||||||
|
|
||||||
class Footnote(Enum):
|
class Footnote(Enum):
|
||||||
@@ -214,16 +215,12 @@ class GMPlatformConfig(PlatformConfig):
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GMASCMPlatformConfig(GMPlatformConfig):
|
class GMASCMPlatformConfig(GMPlatformConfig):
|
||||||
def init(self):
|
pass
|
||||||
# ASCM is supported, but due to a janky install and hardware configuration, we are not showing in the car docs
|
|
||||||
self.car_docs = []
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GMSDGMPlatformConfig(GMPlatformConfig):
|
class GMSDGMPlatformConfig(GMPlatformConfig):
|
||||||
def init(self):
|
pass
|
||||||
# Don't show in docs until the harness is sold. See https://github.com/commaai/openpilot/issues/32471
|
|
||||||
self.car_docs = []
|
|
||||||
|
|
||||||
|
|
||||||
class CAR(Platforms):
|
class CAR(Platforms):
|
||||||
@@ -241,17 +238,17 @@ class CAR(Platforms):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
CHEVROLET_VOLT_ASCM = GMPlatformConfig(
|
CHEVROLET_VOLT_ASCM = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Volt 2017-18 ASCM Harness", min_enable_speed=0, video="https://youtu.be/QeMCN_4TFfQ")],
|
[GMCarDocs("Chevrolet Volt ASCM Harness 2017-18", min_enable_speed=0, video="https://youtu.be/QeMCN_4TFfQ")],
|
||||||
CHEVROLET_VOLT.specs,
|
CHEVROLET_VOLT.specs,
|
||||||
dbc_dict=CHEVROLET_VOLT.dbc_dict,
|
dbc_dict=CHEVROLET_VOLT.dbc_dict,
|
||||||
)
|
)
|
||||||
CHEVROLET_VOLT_CAMERA = GMPlatformConfig(
|
CHEVROLET_VOLT_CAMERA = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Volt 2017-18 Camera Harness", "Flashed camera-forward integration with ACC")],
|
[GMCarDocs("Chevrolet Volt Camera Harness 2017-18", "Flashed camera-forward integration with ACC")],
|
||||||
CHEVROLET_VOLT.specs,
|
CHEVROLET_VOLT.specs,
|
||||||
dbc_dict=CHEVROLET_VOLT.dbc_dict,
|
dbc_dict=CHEVROLET_VOLT.dbc_dict,
|
||||||
)
|
)
|
||||||
CHEVROLET_VOLT_CC = GMPlatformConfig(
|
CHEVROLET_VOLT_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Volt 2017-18 - No-ACC", min_enable_speed=0)],
|
[GMCarDocs("Chevrolet Volt No-ACC 2016-18 (OBD Harness)", "Redneck ACC", min_enable_speed=0)],
|
||||||
CHEVROLET_VOLT.specs,
|
CHEVROLET_VOLT.specs,
|
||||||
dbc_dict=CHEVROLET_VOLT.dbc_dict,
|
dbc_dict=CHEVROLET_VOLT.dbc_dict,
|
||||||
)
|
)
|
||||||
@@ -264,7 +261,7 @@ class CAR(Platforms):
|
|||||||
GMCarSpecs(mass=1496, wheelbase=2.83, steerRatio=15.8, centerToFrontRatio=0.4),
|
GMCarSpecs(mass=1496, wheelbase=2.83, steerRatio=15.8, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
CHEVROLET_MALIBU_ASCM = GMPlatformConfig(
|
CHEVROLET_MALIBU_ASCM = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Malibu 2017-19 ASCM Harness")],
|
[GMCarDocs("Chevrolet Malibu ASCM Harness 2017-19")],
|
||||||
CHEVROLET_MALIBU.specs,
|
CHEVROLET_MALIBU.specs,
|
||||||
)
|
)
|
||||||
GMC_ACADIA = GMASCMPlatformConfig(
|
GMC_ACADIA = GMASCMPlatformConfig(
|
||||||
@@ -272,7 +269,7 @@ class CAR(Platforms):
|
|||||||
GMCarSpecs(mass=1975, wheelbase=2.86, steerRatio=14.4, centerToFrontRatio=0.4),
|
GMCarSpecs(mass=1975, wheelbase=2.86, steerRatio=14.4, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
GMC_ACADIA_ASCM = GMPlatformConfig(
|
GMC_ACADIA_ASCM = GMPlatformConfig(
|
||||||
[GMCarDocs("GMC Acadia 2018 ASCM Harness", video="https://www.youtube.com/watch?v=0ZN6DdsBUZo")],
|
[GMCarDocs("GMC Acadia ASCM Harness 2018", video="https://www.youtube.com/watch?v=0ZN6DdsBUZo")],
|
||||||
GMC_ACADIA.specs,
|
GMC_ACADIA.specs,
|
||||||
)
|
)
|
||||||
BUICK_LACROSSE = GMASCMPlatformConfig(
|
BUICK_LACROSSE = GMASCMPlatformConfig(
|
||||||
@@ -280,11 +277,11 @@ class CAR(Platforms):
|
|||||||
GMCarSpecs(mass=1712, wheelbase=2.91, steerRatio=15.8, centerToFrontRatio=0.4),
|
GMCarSpecs(mass=1712, wheelbase=2.91, steerRatio=15.8, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
BUICK_LACROSSE_ASCM = GMPlatformConfig(
|
BUICK_LACROSSE_ASCM = GMPlatformConfig(
|
||||||
[GMCarDocs("Buick LaCrosse 2017-19 ASCM Harness")],
|
[GMCarDocs("Buick LaCrosse ASCM Harness 2017-19")],
|
||||||
BUICK_LACROSSE.specs,
|
BUICK_LACROSSE.specs,
|
||||||
)
|
)
|
||||||
BUICK_LACROSSE_ASCM_19US = GMPlatformConfig(
|
BUICK_LACROSSE_ASCM_19US = GMPlatformConfig(
|
||||||
[GMCarDocs("Buick LaCrosse 2019 US ASCM Harness")],
|
[GMCarDocs("Buick LaCrosse US ASCM Harness 2019")],
|
||||||
BUICK_LACROSSE.specs,
|
BUICK_LACROSSE.specs,
|
||||||
)
|
)
|
||||||
BUICK_REGAL = GMASCMPlatformConfig(
|
BUICK_REGAL = GMASCMPlatformConfig(
|
||||||
@@ -296,7 +293,7 @@ class CAR(Platforms):
|
|||||||
GMCarSpecs(mass=2564, wheelbase=2.95, steerRatio=17.3),
|
GMCarSpecs(mass=2564, wheelbase=2.95, steerRatio=17.3),
|
||||||
)
|
)
|
||||||
CADILLAC_ESCALADE_ASCM = GMPlatformConfig(
|
CADILLAC_ESCALADE_ASCM = GMPlatformConfig(
|
||||||
[GMCarDocs("Cadillac Escalade 2018 ASCM Harness", "Driver Assist Package")],
|
[GMCarDocs("Cadillac Escalade ASCM Harness 2018", "Driver Assist Package")],
|
||||||
CADILLAC_ESCALADE.specs,
|
CADILLAC_ESCALADE.specs,
|
||||||
)
|
)
|
||||||
CADILLAC_ESCALADE_ESV = GMASCMPlatformConfig(
|
CADILLAC_ESCALADE_ESV = GMASCMPlatformConfig(
|
||||||
@@ -308,29 +305,29 @@ class CAR(Platforms):
|
|||||||
CADILLAC_ESCALADE_ESV.specs,
|
CADILLAC_ESCALADE_ESV.specs,
|
||||||
)
|
)
|
||||||
CADILLAC_ESCALADE_ESV_2019_ASCM = GMPlatformConfig(
|
CADILLAC_ESCALADE_ESV_2019_ASCM = GMPlatformConfig(
|
||||||
[GMCarDocs("Cadillac Escalade ESV Platinum 2019 ASCM Harness", "Adaptive Cruise Control (ACC) & LKAS")],
|
[GMCarDocs("Cadillac Escalade ESV Platinum ASCM Harness 2019", "Adaptive Cruise Control (ACC) & LKAS")],
|
||||||
CADILLAC_ESCALADE_ESV_2019.specs,
|
CADILLAC_ESCALADE_ESV_2019.specs,
|
||||||
)
|
)
|
||||||
CHEVROLET_BOLT_ACC_2022_2023 = GMPlatformConfig(
|
CHEVROLET_BOLT_ACC_2022_2023 = GMPlatformConfig(
|
||||||
[
|
[
|
||||||
GMCarDocs("Chevrolet Bolt ACC 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", video="https://youtu.be/xvwzGMUA210"),
|
GMCarDocs("Chevrolet Bolt EV & EUV ACC 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", video="https://youtu.be/xvwzGMUA210"),
|
||||||
],
|
],
|
||||||
GMCarSpecs(mass=1669, wheelbase=2.63779, steerRatio=16.8, centerToFrontRatio=0.4, tireStiffnessFactor=1.0),
|
GMCarSpecs(mass=1669, wheelbase=2.63779, steerRatio=16.8, centerToFrontRatio=0.4, tireStiffnessFactor=1.0),
|
||||||
)
|
)
|
||||||
CHEVROLET_BOLT_ACC_2022_2023_PEDAL = GMPlatformConfig(
|
CHEVROLET_BOLT_ACC_2022_2023_PEDAL = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Bolt EV 2022-23 ACC w Pedal")],
|
[GMCarDocs("Chevrolet Bolt EV & EUV ACC w Pedal 2022-23")],
|
||||||
CHEVROLET_BOLT_ACC_2022_2023.specs,
|
CHEVROLET_BOLT_ACC_2022_2023.specs,
|
||||||
)
|
)
|
||||||
CHEVROLET_BOLT_CC_2022_2023 = GMPlatformConfig(
|
CHEVROLET_BOLT_CC_2022_2023 = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Bolt EV 2022-23 - No-ACC")],
|
[GMCarDocs("Chevrolet Bolt EV & EUV No-ACC 2022-23")],
|
||||||
CHEVROLET_BOLT_ACC_2022_2023.specs,
|
CHEVROLET_BOLT_ACC_2022_2023.specs,
|
||||||
)
|
)
|
||||||
CHEVROLET_BOLT_CC_2018_2021 = GMPlatformConfig(
|
CHEVROLET_BOLT_CC_2018_2021 = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Bolt EV 2018-21 - No-ACC")],
|
[GMCarDocs("Chevrolet Bolt EV No-ACC 2018-21")],
|
||||||
CHEVROLET_BOLT_ACC_2022_2023.specs,
|
CHEVROLET_BOLT_ACC_2022_2023.specs,
|
||||||
)
|
)
|
||||||
CHEVROLET_BOLT_CC_2017 = GMPlatformConfig(
|
CHEVROLET_BOLT_CC_2017 = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Bolt EV 2017 - No-ACC")],
|
[GMCarDocs("Chevrolet Bolt EV No-ACC 2017")],
|
||||||
CHEVROLET_BOLT_ACC_2022_2023.specs,
|
CHEVROLET_BOLT_ACC_2022_2023.specs,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -343,8 +340,8 @@ class CAR(Platforms):
|
|||||||
)
|
)
|
||||||
CHEVROLET_SILVERADO_CC = GMPlatformConfig(
|
CHEVROLET_SILVERADO_CC = GMPlatformConfig(
|
||||||
[
|
[
|
||||||
GMCarDocs("Chevrolet Silverado 1500 - No-ACC"),
|
GMCarDocs("Chevrolet Silverado 1500 No-ACC 2020-21"),
|
||||||
GMCarDocs("GMC Sierra 1500 - No-ACC"),
|
GMCarDocs("GMC Sierra 1500 No-ACC 2020-21"),
|
||||||
],
|
],
|
||||||
CHEVROLET_SILVERADO.specs,
|
CHEVROLET_SILVERADO.specs,
|
||||||
)
|
)
|
||||||
@@ -361,7 +358,7 @@ class CAR(Platforms):
|
|||||||
CarSpecs(mass=2731, wheelbase=3.302, steerRatio=17.3, centerToFrontRatio=0.49),
|
CarSpecs(mass=2731, wheelbase=3.302, steerRatio=17.3, centerToFrontRatio=0.49),
|
||||||
)
|
)
|
||||||
GMC_YUKON_CC = GMPlatformConfig(
|
GMC_YUKON_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("GMC Yukon - No-ACC")],
|
[GMCarDocs("GMC Yukon No-ACC 2019-20")],
|
||||||
CarSpecs(mass=2541, wheelbase=2.95, steerRatio=16.3, centerToFrontRatio=0.4),
|
CarSpecs(mass=2541, wheelbase=2.95, steerRatio=16.3, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
GMC_YUKON = GMPlatformConfig(
|
GMC_YUKON = GMPlatformConfig(
|
||||||
@@ -373,7 +370,7 @@ class CAR(Platforms):
|
|||||||
GMCarSpecs(mass=1660, wheelbase=2.78, steerRatio=14.4, centerToFrontRatio=0.4),
|
GMCarSpecs(mass=1660, wheelbase=2.78, steerRatio=14.4, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
CADILLAC_XT4_CC = GMPlatformConfig(
|
CADILLAC_XT4_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Cadillac XT4 - No-ACC")],
|
[GMCarDocs("Cadillac XT4 No-ACC 2023")],
|
||||||
CADILLAC_XT4.specs,
|
CADILLAC_XT4.specs,
|
||||||
)
|
)
|
||||||
CADILLAC_XT5 = GMSDGMPlatformConfig(
|
CADILLAC_XT5 = GMSDGMPlatformConfig(
|
||||||
@@ -405,35 +402,35 @@ class CAR(Platforms):
|
|||||||
CarSpecs(mass=2050, wheelbase=2.86, steerRatio=16.0, centerToFrontRatio=0.5),
|
CarSpecs(mass=2050, wheelbase=2.86, steerRatio=16.0, centerToFrontRatio=0.5),
|
||||||
)
|
)
|
||||||
CADILLAC_CT6_CC = GMPlatformConfig(
|
CADILLAC_CT6_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Cadillac CT6 - No-ACC")],
|
[GMCarDocs("Cadillac CT6 No-ACC 2016-20")],
|
||||||
CarSpecs(mass=2358, wheelbase=3.11, steerRatio=17.7, centerToFrontRatio=0.4),
|
CarSpecs(mass=2358, wheelbase=3.11, steerRatio=17.7, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
CADILLAC_XT5_CC = GMPlatformConfig(
|
CADILLAC_XT5_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Cadillac XT5 - No-ACC")],
|
[GMCarDocs("Cadillac XT5 No-ACC 2022")],
|
||||||
CADILLAC_XT5.specs,
|
CADILLAC_XT5.specs,
|
||||||
)
|
)
|
||||||
CHEVROLET_EQUINOX_CC = GMPlatformConfig(
|
CHEVROLET_EQUINOX_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Equinox 2019-22 - No-ACC")],
|
[GMCarDocs("Chevrolet Equinox No-ACC 2019-22")],
|
||||||
CHEVROLET_EQUINOX.specs,
|
CHEVROLET_EQUINOX.specs,
|
||||||
)
|
)
|
||||||
CHEVROLET_MALIBU_CC = GMPlatformConfig(
|
CHEVROLET_MALIBU_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Malibu 2023 - No-ACC")],
|
[GMCarDocs("Chevrolet Malibu No-ACC 2023")],
|
||||||
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=18.25, centerToFrontRatio=0.4, tireStiffnessFactor=0.997),
|
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=18.25, centerToFrontRatio=0.4, tireStiffnessFactor=0.997),
|
||||||
)
|
)
|
||||||
CHEVROLET_MALIBU_HYBRID_CC = GMPlatformConfig(
|
CHEVROLET_MALIBU_HYBRID_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Malibu Hybrid 2017 - No-ACC")],
|
[GMCarDocs("Chevrolet Malibu Hybrid No-ACC 2017")],
|
||||||
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4),
|
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
CHEVROLET_SUBURBAN_CC = GMPlatformConfig(
|
CHEVROLET_SUBURBAN_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Suburban Premier 2016-20 - No-ACC")],
|
[GMCarDocs("Chevrolet Suburban Premier No-ACC 2016-20")],
|
||||||
CHEVROLET_SUBURBAN.specs,
|
CHEVROLET_SUBURBAN.specs,
|
||||||
)
|
)
|
||||||
CHEVROLET_TRAILBLAZER_CC = GMPlatformConfig(
|
CHEVROLET_TRAILBLAZER_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Trailblazer 2021-22 - No-ACC")],
|
[GMCarDocs("Chevrolet Trailblazer No-ACC 2021-22")],
|
||||||
CHEVROLET_TRAILBLAZER.specs,
|
CHEVROLET_TRAILBLAZER.specs,
|
||||||
)
|
)
|
||||||
CHEVROLET_TRAX = GMPlatformConfig(
|
CHEVROLET_TRAX = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet TRAX 2024")],
|
[GMCarDocs("Chevrolet TRAX 2024-25")],
|
||||||
CarSpecs(mass=1365, wheelbase=2.7, steerRatio=16.4, centerToFrontRatio=0.4),
|
CarSpecs(mass=1365, wheelbase=2.7, steerRatio=16.4, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from datetime import UTC, datetime
|
||||||
|
from collections.abc import Callable, Mapping
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from opendbc.car.common.conversions import Conversions as CV
|
||||||
|
from opendbc.car.ford.values import CAR as FORD_CAR
|
||||||
|
from opendbc.car.gm.values import CAR as GM_CAR
|
||||||
|
|
||||||
|
|
||||||
|
CarGpsSample = dict[str, Any]
|
||||||
|
CanGpsDecoder = Callable[..., CarGpsSample | None]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class CarGpsConfig:
|
||||||
|
"""Vehicle-specific CAN GPS inputs and decoder."""
|
||||||
|
|
||||||
|
brand: str
|
||||||
|
messages: tuple[str, ...]
|
||||||
|
decoder: CanGpsDecoder
|
||||||
|
|
||||||
|
|
||||||
|
def _dop_accuracy(dop: float, default: float = 500.0) -> float:
|
||||||
|
"""Convert Ford's dimensionless DOP into a conservative meter estimate."""
|
||||||
|
return max(1.0, dop * 5.0) if 0.0 <= dop <= 5.8 else default
|
||||||
|
|
||||||
|
|
||||||
|
def parse_ford_can_gps(nav1: Mapping[str, float], nav2: Mapping[str, float], nav3: Mapping[str, float]) -> CarGpsSample | None:
|
||||||
|
"""Decode the Ford APIM GPS messages into the fields used by gpsLocationExternal."""
|
||||||
|
year = int(nav2["GpsUtcYr_No_Actl"])
|
||||||
|
month = int(nav2["GpsUtcMnth_No_Actl"])
|
||||||
|
day = int(nav2["GpsUtcDay_No_Actl"])
|
||||||
|
hour = int(nav2["GPS_UTC_hours"])
|
||||||
|
minute = int(nav2["GPS_UTC_minutes"])
|
||||||
|
second = int(nav2["GPS_UTC_seconds"])
|
||||||
|
try:
|
||||||
|
timestamp_ms = int(datetime(year, month, day, hour, minute, second, tzinfo=UTC).timestamp() * 1000)
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
latitude_direction = int(nav1["GpsHsphLattSth_D_Actl"])
|
||||||
|
longitude_direction = int(nav1["GpsHsphLongEast_D_Actl"])
|
||||||
|
latitude_degrees = abs(float(nav1["GPS_Latitude_Degrees"]))
|
||||||
|
longitude_degrees = abs(float(nav1["GPS_Longitude_Degrees"]))
|
||||||
|
latitude_minutes = float(nav1["GPS_Latitude_Minutes"]) + float(nav1["GPS_Latitude_Min_dec"])
|
||||||
|
longitude_minutes = float(nav1["GPS_Longitude_Minutes"]) + float(nav1["GPS_Longitude_Min_dec"])
|
||||||
|
|
||||||
|
coordinates_valid = (
|
||||||
|
latitude_direction in (1, 2) and longitude_direction in (1, 2) and
|
||||||
|
0.0 <= latitude_degrees <= 90.0 and 0.0 <= longitude_degrees <= 180.0 and
|
||||||
|
0.0 <= latitude_minutes < 60.0 and 0.0 <= longitude_minutes < 60.0
|
||||||
|
)
|
||||||
|
latitude = (1.0 if latitude_direction == 2 else -1.0) * (latitude_degrees + latitude_minutes / 60.0) if coordinates_valid else 0.0
|
||||||
|
longitude = (1.0 if longitude_direction == 1 else -1.0) * (longitude_degrees + longitude_minutes / 60.0) if coordinates_valid else 0.0
|
||||||
|
|
||||||
|
dimension = int(nav3["GPS_dimension"])
|
||||||
|
has_fix = coordinates_valid and dimension in (1, 2) and int(nav2["Gps_B_Falt"]) == 0
|
||||||
|
|
||||||
|
speed_mph = float(nav3["GPS_Speed"])
|
||||||
|
speed_mps = speed_mph * CV.MPH_TO_MS
|
||||||
|
heading = float(nav3["GPS_Heading"])
|
||||||
|
if speed_mph in (254.0, 255.0) or not math.isfinite(speed_mps) or not 0.0 <= speed_mps <= 200.0:
|
||||||
|
speed_mps = 0.0
|
||||||
|
if not math.isfinite(heading) or not 0.0 <= heading < 360.0:
|
||||||
|
heading = 0.0
|
||||||
|
|
||||||
|
vertical_accuracy = _dop_accuracy(float(nav3["GPS_Vdop"]))
|
||||||
|
horizontal_accuracy = _dop_accuracy(float(nav3["GPS_Hdop"]))
|
||||||
|
satellite_count = int(nav3["GPS_Sat_num_in_view"])
|
||||||
|
if not 0 <= satellite_count < 30: # 30 and 31 are Ford's unknown/invalid values.
|
||||||
|
satellite_count = 0
|
||||||
|
|
||||||
|
heading_rad = math.radians(heading)
|
||||||
|
return {
|
||||||
|
"latitude": latitude,
|
||||||
|
"longitude": longitude,
|
||||||
|
"altitude": (float(nav3["GPS_MSL_altitude"]) * 0.3048) if has_fix else 0.0,
|
||||||
|
"speed": speed_mps,
|
||||||
|
"bearingDeg": heading,
|
||||||
|
"horizontalAccuracy": horizontal_accuracy,
|
||||||
|
"unixTimestampMillis": timestamp_ms,
|
||||||
|
"verticalAccuracy": vertical_accuracy,
|
||||||
|
"bearingAccuracyDeg": max(5.0, horizontal_accuracy * 2.0) if speed_mps > 1.0 else 180.0,
|
||||||
|
"speedAccuracy": max(0.5, horizontal_accuracy),
|
||||||
|
"hasFix": has_fix,
|
||||||
|
"satelliteCount": satellite_count,
|
||||||
|
"vNED": [speed_mps * math.cos(heading_rad), speed_mps * math.sin(heading_rad), 0.0],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def parse_chevrolet_bolt_can_gps(position: Mapping[str, float]) -> CarGpsSample | None:
|
||||||
|
"""Decode the Bolt's OnStar GPS position message."""
|
||||||
|
try:
|
||||||
|
latitude = float(position["GPSLatitude"]) / 3_600_000.0
|
||||||
|
longitude = float(position["GPSLongitude"]) / 3_600_000.0
|
||||||
|
except (KeyError, TypeError, ValueError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
coordinates_valid = (
|
||||||
|
math.isfinite(latitude) and math.isfinite(longitude) and
|
||||||
|
-90.0 <= latitude <= 90.0 and -180.0 <= longitude <= 180.0 and
|
||||||
|
(latitude != 0.0 or longitude != 0.0)
|
||||||
|
)
|
||||||
|
if not coordinates_valid:
|
||||||
|
latitude = longitude = 0.0
|
||||||
|
|
||||||
|
return {
|
||||||
|
"latitude": latitude,
|
||||||
|
"longitude": longitude,
|
||||||
|
"altitude": 0.0,
|
||||||
|
"speed": 0.0,
|
||||||
|
"bearingDeg": 0.0,
|
||||||
|
"horizontalAccuracy": 100.0,
|
||||||
|
"unixTimestampMillis": int(datetime.now(UTC).timestamp() * 1000),
|
||||||
|
"verticalAccuracy": 100.0,
|
||||||
|
"bearingAccuracyDeg": 180.0,
|
||||||
|
"speedAccuracy": 100.0,
|
||||||
|
"hasFix": coordinates_valid,
|
||||||
|
"satelliteCount": 0,
|
||||||
|
"vNED": [0.0, 0.0, 0.0],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FORD_MACH_E_GPS_MESSAGES = (
|
||||||
|
"APIMGPS_Data_Nav_1_FD1",
|
||||||
|
"APIMGPS_Data_Nav_2_FD1",
|
||||||
|
"APIMGPS_Data_Nav_3_FD1",
|
||||||
|
)
|
||||||
|
CHEVROLET_BOLT_GPS_MESSAGES = ("TCICOnStarGPSPosition",)
|
||||||
|
|
||||||
|
CHEVROLET_BOLT_GPS_CARS = (
|
||||||
|
GM_CAR.CHEVROLET_BOLT_ACC_2022_2023,
|
||||||
|
GM_CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
|
||||||
|
GM_CAR.CHEVROLET_BOLT_CC_2022_2023,
|
||||||
|
GM_CAR.CHEVROLET_BOLT_CC_2018_2021,
|
||||||
|
GM_CAR.CHEVROLET_BOLT_CC_2017,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
CAR_GPS_CONFIGS: dict[str, CarGpsConfig] = {
|
||||||
|
FORD_CAR.FORD_MUSTANG_MACH_E_MK1: CarGpsConfig(
|
||||||
|
brand="ford",
|
||||||
|
messages=FORD_MACH_E_GPS_MESSAGES,
|
||||||
|
decoder=parse_ford_can_gps,
|
||||||
|
),
|
||||||
|
**{
|
||||||
|
car: CarGpsConfig(
|
||||||
|
brand="gm",
|
||||||
|
messages=CHEVROLET_BOLT_GPS_MESSAGES,
|
||||||
|
decoder=parse_chevrolet_bolt_can_gps,
|
||||||
|
)
|
||||||
|
for car in CHEVROLET_BOLT_GPS_CARS
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_car_gps_config(CP) -> CarGpsConfig | None:
|
||||||
|
config = CAR_GPS_CONFIGS.get(CP.carFingerprint)
|
||||||
|
return config if config is not None and config.brand == CP.brand else None
|
||||||
|
|
||||||
|
|
||||||
|
def car_gps_available(CP) -> bool:
|
||||||
|
return get_car_gps_config(CP) is not None
|
||||||
@@ -7,6 +7,7 @@ from opendbc.car.honda import hondacan
|
|||||||
from opendbc.car.honda.values import (
|
from opendbc.car.honda.values import (
|
||||||
CAR,
|
CAR,
|
||||||
CruiseButtons,
|
CruiseButtons,
|
||||||
|
CruiseSettings,
|
||||||
HONDA_BOSCH,
|
HONDA_BOSCH,
|
||||||
HONDA_BOSCH_CANFD,
|
HONDA_BOSCH_CANFD,
|
||||||
HONDA_BOSCH_RADARLESS,
|
HONDA_BOSCH_RADARLESS,
|
||||||
@@ -16,6 +17,7 @@ from opendbc.car.honda.values import (
|
|||||||
HondaFlags,
|
HondaFlags,
|
||||||
)
|
)
|
||||||
from opendbc.car.interfaces import CarControllerBase
|
from opendbc.car.interfaces import CarControllerBase
|
||||||
|
from opendbc.car.common.pid import PIDController
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
|
|
||||||
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
||||||
@@ -211,6 +213,14 @@ class CarController(CarControllerBase):
|
|||||||
self.CAN = hondacan.CanBus(CP)
|
self.CAN = hondacan.CanBus(CP)
|
||||||
self.tja_control = CP.carFingerprint in HONDA_BOSCH_TJA_CONTROL
|
self.tja_control = CP.carFingerprint in HONDA_BOSCH_TJA_CONTROL
|
||||||
|
|
||||||
|
# MVL CAN-FD ownership state. These do not affect non-CANFD vehicles.
|
||||||
|
self.radar_disable_counter = 0
|
||||||
|
self.radar_mux = 0
|
||||||
|
self.radar_hud_pulse = 0
|
||||||
|
self.last_acc_enabled = False
|
||||||
|
self.lkas_button_send_remaining = 0
|
||||||
|
self.last_lkas_button_frame = 0
|
||||||
|
|
||||||
self.braking = False
|
self.braking = False
|
||||||
self.brake_steady = 0.0
|
self.brake_steady = 0.0
|
||||||
self.brake_last = 0.0
|
self.brake_last = 0.0
|
||||||
@@ -234,6 +244,10 @@ class CarController(CarControllerBase):
|
|||||||
self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor
|
self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor
|
||||||
self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor
|
self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor
|
||||||
self.pitch = 0.0
|
self.pitch = 0.0
|
||||||
|
self.mvl_accord_mode = CP.carFingerprint == CAR.HONDA_ACCORD_11G
|
||||||
|
# MVL Bosch low-speed extra-brake integrator. Active only for Accord 11G MVL mode.
|
||||||
|
self.mvl_brake_pid = PIDController(k_p=0.0, k_i=1.0, pos_limit=0.0, neg_limit=-2.0, rate=50)
|
||||||
|
self.mvl_brake_pid.reset()
|
||||||
|
|
||||||
def _modified_civic_standard_active(self) -> bool:
|
def _modified_civic_standard_active(self) -> bool:
|
||||||
return self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH and bool(self.CP.flags & HondaFlags.EPS_MODIFIED)
|
return self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH and bool(self.CP.flags & HondaFlags.EPS_MODIFIED)
|
||||||
@@ -255,6 +269,7 @@ class CarController(CarControllerBase):
|
|||||||
hud_v_cruise = hud_control.setSpeed / CS.v_cruise_factor if hud_control.speedVisible else 255
|
hud_v_cruise = hud_control.setSpeed / CS.v_cruise_factor if hud_control.speedVisible else 255
|
||||||
pcm_cancel_cmd = CC.cruiseControl.cancel
|
pcm_cancel_cmd = CC.cruiseControl.cancel
|
||||||
gas_interceptor_command = 0.0
|
gas_interceptor_command = 0.0
|
||||||
|
min_gas = self.params.BOSCH_GAS_LOOKUP_BP[0]
|
||||||
if len(CC.orientationNED) == 3:
|
if len(CC.orientationNED) == 3:
|
||||||
self.pitch = CC.orientationNED[1]
|
self.pitch = CC.orientationNED[1]
|
||||||
hill_brake = math.sin(self.pitch) * ACCELERATION_DUE_TO_GRAVITY
|
hill_brake = math.sin(self.pitch) * ACCELERATION_DUE_TO_GRAVITY
|
||||||
@@ -308,11 +323,56 @@ class CarController(CarControllerBase):
|
|||||||
# Send CAN commands
|
# Send CAN commands
|
||||||
can_sends = []
|
can_sends = []
|
||||||
|
|
||||||
# tester present - w/ no response (keeps radar disabled)
|
# Bosch radar ownership. On CAN-FD, leave the stock radar active until the comma relay is open,
|
||||||
|
# then enter extended diagnostics and disable radar RX/TX. This prevents a gap between stock
|
||||||
|
# ACC_CONTROL disappearing and panda permitting openpilot's replacement stream.
|
||||||
if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and self.CP.openpilotLongitudinalControl:
|
if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and self.CP.openpilotLongitudinalControl:
|
||||||
if self.frame % 10 == 0:
|
if self.mvl_accord_mode and CS.stock_acc_alive:
|
||||||
|
if CS.canfd_relay_open:
|
||||||
|
if self.radar_disable_counter % 50 == 0:
|
||||||
|
can_sends.append((0x18DAB0F1, b'\x02\x10\x03\x00\x00\x00\x00\x00', self.CAN.pt))
|
||||||
|
elif self.radar_disable_counter % 50 == 5:
|
||||||
|
can_sends.append((0x18DAB0F1, b'\x03\x28\x83\x03\x00\x00\x00\x00', self.CAN.pt))
|
||||||
|
self.radar_disable_counter += 1
|
||||||
|
elif self.frame % 10 == 0:
|
||||||
can_sends.append(make_tester_present_msg(0x18DAB0F1, self.CAN.pt, suppress_response=True))
|
can_sends.append(make_tester_present_msg(0x18DAB0F1, self.CAN.pt, suppress_response=True))
|
||||||
|
|
||||||
|
# After the stock CAN-FD radar is silent, reproduce its low-rate/tick-aligned messages on both
|
||||||
|
# the PT and camera sides of the open relay. Pack once and mirror identical bytes so counters and
|
||||||
|
# checksums stay synchronized. v3 deliberately uses an idle lane/object payload first; model-based
|
||||||
|
# cluster rendering is deferred until the ownership/DTC handover is proven.
|
||||||
|
mvl_radar_owned = self.mvl_accord_mode and CS.canfd_relay_open and not CS.stock_acc_alive
|
||||||
|
if mvl_radar_owned and self.CP.openpilotLongitudinalControl:
|
||||||
|
if CC.enabled and not self.last_acc_enabled:
|
||||||
|
self.radar_hud_pulse = 30
|
||||||
|
self.last_acc_enabled = CC.enabled
|
||||||
|
|
||||||
|
radar_msgs = []
|
||||||
|
if CS.hud_tick:
|
||||||
|
radar_msgs.append(hondacan.create_radar_hud_canfd(self.packer, self.CAN.pt, CC.enabled, self.radar_hud_pulse > 0))
|
||||||
|
if self.radar_hud_pulse > 0:
|
||||||
|
self.radar_hud_pulse -= 1
|
||||||
|
if CS.supp_tick:
|
||||||
|
radar_msgs.append(hondacan.create_canfd_supplemental(self.packer, self.CAN.pt))
|
||||||
|
if CS.radar_50hz_tick:
|
||||||
|
if self.radar_mux >= 58:
|
||||||
|
self.radar_mux = 1
|
||||||
|
elif self.radar_mux == 10:
|
||||||
|
self.radar_mux = 17
|
||||||
|
elif self.radar_mux == 26:
|
||||||
|
self.radar_mux = 33
|
||||||
|
elif self.radar_mux == 42:
|
||||||
|
self.radar_mux = 49
|
||||||
|
else:
|
||||||
|
self.radar_mux += 1
|
||||||
|
radar_msgs.extend(hondacan.create_canfd_50hz_radar_messages(self.packer, self.CAN.pt, self.radar_mux))
|
||||||
|
if CS.radar_5hz_tick:
|
||||||
|
radar_msgs.extend(hondacan.create_canfd_5hz_radar_messages(self.packer, self.CAN.pt, CS.radar_ref_counter))
|
||||||
|
|
||||||
|
for addr, dat, _ in radar_msgs:
|
||||||
|
can_sends.append((addr, dat, self.CAN.pt))
|
||||||
|
can_sends.append((addr, dat, self.CAN.camera))
|
||||||
|
|
||||||
# Send steering command.
|
# Send steering command.
|
||||||
can_sends.append(hondacan.create_steering_control(self.packer, self.CAN, apply_torque, CC.latActive, self.tja_control))
|
can_sends.append(hondacan.create_steering_control(self.packer, self.CAN, apply_torque, CC.latActive, self.tja_control))
|
||||||
|
|
||||||
@@ -352,23 +412,37 @@ class CarController(CarControllerBase):
|
|||||||
ts = self.frame * DT_CTRL
|
ts = self.frame * DT_CTRL
|
||||||
|
|
||||||
if self.CP.carFingerprint in HONDA_BOSCH:
|
if self.CP.carFingerprint in HONDA_BOSCH:
|
||||||
self.accel = float(np.clip(accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX))
|
if self.mvl_accord_mode and (accel < min_gas) and (1e-3 < CS.out.vEgo < 3.0):
|
||||||
gas_pedal_force = self.accel + hill_brake
|
brake_addon = self.mvl_brake_pid.update(error=accel - CS.out.aEgo, speed=CS.out.vEgo)
|
||||||
|
target_accel = min(accel, accel + brake_addon)
|
||||||
|
else:
|
||||||
|
if self.mvl_accord_mode:
|
||||||
|
self.mvl_brake_pid.reset()
|
||||||
|
target_accel = accel
|
||||||
|
|
||||||
|
self.accel = float(np.clip(target_accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX))
|
||||||
|
# MVL uses requested accel (not extra-brake-adjusted accel) to decide propulsion crossover.
|
||||||
|
gas_pedal_force = (accel if self.mvl_accord_mode else self.accel) + hill_brake
|
||||||
|
|
||||||
if self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS:
|
if self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS:
|
||||||
gas_pedal_force += wind_brake_mps2 * self.bosch_wind_factor
|
gas_pedal_force += wind_brake_mps2 * self.bosch_wind_factor
|
||||||
|
|
||||||
if actuators.longControlState == LongCtrlState.pid and not CS.out.gasPressed:
|
if actuators.longControlState == LongCtrlState.pid and not CS.out.gasPressed:
|
||||||
gas_error = self.accel - CS.out.aEgo
|
gas_error = (accel if self.mvl_accord_mode else self.accel) - CS.out.aEgo
|
||||||
|
|
||||||
if gas_error != 0.0 and gas_pedal_force > 0.0:
|
if gas_error != 0.0 and gas_pedal_force > min_gas:
|
||||||
if self.CP.carFingerprint == CAR.HONDA_INSIGHT:
|
if self.CP.carFingerprint == CAR.HONDA_INSIGHT:
|
||||||
gas_learn_speed = 150.0
|
gas_learn_speed = 150.0
|
||||||
elif self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR):
|
elif self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR):
|
||||||
gas_learn_speed = 300.0
|
gas_learn_speed = 300.0
|
||||||
else:
|
else:
|
||||||
gas_learn_speed = 50.0
|
gas_learn_speed = 50.0
|
||||||
self.bosch_gas_factor = float(np.clip(self.bosch_gas_factor + gas_error / gas_learn_speed * gas_pedal_force, 0.1, 3.0))
|
gas_factor_floor = 0.01 if self.mvl_accord_mode else 0.1
|
||||||
|
gas_learn_force = (gas_pedal_force - min_gas) if self.mvl_accord_mode else gas_pedal_force
|
||||||
|
self.bosch_gas_factor = float(np.clip(
|
||||||
|
self.bosch_gas_factor + gas_error / gas_learn_speed * gas_learn_force,
|
||||||
|
gas_factor_floor, 3.0,
|
||||||
|
))
|
||||||
|
|
||||||
if gas_error != 0.0 and not CS.out.brakePressed and CS.out.vEgo > 0.0:
|
if gas_error != 0.0 and not CS.out.brakePressed and CS.out.vEgo > 0.0:
|
||||||
wind_learn_speed = 100.0 if self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR) else 1000.0
|
wind_learn_speed = 100.0 if self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR) else 1000.0
|
||||||
@@ -378,7 +452,8 @@ class CarController(CarControllerBase):
|
|||||||
else:
|
else:
|
||||||
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor / wind_adjust, 0.1, 3.0))
|
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor / wind_adjust, 0.1, 3.0))
|
||||||
|
|
||||||
if gas_pedal_force <= 0.0:
|
wind_brake_threshold = min_gas if self.mvl_accord_mode else 0.0
|
||||||
|
if gas_pedal_force <= wind_brake_threshold:
|
||||||
self.bosch_wind_factor = max(self.bosch_wind_factor, self.bosch_wind_factor_before_brake)
|
self.bosch_wind_factor = max(self.bosch_wind_factor, self.bosch_wind_factor_before_brake)
|
||||||
else:
|
else:
|
||||||
self.bosch_wind_factor_before_brake = self.bosch_wind_factor
|
self.bosch_wind_factor_before_brake = self.bosch_wind_factor
|
||||||
@@ -390,15 +465,21 @@ class CarController(CarControllerBase):
|
|||||||
self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor
|
self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor
|
||||||
self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor
|
self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor
|
||||||
|
|
||||||
self.gas = float(np.interp(gas_pedal_force * self.bosch_gas_factor, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V))
|
gas_lookup_input = ((gas_pedal_force - min_gas) * self.bosch_gas_factor + min_gas) if self.mvl_accord_mode else \
|
||||||
|
gas_pedal_force * self.bosch_gas_factor
|
||||||
|
self.gas = float(np.interp(gas_lookup_input, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V))
|
||||||
self.gas = min(self.gas, max(60.0, self.bosch_last_gas + 60.0))
|
self.gas = min(self.gas, max(60.0, self.bosch_last_gas + 60.0))
|
||||||
self.bosch_last_gas = self.gas
|
self.bosch_last_gas = self.gas
|
||||||
|
|
||||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||||
self.stopping_counter = self.stopping_counter + 1 if stopping else 0
|
self.stopping_counter = self.stopping_counter + 1 if stopping else 0
|
||||||
can_sends.extend(
|
if not self.mvl_accord_mode or mvl_radar_owned:
|
||||||
hondacan.create_acc_commands(self.packer, self.CAN, CC.enabled, CC.longActive, self.accel, self.gas, self.stopping_counter, self.CP.carFingerprint)
|
can_sends.extend(
|
||||||
)
|
hondacan.create_acc_commands(
|
||||||
|
self.packer, self.CAN, CC.enabled, CC.longActive, self.accel, self.gas, self.stopping_counter, self.CP,
|
||||||
|
gas_force=gas_pedal_force if self.mvl_accord_mode else None,
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
apply_brake = np.clip(self.brake_last - wind_brake, 0.0, 1.0)
|
apply_brake = np.clip(self.brake_last - wind_brake, 0.0, 1.0)
|
||||||
apply_brake = int(np.clip(apply_brake * self.params.NIDEC_BRAKE_MAX, 0, self.params.NIDEC_BRAKE_MAX - 1))
|
apply_brake = int(np.clip(apply_brake * self.params.NIDEC_BRAKE_MAX, 0, self.params.NIDEC_BRAKE_MAX - 1))
|
||||||
@@ -440,9 +521,16 @@ class CarController(CarControllerBase):
|
|||||||
idx = (self.frame // 2) % 0x10
|
idx = (self.frame // 2) % 0x10
|
||||||
can_sends.append(create_gas_interceptor_command(self.packer, gas_interceptor_command, idx))
|
can_sends.append(create_gas_interceptor_command(self.packer, gas_interceptor_command, idx))
|
||||||
|
|
||||||
# Send dashboard UI commands.
|
# Send dashboard UI commands. On CAN-FD, ACC_HUD is owned by the radar and must only start
|
||||||
|
# after the handover, aligned to the radar's 10 Hz HUD tick.
|
||||||
|
if (mvl_radar_owned and CS.hud_tick and self.CP.openpilotLongitudinalControl):
|
||||||
|
can_sends.append(
|
||||||
|
hondacan.create_acc_hud(self.packer, self.CAN.pt, self.CP, CC.enabled, pcm_speed, actuators.accel,
|
||||||
|
hud_control, hud_v_cruise, CS.is_metric, CS.acc_hud)
|
||||||
|
)
|
||||||
|
|
||||||
if self.frame % 10 == 0:
|
if self.frame % 10 == 0:
|
||||||
if self.CP.openpilotLongitudinalControl:
|
if self.CP.openpilotLongitudinalControl and not self.mvl_accord_mode:
|
||||||
# On Nidec, this also controls longitudinal positive acceleration
|
# On Nidec, this also controls longitudinal positive acceleration
|
||||||
can_sends.append(
|
can_sends.append(
|
||||||
hondacan.create_acc_hud(self.packer, self.CAN.pt, self.CP, CC.enabled, pcm_speed, pcm_accel, hud_control, hud_v_cruise, CS.is_metric, CS.acc_hud)
|
hondacan.create_acc_hud(self.packer, self.CAN.pt, self.CP, CC.enabled, pcm_speed, pcm_accel, hud_control, hud_v_cruise, CS.is_metric, CS.acc_hud)
|
||||||
@@ -458,7 +546,7 @@ class CarController(CarControllerBase):
|
|||||||
|
|
||||||
if self.CP.openpilotLongitudinalControl:
|
if self.CP.openpilotLongitudinalControl:
|
||||||
# TODO: combining with create_acc_hud block above will change message order and will need replay logs regenerated
|
# TODO: combining with create_acc_hud block above will change message order and will need replay logs regenerated
|
||||||
if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS):
|
if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS - {CAR.HONDA_ACCORD_11G}):
|
||||||
can_sends.append(hondacan.create_radar_hud(self.packer, self.CAN.pt))
|
can_sends.append(hondacan.create_radar_hud(self.packer, self.CAN.pt))
|
||||||
if self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH:
|
if self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH:
|
||||||
can_sends.append(hondacan.create_legacy_brake_command(self.packer, self.CAN.pt))
|
can_sends.append(hondacan.create_legacy_brake_command(self.packer, self.CAN.pt))
|
||||||
@@ -469,6 +557,29 @@ class CarController(CarControllerBase):
|
|||||||
else:
|
else:
|
||||||
self.gas = pcm_accel / self.params.NIDEC_GAS_MAX
|
self.gas = pcm_accel / self.params.NIDEC_GAS_MAX
|
||||||
|
|
||||||
|
# CAN-FD: while engaged, the camera still needs a valid SCM_BUTTONS stream behind the open relay.
|
||||||
|
# Take over that stream, echoing the live ambient-light byte. Also send a short LKAS-setting pulse
|
||||||
|
# when stock LKAS is ready, matching MVL's workaround for the Honda touch-steering-wheel timer.
|
||||||
|
if (self.mvl_accord_mode and CC.enabled and self.frame % 4 == 0
|
||||||
|
and not pcm_cancel_cmd and not CC.cruiseControl.resume):
|
||||||
|
if (self.lkas_button_send_remaining == 0 and CS.lkas_hud["LKAS_READY"]
|
||||||
|
and self.frame >= self.last_lkas_button_frame + 500):
|
||||||
|
self.lkas_button_send_remaining = 3
|
||||||
|
|
||||||
|
if self.lkas_button_send_remaining > 0:
|
||||||
|
self.last_lkas_button_frame = self.frame
|
||||||
|
self.lkas_button_send_remaining -= 1
|
||||||
|
cruise_setting = CruiseSettings.LKAS
|
||||||
|
elif CS.cruise_setting == CruiseSettings.LKAS:
|
||||||
|
cruise_setting = 0
|
||||||
|
else:
|
||||||
|
cruise_setting = CS.cruise_setting
|
||||||
|
|
||||||
|
can_sends.append(hondacan.spam_buttons_command(
|
||||||
|
self.packer, self.CAN, CS.cruise_buttons, self.CP.carFingerprint,
|
||||||
|
cruise_setting=cruise_setting, ambient_light=CS.scm_ambient_light, bus=self.CAN.camera,
|
||||||
|
))
|
||||||
|
|
||||||
if self.frame > 0 and self.frame % 6000 == 0:
|
if self.frame > 0 and self.frame % 6000 == 0:
|
||||||
self.param_store.put_float("HondaGasFactorParams", self.bosch_gas_factor)
|
self.param_store.put_float("HondaGasFactorParams", self.bosch_gas_factor)
|
||||||
self.param_store.put_float("HondaWindFactorParams", self.bosch_wind_factor)
|
self.param_store.put_float("HondaWindFactorParams", self.bosch_wind_factor)
|
||||||
|
|||||||
@@ -68,11 +68,33 @@ class CarState(CarStateBase):
|
|||||||
self.initial_accFault_cleared = False
|
self.initial_accFault_cleared = False
|
||||||
self.initial_accFault_cleared_timer = int(10 / DT_CTRL)
|
self.initial_accFault_cleared_timer = int(10 / DT_CTRL)
|
||||||
|
|
||||||
|
# CAN-FD deferred radar handover state. The stock radar remains responsible for ACC_CONTROL
|
||||||
|
# until the relay is open and the controller has silenced it; radar reference/tick messages are
|
||||||
|
# used to keep the replacement radar look-alikes on the stock cadence after the handover.
|
||||||
|
self.radar_ref_counter = 0
|
||||||
|
self.radar_5hz_tick_counter = 0
|
||||||
|
self.radar_5hz_tick = False
|
||||||
|
self.supp_tick_counter = 0
|
||||||
|
self.supp_tick = False
|
||||||
|
self.hud_tick_counter = 0
|
||||||
|
self.hud_tick = False
|
||||||
|
self.radar_50hz_tick_counter = 0
|
||||||
|
self.radar_50hz_tick = False
|
||||||
|
self.scm_ambient_light = 0
|
||||||
|
self.stock_acc_counter = 0
|
||||||
|
self.stock_acc_alive = False
|
||||||
|
self.camera_steer_counter = 0
|
||||||
|
self.camera_steer_seen = False
|
||||||
|
self.canfd_frames = 0
|
||||||
|
self.canfd_relay_open = False
|
||||||
|
|
||||||
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
|
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
|
||||||
cp = can_parsers[Bus.pt]
|
cp = can_parsers[Bus.pt]
|
||||||
cp_cam = can_parsers[Bus.cam]
|
cp_cam = can_parsers[Bus.cam]
|
||||||
if self.CP.enableBsm:
|
if self.CP.enableBsm:
|
||||||
cp_body = can_parsers[Bus.body]
|
cp_body = can_parsers[Bus.body]
|
||||||
|
if self.CP.carFingerprint == CAR.HONDA_ACCORD_11G:
|
||||||
|
cp_radar = can_parsers[Bus.radar]
|
||||||
|
|
||||||
ret = structs.CarState()
|
ret = structs.CarState()
|
||||||
|
|
||||||
@@ -85,6 +107,10 @@ class CarState(CarStateBase):
|
|||||||
prev_cruise_setting = self.cruise_setting
|
prev_cruise_setting = self.cruise_setting
|
||||||
self.cruise_setting = cp.vl["SCM_BUTTONS"]["CRUISE_SETTING"]
|
self.cruise_setting = cp.vl["SCM_BUTTONS"]["CRUISE_SETTING"]
|
||||||
self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"]
|
self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"]
|
||||||
|
if self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | {CAR.HONDA_ACCORD_11G}):
|
||||||
|
# The camera consumes this byte in SCM_BUTTONS too (adaptive high beam); preserve it when
|
||||||
|
# openpilot temporarily takes over SCM_BUTTONS toward the camera.
|
||||||
|
self.scm_ambient_light = cp.vl["SCM_BUTTONS"]["AMBIENT_LIGHT_MAYBE"]
|
||||||
|
|
||||||
# used for car hud message
|
# used for car hud message
|
||||||
self.is_metric = self.CP.carFingerprint in (CAR.HONDA_ODYSSEY_TWN,) or not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
|
self.is_metric = self.CP.carFingerprint in (CAR.HONDA_ODYSSEY_TWN,) or not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
|
||||||
@@ -116,8 +142,8 @@ class CarState(CarStateBase):
|
|||||||
steer_status = self.steer_status_values[cp.vl["STEER_STATUS"]["STEER_STATUS"]]
|
steer_status = self.steer_status_values[cp.vl["STEER_STATUS"]["STEER_STATUS"]]
|
||||||
ret.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TJA_LOW_SPEED_LOCKOUT",
|
ret.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TJA_LOW_SPEED_LOCKOUT",
|
||||||
"TMP_FAULT")
|
"TMP_FAULT")
|
||||||
if self.CP.carFingerprint in HONDA_BOSCH_ALT_RADAR:
|
if self.CP.carFingerprint in (HONDA_BOSCH_ALT_RADAR | {CAR.HONDA_ACCORD_11G}):
|
||||||
# TODO: See if this logic works for all other Honda
|
# MVL treats CAN-FD low-speed lockout as an expected EPS state too.
|
||||||
min_steer_speed = max(CarControllerParams.STEER_GLOBAL_MIN_SPEED, self.CP.minSteerSpeed)
|
min_steer_speed = max(CarControllerParams.STEER_GLOBAL_MIN_SPEED, self.CP.minSteerSpeed)
|
||||||
expected_low_speed_lockout = steer_status == "LOW_SPEED_LOCKOUT" and ret.vEgo < min_steer_speed
|
expected_low_speed_lockout = steer_status == "LOW_SPEED_LOCKOUT" and ret.vEgo < min_steer_speed
|
||||||
ret.steerFaultTemporary = steer_status != "NORMAL" and not expected_low_speed_lockout
|
ret.steerFaultTemporary = steer_status != "NORMAL" and not expected_low_speed_lockout
|
||||||
@@ -201,17 +227,18 @@ class CarState(CarStateBase):
|
|||||||
if self.CP.flags & HondaFlags.BOSCH_ALT_BRAKE:
|
if self.CP.flags & HondaFlags.BOSCH_ALT_BRAKE:
|
||||||
ret.brakePressed = cp.vl["BRAKE_MODULE"]["BRAKE_PRESSED"] != 0
|
ret.brakePressed = cp.vl["BRAKE_MODULE"]["BRAKE_PRESSED"] != 0
|
||||||
else:
|
else:
|
||||||
|
powertrain_data = cp.vl["POWERTRAIN_DATA"]
|
||||||
# brake switch has shown some single time step noise, so only considered when
|
# brake switch has shown some single time step noise, so only considered when
|
||||||
# switch is on for at least 2 consecutive CAN samples
|
# switch is on for at least 2 consecutive CAN samples
|
||||||
# brake switch rises earlier than brake pressed but is never 1 when in park
|
# brake switch rises earlier than brake pressed but is never 1 when in park
|
||||||
brake_switch_vals = cp.vl_all["POWERTRAIN_DATA"]["BRAKE_SWITCH"]
|
brake_switch_vals = cp.vl_all["POWERTRAIN_DATA"]["BRAKE_SWITCH"]
|
||||||
if len(brake_switch_vals):
|
if len(brake_switch_vals):
|
||||||
brake_switch = cp.vl["POWERTRAIN_DATA"]["BRAKE_SWITCH"] != 0
|
brake_switch = powertrain_data["BRAKE_SWITCH"] != 0
|
||||||
if len(brake_switch_vals) > 1:
|
if len(brake_switch_vals) > 1:
|
||||||
self.brake_switch_prev = brake_switch_vals[-2] != 0
|
self.brake_switch_prev = brake_switch_vals[-2] != 0
|
||||||
self.brake_switch_active = brake_switch and self.brake_switch_prev
|
self.brake_switch_active = brake_switch and self.brake_switch_prev
|
||||||
self.brake_switch_prev = brake_switch
|
self.brake_switch_prev = brake_switch
|
||||||
ret.brakePressed = (cp.vl["POWERTRAIN_DATA"]["BRAKE_PRESSED"] != 0) or self.brake_switch_active
|
ret.brakePressed = (powertrain_data["BRAKE_PRESSED"] != 0) or self.brake_switch_active
|
||||||
|
|
||||||
ret.brake = cp.vl["VSA_STATUS"]["USER_BRAKE"]
|
ret.brake = cp.vl["VSA_STATUS"]["USER_BRAKE"]
|
||||||
ret.cruiseState.enabled = cp.vl["POWERTRAIN_DATA"]["ACC_STATUS"] != 0
|
ret.cruiseState.enabled = cp.vl["POWERTRAIN_DATA"]["ACC_STATUS"] != 0
|
||||||
@@ -248,6 +275,63 @@ class CarState(CarStateBase):
|
|||||||
if self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_CANFD):
|
if self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_CANFD):
|
||||||
self.lkas_hud = cp_cam.vl["LKAS_HUD"]
|
self.lkas_hud = cp_cam.vl["LKAS_HUD"]
|
||||||
|
|
||||||
|
if self.CP.carFingerprint == CAR.HONDA_ACCORD_11G:
|
||||||
|
# Phase replacement radar messages from the stock radar's tick references. CarState reads the
|
||||||
|
# tick in one 100 Hz cycle and CarController transmits on the next, so pulse one frame before
|
||||||
|
# the expected next stock tick.
|
||||||
|
self.radar_ref_counter = cp.vl["RADAR_REFERENCE"]["COUNTER"]
|
||||||
|
|
||||||
|
ref_tick_vals = cp.vl_all.get("RADAR_REFERENCE", {}).get("COUNTER", [])
|
||||||
|
if len(ref_tick_vals) > 0:
|
||||||
|
self.radar_5hz_tick_counter = 0
|
||||||
|
else:
|
||||||
|
self.radar_5hz_tick_counter += 1
|
||||||
|
self.radar_5hz_tick = self.radar_5hz_tick_counter == 11
|
||||||
|
|
||||||
|
supp_tick_vals = cp_radar.vl_all.get("RADAR_SUPP_TICK_REFERENCE", {}).get("IGNORE", [])
|
||||||
|
if len(supp_tick_vals) > 0:
|
||||||
|
self.supp_tick_counter = 0
|
||||||
|
else:
|
||||||
|
self.supp_tick_counter += 1
|
||||||
|
self.supp_tick = self.supp_tick_counter == 99
|
||||||
|
|
||||||
|
hud_tick_vals = cp_radar.vl_all.get("RADAR_HUD_TICK_REFERENCE", {}).get("IGNORE", [])
|
||||||
|
if len(hud_tick_vals) > 0:
|
||||||
|
self.hud_tick_counter = 0
|
||||||
|
else:
|
||||||
|
self.hud_tick_counter += 1
|
||||||
|
self.hud_tick = self.hud_tick_counter == 9
|
||||||
|
|
||||||
|
tick_50hz_vals = cp_radar.vl_all.get("RADAR_50HZ_TICK_REFERENCE", {}).get("IGNORE", [])
|
||||||
|
if len(tick_50hz_vals) > 0:
|
||||||
|
self.radar_50hz_tick_counter = 0
|
||||||
|
else:
|
||||||
|
self.radar_50hz_tick_counter += 1
|
||||||
|
self.radar_50hz_tick = self.radar_50hz_tick_counter == 1
|
||||||
|
|
||||||
|
# ACC_CONTROL is normally present every 2 frames. Keep treating the stock radar as alive until
|
||||||
|
# four consecutive frames have passed without it, preventing overlap between stock and OP ACC.
|
||||||
|
self.canfd_frames += 1
|
||||||
|
if len(cp.vl_all.get("ACC_CONTROL", {}).get("COUNTER", [])) > 0:
|
||||||
|
self.stock_acc_counter = 0
|
||||||
|
else:
|
||||||
|
self.stock_acc_counter += 1
|
||||||
|
self.stock_acc_alive = self.stock_acc_counter < 4
|
||||||
|
|
||||||
|
# Before the relay opens, the camera's STEERING_CONTROL is physically visible on PT. Once the
|
||||||
|
# relay opens it disappears. Fallback to 5 seconds in case the camera frame was never observed.
|
||||||
|
if len(cp.vl_all.get("STEERING_CONTROL", {}).get("COUNTER", [])) > 0:
|
||||||
|
self.camera_steer_counter = 0
|
||||||
|
self.camera_steer_seen = True
|
||||||
|
else:
|
||||||
|
self.camera_steer_counter += 1
|
||||||
|
self.canfd_relay_open = (self.camera_steer_seen and self.camera_steer_counter >= 5) or self.canfd_frames >= 500
|
||||||
|
else:
|
||||||
|
self.supp_tick = False
|
||||||
|
self.hud_tick = False
|
||||||
|
self.radar_5hz_tick = False
|
||||||
|
self.radar_50hz_tick = False
|
||||||
|
|
||||||
if self.CP.enableBsm:
|
if self.CP.enableBsm:
|
||||||
# BSM messages are on B-CAN, requires a panda forwarding B-CAN messages to CAN 0
|
# BSM messages are on B-CAN, requires a panda forwarding B-CAN messages to CAN 0
|
||||||
# more info here: https://github.com/commaai/openpilot/pull/1867
|
# more info here: https://github.com/commaai/openpilot/pull/1867
|
||||||
@@ -269,11 +353,27 @@ class CarState(CarStateBase):
|
|||||||
return ret, fp_ret
|
return ret, fp_ret
|
||||||
|
|
||||||
def get_can_parsers(self, CP):
|
def get_can_parsers(self, CP):
|
||||||
|
pt_messages = [("GAS_SENSOR", 0)] if CP.enableGasInterceptorDEPRECATED else []
|
||||||
|
if CP.carFingerprint == CAR.HONDA_ACCORD_11G:
|
||||||
|
# Both deliberately go silent during the handover, so skip alive/timeout checks.
|
||||||
|
pt_messages += [("ACC_CONTROL", float("nan")), ("STEERING_CONTROL", float("nan"))]
|
||||||
|
|
||||||
|
pt_parser = CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CanBus(CP).pt)
|
||||||
|
if CP.enableGasInterceptorDEPRECATED:
|
||||||
|
pt_parser.message_states[0x201].ignore_checksum = True
|
||||||
|
pt_parser.message_states[0x201].ignore_counter = True
|
||||||
|
|
||||||
parsers = {
|
parsers = {
|
||||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).pt),
|
Bus.pt: pt_parser,
|
||||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).camera),
|
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).camera),
|
||||||
}
|
}
|
||||||
if CP.enableBsm:
|
if CP.enableBsm:
|
||||||
parsers[Bus.body] = CANParser(DBC[CP.carFingerprint][Bus.body], [], CanBus(CP).radar)
|
parsers[Bus.body] = CANParser(DBC[CP.carFingerprint][Bus.body], [], CanBus(CP).radar)
|
||||||
|
if CP.carFingerprint == CAR.HONDA_ACCORD_11G:
|
||||||
|
parsers[Bus.radar] = CANParser(DBC[CP.carFingerprint][Bus.radar], [
|
||||||
|
("RADAR_SUPP_TICK_REFERENCE", 0),
|
||||||
|
("RADAR_HUD_TICK_REFERENCE", 0),
|
||||||
|
("RADAR_50HZ_TICK_REFERENCE", 0),
|
||||||
|
], CanBus(CP).radar)
|
||||||
|
|
||||||
return parsers
|
return parsers
|
||||||
|
|||||||
@@ -257,7 +257,6 @@ FW_VERSIONS = {
|
|||||||
(Ecu.eps, 0x18da30f1, None): [
|
(Ecu.eps, 0x18da30f1, None): [
|
||||||
b'39990-TBA-C120\x00\x00',
|
b'39990-TBA-C120\x00\x00',
|
||||||
b'39990-TBA-C020\x00\x00',
|
b'39990-TBA-C020\x00\x00',
|
||||||
b'39990-TBA-C120\x00\x00',
|
|
||||||
b'39990-TEA-T330\x00\x00',
|
b'39990-TEA-T330\x00\x00',
|
||||||
b'39990-TEA-T820\x00\x00',
|
b'39990-TEA-T820\x00\x00',
|
||||||
b'39990-TEZ-T020\x00\x00',
|
b'39990-TEZ-T020\x00\x00',
|
||||||
@@ -994,6 +993,7 @@ FW_VERSIONS = {
|
|||||||
b'36161-T47-A060\x00\x00',
|
b'36161-T47-A060\x00\x00',
|
||||||
b'36161-T47-A070\x00\x00',
|
b'36161-T47-A070\x00\x00',
|
||||||
b'8S102-T20-AA10\x00\x00',
|
b'8S102-T20-AA10\x00\x00',
|
||||||
|
b'8S102-T20-AA20\x00\x00',
|
||||||
b'8S102-T43-J540\x00\x00',
|
b'8S102-T43-J540\x00\x00',
|
||||||
b'8S102-T47-AA10\x00\x00',
|
b'8S102-T47-AA10\x00\x00',
|
||||||
b'8S102-T47-AA20\x00\x00',
|
b'8S102-T47-AA20\x00\x00',
|
||||||
@@ -1002,6 +1002,7 @@ FW_VERSIONS = {
|
|||||||
b'8S102-T56-A070\x00\x00',
|
b'8S102-T56-A070\x00\x00',
|
||||||
b'8S102-T60-AA10\x00\x00',
|
b'8S102-T60-AA10\x00\x00',
|
||||||
b'8S102-T64-A040\x00\x00',
|
b'8S102-T64-A040\x00\x00',
|
||||||
|
b'8S102-T64-A050\x00\x00',
|
||||||
],
|
],
|
||||||
(Ecu.vsa, 0x18da28f1, None): [
|
(Ecu.vsa, 0x18da28f1, None): [
|
||||||
b'57114-T20-AB40\x00\x00',
|
b'57114-T20-AB40\x00\x00',
|
||||||
@@ -1038,6 +1039,8 @@ FW_VERSIONS = {
|
|||||||
(Ecu.fwdCamera, 0x18dab5f1, None): [
|
(Ecu.fwdCamera, 0x18dab5f1, None): [
|
||||||
b'8S102-30A-A050\x00\x00',
|
b'8S102-30A-A050\x00\x00',
|
||||||
b'8S102-30A-A060\x00\x00',
|
b'8S102-30A-A060\x00\x00',
|
||||||
|
b'8S102-30A-A070\x00\x00',
|
||||||
|
b'8S102-30A-A080\x00\x00',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
CAR.HONDA_CRV_6G: {
|
CAR.HONDA_CRV_6G: {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from opendbc.car import CanBusBase
|
|||||||
from opendbc.car.common.conversions import Conversions as CV
|
from opendbc.car.common.conversions import Conversions as CV
|
||||||
from opendbc.car.honda.values import (HondaFlags, HONDA_BOSCH, HONDA_BOSCH_ALT_RADAR, HONDA_BOSCH_RADARLESS,
|
from opendbc.car.honda.values import (HondaFlags, HONDA_BOSCH, HONDA_BOSCH_ALT_RADAR, HONDA_BOSCH_RADARLESS,
|
||||||
HONDA_BOSCH_CANFD, CarControllerParams)
|
HONDA_BOSCH_CANFD, CarControllerParams)
|
||||||
|
from opendbc.car.honda.values import CAR
|
||||||
|
|
||||||
# CAN bus layout with relay
|
# CAN bus layout with relay
|
||||||
# 0 = ACC-CAN - radar side
|
# 0 = ACC-CAN - radar side
|
||||||
@@ -70,14 +71,16 @@ def create_brake_command(packer, CAN, apply_brake, pump_on, pcm_override, pcm_ca
|
|||||||
return packer.make_can_msg("BRAKE_COMMAND", CAN.pt, values)
|
return packer.make_can_msg("BRAKE_COMMAND", CAN.pt, values)
|
||||||
|
|
||||||
|
|
||||||
def create_acc_commands(packer, CAN, enabled, active, accel, gas, stopping_counter, car_fingerprint):
|
def create_acc_commands(packer, CAN, enabled, active, accel, gas, stopping_counter, CP, gas_force=None):
|
||||||
commands = []
|
commands = []
|
||||||
min_gas_accel = CarControllerParams.BOSCH_GAS_LOOKUP_BP[0]
|
min_gas_accel = CarControllerParams.BOSCH_GAS_LOOKUP_BP[0]
|
||||||
|
|
||||||
control_on = 5 if enabled else 0
|
control_on = 5 if enabled else 0
|
||||||
gas_command = gas if active and accel > min_gas_accel else -30000
|
if gas_force is None:
|
||||||
|
gas_force = accel
|
||||||
|
gas_command = gas if active and gas_force > min_gas_accel else -30000
|
||||||
accel_command = accel if active else 0
|
accel_command = accel if active else 0
|
||||||
braking = 1 if active and accel < min_gas_accel else 0
|
braking = 1 if active and gas_force < min_gas_accel else 0
|
||||||
standstill = 1 if active and stopping_counter > 0 else 0
|
standstill = 1 if active and stopping_counter > 0 else 0
|
||||||
standstill_release = 1 if active and stopping_counter == 0 else 0
|
standstill_release = 1 if active and stopping_counter == 0 else 0
|
||||||
|
|
||||||
@@ -87,7 +90,7 @@ def create_acc_commands(packer, CAN, enabled, active, accel, gas, stopping_count
|
|||||||
'STANDSTILL': standstill,
|
'STANDSTILL': standstill,
|
||||||
}
|
}
|
||||||
|
|
||||||
if car_fingerprint in HONDA_BOSCH_RADARLESS:
|
if CP.carFingerprint in HONDA_BOSCH_RADARLESS:
|
||||||
acc_control_values.update({
|
acc_control_values.update({
|
||||||
"CONTROL_ON": enabled,
|
"CONTROL_ON": enabled,
|
||||||
"IDLESTOP_ALLOW": stopping_counter > 200, # allow idle stop after 4 seconds (50 Hz)
|
"IDLESTOP_ALLOW": stopping_counter > 200, # allow idle stop after 4 seconds (50 Hz)
|
||||||
@@ -147,10 +150,20 @@ def create_acc_hud(packer, bus, CP, enabled, pcm_speed, pcm_accel, hud_control,
|
|||||||
'SET_ME_X01_2': 1,
|
'SET_ME_X01_2': 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if CP.carFingerprint == CAR.HONDA_ACCORD_11G:
|
||||||
|
# Stock CAN-FD radar toggles these together with ACC/lead/braking state. Keeping them low when
|
||||||
|
# neither lead nor braking is present matches MVL's observed CAN-FD payload shape.
|
||||||
|
set_me = int(enabled and (bool(acc_hud_values['HUD_LEAD']) or (pcm_accel < 0.2)))
|
||||||
|
acc_hud_values['SET_ME_X01'] = set_me
|
||||||
|
acc_hud_values['SET_ME_X01_2'] = set_me
|
||||||
|
|
||||||
if CP.carFingerprint in HONDA_BOSCH:
|
if CP.carFingerprint in HONDA_BOSCH:
|
||||||
acc_hud_values['ACC_ON'] = int(enabled)
|
acc_hud_values['ACC_ON'] = int(enabled)
|
||||||
acc_hud_values['FCM_OFF'] = 1
|
# Preserve StarPilot's existing Bosch HUD behavior outside CAN-FD. MVL's CAN-FD
|
||||||
acc_hud_values['FCM_OFF_2'] = 1
|
# replacement radar expects FCW/CMBS enabled, while legacy Bosch keeps them off.
|
||||||
|
canfd = CP.carFingerprint == CAR.HONDA_ACCORD_11G
|
||||||
|
acc_hud_values['FCM_OFF'] = 0 if canfd else 1
|
||||||
|
acc_hud_values['FCM_OFF_2'] = 0 if canfd else 1
|
||||||
else:
|
else:
|
||||||
# Shows the distance bars, TODO: stock camera shows updates temporarily while disabled
|
# Shows the distance bars, TODO: stock camera shows updates temporarily while disabled
|
||||||
acc_hud_values['ACC_ON'] = int(enabled)
|
acc_hud_values['ACC_ON'] = int(enabled)
|
||||||
@@ -219,16 +232,104 @@ def create_legacy_brake_command(packer, bus):
|
|||||||
return packer.make_can_msg("LEGACY_BRAKE_COMMAND", bus, {})
|
return packer.make_can_msg("LEGACY_BRAKE_COMMAND", bus, {})
|
||||||
|
|
||||||
|
|
||||||
def spam_buttons_command(packer, CAN, button_val, car_fingerprint):
|
def spam_buttons_command(packer, CAN, button_val, car_fingerprint, cruise_setting=0, ambient_light=None, bus=None):
|
||||||
values = {
|
values = {
|
||||||
'CRUISE_BUTTONS': button_val,
|
'CRUISE_BUTTONS': button_val,
|
||||||
'CRUISE_SETTING': 0,
|
'CRUISE_SETTING': cruise_setting,
|
||||||
}
|
}
|
||||||
# send buttons to camera on radarless (camera does ACC) cars
|
# Existing StarPilot callers should retain their previous payload; only the CAN-FD camera
|
||||||
bus = CAN.camera if car_fingerprint in HONDA_BOSCH_RADARLESS else CAN.pt
|
# takeover path explicitly echoes the live ambient-light byte.
|
||||||
|
if ambient_light is not None:
|
||||||
|
values['AMBIENT_LIGHT_MAYBE'] = ambient_light
|
||||||
|
if bus is None:
|
||||||
|
# send buttons to camera on radarless (camera does ACC) cars
|
||||||
|
bus = CAN.camera if car_fingerprint in HONDA_BOSCH_RADARLESS else CAN.pt
|
||||||
return packer.make_can_msg("SCM_BUTTONS", bus, values)
|
return packer.make_can_msg("SCM_BUTTONS", bus, values)
|
||||||
|
|
||||||
|
|
||||||
|
def create_radar_hud_canfd(packer, bus, acc, acc_pulse=False):
|
||||||
|
values = {
|
||||||
|
'CMBS_ENABLED_MAYBE': 1 if (acc and acc_pulse) else 0,
|
||||||
|
'ACC_ON': acc,
|
||||||
|
'SET_ME_X01': 0x01,
|
||||||
|
'SET_ME_X01_2': 0x01,
|
||||||
|
}
|
||||||
|
return packer.make_can_msg("RADAR_HUD_CANFD", bus, values)
|
||||||
|
|
||||||
|
|
||||||
|
def create_canfd_supplemental(packer, bus):
|
||||||
|
values = {
|
||||||
|
'SET_ME_X01': 0x01,
|
||||||
|
'SET_ME_X41': 0x41,
|
||||||
|
}
|
||||||
|
return packer.make_can_msg("BOSCH_SUPPLEMENTAL_CANFD", bus, values)
|
||||||
|
|
||||||
|
|
||||||
|
RADAR_MUX_BANK_STARTS = (1, 17, 33, 49)
|
||||||
|
PATH_OFFSET_INVALID = 2047
|
||||||
|
# These extended IDs use the CAN-FD checksum offset used by the Accord 11G
|
||||||
|
# replacement-radar stream. Keep the legacy Honda offset for existing high-ID
|
||||||
|
# messages on other Honda platforms.
|
||||||
|
HONDA_CANFD_MVL_CHECKSUM_IDS = frozenset((
|
||||||
|
0x6CD5558, 0x6CD5559, 0xF31AA52, 0xF31AA5C, 0x1A45AA4E,
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
def _lane_path_offsets(radar_mux):
|
||||||
|
pos = next((radar_mux - start for start in RADAR_MUX_BANK_STARTS if start <= radar_mux <= start + 9), 0)
|
||||||
|
if pos == 0:
|
||||||
|
return (0, 0, 0, 0)
|
||||||
|
if pos == 1:
|
||||||
|
return (0, 0, PATH_OFFSET_INVALID, PATH_OFFSET_INVALID)
|
||||||
|
return (PATH_OFFSET_INVALID,) * 4
|
||||||
|
|
||||||
|
|
||||||
|
def create_canfd_50hz_radar_messages(packer, bus, radar_mux):
|
||||||
|
offsets = _lane_path_offsets(radar_mux)
|
||||||
|
lane_path_values = {
|
||||||
|
'MUX': radar_mux,
|
||||||
|
'PATH_OFFSET_1': offsets[0],
|
||||||
|
'PATH_OFFSET_2': offsets[1],
|
||||||
|
'PATH_OFFSET_3': offsets[2],
|
||||||
|
'PATH_OFFSET_4': offsets[3],
|
||||||
|
}
|
||||||
|
hud_objects_values = {
|
||||||
|
'MUX': radar_mux,
|
||||||
|
'OBJECT_ID': 0,
|
||||||
|
'IS_LEAD_CAR': 0,
|
||||||
|
'CAR_TYPE': -1,
|
||||||
|
'ROTATION': -128,
|
||||||
|
'LONG_DIST': 196.9,
|
||||||
|
'LAT_DIST': 204.7,
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
packer.make_can_msg('LANE_PATH', bus, lane_path_values),
|
||||||
|
packer.make_can_msg('HUD_OBJECTS', bus, hud_objects_values),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def create_canfd_5hz_radar_messages(packer, bus, radar_ref_cntr):
|
||||||
|
radar_lead_values = {
|
||||||
|
'CNTR_REF': radar_ref_cntr,
|
||||||
|
'SET_ME_X01': 0x01,
|
||||||
|
'TARGET_SPEED_MAYBE': 140,
|
||||||
|
# v3 initially sends MVL's stock-like idle lane state. Model-derived dash rendering can be added
|
||||||
|
# separately after the DTC/ownership handover is proven on-car.
|
||||||
|
'LEFT_LANE': 0,
|
||||||
|
'RIGHT_LANE': 0,
|
||||||
|
'LANE_PATH_LENGTH': 6,
|
||||||
|
}
|
||||||
|
radar_lead2_values = {
|
||||||
|
'SET_ME_X88': 136,
|
||||||
|
'SET_ME_X78': 120,
|
||||||
|
'LEAD_DISTANCE_MAYBE': 0,
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
packer.make_can_msg('RADAR_LEAD', bus, radar_lead_values),
|
||||||
|
packer.make_can_msg('RADAR_LEAD2', bus, radar_lead2_values),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def honda_checksum(address: int, sig, d: bytearray) -> int:
|
def honda_checksum(address: int, sig, d: bytearray) -> int:
|
||||||
s = 0
|
s = 0
|
||||||
extended = address > 0x7FF
|
extended = address > 0x7FF
|
||||||
@@ -243,5 +344,5 @@ def honda_checksum(address: int, sig, d: bytearray) -> int:
|
|||||||
s += (x & 0xF) + (x >> 4)
|
s += (x & 0xF) + (x >> 4)
|
||||||
s = 8 - s
|
s = 8 - s
|
||||||
if extended:
|
if extended:
|
||||||
s += 3
|
s += 10 if address in HONDA_CANFD_MVL_CHECKSUM_IDS else 3
|
||||||
return s & 0xF
|
return s & 0xF
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from openpilot.common.params import Params, UnknownKeyName
|
||||||
from opendbc.car import get_safety_config, structs, uds
|
from opendbc.car import get_safety_config, structs, uds
|
||||||
from opendbc.car.common.conversions import Conversions as CV
|
from opendbc.car.common.conversions import Conversions as CV
|
||||||
from opendbc.car.disable_ecu import disable_ecu
|
from opendbc.car.disable_ecu import disable_ecu
|
||||||
from opendbc.car.honda.hondacan import CanBus
|
from opendbc.car.honda.hondacan import CanBus
|
||||||
from opendbc.car.honda.values import CarControllerParams, HondaFlags, CAR, HONDA_BOSCH, HONDA_BOSCH_CANFD, \
|
from opendbc.car.honda.values import CarControllerParams, HondaFlags, CAR, HONDA_BOSCH, HONDA_BOSCH_A, HONDA_BOSCH_A_RADAR_VERIFIED, HONDA_BOSCH_CANFD, \
|
||||||
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, HondaSafetyFlags
|
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, HondaSafetyFlags
|
||||||
from opendbc.car.honda.carcontroller import CarController
|
from opendbc.car.honda.carcontroller import CarController
|
||||||
from opendbc.car.honda.carstate import CarState
|
from opendbc.car.honda.carstate import CarState
|
||||||
@@ -44,7 +45,17 @@ class CarInterface(CarInterfaceBase):
|
|||||||
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
|
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
|
||||||
ret.safetyConfigs = cfgs
|
ret.safetyConfigs = cfgs
|
||||||
|
|
||||||
ret.radarUnavailable = True
|
# HONDA_BOSCH_A describes the physical harness family. Radar remains unavailable until the
|
||||||
|
# exact platform is added to HONDA_BOSCH_A_RADAR_VERIFIED after real-capture validation.
|
||||||
|
try:
|
||||||
|
# The explicit default keeps the verified platform usable on installs that have not yet
|
||||||
|
# persisted the internal kill-switch parameter; the verified-platform set remains mandatory.
|
||||||
|
bosch_a_radar_tryout = not docs and Params().get_bool("HondaBoschARadar", default=True)
|
||||||
|
except UnknownKeyName:
|
||||||
|
bosch_a_radar_tryout = False
|
||||||
|
ret.radarUnavailable = not (candidate in HONDA_BOSCH_A and
|
||||||
|
candidate in HONDA_BOSCH_A_RADAR_VERIFIED and
|
||||||
|
bosch_a_radar_tryout)
|
||||||
# Disable the radar and let openpilot control longitudinal
|
# Disable the radar and let openpilot control longitudinal
|
||||||
# WARNING: THIS DISABLES AEB!
|
# WARNING: THIS DISABLES AEB!
|
||||||
# If Bosch radarless, this blocks ACC messages from the camera
|
# If Bosch radarless, this blocks ACC messages from the camera
|
||||||
@@ -143,9 +154,13 @@ class CarInterface(CarInterfaceBase):
|
|||||||
CarControllerParams.BOSCH_GAS_LOOKUP_BP = [-0.2, 2.0]
|
CarControllerParams.BOSCH_GAS_LOOKUP_BP = [-0.2, 2.0]
|
||||||
|
|
||||||
elif candidate == CAR.HONDA_ACCORD_11G:
|
elif candidate == CAR.HONDA_ACCORD_11G:
|
||||||
ret.steerActuatorDelay = 0.22
|
# MVL Boston sp-honda-dev-202608 tuning (48211d6a63).
|
||||||
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 5200], [0, 2560, 12747]]
|
ret.longitudinalActuatorDelay = 0.05
|
||||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
ret.steerActuatorDelay = 0.3
|
||||||
|
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 12789], [0, 12789]]
|
||||||
|
ret.lateralTuning.pid.kf = 0.000035
|
||||||
|
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.115], [0.052]]
|
||||||
|
CarControllerParams.BOSCH_GAS_LOOKUP_BP = [0.0, 2.0]
|
||||||
|
|
||||||
elif candidate == CAR.ACURA_ILX:
|
elif candidate == CAR.ACURA_ILX:
|
||||||
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] # TODO: determine if there is a dead zone at the top end
|
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] # TODO: determine if there is a dead zone at the top end
|
||||||
@@ -314,6 +329,8 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.RADARLESS.value
|
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.RADARLESS.value
|
||||||
if candidate in HONDA_BOSCH_CANFD:
|
if candidate in HONDA_BOSCH_CANFD:
|
||||||
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.BOSCH_CANFD.value
|
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.BOSCH_CANFD.value
|
||||||
|
if candidate == CAR.HONDA_ACCORD_11G:
|
||||||
|
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.BOSCH_CANFD_MVL.value
|
||||||
|
|
||||||
# min speed to enable ACC. if car can do stop and go, then set enabling speed
|
# min speed to enable ACC. if car can do stop and go, then set enabling speed
|
||||||
# to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not
|
# to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not
|
||||||
@@ -345,6 +362,13 @@ class CarInterface(CarInterfaceBase):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def init(CP, can_recv, can_send, communication_control=None):
|
def init(CP, can_recv, can_send, communication_control=None):
|
||||||
if CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and CP.openpilotLongitudinalControl:
|
if CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and CP.openpilotLongitudinalControl:
|
||||||
|
# CAN-FD radar ownership is handed over only after the comma relay is confirmed open.
|
||||||
|
# Disabling the radar here can create a gap before panda enters the Honda safety mode and
|
||||||
|
# replacement ACC_CONTROL is permitted, which can latch CRUISE_FAULT/DTCs in the brake module.
|
||||||
|
# deinit() still passes an explicit enable request and therefore falls through to disable_ecu.
|
||||||
|
if CP.carFingerprint == CAR.HONDA_ACCORD_11G and communication_control is None:
|
||||||
|
return
|
||||||
|
|
||||||
# 0x80 silences response
|
# 0x80 silences response
|
||||||
if communication_control is None:
|
if communication_control is None:
|
||||||
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.DISABLE_RX_DISABLE_TX,
|
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.DISABLE_RX_DISABLE_TX,
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import math
|
||||||
|
from collections import deque
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
from opendbc.can import CANParser
|
from opendbc.can import CANParser
|
||||||
from opendbc.car import Bus, structs
|
from opendbc.car import Bus, structs
|
||||||
from opendbc.car.interfaces import RadarInterfaceBase
|
from opendbc.car.honda.hondacan import CanBus
|
||||||
from opendbc.car.honda.values import DBC
|
from opendbc.car.honda.values import DBC
|
||||||
|
from opendbc.car.interfaces import RadarInterfaceBase
|
||||||
|
|
||||||
|
|
||||||
def _create_nidec_can_parser(car_fingerprint):
|
def _create_nidec_can_parser(car_fingerprint):
|
||||||
@@ -11,39 +16,615 @@ def _create_nidec_can_parser(car_fingerprint):
|
|||||||
return CANParser(DBC[car_fingerprint][Bus.radar], messages, 1)
|
return CANParser(DBC[car_fingerprint][Bus.radar], messages, 1)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Honda Bosch-A 16-slot object bank
|
||||||
|
# ============================================================================
|
||||||
|
# 16 CAN-visible object slots. Each slot has 4 main frames (f0..f3, one CAN ID each -- NOT sub-frames
|
||||||
|
# muxed onto a shared ID) plus one synchronized auxiliary 5th frame. This supersedes any prior model of
|
||||||
|
# 0x280/0x284/0x288/0x28C as pieces of one object, or of 0x2C8/0x2C9 as a separate "coarse" list: it is
|
||||||
|
# ONE 16-slot bank with one auxiliary frame per slot. See honda_bosch_a_radar.dbc for the bit geometry.
|
||||||
|
BOSCH_A_DBC_NAME = 'honda_bosch_a_radar'
|
||||||
|
BOSCH_A_NUM_SLOTS = 16
|
||||||
|
|
||||||
|
|
||||||
|
def _bosch_a_main_base(slot: int) -> int:
|
||||||
|
return 0x280 + 4 * slot if slot < 4 else 0x2D0 + 4 * (slot - 4)
|
||||||
|
|
||||||
|
|
||||||
|
def _bosch_a_aux_id(slot: int) -> int:
|
||||||
|
return 0x2C8 + slot if slot < 8 else 0x290 + (slot - 8)
|
||||||
|
|
||||||
|
|
||||||
|
BOSCH_A_MAIN_IDS = [[_bosch_a_main_base(s) + i for i in range(4)] for s in range(BOSCH_A_NUM_SLOTS)]
|
||||||
|
BOSCH_A_AUX_IDS = [_bosch_a_aux_id(s) for s in range(BOSCH_A_NUM_SLOTS)]
|
||||||
|
BOSCH_A_ALL_IDS = [addr for ids in BOSCH_A_MAIN_IDS for addr in ids] + BOSCH_A_AUX_IDS
|
||||||
|
|
||||||
|
# Publish RadarPoints when the last MAIN object frame arrives. Passive captures prove that slot 15's
|
||||||
|
# companion frame, 0x297, follows 0x2FF and is the final observed object-family frame in a full sweep:
|
||||||
|
#
|
||||||
|
# ... 0x2FC, 0x2FD, 0x2FE, 0x2FF, 0x297
|
||||||
|
#
|
||||||
|
# Keep 0x2FF as the RadarPoint trigger while the companion data remains optional/debug-only. Making
|
||||||
|
# 0x297 the sole trigger would allow one dropped auxiliary frame to suppress an otherwise-valid point
|
||||||
|
# update, contrary to the parser's "aux never gates validity" contract.
|
||||||
|
BOSCH_A_TRIGGER_MSG = BOSCH_A_MAIN_IDS[BOSCH_A_NUM_SLOTS - 1][3]
|
||||||
|
BOSCH_A_SWEEP_END_MSG = BOSCH_A_AUX_IDS[BOSCH_A_NUM_SLOTS - 1] # 0x297
|
||||||
|
|
||||||
|
# Observed coherent Bosch-A sweep cadence is ~14.5-16 Hz in the available captures.
|
||||||
|
BOSCH_A_FREQ_HZ = 15
|
||||||
|
|
||||||
|
# Range: f0 raw_range (12-bit, B2:B3 high nibble) -> meters. Firmware q16 = 8*raw_range; physical
|
||||||
|
# calibration keeps slope/offset as named, replay-refinable constants (do not add a second radar/camera
|
||||||
|
# longitudinal offset on top of this).
|
||||||
|
BOSCH_A_RANGE_SCALE_M = 0.05712
|
||||||
|
BOSCH_A_RANGE_OFFSET_M = -3.0
|
||||||
|
|
||||||
|
# Azimuth: f0 raw_angle (11-bit, B4:B5 high 3 bits), offset-binary about 1024.
|
||||||
|
#
|
||||||
|
# The f3 angular-edge pair independently closes the exact center-angle scale:
|
||||||
|
# azimuth_rad = (raw_angle - 1024) / 2048
|
||||||
|
#
|
||||||
|
# This supersedes the older empirical 0.032 deg/count fit.
|
||||||
|
BOSCH_A_AZIMUTH_SCALE_RAD = 1.0 / 2048.0
|
||||||
|
BOSCH_A_AZIMUTH_CENTER = 1024
|
||||||
|
|
||||||
|
# Invalid sentinels (section 3/4/5/6 of the spec).
|
||||||
|
BOSCH_A_STATUS_INVALID = 0xF
|
||||||
|
BOSCH_A_RANGE_RAW_INVALID = 0xFFF
|
||||||
|
BOSCH_A_ANGLE_RAW_INVALID = 0x7FF
|
||||||
|
BOSCH_A_LIFE_INVALID = 0xFFF
|
||||||
|
BOSCH_A_TRACK_ID_MIN = 1
|
||||||
|
BOSCH_A_TRACK_ID_MAX = 0x3F
|
||||||
|
# AUX logical 0x00CA has an explicit 0x3FF invalid sentinel. Firmware proves the normalization below;
|
||||||
|
# captures strongly support interpreting the active value as previous/current range ratio.
|
||||||
|
BOSCH_A_RANGE_RATIO_INVALID = 0x3FF
|
||||||
|
BOSCH_A_LOGICAL_00CA_INVALID = BOSCH_A_RANGE_RATIO_INVALID # compatibility/debug alias
|
||||||
|
BOSCH_A_RANGE_RATIO_SCALE = 0.001
|
||||||
|
BOSCH_A_RANGE_RATIO_OFFSET = 0.5
|
||||||
|
|
||||||
|
# The synchronized AUX frame contains an 11-bit offset-binary velocity-like field and a 10-bit
|
||||||
|
# companion quality/uncertainty field. The byte locations are now decoded in the DBC. The exact
|
||||||
|
# Bosch descriptor name is still being verified, so keep the conversion constants isolated here.
|
||||||
|
# Capture validation shows active values in [0, 1728], with 0x7FE used as the inactive sentinel.
|
||||||
|
BOSCH_A_DIRECT_VREL_INVALID = 0x7FE
|
||||||
|
BOSCH_A_DIRECT_VREL_MIN_RAW = 0
|
||||||
|
BOSCH_A_DIRECT_VREL_MAX_RAW = 1728
|
||||||
|
BOSCH_A_DIRECT_VREL_CENTER_RAW = 864
|
||||||
|
BOSCH_A_DIRECT_VREL_SCALE_MPS = 1.0 / 64.0
|
||||||
|
# Empirical raw-quality policy. U11 error against an independent range-derivative reference rises
|
||||||
|
# with u10 in a graded way, not a cliff: replay evidence bins it roughly as 0-255 clean, 256-511 only
|
||||||
|
# mildly degraded, 512-767 clearly degraded, 768+ worst. 511 is set at that mild/clear boundary so
|
||||||
|
# U11 is still trusted directly through the mildly-degraded band; only u10 above this triggers the
|
||||||
|
# high-u10 coast path below. This is deliberately not presented as a Bosch physical unit or
|
||||||
|
# descriptor constant; it keeps saturated/high-uncertainty AUX values from becoming authoritative
|
||||||
|
# velocity measurements.
|
||||||
|
BOSCH_A_DIRECT_VREL_MAX_UNCERTAINTY_RAW = 511
|
||||||
|
|
||||||
|
# Measurement-authority policy. These are replay-derived safety/tuning gates, not recovered Bosch
|
||||||
|
# constants. Range innovation is measured from the previous accepted observation so a reset cannot
|
||||||
|
# become the baseline for following sweeps.
|
||||||
|
BOSCH_A_RANGE_SIGMA_DEGRADED_RAW = 4
|
||||||
|
BOSCH_A_RANGE_INNOVATION_MAX_M = 2.0
|
||||||
|
BOSCH_A_RANGE_INNOVATION_HARD_MAX_M = 5.0
|
||||||
|
BOSCH_A_FALLBACK_RANGE_RATE_MAX_MPS = 50.0
|
||||||
|
BOSCH_A_USE_TAN_LATERAL_PROJECTION = True
|
||||||
|
|
||||||
|
# Accepted-range history is retained for continuity and the adjacent two-point fallback. Rejected
|
||||||
|
# range resets never enter it, and it is not used for a multi-sample OLS velocity fit.
|
||||||
|
BOSCH_A_VREL_MAX_SAMPLES = 8
|
||||||
|
|
||||||
|
# Staleness gate -- TUNING constant, reused plumbing pattern (not a firmware fact). At the observed
|
||||||
|
# ~15 Hz cadence, 0.20 s is approximately three missed sweeps.
|
||||||
|
BOSCH_A_STALE_S = 0.20
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class _BoschASlotState:
|
||||||
|
last_seen_nanos: int | None = None
|
||||||
|
|
||||||
|
# Firmware logical-ID companion data -- telemetry/debug only for now, never a RadarPoint validity
|
||||||
|
# gate. 0x00C9 has a firmware transform but no proven physical meaning; 0x00CA has an explicit
|
||||||
|
# invalid sentinel and its physical meaning remains unresolved.
|
||||||
|
logical_00c9_raw: float = float('nan')
|
||||||
|
logical_00ca_raw: float = float('nan')
|
||||||
|
direct_vrel_raw: int | None = None
|
||||||
|
direct_vrel_uncertainty_raw: int | None = None
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.last_seen_nanos = None
|
||||||
|
self.logical_00c9_raw = float('nan')
|
||||||
|
self.logical_00ca_raw = float('nan')
|
||||||
|
self.direct_vrel_raw = None
|
||||||
|
self.direct_vrel_uncertainty_raw = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class _BoschATrackState:
|
||||||
|
"""Persistent state for one Bosch CAN object identity, independent of wire slot."""
|
||||||
|
track_id: int
|
||||||
|
prev_frame_idx: int | None = None
|
||||||
|
prev_life: int | None = None
|
||||||
|
last_seen_nanos: int | None = None
|
||||||
|
wire_slot: int | None = None
|
||||||
|
samples: deque = field(default_factory=lambda: deque(maxlen=BOSCH_A_VREL_MAX_SAMPLES))
|
||||||
|
last_trusted_vrel: float | None = None
|
||||||
|
last_trusted_vrel_nanos: int | None = None
|
||||||
|
|
||||||
|
|
||||||
|
def _bosch_a_direct_vrel(raw_value: int | float | None,
|
||||||
|
uncertainty_raw: int | float | None = None) -> float | None:
|
||||||
|
"""Decode the capture-validated AUX relative-velocity candidate.
|
||||||
|
|
||||||
|
None means that AUX was absent/invalid and the caller should use the existing fallback policy. The [0, 1728]
|
||||||
|
active domain is deliberately enforced here because values above the observed +13.5 m/s rail have
|
||||||
|
not appeared on active objects; 0x7FE is the observed inactive sentinel.
|
||||||
|
"""
|
||||||
|
if raw_value is None:
|
||||||
|
return None
|
||||||
|
raw = int(raw_value)
|
||||||
|
if raw == BOSCH_A_DIRECT_VREL_INVALID:
|
||||||
|
return None
|
||||||
|
if not BOSCH_A_DIRECT_VREL_MIN_RAW <= raw <= BOSCH_A_DIRECT_VREL_MAX_RAW:
|
||||||
|
return None
|
||||||
|
# u10 is retained as a raw quality indicator because its physical units remain unresolved. The
|
||||||
|
# conservative threshold is evidence-backed tuning, not a recovered firmware validity rule.
|
||||||
|
if uncertainty_raw is not None and int(uncertainty_raw) > BOSCH_A_DIRECT_VREL_MAX_UNCERTAINTY_RAW:
|
||||||
|
return None
|
||||||
|
return (raw - BOSCH_A_DIRECT_VREL_CENTER_RAW) * BOSCH_A_DIRECT_VREL_SCALE_MPS
|
||||||
|
|
||||||
|
|
||||||
|
def _bosch_a_range_ratio(raw_value: int | float | None) -> float | None:
|
||||||
|
if raw_value is None:
|
||||||
|
return None
|
||||||
|
raw = int(raw_value)
|
||||||
|
if raw == BOSCH_A_RANGE_RATIO_INVALID or not 0 <= raw < BOSCH_A_RANGE_RATIO_INVALID:
|
||||||
|
return None
|
||||||
|
return BOSCH_A_RANGE_RATIO_OFFSET + BOSCH_A_RANGE_RATIO_SCALE * raw
|
||||||
|
|
||||||
|
|
||||||
|
def _bosch_a_range_ratio_vrel(raw_value: int | float | None, d_rel: float, dt: float) -> float | None:
|
||||||
|
"""Return the range rate implied by the empirical previous/current range ratio."""
|
||||||
|
ratio = _bosch_a_range_ratio(raw_value)
|
||||||
|
if ratio is None or dt <= 0.0 or not math.isfinite(d_rel):
|
||||||
|
return None
|
||||||
|
return d_rel * (1.0 - ratio) / dt
|
||||||
|
|
||||||
|
|
||||||
|
def _bosch_a_measurement_degraded(range_sigma_raw: int, existence_raw: int,
|
||||||
|
direct_vrel_uncertainty_raw: int | None) -> bool:
|
||||||
|
range_quality_bad = range_sigma_raw >= BOSCH_A_RANGE_SIGMA_DEGRADED_RAW or existence_raw in (0, 0x7F)
|
||||||
|
velocity_quality_bad = (direct_vrel_uncertainty_raw is not None and
|
||||||
|
direct_vrel_uncertainty_raw > BOSCH_A_DIRECT_VREL_MAX_UNCERTAINTY_RAW)
|
||||||
|
return range_quality_bad or velocity_quality_bad
|
||||||
|
|
||||||
|
|
||||||
|
def _create_bosch_a_can_parser(CP):
|
||||||
|
messages = [(addr, BOSCH_A_FREQ_HZ) for addr in BOSCH_A_ALL_IDS]
|
||||||
|
# Bus.radar selects the Bosch-A DBC; the object/fusion feed itself is
|
||||||
|
# physically on the camera-side ACC-CAN.
|
||||||
|
return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, CanBus(CP).camera)
|
||||||
|
|
||||||
|
|
||||||
class RadarInterface(RadarInterfaceBase):
|
class RadarInterface(RadarInterfaceBase):
|
||||||
def __init__(self, CP):
|
def __init__(self, CP):
|
||||||
super().__init__(CP)
|
super().__init__(CP)
|
||||||
self.track_id = 0
|
|
||||||
self.radar_fault = False
|
|
||||||
self.radar_wrong_config = False
|
|
||||||
self.radar_off_can = CP.radarUnavailable
|
self.radar_off_can = CP.radarUnavailable
|
||||||
|
self.bosch_a_radar = (not self.radar_off_can and Bus.radar in DBC[CP.carFingerprint] and
|
||||||
|
DBC[CP.carFingerprint][Bus.radar] == BOSCH_A_DBC_NAME)
|
||||||
|
|
||||||
# Nidec
|
|
||||||
if self.radar_off_can:
|
if self.radar_off_can:
|
||||||
self.rcp = None
|
self.rcp = None
|
||||||
|
self.trigger_msg = 0x445
|
||||||
|
elif self.bosch_a_radar:
|
||||||
|
self.rcp = _create_bosch_a_can_parser(CP)
|
||||||
|
self.trigger_msg = BOSCH_A_TRIGGER_MSG
|
||||||
|
self._slots = [_BoschASlotState() for _ in range(BOSCH_A_NUM_SLOTS)]
|
||||||
|
self._tracks: dict[int, _BoschATrackState] = {}
|
||||||
|
self._slot_track_ids: list[int | None] = [None] * BOSCH_A_NUM_SLOTS
|
||||||
|
self._last_trigger_nanos = -1
|
||||||
else:
|
else:
|
||||||
|
# Nidec
|
||||||
self.rcp = _create_nidec_can_parser(CP.carFingerprint)
|
self.rcp = _create_nidec_can_parser(CP.carFingerprint)
|
||||||
self.trigger_msg = 0x445
|
self.trigger_msg = 0x445
|
||||||
|
self.track_id = 0
|
||||||
|
self.radar_fault = False
|
||||||
|
self.radar_wrong_config = False
|
||||||
|
|
||||||
self.updated_messages = set()
|
self.updated_messages = set()
|
||||||
|
|
||||||
def update(self, can_strings):
|
def update(self, can_strings):
|
||||||
# in Bosch radar and we are only steering for now, so sleep 0.05s to keep
|
if self.radar_off_can or self.rcp is None:
|
||||||
# radard at 20Hz and return no points
|
|
||||||
if self.radar_off_can:
|
|
||||||
return super().update(None)
|
return super().update(None)
|
||||||
|
|
||||||
vls = self.rcp.update(can_strings)
|
vls = self.rcp.update(can_strings)
|
||||||
self.updated_messages.update(vls)
|
self.updated_messages.update(vls)
|
||||||
|
|
||||||
if self.trigger_msg not in self.updated_messages:
|
if self.trigger_msg not in self.updated_messages:
|
||||||
|
if self.bosch_a_radar and self._last_trigger_nanos >= 0:
|
||||||
|
now = self.rcp._last_update_nanos
|
||||||
|
if (now - self._last_trigger_nanos) * 1e-9 > BOSCH_A_STALE_S:
|
||||||
|
return self._bosch_a_stale_radardata()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
rr = self._update(self.updated_messages)
|
rr = self._update(self.updated_messages)
|
||||||
self.updated_messages.clear()
|
self.updated_messages.clear()
|
||||||
return rr
|
return rr
|
||||||
|
|
||||||
|
def _bosch_a_stale_radardata(self):
|
||||||
|
# Whole-bus silence: clear every live point/history and emit an EMPTY RadarData (not None) so
|
||||||
|
# radard drops any lead within a cycle instead of freezing a phantom. The next observation starts
|
||||||
|
# a fresh incarnation for its CAN identity.
|
||||||
|
self.pts.clear()
|
||||||
|
self._tracks.clear()
|
||||||
|
self._slot_track_ids = [None] * BOSCH_A_NUM_SLOTS
|
||||||
|
for slot_state in self._slots:
|
||||||
|
slot_state.reset()
|
||||||
|
self._last_trigger_nanos = -1
|
||||||
|
stale = structs.RadarData()
|
||||||
|
if not self.rcp.can_valid:
|
||||||
|
stale.errors.canError = True
|
||||||
|
stale.errors.radarUnavailableTemporary = True
|
||||||
|
return stale
|
||||||
|
|
||||||
|
def _bosch_a_retire_track(self, track_id: int):
|
||||||
|
self._tracks.pop(track_id, None)
|
||||||
|
self.pts.pop(track_id, None)
|
||||||
|
for slot, slot_track_id in enumerate(self._slot_track_ids):
|
||||||
|
if slot_track_id == track_id:
|
||||||
|
self._slot_track_ids[slot] = None
|
||||||
|
|
||||||
|
def _bosch_a_retire_stale_tracks(self, now: int):
|
||||||
|
for track_id, track in list(self._tracks.items()):
|
||||||
|
if track.last_seen_nanos is not None and (now - track.last_seen_nanos) * 1e-9 > BOSCH_A_STALE_S:
|
||||||
|
self._bosch_a_retire_track(track_id)
|
||||||
|
|
||||||
def _update(self, updated_messages):
|
def _update(self, updated_messages):
|
||||||
|
if self.bosch_a_radar:
|
||||||
|
return self._update_bosch_a(updated_messages)
|
||||||
|
return self._update_nidec(updated_messages)
|
||||||
|
|
||||||
|
def _update_bosch_a(self, updated_messages):
|
||||||
|
ret = structs.RadarData()
|
||||||
|
if not self.rcp.can_valid:
|
||||||
|
ret.errors.canError = True
|
||||||
|
|
||||||
|
now = self.rcp._last_update_nanos
|
||||||
|
self._last_trigger_nanos = now
|
||||||
|
self._bosch_a_retire_stale_tracks(now)
|
||||||
|
|
||||||
|
observations = []
|
||||||
|
|
||||||
|
for slot in range(BOSCH_A_NUM_SLOTS):
|
||||||
|
f0, f1, f2, f3 = BOSCH_A_MAIN_IDS[slot]
|
||||||
|
aux = BOSCH_A_AUX_IDS[slot]
|
||||||
|
st = self._slots[slot]
|
||||||
|
|
||||||
|
if not (f0 in updated_messages and f1 in updated_messages and
|
||||||
|
f2 in updated_messages and f3 in updated_messages):
|
||||||
|
# Incomplete main-frame set: a missing CAN frame must not be treated as a lifecycle mismatch or
|
||||||
|
# death/replacement. Logical tracks are retired independently by their global staleness gate.
|
||||||
|
continue
|
||||||
|
|
||||||
|
v0 = self.rcp.vl[f0]
|
||||||
|
v1 = self.rcp.vl[f1]
|
||||||
|
v2 = self.rcp.vl[f2]
|
||||||
|
v3 = self.rcp.vl[f3]
|
||||||
|
|
||||||
|
idx0 = int(v0['FRAME_IDX'])
|
||||||
|
if not (idx0 == int(v1['FRAME_IDX']) == int(v2['FRAME_IDX']) == int(v3['FRAME_IDX'])):
|
||||||
|
# The four main frames don't share a common cycle index -- not a coherent observation this
|
||||||
|
# window. Only combine main-frame data from a coherent common frame index (section 2).
|
||||||
|
continue
|
||||||
|
|
||||||
|
status = int(v0['STATUS'])
|
||||||
|
range_raw = int(v0['RANGE_RAW'])
|
||||||
|
angle_raw = int(v0['AZIMUTH_RAW'])
|
||||||
|
range_sigma_raw = int(v0['RANGE_SIGMA_RAW'])
|
||||||
|
existence_raw = int(v1['OBJECT_EXISTENCE_PROBABILITY_RAW'])
|
||||||
|
life = int(v2['LIFECYCLE_RAW'])
|
||||||
|
track_id = int(v3['TRACK_ID'])
|
||||||
|
track_id_valid = BOSCH_A_TRACK_ID_MIN <= track_id <= BOSCH_A_TRACK_ID_MAX
|
||||||
|
st.last_seen_nanos = now
|
||||||
|
direct_vrel_raw = None
|
||||||
|
direct_vrel_uncertainty_raw = None
|
||||||
|
range_ratio_raw = None
|
||||||
|
|
||||||
|
# Attach synchronized companion data only when its cycle matches. Missing AUX never invalidates
|
||||||
|
# an otherwise coherent F0-F3 object; it only removes independent motion/quality evidence.
|
||||||
|
if aux in updated_messages:
|
||||||
|
av = self.rcp.vl[aux]
|
||||||
|
if int(av['FRAME_IDX']) == idx0:
|
||||||
|
direct_vrel_raw = int(av['REL_VELOCITY_RAW'])
|
||||||
|
direct_vrel_uncertainty_raw = int(av['REL_VELOCITY_UNCERTAINTY_RAW'])
|
||||||
|
range_ratio_raw = int(av['RANGE_RATIO_RAW'])
|
||||||
|
logical_00c9_raw = av['FW_LID_00C9_RAW']
|
||||||
|
logical_00ca_raw = av['FW_LID_00CA_RAW']
|
||||||
|
st.logical_00c9_raw = logical_00c9_raw
|
||||||
|
st.logical_00ca_raw = (
|
||||||
|
logical_00ca_raw if logical_00ca_raw != BOSCH_A_LOGICAL_00CA_INVALID else float('nan')
|
||||||
|
)
|
||||||
|
st.direct_vrel_raw = direct_vrel_raw
|
||||||
|
st.direct_vrel_uncertainty_raw = direct_vrel_uncertainty_raw
|
||||||
|
|
||||||
|
object_valid = (status != BOSCH_A_STATUS_INVALID and range_raw != BOSCH_A_RANGE_RAW_INVALID and
|
||||||
|
angle_raw != BOSCH_A_ANGLE_RAW_INVALID and life != BOSCH_A_LIFE_INVALID)
|
||||||
|
|
||||||
|
observations.append({
|
||||||
|
'slot': slot,
|
||||||
|
'frame_idx': idx0,
|
||||||
|
'life': life,
|
||||||
|
'track_id': track_id,
|
||||||
|
'track_id_valid': track_id_valid,
|
||||||
|
'object_valid': object_valid,
|
||||||
|
'range_sigma_raw': range_sigma_raw,
|
||||||
|
'existence_raw': existence_raw,
|
||||||
|
'direct_vrel_raw': direct_vrel_raw,
|
||||||
|
'direct_vrel_uncertainty_raw': direct_vrel_uncertainty_raw,
|
||||||
|
'range_ratio_raw': range_ratio_raw,
|
||||||
|
})
|
||||||
|
|
||||||
|
# First collapse duplicate wire observations of one CAN identity. The dictionary is also the
|
||||||
|
# output uniqueness boundary: one valid Bosch identity can never create two RadarPoints.
|
||||||
|
valid_by_id = {}
|
||||||
|
for observation in observations:
|
||||||
|
if not (observation['object_valid'] and observation['track_id_valid']):
|
||||||
|
# An invalid observation ends publication for the object currently occupying this wire slot,
|
||||||
|
# but it does not immediately destroy the persistent state. The object may be multiplexed to
|
||||||
|
# another slot or may return before the per-identity stale deadline; a later lifecycle break
|
||||||
|
# or staleness expiry will clear its derivative history.
|
||||||
|
ids_to_hide = {self._slot_track_ids[observation['slot']]}
|
||||||
|
if observation['track_id_valid']:
|
||||||
|
ids_to_hide.add(observation['track_id'])
|
||||||
|
for invalid_id in ids_to_hide - {None}:
|
||||||
|
self.pts.pop(invalid_id, None)
|
||||||
|
continue
|
||||||
|
track_id = observation['track_id']
|
||||||
|
current = valid_by_id.get(track_id)
|
||||||
|
if current is None:
|
||||||
|
valid_by_id[track_id] = observation
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Prefer the wire slot currently associated with the persistent state. If neither candidate is
|
||||||
|
# preferred, retain the lower slot for deterministic handling of a malformed duplicate frame.
|
||||||
|
track = self._tracks.get(track_id)
|
||||||
|
current_score = (0 if track is not None and track.wire_slot == current['slot'] else 1, current['slot'])
|
||||||
|
candidate_score = (0 if track is not None and track.wire_slot == observation['slot'] else 1,
|
||||||
|
observation['slot'])
|
||||||
|
if candidate_score < current_score:
|
||||||
|
valid_by_id[track_id] = observation
|
||||||
|
|
||||||
|
valid_ids = set(valid_by_id)
|
||||||
|
for track_id, observation in sorted(valid_by_id.items(), key=lambda item: item[1]['slot']):
|
||||||
|
slot = observation['slot']
|
||||||
|
idx0 = observation['frame_idx']
|
||||||
|
life = observation['life']
|
||||||
|
|
||||||
|
# A wire-slot replacement ends publication for the old occupant, but not its persistent
|
||||||
|
# identity/history. If the old ID is still valid in another slot this sweep, keep its point;
|
||||||
|
# otherwise hide it until that ID returns or reaches its own stale deadline.
|
||||||
|
old_id = self._slot_track_ids[slot]
|
||||||
|
if old_id is not None and old_id != track_id and old_id not in valid_ids:
|
||||||
|
self.pts.pop(old_id, None)
|
||||||
|
|
||||||
|
track = self._tracks.get(track_id)
|
||||||
|
if track is None:
|
||||||
|
track = _BoschATrackState(track_id=track_id)
|
||||||
|
self._tracks[track_id] = track
|
||||||
|
|
||||||
|
same_incarnation = False
|
||||||
|
if track.prev_frame_idx is not None and track.prev_life is not None:
|
||||||
|
frame_delta = (idx0 - track.prev_frame_idx) & 0xF
|
||||||
|
life_delta = (life - track.prev_life) & 0xFFF
|
||||||
|
same_incarnation = life_delta == 2 * frame_delta
|
||||||
|
|
||||||
|
if not same_incarnation:
|
||||||
|
# The CAN identity remains the externally-visible key, but a lifecycle discontinuity starts a
|
||||||
|
# new incarnation and must not inherit the previous object's range-rate history.
|
||||||
|
track.samples.clear()
|
||||||
|
track.last_trusted_vrel = None
|
||||||
|
track.last_trusted_vrel_nanos = None
|
||||||
|
self.pts.pop(track_id, None)
|
||||||
|
|
||||||
|
v0 = self.rcp.vl[BOSCH_A_MAIN_IDS[slot][0]]
|
||||||
|
range_raw = int(v0['RANGE_RAW'])
|
||||||
|
angle_raw = int(v0['AZIMUTH_RAW'])
|
||||||
|
dRel = BOSCH_A_RANGE_SCALE_M * range_raw + BOSCH_A_RANGE_OFFSET_M
|
||||||
|
azimuth_rad = BOSCH_A_AZIMUTH_SCALE_RAD * (angle_raw - BOSCH_A_AZIMUTH_CENTER)
|
||||||
|
# The firmware's internal geometry path uses tan(angle) for a forward-axis distance. The
|
||||||
|
# Bosch object range is consumed as that forward-axis quantity here, so use the same projection
|
||||||
|
# rather than treating it as radial/slant range. Keep the switch explicit while the final
|
||||||
|
# output bridge remains under static review.
|
||||||
|
#
|
||||||
|
# Sign: AZIMUTH_RAW > center (positive azimuth_rad) is a LEFT-of-center detection in car frame's
|
||||||
|
# y axis (left is positive), matching the Nidec RadarPoint.yRel contract. Confirmed against real
|
||||||
|
# captures 2026-08-22: a stationary cluster of queued vehicles visible on the left in the road
|
||||||
|
# camera was rendering on the right in both the Qt and raylib radar-track overlays with the
|
||||||
|
# previously-flipped sign.
|
||||||
|
lateral_projection = math.tan if BOSCH_A_USE_TAN_LATERAL_PROJECTION else math.sin
|
||||||
|
yRel = dRel * lateral_projection(azimuth_rad)
|
||||||
|
|
||||||
|
now_s = now * 1e-9
|
||||||
|
direct_vrel_raw = observation['direct_vrel_raw']
|
||||||
|
direct_vrel_uncertainty_raw = observation['direct_vrel_uncertainty_raw']
|
||||||
|
direct_vrel = _bosch_a_direct_vrel(direct_vrel_raw, direct_vrel_uncertainty_raw)
|
||||||
|
live_direct_vrel = _bosch_a_direct_vrel(direct_vrel_raw)
|
||||||
|
range_ratio_raw = observation['range_ratio_raw']
|
||||||
|
|
||||||
|
# A live U11 rejected solely by the conservative U10 qualification threshold is neither an
|
||||||
|
# unavailable velocity nor permission to synthesize a one-sweep range derivative. It is also
|
||||||
|
# NOT permission to skip range-innovation checking below: u10 correlates with range_sigma in
|
||||||
|
# replay data, so a high-u10 sweep is exactly the condition where a bad/discontinuous range
|
||||||
|
# (slot migration, reset) is most likely, not less likely. Range acceptance is therefore
|
||||||
|
# decided on the same terms as every other sweep first; only once the range clears that gate
|
||||||
|
# does a high-u10 U11 fall back to coasting instead of publishing a synthesized derivative.
|
||||||
|
high_u10_live_vrel = (direct_vrel is None and live_direct_vrel is not None and
|
||||||
|
direct_vrel_uncertainty_raw is not None and
|
||||||
|
direct_vrel_uncertainty_raw > BOSCH_A_DIRECT_VREL_MAX_UNCERTAINTY_RAW)
|
||||||
|
|
||||||
|
# Validate against the previous accepted range. Qualified U11 and the range-ratio field are
|
||||||
|
# independent corroboration paths; high-U10 U11 is deliberately excluded from this decision.
|
||||||
|
previous_sample = track.samples[-1] if track.samples else None
|
||||||
|
fallback_vrel = 0.0
|
||||||
|
ratio_vrel = None
|
||||||
|
range_rejected = False
|
||||||
|
degraded = _bosch_a_measurement_degraded(
|
||||||
|
observation['range_sigma_raw'], observation['existence_raw'], direct_vrel_uncertainty_raw,
|
||||||
|
)
|
||||||
|
if previous_sample is not None:
|
||||||
|
previous_time, previous_range = previous_sample
|
||||||
|
dt = now_s - previous_time
|
||||||
|
if dt <= 0.0:
|
||||||
|
range_rejected = True
|
||||||
|
else:
|
||||||
|
fallback_vrel = (dRel - previous_range) / dt
|
||||||
|
ratio = _bosch_a_range_ratio(range_ratio_raw)
|
||||||
|
ratio_vrel = _bosch_a_range_ratio_vrel(range_ratio_raw, dRel, dt)
|
||||||
|
|
||||||
|
residuals_m = []
|
||||||
|
if direct_vrel is not None:
|
||||||
|
residuals_m.append(abs(dRel - (previous_range + direct_vrel * dt)))
|
||||||
|
if ratio is not None:
|
||||||
|
residuals_m.append(abs(previous_range - dRel * ratio))
|
||||||
|
|
||||||
|
if residuals_m:
|
||||||
|
innovation_m = min(residuals_m)
|
||||||
|
range_rejected = (
|
||||||
|
innovation_m > BOSCH_A_RANGE_INNOVATION_HARD_MAX_M or
|
||||||
|
(degraded and innovation_m > BOSCH_A_RANGE_INNOVATION_MAX_M)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
range_rejected = abs(fallback_vrel) > BOSCH_A_FALLBACK_RANGE_RATE_MAX_MPS
|
||||||
|
|
||||||
|
if range_rejected:
|
||||||
|
# Keep the last accepted point briefly as an unmeasured coast. The rejected geometry is not
|
||||||
|
# published and never becomes the baseline for a later derivative.
|
||||||
|
accepted_fresh = previous_sample is not None and now_s - previous_sample[0] <= BOSCH_A_STALE_S
|
||||||
|
point = self.pts.get(track_id)
|
||||||
|
if accepted_fresh and point is not None:
|
||||||
|
point.measured = False
|
||||||
|
else:
|
||||||
|
self.pts.pop(track_id, None)
|
||||||
|
track.prev_frame_idx = idx0
|
||||||
|
track.prev_life = life
|
||||||
|
track.last_seen_nanos = now
|
||||||
|
track.wire_slot = slot
|
||||||
|
for old_slot, old_id in enumerate(self._slot_track_ids):
|
||||||
|
if old_slot != slot and old_id == track_id:
|
||||||
|
self._slot_track_ids[old_slot] = None
|
||||||
|
self._slot_track_ids[slot] = track_id
|
||||||
|
continue
|
||||||
|
|
||||||
|
if high_u10_live_vrel:
|
||||||
|
# The range cleared innovation checking above, so geometry here is trustworthy; only vRel is
|
||||||
|
# in question. Preserve current geometry but coast only a recent authoritative motion
|
||||||
|
# estimate without a KF update, rather than publishing a one-sweep-derivative synthesis.
|
||||||
|
trusted_fresh = (track.last_trusted_vrel is not None and track.last_trusted_vrel_nanos is not None and
|
||||||
|
(now - track.last_trusted_vrel_nanos) * 1e-9 <= BOSCH_A_STALE_S)
|
||||||
|
if trusted_fresh:
|
||||||
|
point = self.pts.get(track_id)
|
||||||
|
if point is not None:
|
||||||
|
point.dRel = dRel
|
||||||
|
point.yRel = yRel
|
||||||
|
point.vRel = track.last_trusted_vrel
|
||||||
|
point.measured = False
|
||||||
|
else:
|
||||||
|
track.last_trusted_vrel = None
|
||||||
|
track.last_trusted_vrel_nanos = None
|
||||||
|
self.pts.pop(track_id, None)
|
||||||
|
|
||||||
|
# Do not let a coast-only range observation become a future derivative baseline.
|
||||||
|
track.prev_frame_idx = idx0
|
||||||
|
track.prev_life = life
|
||||||
|
track.last_seen_nanos = now
|
||||||
|
track.wire_slot = slot
|
||||||
|
for old_slot, old_id in enumerate(self._slot_track_ids):
|
||||||
|
if old_slot != slot and old_id == track_id:
|
||||||
|
self._slot_track_ids[old_slot] = None
|
||||||
|
self._slot_track_ids[slot] = track_id
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Native U11 is unavailable here (sentinel/out-of-range -- the high-u10-but-live case above
|
||||||
|
# already returned before this point) and the range-ratio field is unusable or degraded too.
|
||||||
|
# The remaining option is the raw one-sweep (dRel-previous_range)/dt derivative, which is
|
||||||
|
# structurally the same hazard the high-u10 case guards against: a synthesized rate becoming an
|
||||||
|
# authoritative measurement. Coast a recent trusted velocity instead, on the same terms as above,
|
||||||
|
# rather than publish it.
|
||||||
|
# A true birth observation (no previous accepted range yet) can never mature into a published
|
||||||
|
# point this cycle regardless of vRel source -- `matured` below requires a second sample -- so
|
||||||
|
# only intercept once a fallback derivative would actually have something to poison.
|
||||||
|
u11_and_ratio_unavailable = (direct_vrel is None and (ratio_vrel is None or degraded) and
|
||||||
|
previous_sample is not None)
|
||||||
|
if u11_and_ratio_unavailable:
|
||||||
|
trusted_fresh = (track.last_trusted_vrel is not None and track.last_trusted_vrel_nanos is not None and
|
||||||
|
(now - track.last_trusted_vrel_nanos) * 1e-9 <= BOSCH_A_STALE_S)
|
||||||
|
if trusted_fresh:
|
||||||
|
point = self.pts.get(track_id)
|
||||||
|
if point is not None:
|
||||||
|
point.dRel = dRel
|
||||||
|
point.yRel = yRel
|
||||||
|
point.vRel = track.last_trusted_vrel
|
||||||
|
point.measured = False
|
||||||
|
else:
|
||||||
|
track.last_trusted_vrel = None
|
||||||
|
track.last_trusted_vrel_nanos = None
|
||||||
|
self.pts.pop(track_id, None)
|
||||||
|
|
||||||
|
# Do not let a coast-only range observation become a future derivative baseline.
|
||||||
|
track.prev_frame_idx = idx0
|
||||||
|
track.prev_life = life
|
||||||
|
track.last_seen_nanos = now
|
||||||
|
track.wire_slot = slot
|
||||||
|
for old_slot, old_id in enumerate(self._slot_track_ids):
|
||||||
|
if old_slot != slot and old_id == track_id:
|
||||||
|
self._slot_track_ids[old_slot] = None
|
||||||
|
self._slot_track_ids[slot] = track_id
|
||||||
|
continue
|
||||||
|
|
||||||
|
track.samples.append((now_s, dRel))
|
||||||
|
sample_count = len(track.samples)
|
||||||
|
|
||||||
|
# Prefer qualified native U11; otherwise the range-ratio field. The raw one-sweep derivative is
|
||||||
|
# never published as a measurement -- see the coast/drop branch above, which intercepts before
|
||||||
|
# this point whenever neither native U11 nor the ratio field is usable.
|
||||||
|
if direct_vrel is not None:
|
||||||
|
vRel = direct_vrel
|
||||||
|
else:
|
||||||
|
vRel = ratio_vrel
|
||||||
|
trustworthy_vrel = True
|
||||||
|
|
||||||
|
# A birth observation has no range-rate yet. Keep it as history, but do not publish a RadarPoint
|
||||||
|
# until a second coherent observation of the same CAN identity supplies a finite derivative.
|
||||||
|
matured = sample_count >= 2 and math.isfinite(vRel)
|
||||||
|
if trustworthy_vrel:
|
||||||
|
track.last_trusted_vrel = vRel
|
||||||
|
track.last_trusted_vrel_nanos = now
|
||||||
|
if matured and track_id not in self.pts:
|
||||||
|
self.pts[track_id] = structs.RadarData.RadarPoint()
|
||||||
|
self.pts[track_id].trackId = track_id
|
||||||
|
self.pts[track_id].aRel = float('nan')
|
||||||
|
self.pts[track_id].yvRel = float('nan')
|
||||||
|
|
||||||
|
if matured:
|
||||||
|
self.pts[track_id].dRel = dRel
|
||||||
|
self.pts[track_id].yRel = yRel
|
||||||
|
self.pts[track_id].vRel = vRel
|
||||||
|
self.pts[track_id].measured = True
|
||||||
|
else:
|
||||||
|
self.pts.pop(track_id, None)
|
||||||
|
|
||||||
|
track.prev_frame_idx = idx0
|
||||||
|
track.prev_life = life
|
||||||
|
track.last_seen_nanos = now
|
||||||
|
track.wire_slot = slot
|
||||||
|
for old_slot, old_id in enumerate(self._slot_track_ids):
|
||||||
|
if old_slot != slot and old_id == track_id:
|
||||||
|
self._slot_track_ids[old_slot] = None
|
||||||
|
self._slot_track_ids[slot] = track_id
|
||||||
|
|
||||||
|
ret.points = [self.pts[track_id] for track_id in sorted(self.pts)]
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def _update_nidec(self, updated_messages):
|
||||||
ret = structs.RadarData()
|
ret = structs.RadarData()
|
||||||
|
|
||||||
for ii in sorted(updated_messages):
|
for ii in sorted(updated_messages):
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@ import re
|
|||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from opendbc.car import structs
|
from opendbc.car import Bus, structs
|
||||||
from opendbc.car.structs import CarParams
|
from opendbc.car.structs import CarParams
|
||||||
from opendbc.car import gen_empty_fingerprint
|
from opendbc.car import gen_empty_fingerprint
|
||||||
from opendbc.car.honda.interface import CarInterface
|
from opendbc.car.honda.interface import CarInterface
|
||||||
@@ -196,6 +196,16 @@ class TestHondaFingerprint:
|
|||||||
assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_CANFD
|
assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_CANFD
|
||||||
assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_LONG
|
assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_LONG
|
||||||
|
|
||||||
|
def test_mvl_handover_is_scoped_to_accord_11g(self):
|
||||||
|
toggles = get_test_toggles()
|
||||||
|
accord_cp = CarInterface.get_params(CAR.HONDA_ACCORD_11G, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||||
|
crv_cp = CarInterface.get_params(CAR.HONDA_CRV_6G, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||||
|
|
||||||
|
assert Bus.radar in DBC[accord_cp.carFingerprint]
|
||||||
|
assert Bus.radar not in DBC[crv_cp.carFingerprint]
|
||||||
|
assert accord_cp.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_CANFD_MVL
|
||||||
|
assert not crv_cp.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_CANFD_MVL
|
||||||
|
|
||||||
def test_nidec_pedal_detection_enables_interceptor_path(self):
|
def test_nidec_pedal_detection_enables_interceptor_path(self):
|
||||||
toggles = get_test_toggles()
|
toggles = get_test_toggles()
|
||||||
fingerprint = gen_empty_fingerprint()
|
fingerprint = gen_empty_fingerprint()
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ class HondaSafetyFlags(IntFlag):
|
|||||||
RADARLESS = 8
|
RADARLESS = 8
|
||||||
BOSCH_CANFD = 16
|
BOSCH_CANFD = 16
|
||||||
GAS_INTERCEPTOR = 32
|
GAS_INTERCEPTOR = 32
|
||||||
|
# Accord 11G MVL radar/camera handover messages. Keep the generic CAN-FD
|
||||||
|
# safety profile unchanged for other Honda CAN-FD platforms (for example CR-V 6G).
|
||||||
|
BOSCH_CANFD_MVL = 64
|
||||||
|
|
||||||
|
|
||||||
class HondaFlags(IntFlag):
|
class HondaFlags(IntFlag):
|
||||||
@@ -117,11 +120,17 @@ class HondaCarDocs(CarDocs):
|
|||||||
|
|
||||||
self.car_parts = CarParts.common([harness])
|
self.car_parts = CarParts.common([harness])
|
||||||
|
|
||||||
|
if CP.alphaLongitudinalAvailable:
|
||||||
|
self.footnotes.append(Footnote.EXP_LONG)
|
||||||
|
|
||||||
|
|
||||||
class Footnote(Enum):
|
class Footnote(Enum):
|
||||||
CIVIC_DIESEL = CarFootnote(
|
CIVIC_DIESEL = CarFootnote(
|
||||||
"2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.",
|
"2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.",
|
||||||
Column.FSR_STEERING)
|
Column.FSR_STEERING)
|
||||||
|
EXP_LONG = CarFootnote(
|
||||||
|
"Enabling longitudinal control (alpha) will disable all CMBS functionality, including AEB and FCW.",
|
||||||
|
Column.LONGITUDINAL)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -162,7 +171,12 @@ class CAR(Platforms):
|
|||||||
HondaCarDocs("Honda N-Box 2018", "All", min_steer_speed=5.),
|
HondaCarDocs("Honda N-Box 2018", "All", min_steer_speed=5.),
|
||||||
],
|
],
|
||||||
CarSpecs(mass=890., wheelbase=2.520, steerRatio=18.64),
|
CarSpecs(mass=890., wheelbase=2.520, steerRatio=18.64),
|
||||||
{Bus.pt: 'acura_rdx_2020_can_generated'},
|
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
|
||||||
|
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
|
||||||
|
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
|
||||||
|
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
|
||||||
|
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
|
||||||
|
{Bus.pt: 'acura_rdx_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
|
||||||
)
|
)
|
||||||
HONDA_ACCORD = HondaBoschPlatformConfig(
|
HONDA_ACCORD = HondaBoschPlatformConfig(
|
||||||
[
|
[
|
||||||
@@ -172,15 +186,21 @@ class CAR(Platforms):
|
|||||||
],
|
],
|
||||||
# steerRatio: 11.82 is spec end-to-end
|
# steerRatio: 11.82 is spec end-to-end
|
||||||
CarSpecs(mass=3279 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.33, centerToFrontRatio=0.39, tireStiffnessFactor=0.8467),
|
CarSpecs(mass=3279 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.33, centerToFrontRatio=0.39, tireStiffnessFactor=0.8467),
|
||||||
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
|
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
|
||||||
|
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
|
||||||
|
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
|
||||||
|
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
|
||||||
|
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
|
||||||
|
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
|
||||||
flags=HondaFlags.ALLOW_MANUAL_TRANS,
|
flags=HondaFlags.ALLOW_MANUAL_TRANS,
|
||||||
)
|
)
|
||||||
HONDA_ACCORD_11G = HondaBoschCANFDPlatformConfig(
|
HONDA_ACCORD_11G = HondaBoschCANFDPlatformConfig(
|
||||||
[
|
[
|
||||||
HondaCarDocs("Honda Accord 2023-25", "All"),
|
HondaCarDocs("Honda Accord 2023-25", "All"),
|
||||||
HondaCarDocs("Honda Accord Hybrid 2023-25", "All"),
|
HondaCarDocs("Honda Accord Hybrid 2023-25", "All"),
|
||||||
],
|
],
|
||||||
CarSpecs(mass=3477 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.0, centerToFrontRatio=0.39),
|
CarSpecs(mass=3477 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.7, centerToFrontRatio=0.39),
|
||||||
|
{Bus.pt: 'honda_common_canfd_generated', Bus.radar: 'honda_common_canfd_generated'},
|
||||||
)
|
)
|
||||||
HONDA_CIVIC_BOSCH = HondaBoschPlatformConfig(
|
HONDA_CIVIC_BOSCH = HondaBoschPlatformConfig(
|
||||||
[
|
[
|
||||||
@@ -190,12 +210,22 @@ class CAR(Platforms):
|
|||||||
HondaCarDocs("Honda Civic Hatchback 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS),
|
HondaCarDocs("Honda Civic Hatchback 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS),
|
||||||
],
|
],
|
||||||
CarSpecs(mass=1326, wheelbase=2.7, steerRatio=15.38, centerToFrontRatio=0.4), # steerRatio: 10.93 is end-to-end spec
|
CarSpecs(mass=1326, wheelbase=2.7, steerRatio=15.38, centerToFrontRatio=0.4), # steerRatio: 10.93 is end-to-end spec
|
||||||
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
|
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
|
||||||
|
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
|
||||||
|
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
|
||||||
|
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
|
||||||
|
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
|
||||||
|
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
|
||||||
)
|
)
|
||||||
HONDA_CIVIC_BOSCH_DIESEL = HondaBoschPlatformConfig(
|
HONDA_CIVIC_BOSCH_DIESEL = HondaBoschPlatformConfig(
|
||||||
[], # don't show in docs
|
[], # don't show in docs
|
||||||
HONDA_CIVIC_BOSCH.specs,
|
HONDA_CIVIC_BOSCH.specs,
|
||||||
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
|
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
|
||||||
|
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
|
||||||
|
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
|
||||||
|
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
|
||||||
|
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
|
||||||
|
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
|
||||||
)
|
)
|
||||||
HONDA_CIVIC_2022 = HondaBoschPlatformConfig(
|
HONDA_CIVIC_2022 = HondaBoschPlatformConfig(
|
||||||
[
|
[
|
||||||
@@ -214,7 +244,12 @@ class CAR(Platforms):
|
|||||||
[HondaCarDocs("Honda CR-V 2017-22", min_steer_speed=15. * CV.MPH_TO_MS)],
|
[HondaCarDocs("Honda CR-V 2017-22", min_steer_speed=15. * CV.MPH_TO_MS)],
|
||||||
# steerRatio: 12.3 is spec end-to-end
|
# steerRatio: 12.3 is spec end-to-end
|
||||||
CarSpecs(mass=3410 * CV.LB_TO_KG, wheelbase=2.66, steerRatio=16.0, centerToFrontRatio=0.41, tireStiffnessFactor=0.677),
|
CarSpecs(mass=3410 * CV.LB_TO_KG, wheelbase=2.66, steerRatio=16.0, centerToFrontRatio=0.41, tireStiffnessFactor=0.677),
|
||||||
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.body: 'honda_crv_ex_2017_body_generated'},
|
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
|
||||||
|
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
|
||||||
|
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
|
||||||
|
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
|
||||||
|
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
|
||||||
|
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.body: 'honda_crv_ex_2017_body_generated', Bus.radar: 'honda_bosch_a_radar'},
|
||||||
flags=HondaFlags.BOSCH_ALT_BRAKE,
|
flags=HondaFlags.BOSCH_ALT_BRAKE,
|
||||||
)
|
)
|
||||||
HONDA_CRV_6G = HondaBoschCANFDPlatformConfig(
|
HONDA_CRV_6G = HondaBoschCANFDPlatformConfig(
|
||||||
@@ -228,7 +263,12 @@ class CAR(Platforms):
|
|||||||
[HondaCarDocs("Honda CR-V Hybrid 2017-22", min_steer_speed=12. * CV.MPH_TO_MS)],
|
[HondaCarDocs("Honda CR-V Hybrid 2017-22", min_steer_speed=12. * CV.MPH_TO_MS)],
|
||||||
# mass: mean of 4 models in kg, steerRatio: 12.3 is spec end-to-end
|
# mass: mean of 4 models in kg, steerRatio: 12.3 is spec end-to-end
|
||||||
CarSpecs(mass=1667, wheelbase=2.66, steerRatio=16, centerToFrontRatio=0.41, tireStiffnessFactor=0.677),
|
CarSpecs(mass=1667, wheelbase=2.66, steerRatio=16, centerToFrontRatio=0.41, tireStiffnessFactor=0.677),
|
||||||
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
|
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
|
||||||
|
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
|
||||||
|
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
|
||||||
|
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
|
||||||
|
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
|
||||||
|
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
|
||||||
)
|
)
|
||||||
HONDA_HRV_3G = HondaBoschPlatformConfig(
|
HONDA_HRV_3G = HondaBoschPlatformConfig(
|
||||||
[HondaCarDocs("Honda HR-V 2023-25", "All")],
|
[HondaCarDocs("Honda HR-V 2023-25", "All")],
|
||||||
@@ -245,7 +285,12 @@ class CAR(Platforms):
|
|||||||
ACURA_RDX_3G = HondaBoschPlatformConfig(
|
ACURA_RDX_3G = HondaBoschPlatformConfig(
|
||||||
[HondaCarDocs("Acura RDX 2019-21", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
|
[HondaCarDocs("Acura RDX 2019-21", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
|
||||||
CarSpecs(mass=4068 * CV.LB_TO_KG, wheelbase=2.75, steerRatio=11.95, centerToFrontRatio=0.41, tireStiffnessFactor=0.677), # as spec
|
CarSpecs(mass=4068 * CV.LB_TO_KG, wheelbase=2.75, steerRatio=11.95, centerToFrontRatio=0.41, tireStiffnessFactor=0.677), # as spec
|
||||||
{Bus.pt: 'acura_rdx_2020_can_generated'},
|
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
|
||||||
|
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
|
||||||
|
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
|
||||||
|
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
|
||||||
|
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
|
||||||
|
{Bus.pt: 'acura_rdx_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
|
||||||
flags=HondaFlags.BOSCH_ALT_BRAKE,
|
flags=HondaFlags.BOSCH_ALT_BRAKE,
|
||||||
)
|
)
|
||||||
ACURA_RDX_3G_MMR = HondaBoschPlatformConfig(
|
ACURA_RDX_3G_MMR = HondaBoschPlatformConfig(
|
||||||
@@ -257,17 +302,32 @@ class CAR(Platforms):
|
|||||||
HONDA_INSIGHT = HondaBoschPlatformConfig(
|
HONDA_INSIGHT = HondaBoschPlatformConfig(
|
||||||
[HondaCarDocs("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
|
[HondaCarDocs("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
|
||||||
CarSpecs(mass=2987 * CV.LB_TO_KG, wheelbase=2.7, steerRatio=15.0, centerToFrontRatio=0.39, tireStiffnessFactor=0.82), # as spec
|
CarSpecs(mass=2987 * CV.LB_TO_KG, wheelbase=2.7, steerRatio=15.0, centerToFrontRatio=0.39, tireStiffnessFactor=0.82), # as spec
|
||||||
{Bus.pt: 'honda_insight_ex_2019_can_generated'},
|
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
|
||||||
|
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
|
||||||
|
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
|
||||||
|
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
|
||||||
|
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
|
||||||
|
{Bus.pt: 'honda_insight_ex_2019_can_generated', Bus.radar: 'honda_bosch_a_radar'},
|
||||||
)
|
)
|
||||||
HONDA_E = HondaBoschPlatformConfig(
|
HONDA_E = HondaBoschPlatformConfig(
|
||||||
[HondaCarDocs("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
|
[HondaCarDocs("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
|
||||||
CarSpecs(mass=3338.8 * CV.LB_TO_KG, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
|
CarSpecs(mass=3338.8 * CV.LB_TO_KG, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
|
||||||
{Bus.pt: 'acura_rdx_2020_can_generated'},
|
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
|
||||||
|
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
|
||||||
|
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
|
||||||
|
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
|
||||||
|
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
|
||||||
|
{Bus.pt: 'acura_rdx_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
|
||||||
)
|
)
|
||||||
HONDA_E_ADVANCE = HondaBoschPlatformConfig(
|
HONDA_E_ADVANCE = HondaBoschPlatformConfig(
|
||||||
[], # don't show in docs, base trim already in docs
|
[], # don't show in docs, base trim already in docs
|
||||||
CarSpecs(mass=1527, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
|
CarSpecs(mass=1527, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
|
||||||
{Bus.pt: 'honda_e_advance_2020_can_generated'},
|
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
|
||||||
|
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
|
||||||
|
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
|
||||||
|
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
|
||||||
|
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
|
||||||
|
{Bus.pt: 'honda_e_advance_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
|
||||||
)
|
)
|
||||||
HONDA_PILOT_4G = HondaBoschCANFDPlatformConfig(
|
HONDA_PILOT_4G = HondaBoschCANFDPlatformConfig(
|
||||||
[HondaCarDocs("Honda Pilot 2023-25", "All")],
|
[HondaCarDocs("Honda Pilot 2023-25", "All")],
|
||||||
@@ -468,6 +528,12 @@ HONDA_BOSCH = CAR.with_flags(HondaFlags.BOSCH)
|
|||||||
HONDA_BOSCH_RADARLESS = CAR.with_flags(HondaFlags.BOSCH_RADARLESS)
|
HONDA_BOSCH_RADARLESS = CAR.with_flags(HondaFlags.BOSCH_RADARLESS)
|
||||||
HONDA_BOSCH_CANFD = CAR.with_flags(HondaFlags.BOSCH_CANFD)
|
HONDA_BOSCH_CANFD = CAR.with_flags(HondaFlags.BOSCH_CANFD)
|
||||||
HONDA_BOSCH_ALT_RADAR = CAR.with_flags(HondaFlags.BOSCH_ALT_RADAR)
|
HONDA_BOSCH_ALT_RADAR = CAR.with_flags(HondaFlags.BOSCH_ALT_RADAR)
|
||||||
|
# Plain bosch_a harness: not CANFD, not radarless, not alt-radar. These platforms have a firmware-correct
|
||||||
|
# RadarInterface (16-slot Bosch-A object bank, RX-only, see radar_interface.py) available behind
|
||||||
|
# HondaBoschARadar. This describes hardware compatibility only; it is deliberately separate from the
|
||||||
|
# verified set below so a newly supported model cannot start using unvalidated radar data by accident.
|
||||||
|
HONDA_BOSCH_A = HONDA_BOSCH - HONDA_BOSCH_RADARLESS - HONDA_BOSCH_CANFD - HONDA_BOSCH_ALT_RADAR
|
||||||
|
HONDA_BOSCH_A_RADAR_VERIFIED = frozenset({CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CRV_5G})
|
||||||
HONDA_BOSCH_TJA_CONTROL = CAR.with_flags(HondaFlags.BOSCH_TJA_CONTROL)
|
HONDA_BOSCH_TJA_CONTROL = CAR.with_flags(HondaFlags.BOSCH_TJA_CONTROL)
|
||||||
HONDA_CAMERA_MESSAGE_CARS = {
|
HONDA_CAMERA_MESSAGE_CARS = {
|
||||||
CAR.HONDA_ACCORD,
|
CAR.HONDA_ACCORD,
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ from opendbc.car.common.conversions import Conversions as CV
|
|||||||
from opendbc.car.hyundai import hyundaicanfd, hyundaican
|
from opendbc.car.hyundai import hyundaicanfd, hyundaican
|
||||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||||
from opendbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR, CANFD_ANGLE_LONGITUDINAL_CAR, \
|
from opendbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR, CANFD_ANGLE_LONGITUDINAL_CAR, \
|
||||||
CANFD_RADAR_LIVE_LONGITUDINAL_CAR, kia_ev6_gt_line_longitudinal_tuning
|
CANFD_RADAR_LIVE_LONGITUDINAL_CAR, CANFD_ALT_BUTTONS_RESUME_CAR, kia_ev6_gt_line_longitudinal_tuning, \
|
||||||
|
KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID
|
||||||
from opendbc.car.interfaces import CarControllerBase
|
from opendbc.car.interfaces import CarControllerBase
|
||||||
from opendbc.car.vehicle_model import VehicleModel
|
from opendbc.car.vehicle_model import VehicleModel
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
|
from openpilot.starpilot.common.testing_grounds import testing_ground
|
||||||
|
|
||||||
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
||||||
LongCtrlState = structs.CarControl.Actuators.LongControlState
|
LongCtrlState = structs.CarControl.Actuators.LongControlState
|
||||||
@@ -32,6 +34,7 @@ HYUNDAI_CANFD_SCC_DECEL_STEP = 12.5 / 50.0
|
|||||||
IONIQ_6_RESPONSE_MULTIPLIER = 1.2
|
IONIQ_6_RESPONSE_MULTIPLIER = 1.2
|
||||||
IONIQ_6_CANFD_SCC_ACCEL_STEP = (6.0 / 50.0) * IONIQ_6_RESPONSE_MULTIPLIER
|
IONIQ_6_CANFD_SCC_ACCEL_STEP = (6.0 / 50.0) * IONIQ_6_RESPONSE_MULTIPLIER
|
||||||
IONIQ_6_CANFD_SCC_DECEL_STEP = (15.0 / 50.0) * IONIQ_6_RESPONSE_MULTIPLIER
|
IONIQ_6_CANFD_SCC_DECEL_STEP = (15.0 / 50.0) * IONIQ_6_RESPONSE_MULTIPLIER
|
||||||
|
EV9_CANFD_SCC_DECEL_STEP = 10.0 / 50.0
|
||||||
GENESIS_G90_STOP_HOLD_SPEED_BP = [0.0, 0.03, 0.08, 0.16, 0.3, 0.5, 0.8, 1.2, 2.0, 3.0]
|
GENESIS_G90_STOP_HOLD_SPEED_BP = [0.0, 0.03, 0.08, 0.16, 0.3, 0.5, 0.8, 1.2, 2.0, 3.0]
|
||||||
GENESIS_G90_STOP_HOLD_ACCEL_V = [-0.10, -0.10, -0.12, -0.18, -0.30, -0.50, -0.75, -1.00, -1.40, -1.80]
|
GENESIS_G90_STOP_HOLD_ACCEL_V = [-0.10, -0.10, -0.12, -0.18, -0.30, -0.50, -0.75, -1.00, -1.40, -1.80]
|
||||||
GENESIS_G90_STOP_HOLD_RELAX_SPEED_BP = [0.0, 0.08, 0.16, 0.3, 0.5, 0.8, 1.2, 2.0, 3.0]
|
GENESIS_G90_STOP_HOLD_RELAX_SPEED_BP = [0.0, 0.08, 0.16, 0.3, 0.5, 0.8, 1.2, 2.0, 3.0]
|
||||||
@@ -42,6 +45,7 @@ GENESIS_G90_RELEASE_DECEL_STEP_V = [0.16, 0.18, 0.18]
|
|||||||
GENESIS_G90_RELEASE_MAX_SPEED = 0.8
|
GENESIS_G90_RELEASE_MAX_SPEED = 0.8
|
||||||
IONIQ_6_LONG_MIN_JERK = 0.5 * IONIQ_6_RESPONSE_MULTIPLIER
|
IONIQ_6_LONG_MIN_JERK = 0.5 * IONIQ_6_RESPONSE_MULTIPLIER
|
||||||
IONIQ_6_LONG_JERK_LIMIT = 4.8 * IONIQ_6_RESPONSE_MULTIPLIER
|
IONIQ_6_LONG_JERK_LIMIT = 4.8 * IONIQ_6_RESPONSE_MULTIPLIER
|
||||||
|
EV9_LONG_DECEL_JERK = 2.0
|
||||||
IONIQ_6_LONG_LOOKAHEAD_JERK_BP = [2.0, 5.0, 20.0]
|
IONIQ_6_LONG_LOOKAHEAD_JERK_BP = [2.0, 5.0, 20.0]
|
||||||
IONIQ_6_LONG_LOOKAHEAD_JERK_V = [0.3 / IONIQ_6_RESPONSE_MULTIPLIER,
|
IONIQ_6_LONG_LOOKAHEAD_JERK_V = [0.3 / IONIQ_6_RESPONSE_MULTIPLIER,
|
||||||
0.45 / IONIQ_6_RESPONSE_MULTIPLIER,
|
0.45 / IONIQ_6_RESPONSE_MULTIPLIER,
|
||||||
@@ -76,12 +80,22 @@ BLINDSPOT_WARNING_SOUND_SAMPLES = 36
|
|||||||
|
|
||||||
|
|
||||||
def egmp_dynamic_longitudinal_tuning(CP) -> bool:
|
def egmp_dynamic_longitudinal_tuning(CP) -> bool:
|
||||||
return CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9) or \
|
return CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE) or \
|
||||||
kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, getattr(CP, "carVin", ""))
|
kia_ev6_gt_line_longitudinal_tuning(
|
||||||
|
CP.carFingerprint, getattr(CP, "carVin", ""),
|
||||||
|
testing_ground.use(KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_canfd_scc_decel_step(CP) -> float:
|
||||||
|
return EV9_CANFD_SCC_DECEL_STEP if CP.carFingerprint == CAR.KIA_EV9 else IONIQ_6_CANFD_SCC_DECEL_STEP
|
||||||
|
|
||||||
|
|
||||||
def should_reset_ev6_gt_line_longitudinal_tuning(CP, long_control_state: LongCtrlState) -> bool:
|
def should_reset_ev6_gt_line_longitudinal_tuning(CP, long_control_state: LongCtrlState) -> bool:
|
||||||
return kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, getattr(CP, "carVin", "")) and \
|
return kia_ev6_gt_line_longitudinal_tuning(
|
||||||
|
CP.carFingerprint, getattr(CP, "carVin", ""),
|
||||||
|
testing_ground.use(KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID),
|
||||||
|
) and \
|
||||||
long_control_state == LongCtrlState.off
|
long_control_state == LongCtrlState.off
|
||||||
|
|
||||||
|
|
||||||
@@ -152,6 +166,15 @@ def should_track_stop_accel_directly(stopping: bool, v_ego: float,
|
|||||||
return bool(stopping and v_ego > EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED and accel_cmd < actual_accel)
|
return bool(stopping and v_ego > EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED and accel_cmd < actual_accel)
|
||||||
|
|
||||||
|
|
||||||
|
def should_track_stop_accel_directly_for_car(car_fingerprint, stopping: bool, v_ego: float,
|
||||||
|
accel_cmd: float, actual_accel: float) -> bool:
|
||||||
|
# EV9 uses the low-speed stop cap to avoid a harsh lead re-brake handoff.
|
||||||
|
# Keep direct tracking for the other CCNC angle-steering platform.
|
||||||
|
return car_fingerprint != CAR.KIA_EV9 and should_track_stop_accel_directly(
|
||||||
|
stopping, v_ego, accel_cmd, actual_accel,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def should_use_ev6_gt_line_stop_direct_tracking(ev6_gt_line: bool, stopping: bool, v_ego: float,
|
def should_use_ev6_gt_line_stop_direct_tracking(ev6_gt_line: bool, stopping: bool, v_ego: float,
|
||||||
accel_cmd: float, actual_accel: float) -> bool:
|
accel_cmd: float, actual_accel: float) -> bool:
|
||||||
return bool(ev6_gt_line and stopping and v_ego > EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED and accel_cmd < actual_accel)
|
return bool(ev6_gt_line and stopping and v_ego > EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED and accel_cmd < actual_accel)
|
||||||
@@ -233,7 +256,8 @@ def reset_egmp_longitudinal_tuning(state: Ioniq6LongitudinalTuningState) -> Ioni
|
|||||||
|
|
||||||
def update_ioniq_6_longitudinal_tuning(state: Ioniq6LongitudinalTuningState, accel_cmd: float, v_ego: float, a_ego: float,
|
def update_ioniq_6_longitudinal_tuning(state: Ioniq6LongitudinalTuningState, accel_cmd: float, v_ego: float, a_ego: float,
|
||||||
long_control_state: LongCtrlState, long_active: bool,
|
long_control_state: LongCtrlState, long_active: bool,
|
||||||
ev6_gt_line: bool = False, low_speed_stop_brake_cap: bool = False) -> Ioniq6LongitudinalTuningState:
|
ev6_gt_line: bool = False, low_speed_stop_brake_cap: bool = False,
|
||||||
|
ev9: bool = False) -> Ioniq6LongitudinalTuningState:
|
||||||
starting = long_control_state == LongCtrlState.starting
|
starting = long_control_state == LongCtrlState.starting
|
||||||
stopping = long_control_state == LongCtrlState.stopping
|
stopping = long_control_state == LongCtrlState.stopping
|
||||||
restart_from_stop = state.long_control_state_last in (LongCtrlState.stopping, LongCtrlState.starting) and \
|
restart_from_stop = state.long_control_state_last in (LongCtrlState.stopping, LongCtrlState.starting) and \
|
||||||
@@ -273,6 +297,8 @@ def update_ioniq_6_longitudinal_tuning(state: Ioniq6LongitudinalTuningState, acc
|
|||||||
dynamic_lower_jerk = _calculate_ioniq_6_dynamic_lower_jerk(dynamic_accel_error)
|
dynamic_lower_jerk = _calculate_ioniq_6_dynamic_lower_jerk(dynamic_accel_error)
|
||||||
state.jerk_upper = desired_jerk_upper
|
state.jerk_upper = desired_jerk_upper
|
||||||
state.jerk_lower = min(dynamic_lower_jerk, lower_speed_limit)
|
state.jerk_lower = min(dynamic_lower_jerk, lower_speed_limit)
|
||||||
|
if ev9:
|
||||||
|
state.jerk_lower = min(state.jerk_lower, EV9_LONG_DECEL_JERK)
|
||||||
|
|
||||||
if state.stopping:
|
if state.stopping:
|
||||||
stop_brake_cap_max_speed = EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED if ev6_gt_line or low_speed_stop_brake_cap else \
|
stop_brake_cap_max_speed = EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED if ev6_gt_line or low_speed_stop_brake_cap else \
|
||||||
@@ -390,6 +416,27 @@ def process_hud_alert(enabled, fingerprint, hud_control):
|
|||||||
return sys_warning, sys_state, left_lane_warning, right_lane_warning
|
return sys_warning, sys_state, left_lane_warning, right_lane_warning
|
||||||
|
|
||||||
|
|
||||||
|
def preserve_stock_canfd_lfa_status(car_fingerprint) -> bool:
|
||||||
|
return car_fingerprint not in (CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN)
|
||||||
|
|
||||||
|
|
||||||
|
def preserve_stock_canfd_lkas_status(car_fingerprint) -> bool:
|
||||||
|
return car_fingerprint not in (CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN)
|
||||||
|
|
||||||
|
|
||||||
|
def suppress_redundant_gv70_brake_cancel(CP, brake_pressed: bool, lat_active: bool) -> bool:
|
||||||
|
return bool(
|
||||||
|
CP.carFingerprint == CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN and
|
||||||
|
not CP.openpilotLongitudinalControl and brake_pressed and lat_active
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def clear_ioniq_6_torque_when_request_inactive(CP, apply_torque: int, apply_steer_req: bool) -> int:
|
||||||
|
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and not apply_steer_req:
|
||||||
|
return 0
|
||||||
|
return apply_torque
|
||||||
|
|
||||||
|
|
||||||
class CarController(CarControllerBase):
|
class CarController(CarControllerBase):
|
||||||
def __init__(self, dbc_names, CP):
|
def __init__(self, dbc_names, CP):
|
||||||
super().__init__(dbc_names, CP)
|
super().__init__(dbc_names, CP)
|
||||||
@@ -411,11 +458,11 @@ class CarController(CarControllerBase):
|
|||||||
self.ecu_disable_failed = False
|
self.ecu_disable_failed = False
|
||||||
self._ecu_disable_checked = False
|
self._ecu_disable_checked = False
|
||||||
self._params = Params()
|
self._params = Params()
|
||||||
if CP.carFingerprint == CAR.KIA_EV9:
|
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR:
|
||||||
self._ev9_long_tuning = EV9LongitudinalTuningState()
|
self._ev9_long_tuning = EV9LongitudinalTuningState()
|
||||||
self._left_blindspot_warning = BlindspotWarningState()
|
self._left_blindspot_warning = BlindspotWarningState()
|
||||||
self._right_blindspot_warning = BlindspotWarningState()
|
self._right_blindspot_warning = BlindspotWarningState()
|
||||||
self.long_active_ecu = self.CP.openpilotLongitudinalControl
|
self.long_active_ecu = self.CP.openpilotLongitudinalControl and not (self.CP.flags & HyundaiFlags.NON_SCC)
|
||||||
self._ioniq_6_lane_change_ui_side = None
|
self._ioniq_6_lane_change_ui_side = None
|
||||||
self._ioniq_6_lane_change_ui_frames = 0
|
self._ioniq_6_lane_change_ui_frames = 0
|
||||||
self._ioniq_6_long_tuning = Ioniq6LongitudinalTuningState()
|
self._ioniq_6_long_tuning = Ioniq6LongitudinalTuningState()
|
||||||
@@ -423,6 +470,7 @@ class CarController(CarControllerBase):
|
|||||||
self._dash_lat_disengage_blink_frame = 0
|
self._dash_lat_disengage_blink_frame = 0
|
||||||
self._dash_lat_disengage_init = False
|
self._dash_lat_disengage_init = False
|
||||||
self._dash_prev_lat_active = False
|
self._dash_prev_lat_active = False
|
||||||
|
self._ray_lkas11_active = False
|
||||||
|
|
||||||
def _update_dash_icon_state(self, CC):
|
def _update_dash_icon_state(self, CC):
|
||||||
if CC.latActive:
|
if CC.latActive:
|
||||||
@@ -515,6 +563,8 @@ class CarController(CarControllerBase):
|
|||||||
drive_gear = CS.out.gearShifter == structs.CarState.GearShifter.drive
|
drive_gear = CS.out.gearShifter == structs.CarState.GearShifter.drive
|
||||||
angle_lat_active = direct_angle_request_allowed(CS.out.vEgoRaw, measured_steering_angle, self.apply_angle_last,
|
angle_lat_active = direct_angle_request_allowed(CS.out.vEgoRaw, measured_steering_angle, self.apply_angle_last,
|
||||||
drive_gear, self.BASELINE_VM, self.params) and not CS.angle_steering_fault
|
drive_gear, self.BASELINE_VM, self.params) and not CS.angle_steering_fault
|
||||||
|
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_5_PE and CS.out.standstill:
|
||||||
|
angle_lat_active = False
|
||||||
self.direct_angle_request_allowed = angle_lat_active
|
self.direct_angle_request_allowed = angle_lat_active
|
||||||
apply_angle = measured_steering_angle
|
apply_angle = measured_steering_angle
|
||||||
|
|
||||||
@@ -570,6 +620,8 @@ class CarController(CarControllerBase):
|
|||||||
if not CC.latActive:
|
if not CC.latActive:
|
||||||
apply_torque = 0
|
apply_torque = 0
|
||||||
|
|
||||||
|
apply_torque = clear_ioniq_6_torque_when_request_inactive(self.CP, apply_torque, apply_steer_req)
|
||||||
|
|
||||||
# Hold torque with induced temporary fault when cutting the actuation bit
|
# Hold torque with induced temporary fault when cutting the actuation bit
|
||||||
# FIXME: we don't use this with CAN FD?
|
# FIXME: we don't use this with CAN FD?
|
||||||
torque_fault = CC.latActive and not apply_steer_req
|
torque_fault = CC.latActive and not apply_steer_req
|
||||||
@@ -592,13 +644,16 @@ class CarController(CarControllerBase):
|
|||||||
|
|
||||||
# When ECU disable was skipped (car started in READY mode), don't send any
|
# When ECU disable was skipped (car started in READY mode), don't send any
|
||||||
# longitudinal messages - stock ECU is still active and these would conflict
|
# longitudinal messages - stock ECU is still active and these would conflict
|
||||||
self.long_active_ecu = self.CP.openpilotLongitudinalControl and not self.ecu_disable_failed
|
self.long_active_ecu = self.CP.openpilotLongitudinalControl and not (self.CP.flags & HyundaiFlags.NON_SCC) and not self.ecu_disable_failed
|
||||||
|
|
||||||
use_egmp_dynamic_long_tuning = egmp_dynamic_longitudinal_tuning(self.CP) and self.long_active_ecu and \
|
use_egmp_dynamic_long_tuning = egmp_dynamic_longitudinal_tuning(self.CP) and self.long_active_ecu and \
|
||||||
actuators.longControlState in (LongCtrlState.starting, LongCtrlState.pid, LongCtrlState.stopping)
|
actuators.longControlState in (LongCtrlState.starting, LongCtrlState.pid, LongCtrlState.stopping)
|
||||||
is_ev6_gt_line = kia_ev6_gt_line_longitudinal_tuning(self.CP.carFingerprint, getattr(self.CP, "carVin", ""))
|
is_ev6_gt_line = kia_ev6_gt_line_longitudinal_tuning(
|
||||||
is_ev9 = self.CP.carFingerprint == CAR.KIA_EV9
|
self.CP.carFingerprint, getattr(self.CP, "carVin", ""),
|
||||||
if is_ev9 and (self._ev9_long_tuning.stop_request or not CC.enabled or CC.cruiseControl.override):
|
testing_ground.use(KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID),
|
||||||
|
)
|
||||||
|
is_ccnc_angle_long = self.CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR
|
||||||
|
if is_ccnc_angle_long and (self._ev9_long_tuning.stop_request or not CC.enabled or CC.cruiseControl.override):
|
||||||
self._ioniq_6_long_tuning = reset_egmp_longitudinal_tuning(self._ioniq_6_long_tuning)
|
self._ioniq_6_long_tuning = reset_egmp_longitudinal_tuning(self._ioniq_6_long_tuning)
|
||||||
if should_reset_ev6_gt_line_longitudinal_tuning(self.CP, actuators.longControlState):
|
if should_reset_ev6_gt_line_longitudinal_tuning(self.CP, actuators.longControlState):
|
||||||
self._ioniq_6_long_tuning = reset_ev6_gt_line_longitudinal_tuning(self._ioniq_6_long_tuning, self.CP,
|
self._ioniq_6_long_tuning = reset_ev6_gt_line_longitudinal_tuning(self._ioniq_6_long_tuning, self.CP,
|
||||||
@@ -608,25 +663,30 @@ class CarController(CarControllerBase):
|
|||||||
CS.out.vEgo, CS.out.aEgo,
|
CS.out.vEgo, CS.out.aEgo,
|
||||||
actuators.longControlState, self.long_active_ecu,
|
actuators.longControlState, self.long_active_ecu,
|
||||||
ev6_gt_line=is_ev6_gt_line,
|
ev6_gt_line=is_ev6_gt_line,
|
||||||
low_speed_stop_brake_cap=is_ev9)
|
low_speed_stop_brake_cap=is_ccnc_angle_long,
|
||||||
|
ev9=self.CP.carFingerprint == CAR.KIA_EV9)
|
||||||
use_egmp_smoothed_accel = use_egmp_dynamic_long_tuning and (
|
use_egmp_smoothed_accel = use_egmp_dynamic_long_tuning and (
|
||||||
accel_cmd >= self._ioniq_6_long_tuning.actual_accel or
|
accel_cmd >= self._ioniq_6_long_tuning.actual_accel or
|
||||||
self._ioniq_6_long_tuning.launch_active or
|
self._ioniq_6_long_tuning.launch_active or
|
||||||
self._ioniq_6_long_tuning.stopping
|
self._ioniq_6_long_tuning.stopping or
|
||||||
|
self.CP.carFingerprint == CAR.KIA_EV9
|
||||||
)
|
)
|
||||||
if should_use_ev6_gt_line_stop_direct_tracking(is_ev6_gt_line, self._ioniq_6_long_tuning.stopping,
|
if should_use_ev6_gt_line_stop_direct_tracking(is_ev6_gt_line, self._ioniq_6_long_tuning.stopping,
|
||||||
CS.out.vEgo, accel_cmd, self._ioniq_6_long_tuning.actual_accel):
|
CS.out.vEgo, accel_cmd, self._ioniq_6_long_tuning.actual_accel):
|
||||||
use_egmp_smoothed_accel = False
|
use_egmp_smoothed_accel = False
|
||||||
if is_ev9 and should_track_stop_accel_directly(self._ioniq_6_long_tuning.stopping, CS.out.vEgo,
|
if is_ccnc_angle_long and should_track_stop_accel_directly_for_car(
|
||||||
accel_cmd, self._ioniq_6_long_tuning.actual_accel):
|
self.CP.carFingerprint, self._ioniq_6_long_tuning.stopping, CS.out.vEgo,
|
||||||
|
accel_cmd, self._ioniq_6_long_tuning.actual_accel,
|
||||||
|
):
|
||||||
use_egmp_smoothed_accel = False
|
use_egmp_smoothed_accel = False
|
||||||
if use_egmp_dynamic_long_tuning:
|
if use_egmp_dynamic_long_tuning:
|
||||||
if use_egmp_smoothed_accel:
|
if use_egmp_smoothed_accel:
|
||||||
accel = self._ioniq_6_long_tuning.actual_accel
|
accel = self._ioniq_6_long_tuning.actual_accel
|
||||||
stopping = self._ioniq_6_long_tuning.stopping
|
stopping = self._ioniq_6_long_tuning.stopping
|
||||||
else:
|
else:
|
||||||
|
decel_step = get_canfd_scc_decel_step(self.CP)
|
||||||
accel = float(np.clip(accel_cmd,
|
accel = float(np.clip(accel_cmd,
|
||||||
self.accel_last - IONIQ_6_CANFD_SCC_DECEL_STEP,
|
self.accel_last - decel_step,
|
||||||
self.accel_last + IONIQ_6_CANFD_SCC_ACCEL_STEP))
|
self.accel_last + IONIQ_6_CANFD_SCC_ACCEL_STEP))
|
||||||
self._ioniq_6_long_tuning.desired_accel = accel_cmd
|
self._ioniq_6_long_tuning.desired_accel = accel_cmd
|
||||||
self._ioniq_6_long_tuning.actual_accel = accel
|
self._ioniq_6_long_tuning.actual_accel = accel
|
||||||
@@ -663,7 +723,7 @@ class CarController(CarControllerBase):
|
|||||||
stopping, hud_control, CS, CC, starpilot_toggles, lka_icon, lfa_icon))
|
stopping, hud_control, CS, CC, starpilot_toggles, lka_icon, lfa_icon))
|
||||||
else:
|
else:
|
||||||
can_sends.extend(self.create_can_msgs(apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel,
|
can_sends.extend(self.create_can_msgs(apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel,
|
||||||
stopping, hud_control, actuators, CS, CC, lfa_icon))
|
stopping, hud_control, actuators, CS, CC, lka_icon, lfa_icon))
|
||||||
|
|
||||||
new_actuators = actuators.as_builder()
|
new_actuators = actuators.as_builder()
|
||||||
if self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
|
if self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
|
||||||
@@ -678,24 +738,45 @@ class CarController(CarControllerBase):
|
|||||||
self.frame += 1
|
self.frame += 1
|
||||||
return new_actuators, can_sends
|
return new_actuators, can_sends
|
||||||
|
|
||||||
def create_can_msgs(self, apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel, stopping, hud_control, actuators, CS, CC, lfa_icon):
|
def create_can_msgs(self, apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel, stopping, hud_control, actuators, CS, CC, lka_icon, lfa_icon):
|
||||||
can_sends = []
|
can_sends = []
|
||||||
can_canfd_blended = bool(self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED)
|
can_canfd_blended = bool(self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED)
|
||||||
|
blended_hda2 = can_canfd_blended and bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING)
|
||||||
|
|
||||||
# HUD messages
|
# HUD messages
|
||||||
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
||||||
hud_control)
|
hud_control)
|
||||||
|
|
||||||
if can_canfd_blended:
|
if blended_hda2:
|
||||||
|
can_sends.extend(hyundaicanfd.create_steering_messages(
|
||||||
|
self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque, 0.0,
|
||||||
|
))
|
||||||
|
if self.long_active_ecu:
|
||||||
|
can_sends.extend(hyundaican.create_lkas11_can_canfd_blended(
|
||||||
|
self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
|
||||||
|
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
||||||
|
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||||
|
left_lane_warning, right_lane_warning, CS.msg_364,
|
||||||
|
include_alerts=False,
|
||||||
|
counter_mod=0xF,
|
||||||
|
))
|
||||||
|
if self.frame % 5 == 0:
|
||||||
|
can_sends.append(hyundaicanfd.create_suppress_lfa(
|
||||||
|
self.packer, self.CAN, CS.lfa_block_msg, False,
|
||||||
|
))
|
||||||
|
elif can_canfd_blended:
|
||||||
can_sends.extend(hyundaican.create_lkas11_can_canfd_blended(self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
|
can_sends.extend(hyundaican.create_lkas11_can_canfd_blended(self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
|
||||||
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
||||||
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||||
left_lane_warning, right_lane_warning, CS.msg_364))
|
left_lane_warning, right_lane_warning, CS.msg_364))
|
||||||
else:
|
else:
|
||||||
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
|
if self.CP.carFingerprint != CAR.KIA_RAY_EV or self._ray_lkas11_active:
|
||||||
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
|
||||||
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
||||||
left_lane_warning, right_lane_warning))
|
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||||
|
left_lane_warning, right_lane_warning, lka_icon))
|
||||||
|
if self.CP.carFingerprint == CAR.KIA_RAY_EV:
|
||||||
|
self._ray_lkas11_active = True
|
||||||
|
|
||||||
# Button messages
|
# Button messages
|
||||||
if not self.long_active_ecu:
|
if not self.long_active_ecu:
|
||||||
@@ -712,13 +793,23 @@ class CarController(CarControllerBase):
|
|||||||
can_sends.extend(self._create_can_redneck_button_messages(CS))
|
can_sends.extend(self._create_can_redneck_button_messages(CS))
|
||||||
|
|
||||||
if self.long_active_ecu and can_canfd_blended:
|
if self.long_active_ecu and can_canfd_blended:
|
||||||
can_sends.extend(hyundaican.create_radar_aux_messages(self.packer, self.CAN, self.frame))
|
if blended_hda2:
|
||||||
|
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame, blended_hda2=True))
|
||||||
|
can_sends.extend(hyundaican.create_radar_aux_messages(self.packer, self.CAN, self.frame, hda2=blended_hda2))
|
||||||
|
|
||||||
if self.frame % 2 == 0 and self.long_active_ecu:
|
if self.frame % 2 == 0 and self.long_active_ecu:
|
||||||
# TODO: unclear if this is needed
|
# TODO: unclear if this is needed
|
||||||
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
|
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
|
||||||
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
|
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
|
||||||
if can_canfd_blended:
|
main_cruise_enabled = getattr(CS, "main_cruise_on", False) if getattr(CS, "main_cruise_tracking", False) else True
|
||||||
|
if blended_hda2:
|
||||||
|
stopping = stopping and CS.out.vEgoRaw < 0.1
|
||||||
|
can_sends.extend(hyundaican.create_acc_commands_can_canfd_blended_hda2(
|
||||||
|
self.packer, CC.enabled, accel, self.accel_last, jerk, int(self.frame / 2), hud_control,
|
||||||
|
set_speed_in_units, stopping, CC.cruiseControl.override, use_fca, self.CP,
|
||||||
|
))
|
||||||
|
self.accel_last = accel
|
||||||
|
elif can_canfd_blended:
|
||||||
can_sends.extend(hyundaican.create_acc_commands_can_canfd_blended(self.packer, CC.enabled, accel, jerk,
|
can_sends.extend(hyundaican.create_acc_commands_can_canfd_blended(self.packer, CC.enabled, accel, jerk,
|
||||||
int(self.frame / 2), hud_control,
|
int(self.frame / 2), hud_control,
|
||||||
set_speed_in_units, stopping,
|
set_speed_in_units, stopping,
|
||||||
@@ -726,10 +817,11 @@ class CarController(CarControllerBase):
|
|||||||
else:
|
else:
|
||||||
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
|
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
|
||||||
hud_control, set_speed_in_units, stopping,
|
hud_control, set_speed_in_units, stopping,
|
||||||
CC.cruiseControl.override, use_fca, self.CP))
|
CC.cruiseControl.override, use_fca, self.CP,
|
||||||
|
main_cruise_enabled))
|
||||||
|
|
||||||
# 20 Hz LFA MFA message
|
# 20 Hz LFA MFA message
|
||||||
if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
|
if self.frame % 5 == 0 and (self.CP.flags & HyundaiFlags.SEND_LFA.value or (self.long_active_ecu and blended_hda2)):
|
||||||
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled, self.frame, self.CP, lfa_icon))
|
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled, self.frame, self.CP, lfa_icon))
|
||||||
|
|
||||||
# 5 Hz ACC options
|
# 5 Hz ACC options
|
||||||
@@ -758,7 +850,12 @@ class CarController(CarControllerBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# steering control
|
# steering control
|
||||||
preserve_stock_lkas = bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING) and not self.long_active_ecu
|
# The first-generation Electrified GV70 expects the synthesized LKAS status
|
||||||
|
# payload. Forwarding its stock status bits leaves lane-safety state asserted
|
||||||
|
# while StarPilot is suppressing the stock LFA path.
|
||||||
|
preserve_stock_lkas = bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING) and \
|
||||||
|
not self.long_active_ecu and self.CP.carFingerprint != CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN and \
|
||||||
|
preserve_stock_canfd_lkas_status(self.CP.carFingerprint)
|
||||||
angle_lkas_alt = bool(self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and
|
angle_lkas_alt = bool(self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and
|
||||||
self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||||
ccnc_angle_long = self.CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and \
|
ccnc_angle_long = self.CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and \
|
||||||
@@ -777,10 +874,11 @@ class CarController(CarControllerBase):
|
|||||||
forward_stock_lkas = angle_lkas_alt and (
|
forward_stock_lkas = angle_lkas_alt and (
|
||||||
angle_lkas_alt_standstill_handoff or not (drive_gear and (CC.latActive or CC.enabled))
|
angle_lkas_alt_standstill_handoff or not (drive_gear and (CC.latActive or CC.enabled))
|
||||||
)
|
)
|
||||||
|
preserve_stock_lfa_status = preserve_stock_canfd_lfa_status(self.CP.carFingerprint)
|
||||||
if not forward_stock_lkas and not ccnc_angle_long:
|
if not forward_stock_lkas and not ccnc_angle_long:
|
||||||
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled,
|
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled,
|
||||||
steering_msg_active, apply_torque, apply_angle,
|
steering_msg_active, apply_torque, apply_angle,
|
||||||
CS.stock_lfa_msg,
|
CS.stock_lfa_msg if preserve_stock_lfa_status else None,
|
||||||
CS.stock_lkas_msg if preserve_stock_lkas else None,
|
CS.stock_lkas_msg if preserve_stock_lkas else None,
|
||||||
lka_icon=lka_icon))
|
lka_icon=lka_icon))
|
||||||
direct_steering_active = ccnc_angle_long and drive_gear and CC.latActive and self.direct_angle_request_allowed and not CS.angle_steering_fault
|
direct_steering_active = ccnc_angle_long and drive_gear and CC.latActive and self.direct_angle_request_allowed and not CS.angle_steering_fault
|
||||||
@@ -812,7 +910,8 @@ class CarController(CarControllerBase):
|
|||||||
CC.leftBlinker, CC.rightBlinker, CS.msg_161, CS.msg_162, CS.msg_1b5,
|
CC.leftBlinker, CC.rightBlinker, CS.msg_161, CS.msg_162, CS.msg_1b5,
|
||||||
CS.is_metric, CS.out, CS.out.cruiseState.available, lfa_icon))
|
CS.is_metric, CS.out, CS.out.cruiseState.available, lfa_icon))
|
||||||
else:
|
else:
|
||||||
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled, CS.stock_lfahda_cluster_msg,
|
cluster_base_values = CS.stock_lfahda_cluster_msg if preserve_stock_lfa_status else None
|
||||||
|
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled, cluster_base_values,
|
||||||
lfa_icon=lfa_icon))
|
lfa_icon=lfa_icon))
|
||||||
|
|
||||||
# blinkers
|
# blinkers
|
||||||
@@ -897,16 +996,19 @@ class CarController(CarControllerBase):
|
|||||||
CC.leftBlinker,
|
CC.leftBlinker,
|
||||||
CC.rightBlinker))
|
CC.rightBlinker))
|
||||||
if self.frame % 2 == 0:
|
if self.frame % 2 == 0:
|
||||||
lead_visible, lead_distance, lead_rel_speed = self._get_canfd_scc_lead_state(CC, CS, now_nanos)
|
if self.CP.carFingerprint == CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN:
|
||||||
acc_kwargs = {
|
acc_kwargs = {}
|
||||||
"main_mode_acc": int(CS.out.cruiseState.available),
|
else:
|
||||||
"direct_accel": True,
|
lead_visible, lead_distance, lead_rel_speed = self._get_canfd_scc_lead_state(CC, CS, now_nanos)
|
||||||
"jerk_lower": 5.0,
|
acc_kwargs = {
|
||||||
"jerk_upper": 3.0 if CC.actuators.longControlState == LongCtrlState.pid else 1.0,
|
"main_mode_acc": int(CS.out.cruiseState.available),
|
||||||
"lead_distance": lead_distance,
|
"direct_accel": True,
|
||||||
"lead_rel_speed": lead_rel_speed,
|
"jerk_lower": 5.0,
|
||||||
"lead_visible": lead_visible,
|
"jerk_upper": 3.0 if CC.actuators.longControlState == LongCtrlState.pid else 1.0,
|
||||||
}
|
"lead_distance": lead_distance,
|
||||||
|
"lead_rel_speed": lead_rel_speed,
|
||||||
|
"lead_visible": lead_visible,
|
||||||
|
}
|
||||||
if use_egmp_dynamic_long_tuning:
|
if use_egmp_dynamic_long_tuning:
|
||||||
if use_egmp_smoothed_accel:
|
if use_egmp_smoothed_accel:
|
||||||
acc_kwargs["jerk_lower"] = self._ioniq_6_long_tuning.jerk_lower
|
acc_kwargs["jerk_lower"] = self._ioniq_6_long_tuning.jerk_lower
|
||||||
@@ -938,7 +1040,10 @@ class CarController(CarControllerBase):
|
|||||||
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
|
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
|
||||||
# cruise cancel - suppress when stock ACC is the fallback (ECU disable failed),
|
# cruise cancel - suppress when stock ACC is the fallback (ECU disable failed),
|
||||||
# so openpilot doesn't fight/cancel the user's stock cruise
|
# so openpilot doesn't fight/cancel the user's stock cruise
|
||||||
if CC.cruiseControl.cancel and not self.ecu_disable_failed:
|
suppress_brake_cancel = suppress_redundant_gv70_brake_cancel(
|
||||||
|
self.CP, CS.out.brakePressed, CC.latActive,
|
||||||
|
)
|
||||||
|
if CC.cruiseControl.cancel and not self.ecu_disable_failed and not suppress_brake_cancel:
|
||||||
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||||
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
|
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
|
||||||
self.last_button_frame = self.frame
|
self.last_button_frame = self.frame
|
||||||
@@ -949,9 +1054,13 @@ class CarController(CarControllerBase):
|
|||||||
|
|
||||||
# cruise standstill resume
|
# cruise standstill resume
|
||||||
elif CC.cruiseControl.resume:
|
elif CC.cruiseControl.resume:
|
||||||
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS and self.CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR:
|
||||||
# TODO: resume for alt button cars
|
for _ in range(20):
|
||||||
pass
|
can_sends.append(hyundaicanfd.create_buttons(
|
||||||
|
self.packer, self.CP, self.CAN, (CS.buttons_counter + 1) % 0x100,
|
||||||
|
Buttons.RES_ACCEL, base_values=CS.cruise_buttons_msg,
|
||||||
|
))
|
||||||
|
self.last_button_frame = self.frame
|
||||||
else:
|
else:
|
||||||
for _ in range(20):
|
for _ in range(20):
|
||||||
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.RES_ACCEL))
|
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.RES_ACCEL))
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from opendbc.car.common.conversions import Conversions as CV
|
|||||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||||
from opendbc.car.hyundai.values import HyundaiFlags, HyundaiStarPilotFlags, HyundaiStarPilotSafetyFlags, CAR, DBC, Buttons, CarControllerParams, \
|
from opendbc.car.hyundai.values import HyundaiFlags, HyundaiStarPilotFlags, HyundaiStarPilotSafetyFlags, CAR, DBC, Buttons, CarControllerParams, \
|
||||||
CANFD_ANGLE_LONGITUDINAL_CAR, CANFD_CORNER_RADAR_BSM_CAR, \
|
CANFD_ANGLE_LONGITUDINAL_CAR, CANFD_CORNER_RADAR_BSM_CAR, \
|
||||||
|
CANFD_ALT_BUTTONS_RESUME_CAR, \
|
||||||
hyundai_cancel_button_enables_cruise, ALT_BUS_LDA_BUTTON_CARS, ALT_BUS_LDA_BUTTON_SWL_STAT_CARS
|
hyundai_cancel_button_enables_cruise, ALT_BUS_LDA_BUTTON_CARS, ALT_BUS_LDA_BUTTON_SWL_STAT_CARS
|
||||||
from opendbc.car.interfaces import CarStateBase
|
from opendbc.car.interfaces import CarStateBase
|
||||||
|
|
||||||
@@ -28,6 +29,11 @@ IONIQ_6_BLINDSPOT_LEFT_MASK = 0x10
|
|||||||
CANFD_CAMERA_LEAD_MIN_DISTANCE = 0.1
|
CANFD_CAMERA_LEAD_MIN_DISTANCE = 0.1
|
||||||
ALT_BUS_LDA_BUTTON_BURST_DEBOUNCE_NS = int(1.3e9)
|
ALT_BUS_LDA_BUTTON_BURST_DEBOUNCE_NS = int(1.3e9)
|
||||||
|
|
||||||
|
CLASSIC_MEDIA_BUTTON_CARS = frozenset({
|
||||||
|
CAR.HYUNDAI_ELANTRA_2024,
|
||||||
|
CAR.HYUNDAI_ELANTRA_HEV_2024,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def get_non_scc_cruise_signals(CP) -> tuple[str, str, str, str, str, str]:
|
def get_non_scc_cruise_signals(CP) -> tuple[str, str, str, str, str, str]:
|
||||||
if CP.flags & HyundaiFlags.EV:
|
if CP.flags & HyundaiFlags.EV:
|
||||||
@@ -49,6 +55,15 @@ def calculate_canfd_speed_limit(CP, FPCP, cp, cp_cam, speed_factor):
|
|||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def get_canfd_cruise_available(CP, cp, scc_available: bool) -> bool:
|
||||||
|
# The EV9 fallback keeps stock ACC active when ECU disable is skipped. Its
|
||||||
|
# SCC status remains inactive in that mode, while TCS still reports whether
|
||||||
|
# ACC is fault-free and available.
|
||||||
|
if CP.carFingerprint == CAR.KIA_EV9 and not CP.openpilotLongitudinalControl:
|
||||||
|
return cp.vl["TCS"]["ACCEnable"] == 0
|
||||||
|
return scc_available
|
||||||
|
|
||||||
|
|
||||||
def decode_ioniq_6_blindspot_radar_state(state: int) -> tuple[bool, bool]:
|
def decode_ioniq_6_blindspot_radar_state(state: int) -> tuple[bool, bool]:
|
||||||
state_int = int(state)
|
state_int = int(state)
|
||||||
return bool(state_int & IONIQ_6_BLINDSPOT_LEFT_MASK), bool(state_int & IONIQ_6_BLINDSPOT_RIGHT_MASK)
|
return bool(state_int & IONIQ_6_BLINDSPOT_LEFT_MASK), bool(state_int & IONIQ_6_BLINDSPOT_RIGHT_MASK)
|
||||||
@@ -117,12 +132,15 @@ class CarState(CarStateBase):
|
|||||||
"CRUISE_BUTTONS"
|
"CRUISE_BUTTONS"
|
||||||
self.is_metric = False
|
self.is_metric = False
|
||||||
self.buttons_counter = 0
|
self.buttons_counter = 0
|
||||||
|
self.main_cruise_on = False
|
||||||
|
self.main_cruise_tracking = bool(getattr(FPCP, "flags", 0) & HyundaiStarPilotFlags.MAIN_CRUISE_STATE_TRACKING)
|
||||||
|
|
||||||
self.cruise_info = {}
|
self.cruise_info = {}
|
||||||
self.msg_161 = {}
|
self.msg_161 = {}
|
||||||
self.msg_162 = {}
|
self.msg_162 = {}
|
||||||
self.msg_1b5 = {}
|
self.msg_1b5 = {}
|
||||||
self.msg_364 = {}
|
self.msg_364 = {}
|
||||||
|
self.lfa_block_msg = {}
|
||||||
self.stock_lkas_msg = {}
|
self.stock_lkas_msg = {}
|
||||||
self.stock_lfa_msg = {}
|
self.stock_lfa_msg = {}
|
||||||
self.stock_lfahda_cluster_msg = {}
|
self.stock_lfahda_cluster_msg = {}
|
||||||
@@ -137,7 +155,7 @@ class CarState(CarStateBase):
|
|||||||
self.blindspots_front_corner_1_ts = 0
|
self.blindspots_front_corner_1_ts = 0
|
||||||
self.left_blindspot_from_radar = False
|
self.left_blindspot_from_radar = False
|
||||||
self.right_blindspot_from_radar = False
|
self.right_blindspot_from_radar = False
|
||||||
if CP.carFingerprint == CAR.KIA_EV9:
|
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR:
|
||||||
self.hba_icon = 0
|
self.hba_icon = 0
|
||||||
self.main_cruise_on = False
|
self.main_cruise_on = False
|
||||||
self.angle_steering_angle = 0.0
|
self.angle_steering_angle = 0.0
|
||||||
@@ -155,8 +173,10 @@ class CarState(CarStateBase):
|
|||||||
# Main button also can trigger an engagement on these cars
|
# Main button also can trigger an engagement on these cars
|
||||||
return any(btn in ENABLE_BUTTONS for btn in self.cruise_buttons) or any(self.main_buttons)
|
return any(btn in ENABLE_BUTTONS for btn in self.cruise_buttons) or any(self.main_buttons)
|
||||||
|
|
||||||
def update_main_cruise(self, ret: structs.CarState) -> bool:
|
def update_main_cruise(self, ret: structs.CarState,
|
||||||
if any(be.type == ButtonType.mainCruise and be.pressed for be in ret.buttonEvents):
|
button_events: list[structs.CarState.ButtonEvent] | None = None) -> bool:
|
||||||
|
button_events = ret.buttonEvents if button_events is None else button_events
|
||||||
|
if any(be.type == ButtonType.mainCruise and be.pressed for be in button_events):
|
||||||
self.main_cruise_on = not self.main_cruise_on
|
self.main_cruise_on = not self.main_cruise_on
|
||||||
|
|
||||||
return bool(ret.cruiseState.available and self.main_cruise_on)
|
return bool(ret.cruiseState.available and self.main_cruise_on)
|
||||||
@@ -222,15 +242,23 @@ class CarState(CarStateBase):
|
|||||||
return button_events
|
return button_events
|
||||||
|
|
||||||
def create_lkas_button_events(self, cp: CANParser, prev_lda_button: int) -> list[structs.CarState.ButtonEvent]:
|
def create_lkas_button_events(self, cp: CANParser, prev_lda_button: int) -> list[structs.CarState.ButtonEvent]:
|
||||||
if self.CP.carFingerprint == CAR.HYUNDAI_SONATA_HYBRID:
|
if self.CP.carFingerprint == CAR.HYUNDAI_SONATA:
|
||||||
|
self.lda_button = int(cp.vl["BCM_PO_11"]["LDA_BTN"]) if cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0 else 0
|
||||||
|
elif self.CP.carFingerprint == CAR.HYUNDAI_SONATA_HYBRID:
|
||||||
self.lda_button = self.get_sonata_hybrid_lkas_button_state(cp)
|
self.lda_button = self.get_sonata_hybrid_lkas_button_state(cp)
|
||||||
# Some classic HKG platforms publish the LKAS button on the cluster bus instead of BCM_PO_11.
|
elif self.CP.carFingerprint == CAR.HYUNDAI_ELANTRA_HEV_2024:
|
||||||
elif cp.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0:
|
lda_samples = [
|
||||||
self.lda_button = int(cp.vl["CLU13"]["CF_Clu_LdwsLkasSW"])
|
*cp.vl_all["CLU13"]["CF_Clu_LdwsLkasSW"],
|
||||||
elif cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0:
|
*cp.vl_all["BCM_PO_11"]["LDA_BTN"],
|
||||||
self.lda_button = int(cp.vl["BCM_PO_11"]["LDA_BTN"])
|
]
|
||||||
|
if lda_samples:
|
||||||
|
self.lda_button = int(any(lda_samples))
|
||||||
else:
|
else:
|
||||||
self.lda_button = 0
|
source_states = (
|
||||||
|
int(cp.vl["CLU13"]["CF_Clu_LdwsLkasSW"]) if cp.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0 else 0,
|
||||||
|
int(cp.vl["BCM_PO_11"]["LDA_BTN"]) if cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0 else 0,
|
||||||
|
)
|
||||||
|
self.lda_button = int(any(source_states))
|
||||||
|
|
||||||
return create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas})
|
return create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas})
|
||||||
|
|
||||||
@@ -308,14 +336,19 @@ class CarState(CarStateBase):
|
|||||||
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
|
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
|
||||||
ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
|
ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
|
||||||
|
|
||||||
|
prev_cruise_buttons = self.cruise_buttons[-1]
|
||||||
|
prev_main_buttons = self.main_buttons[-1]
|
||||||
|
prev_lda_button = self.lda_button
|
||||||
|
main_button_events = []
|
||||||
|
if self.main_cruise_tracking:
|
||||||
|
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
|
||||||
|
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
|
||||||
|
main_button_events = create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise})
|
||||||
|
|
||||||
# cruise state
|
# cruise state
|
||||||
no_scc = bool(self.CP.flags & HyundaiFlags.NON_SCC)
|
no_scc = bool(self.CP.flags & HyundaiFlags.NON_SCC)
|
||||||
if self.CP.openpilotLongitudinalControl:
|
if self.CP.carFingerprint == CAR.KIA_RAY_EV:
|
||||||
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
|
pass
|
||||||
ret.cruiseState.available = cp.vl["TCS13"]["ACCEnable"] == 0
|
|
||||||
ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
|
|
||||||
ret.cruiseState.standstill = False
|
|
||||||
ret.cruiseState.nonAdaptive = False
|
|
||||||
elif no_scc:
|
elif no_scc:
|
||||||
cruise_available_msg, cruise_available_sig, cruise_enabled_msg, cruise_enabled_sig, cruise_speed_msg, cruise_speed_sig = get_non_scc_cruise_signals(self.CP)
|
cruise_available_msg, cruise_available_sig, cruise_enabled_msg, cruise_enabled_sig, cruise_speed_msg, cruise_speed_sig = get_non_scc_cruise_signals(self.CP)
|
||||||
ret.cruiseState.available = cp.vl[cruise_available_msg][cruise_available_sig] != 0
|
ret.cruiseState.available = cp.vl[cruise_available_msg][cruise_available_sig] != 0
|
||||||
@@ -323,6 +356,12 @@ class CarState(CarStateBase):
|
|||||||
ret.cruiseState.standstill = False
|
ret.cruiseState.standstill = False
|
||||||
ret.cruiseState.nonAdaptive = False
|
ret.cruiseState.nonAdaptive = False
|
||||||
ret.cruiseState.speed = cp.vl[cruise_speed_msg][cruise_speed_sig] * speed_conv
|
ret.cruiseState.speed = cp.vl[cruise_speed_msg][cruise_speed_sig] * speed_conv
|
||||||
|
elif self.CP.openpilotLongitudinalControl:
|
||||||
|
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
|
||||||
|
ret.cruiseState.available = cp.vl["TCS13"]["ACCEnable"] == 0
|
||||||
|
ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
|
||||||
|
ret.cruiseState.standstill = False
|
||||||
|
ret.cruiseState.nonAdaptive = False
|
||||||
else:
|
else:
|
||||||
scc_msg = "SCC12" if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED else "SCC11"
|
scc_msg = "SCC12" if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED else "SCC11"
|
||||||
ret.cruiseState.available = cp_cruise.vl[scc_msg]["MainMode_ACC"] == 1
|
ret.cruiseState.available = cp_cruise.vl[scc_msg]["MainMode_ACC"] == 1
|
||||||
@@ -331,8 +370,14 @@ class CarState(CarStateBase):
|
|||||||
ret.cruiseState.nonAdaptive = cp_cruise.vl[scc_msg]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash
|
ret.cruiseState.nonAdaptive = cp_cruise.vl[scc_msg]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash
|
||||||
ret.cruiseState.speed = cp_cruise.vl[scc_msg]["VSetDis"] * speed_conv
|
ret.cruiseState.speed = cp_cruise.vl[scc_msg]["VSetDis"] * speed_conv
|
||||||
|
|
||||||
|
if self.CP.openpilotLongitudinalControl and self.main_cruise_tracking:
|
||||||
|
ret.cruiseState.available = self.update_main_cruise(ret, main_button_events)
|
||||||
|
|
||||||
if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED:
|
if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED:
|
||||||
self.msg_364 = copy.copy(cp_cam.vl["ALERTS_364"])
|
if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||||
|
self.lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x2a4"])
|
||||||
|
else:
|
||||||
|
self.msg_364 = copy.copy(cp_cam.vl["ALERTS_364"])
|
||||||
|
|
||||||
# TODO: Find brake pressure
|
# TODO: Find brake pressure
|
||||||
ret.brake = 0
|
ret.brake = 0
|
||||||
@@ -391,22 +436,24 @@ class CarState(CarStateBase):
|
|||||||
ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
|
ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
|
||||||
|
|
||||||
# save the entire LKAS11 and CLU11
|
# save the entire LKAS11 and CLU11
|
||||||
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
|
if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED and self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||||
|
self.lkas11 = {}
|
||||||
|
else:
|
||||||
|
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
|
||||||
self.clu11 = copy.copy(cp.vl["CLU11"])
|
self.clu11 = copy.copy(cp.vl["CLU11"])
|
||||||
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
|
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
|
||||||
prev_cruise_buttons = self.cruise_buttons[-1]
|
if not self.main_cruise_tracking:
|
||||||
prev_main_buttons = self.main_buttons[-1]
|
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
|
||||||
prev_lda_button = self.lda_button
|
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
|
||||||
|
main_button_events = create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise})
|
||||||
lkas_button_events = []
|
lkas_button_events = []
|
||||||
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
|
|
||||||
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
|
|
||||||
if self.CP.carFingerprint in ALT_BUS_LDA_BUTTON_CARS and cp_alt is not None and self.get_alt_bus_lda_button_raw_state(cp_alt)[1] > 0:
|
if self.CP.carFingerprint in ALT_BUS_LDA_BUTTON_CARS and cp_alt is not None and self.get_alt_bus_lda_button_raw_state(cp_alt)[1] > 0:
|
||||||
lkas_button_events = self.create_alt_bus_lda_button_events(cp_alt)
|
lkas_button_events = self.create_alt_bus_lda_button_events(cp_alt)
|
||||||
else:
|
else:
|
||||||
lkas_button_events = self.create_lkas_button_events(cp, prev_lda_button)
|
lkas_button_events = self.create_lkas_button_events(cp, prev_lda_button)
|
||||||
|
|
||||||
ret.buttonEvents = [*self.create_cruise_button_events(self.cruise_buttons[-1], prev_cruise_buttons),
|
ret.buttonEvents = [*self.create_cruise_button_events(self.cruise_buttons[-1], prev_cruise_buttons),
|
||||||
*create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}),
|
*main_button_events,
|
||||||
*lkas_button_events]
|
*lkas_button_events]
|
||||||
|
|
||||||
ret.blockPcmEnable = not self.recent_button_interaction()
|
ret.blockPcmEnable = not self.recent_button_interaction()
|
||||||
@@ -419,6 +466,9 @@ class CarState(CarStateBase):
|
|||||||
ret.lowSpeedAlert = self.low_speed_alert
|
ret.lowSpeedAlert = self.low_speed_alert
|
||||||
|
|
||||||
fp_ret = custom.StarPilotCarState.new_message()
|
fp_ret = custom.StarPilotCarState.new_message()
|
||||||
|
if self.CP.carFingerprint in CLASSIC_MEDIA_BUTTON_CARS:
|
||||||
|
fp_ret.modePressed = bool(cp.vl["GW_SWRC_PE"]["C_ModeSW"])
|
||||||
|
fp_ret.customPressed = bool(cp.vl["GW_SWRC_PE"]["C_MTSSW"])
|
||||||
|
|
||||||
return ret, fp_ret
|
return ret, fp_ret
|
||||||
|
|
||||||
@@ -511,7 +561,8 @@ class CarState(CarStateBase):
|
|||||||
ret.cruiseState.standstill = False
|
ret.cruiseState.standstill = False
|
||||||
else:
|
else:
|
||||||
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
|
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
|
||||||
ret.cruiseState.available = cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1
|
ret.cruiseState.available = get_canfd_cruise_available(
|
||||||
|
self.CP, cp, cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1)
|
||||||
ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
|
ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
|
||||||
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
|
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
|
||||||
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
|
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
|
||||||
@@ -531,7 +582,9 @@ class CarState(CarStateBase):
|
|||||||
self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
|
self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
|
||||||
self.lda_button = cp.vl[self.cruise_btns_msg_canfd]["LDA_BTN"]
|
self.lda_button = cp.vl[self.cruise_btns_msg_canfd]["LDA_BTN"]
|
||||||
self.left_paddle = 0
|
self.left_paddle = 0
|
||||||
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
|
if self.CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR:
|
||||||
|
self.cruise_buttons_msg = copy.copy(cp.vl[self.cruise_btns_msg_canfd])
|
||||||
|
elif self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
|
||||||
self.cruise_buttons_msg = copy.copy(cp.vl["CRUISE_BUTTONS"])
|
self.cruise_buttons_msg = copy.copy(cp.vl["CRUISE_BUTTONS"])
|
||||||
self.left_paddle = cp.vl["CRUISE_BUTTONS"]["LEFT_PADDLE"]
|
self.left_paddle = cp.vl["CRUISE_BUTTONS"]["LEFT_PADDLE"]
|
||||||
self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
|
self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
|
||||||
@@ -564,7 +617,7 @@ class CarState(CarStateBase):
|
|||||||
*create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}),
|
*create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}),
|
||||||
*create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas}),
|
*create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas}),
|
||||||
*create_button_events(self.left_paddle, prev_left_paddle, {1: ButtonType.altButton2})]
|
*create_button_events(self.left_paddle, prev_left_paddle, {1: ButtonType.altButton2})]
|
||||||
if self.CP.openpilotLongitudinalControl and self.CP.carFingerprint == CAR.KIA_EV9:
|
if self.CP.openpilotLongitudinalControl and (self.CP.carFingerprint == CAR.KIA_EV9 or self.main_cruise_tracking):
|
||||||
ret.cruiseState.available = self.update_main_cruise(ret)
|
ret.cruiseState.available = self.update_main_cruise(ret)
|
||||||
|
|
||||||
ret.blockPcmEnable = not self.recent_button_interaction()
|
ret.blockPcmEnable = not self.recent_button_interaction()
|
||||||
@@ -591,14 +644,18 @@ class CarState(CarStateBase):
|
|||||||
def get_can_parsers_canfd(self, CP):
|
def get_can_parsers_canfd(self, CP):
|
||||||
msgs = []
|
msgs = []
|
||||||
cam_msgs = []
|
cam_msgs = []
|
||||||
if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
|
if CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR:
|
||||||
# TODO: this can be removed once we add dynamic support to vl_all
|
msgs.append(("CRUISE_BUTTONS_ALT", 50))
|
||||||
|
elif not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
|
||||||
|
# The EV9 can stop publishing this during the non-ECU-disabled startup
|
||||||
|
# state. Keep decoding it when present without making CAN invalid.
|
||||||
msgs += [
|
msgs += [
|
||||||
# this message is 50Hz but the ECU frequently stops transmitting for ~0.5s
|
("CRUISE_BUTTONS", 0 if CP.carFingerprint == CAR.KIA_EV9 else 1)
|
||||||
("CRUISE_BUTTONS", 1)
|
|
||||||
]
|
]
|
||||||
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||||
msgs.append(("FR_CMR_02_100ms", 10))
|
# EV9 camera status can disappear for an extended period when the
|
||||||
|
# documented ECU startup sequence is skipped.
|
||||||
|
msgs.append(("FR_CMR_02_100ms", 0 if CP.carFingerprint == CAR.KIA_EV9 else 10))
|
||||||
msgs.append(("FR_CMR_03_50ms", 0))
|
msgs.append(("FR_CMR_03_50ms", 0))
|
||||||
cam_msgs.append(("LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS", 0))
|
cam_msgs.append(("LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS", 0))
|
||||||
else:
|
else:
|
||||||
@@ -614,8 +671,7 @@ class CarState(CarStateBase):
|
|||||||
("LFAHDA_CLUSTER", 0), # optional: carries cluster icon state on some variants
|
("LFAHDA_CLUSTER", 0), # optional: carries cluster icon state on some variants
|
||||||
("BLINKER_STALKS", 0), # optional: some trims publish live stalk/light state on ECAN during turn camera events
|
("BLINKER_STALKS", 0), # optional: some trims publish live stalk/light state on ECAN during turn camera events
|
||||||
]
|
]
|
||||||
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and CP.enableBsm:
|
if CP.enableBsm:
|
||||||
# Keep the suppressed ADAS BSM output optional.
|
|
||||||
msgs.append(("BLINDSPOTS_REAR_CORNERS", 0))
|
msgs.append(("BLINDSPOTS_REAR_CORNERS", 0))
|
||||||
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR:
|
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR:
|
||||||
msgs.append(("BLINDSPOTS_FRONT_CORNER_2", 0))
|
msgs.append(("BLINDSPOTS_FRONT_CORNER_2", 0))
|
||||||
@@ -634,10 +690,41 @@ class CarState(CarStateBase):
|
|||||||
if CP.flags & HyundaiFlags.CANFD:
|
if CP.flags & HyundaiFlags.CANFD:
|
||||||
return self.get_can_parsers_canfd(CP)
|
return self.get_can_parsers_canfd(CP)
|
||||||
|
|
||||||
|
if CP.flags & HyundaiFlags.CAN_CANFD_BLENDED and CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||||
|
msgs = [
|
||||||
|
("MDPS12", 100),
|
||||||
|
("TCS11", 100),
|
||||||
|
("TCS13", 50),
|
||||||
|
("TCS15", 10),
|
||||||
|
("CLU11", 50),
|
||||||
|
("CLU15", 5),
|
||||||
|
("ESP12", 100),
|
||||||
|
("CGW1", 10),
|
||||||
|
("CGW2", 5),
|
||||||
|
("WHL_SPD11", 50),
|
||||||
|
("SAS11", 100),
|
||||||
|
("SCC12", 0 if CP.openpilotLongitudinalControl and CP.flags & HyundaiFlags.CANFD_LKA_STEERING else 50),
|
||||||
|
("EMS12", 100),
|
||||||
|
("EMS16", 100),
|
||||||
|
("LVR12", 100),
|
||||||
|
("BCM_PO_11", 0),
|
||||||
|
("CLU13", 0),
|
||||||
|
]
|
||||||
|
if CP.enableBsm:
|
||||||
|
msgs.append(("LCA11", 20))
|
||||||
|
|
||||||
|
return {
|
||||||
|
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], msgs, CanBus(CP).ECAN),
|
||||||
|
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [("CAM_0x2a4", 20)], CanBus(CP).CAM),
|
||||||
|
}
|
||||||
|
|
||||||
msgs = [
|
msgs = [
|
||||||
("BCM_PO_11", 0),
|
("BCM_PO_11", 0),
|
||||||
("CLU13", 0),
|
("CLU13", 0),
|
||||||
]
|
]
|
||||||
|
if CP.carFingerprint in CLASSIC_MEDIA_BUTTON_CARS:
|
||||||
|
# Steering-wheel media switches are event-driven on the refresh Elantra.
|
||||||
|
msgs.append(("GW_SWRC_PE", 0))
|
||||||
if CP.flags & HyundaiFlags.NON_SCC and not (CP.flags & HyundaiFlags.NON_SCC_NO_FCA):
|
if CP.flags & HyundaiFlags.NON_SCC and not (CP.flags & HyundaiFlags.NON_SCC_NO_FCA):
|
||||||
msgs.append(("FCA11", 0)) # Non-SCC trims can stop publishing FCA11; don't let it poison canValid
|
msgs.append(("FCA11", 0)) # Non-SCC trims can stop publishing FCA11; don't let it poison canValid
|
||||||
|
|
||||||
|
|||||||
@@ -1402,6 +1402,14 @@ FW_VERSIONS = {
|
|||||||
b'\xf1\x00JK__ RDR ----- 1.00 1.01 99110-DS500 ',
|
b'\xf1\x00JK__ RDR ----- 1.00 1.01 99110-DS500 ',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
CAR.GENESIS_GV70_2026: {
|
||||||
|
(Ecu.fwdCamera, 0x7c4, None): [
|
||||||
|
b'\xf1\x00JK MFC AT USA LHD 1.00 1.11 99211-IY600 241125',
|
||||||
|
],
|
||||||
|
(Ecu.fwdRadar, 0x7d0, None): [
|
||||||
|
b'\xf1\x00JK__ RDR ----- 1.00 1.01 99110-AR600 ',
|
||||||
|
],
|
||||||
|
},
|
||||||
CAR.GENESIS_GV80_2025: {
|
CAR.GENESIS_GV80_2025: {
|
||||||
(Ecu.fwdRadar, 0x7d0, None): [
|
(Ecu.fwdRadar, 0x7d0, None): [
|
||||||
b'\xf1\x00JX__ RDR ----- 1.00 1.03 99110-T6500 ',
|
b'\xf1\x00JX__ RDR ----- 1.00 1.03 99110-T6500 ',
|
||||||
@@ -1688,4 +1696,9 @@ FW_VERSIONS = {
|
|||||||
b'\xf1\x00BC3 LKA AT EUR LHD 1.00 1.01 99211-Q0100 261',
|
b'\xf1\x00BC3 LKA AT EUR LHD 1.00 1.01 99211-Q0100 261',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
CAR.KIA_RAY_EV: {
|
||||||
|
(Ecu.fwdCamera, 0x7c4, None): [
|
||||||
|
b'\xf1\x00TAM MFC AT KOR LHD 1.00 1.02 99211-E2000 230901',
|
||||||
|
],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf)
|
|||||||
def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||||
torque_fault, lkas11, sys_warning, sys_state, enabled,
|
torque_fault, lkas11, sys_warning, sys_state, enabled,
|
||||||
left_lane, right_lane,
|
left_lane, right_lane,
|
||||||
left_lane_depart, right_lane_depart):
|
left_lane_depart, right_lane_depart, lka_icon):
|
||||||
values = {s: lkas11[s] for s in [
|
values = {s: lkas11[s] for s in [
|
||||||
"CF_Lkas_LdwsActivemode",
|
"CF_Lkas_LdwsActivemode",
|
||||||
"CF_Lkas_LdwsSysState",
|
"CF_Lkas_LdwsSysState",
|
||||||
@@ -40,7 +40,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
|||||||
CAR.HYUNDAI_ELANTRA_HEV_2021, CAR.HYUNDAI_SONATA_HYBRID, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_KONA_HEV, CAR.HYUNDAI_KONA_EV_2022,
|
CAR.HYUNDAI_ELANTRA_HEV_2021, CAR.HYUNDAI_SONATA_HYBRID, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_KONA_HEV, CAR.HYUNDAI_KONA_EV_2022,
|
||||||
CAR.HYUNDAI_SANTA_FE_2022, CAR.KIA_K5_2021, CAR.HYUNDAI_IONIQ_HEV_2022, CAR.HYUNDAI_SANTA_FE_HEV_2022,
|
CAR.HYUNDAI_SANTA_FE_2022, CAR.KIA_K5_2021, CAR.HYUNDAI_IONIQ_HEV_2022, CAR.HYUNDAI_SANTA_FE_HEV_2022,
|
||||||
CAR.HYUNDAI_SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED, CAR.KIA_XCEED_PHEV,
|
CAR.HYUNDAI_SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED, CAR.KIA_XCEED_PHEV,
|
||||||
CAR.HYUNDAI_AZERA_6TH_GEN, CAR.HYUNDAI_AZERA_HEV_6TH_GEN, CAR.HYUNDAI_CUSTIN_1ST_GEN, CAR.HYUNDAI_KONA_2022,
|
CAR.HYUNDAI_AZERA_6TH_GEN, CAR.HYUNDAI_AZERA_HEV_6TH_GEN, CAR.HYUNDAI_CUSTIN_1ST_GEN, CAR.HYUNDAI_KONA_2022, CAR.KIA_RAY_EV,
|
||||||
CAR.HYUNDAI_ELANTRA_2024, CAR.HYUNDAI_ELANTRA_HEV_2024):
|
CAR.HYUNDAI_ELANTRA_2024, CAR.HYUNDAI_ELANTRA_HEV_2024):
|
||||||
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
|
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
|
||||||
values["CF_Lkas_LdwsOpt_USM"] = 2
|
values["CF_Lkas_LdwsOpt_USM"] = 2
|
||||||
@@ -51,7 +51,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
|||||||
# FcwOpt_USM 2 = Green car + lanes
|
# FcwOpt_USM 2 = Green car + lanes
|
||||||
# FcwOpt_USM 1 = White car + lanes
|
# FcwOpt_USM 1 = White car + lanes
|
||||||
# FcwOpt_USM 0 = No car + lanes
|
# FcwOpt_USM 0 = No car + lanes
|
||||||
values["CF_Lkas_FcwOpt_USM"] = 2 if enabled else 1
|
values["CF_Lkas_FcwOpt_USM"] = lka_icon if CP.carFingerprint == CAR.GENESIS_G70_2020 else 2 if enabled else 1
|
||||||
|
|
||||||
# SysWarning 4 = keep hands on wheel
|
# SysWarning 4 = keep hands on wheel
|
||||||
# SysWarning 5 = keep hands on wheel (red)
|
# SysWarning 5 = keep hands on wheel (red)
|
||||||
@@ -60,7 +60,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
|||||||
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
|
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
|
||||||
|
|
||||||
# Likely cars lacking the ability to show individual lane lines in the dash
|
# Likely cars lacking the ability to show individual lane lines in the dash
|
||||||
elif CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL):
|
elif CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.HYUNDAI_KONA_NON_SCC):
|
||||||
# SysWarning 4 = keep hands on wheel + beep
|
# SysWarning 4 = keep hands on wheel + beep
|
||||||
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
|
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
|||||||
# SysState 1-2 = white car + lanes
|
# SysState 1-2 = white car + lanes
|
||||||
# SysState 3 = green car + lanes, green steering wheel
|
# SysState 3 = green car + lanes, green steering wheel
|
||||||
# SysState 4 = green car + lanes
|
# SysState 4 = green car + lanes
|
||||||
values["CF_Lkas_LdwsSysState"] = 3 if enabled else 1
|
values["CF_Lkas_LdwsSysState"] = lka_icon if CP.carFingerprint == CAR.HYUNDAI_KONA_NON_SCC else 3 if enabled else 1
|
||||||
values["CF_Lkas_LdwsOpt_USM"] = 2 # non-2 changes above SysState definition
|
values["CF_Lkas_LdwsOpt_USM"] = 2 # non-2 changes above SysState definition
|
||||||
|
|
||||||
# these have no effect
|
# these have no effect
|
||||||
@@ -80,6 +80,10 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
|||||||
# Genesis and Optima fault when forwarding while engaged
|
# Genesis and Optima fault when forwarding while engaged
|
||||||
values["CF_Lkas_LdwsActivemode"] = 2
|
values["CF_Lkas_LdwsActivemode"] = 2
|
||||||
|
|
||||||
|
if CP.carFingerprint == CAR.KIA_RAY_EV:
|
||||||
|
values["CF_Lkas_LdwsOpt_USM"] = 0
|
||||||
|
values["CF_Lkas_Chksum"] = 0
|
||||||
|
|
||||||
dat = packer.make_can_msg("LKAS11", 0, values)[1]
|
dat = packer.make_can_msg("LKAS11", 0, values)[1]
|
||||||
|
|
||||||
if CP.flags & HyundaiFlags.CHECKSUM_CRC8:
|
if CP.flags & HyundaiFlags.CHECKSUM_CRC8:
|
||||||
@@ -106,7 +110,8 @@ def create_checksum_can_canfd_blended(packer, bus, addr, values):
|
|||||||
def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req,
|
def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req,
|
||||||
torque_fault, lkas11, sys_warning, sys_state, enabled,
|
torque_fault, lkas11, sys_warning, sys_state, enabled,
|
||||||
left_lane, right_lane,
|
left_lane, right_lane,
|
||||||
left_lane_depart, right_lane_depart, msg_364):
|
left_lane_depart, right_lane_depart, msg_364,
|
||||||
|
include_alerts=True, counter_mod=0x10):
|
||||||
bus = CanBus(CP).ECAN
|
bus = CanBus(CP).ECAN
|
||||||
values = {
|
values = {
|
||||||
"CF_Lkas_LdwsActivemode": int(left_lane) + (int(right_lane) << 1),
|
"CF_Lkas_LdwsActivemode": int(left_lane) + (int(right_lane) << 1),
|
||||||
@@ -116,7 +121,7 @@ def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req,
|
|||||||
"CR_Lkas_StrToqReq": apply_steer,
|
"CR_Lkas_StrToqReq": apply_steer,
|
||||||
"CF_Lkas_ActToi": steer_req,
|
"CF_Lkas_ActToi": steer_req,
|
||||||
"CF_Lkas_ToiFlt": torque_fault,
|
"CF_Lkas_ToiFlt": torque_fault,
|
||||||
"CF_Lkas_MsgCount": frame % 0x10,
|
"CF_Lkas_MsgCount": frame % counter_mod,
|
||||||
"NEW_SIGNAL_1": 0,
|
"NEW_SIGNAL_1": 0,
|
||||||
"NEW_SIGNAL_5": 100,
|
"NEW_SIGNAL_5": 100,
|
||||||
}
|
}
|
||||||
@@ -130,13 +135,13 @@ def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req,
|
|||||||
alerts_364.setdefault("BYTE5", 0)
|
alerts_364.setdefault("BYTE5", 0)
|
||||||
alerts_364.setdefault("BYTE6", 0)
|
alerts_364.setdefault("BYTE6", 0)
|
||||||
alerts_364.setdefault("BYTE7", 0)
|
alerts_364.setdefault("BYTE7", 0)
|
||||||
alerts_364["COUNTER"] = frame % 0x10
|
alerts_364["COUNTER"] = frame % counter_mod
|
||||||
alerts_364["CHECKSUM"] = create_checksum_can_canfd_blended(packer, bus, "ALERTS_364", alerts_364)
|
alerts_364["CHECKSUM"] = create_checksum_can_canfd_blended(packer, bus, "ALERTS_364", alerts_364)
|
||||||
|
|
||||||
return [
|
ret = [packer.make_can_msg("LKAS11", bus, values)]
|
||||||
packer.make_can_msg("LKAS11", bus, values),
|
if include_alerts:
|
||||||
packer.make_can_msg("ALERTS_364", bus, alerts_364),
|
ret.append(packer.make_can_msg("ALERTS_364", bus, alerts_364))
|
||||||
]
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def create_clu11(packer, frame, clu11, button, CP):
|
def create_clu11(packer, frame, clu11, button, CP):
|
||||||
@@ -233,11 +238,62 @@ def create_acc_commands_can_canfd_blended(packer, enabled, accel, upper_jerk, id
|
|||||||
return commands
|
return commands
|
||||||
|
|
||||||
|
|
||||||
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP):
|
def create_acc_commands_can_canfd_blended_hda2(packer, enabled, accel, accel_last, upper_jerk, idx,
|
||||||
|
hud_control, set_speed, stopping, long_override, use_fca, CP):
|
||||||
|
commands = []
|
||||||
|
bus = CanBus(CP).ECAN
|
||||||
|
jerk = 5.0
|
||||||
|
|
||||||
|
if not enabled or long_override:
|
||||||
|
accel_raw, accel_value = 0.0, 0.0
|
||||||
|
else:
|
||||||
|
accel_raw = accel
|
||||||
|
accel_value = max(accel_last - jerk / 50.0, min(accel, accel_last + jerk / 50.0))
|
||||||
|
|
||||||
|
message_values = [
|
||||||
|
("SCC11", {
|
||||||
|
"aReqRaw": accel_raw,
|
||||||
|
"aReqValue": accel_value,
|
||||||
|
"JerkUpperLimit": upper_jerk,
|
||||||
|
"JerkLowerLimit": jerk if enabled else 1.0,
|
||||||
|
}),
|
||||||
|
("SCC12", {
|
||||||
|
"MainMode_ACC": 1,
|
||||||
|
"ACCMode_Inactive": 0 if enabled else 1,
|
||||||
|
"TauGapSet": hud_control.leadDistanceBars,
|
||||||
|
"VSetDis": set_speed,
|
||||||
|
"ACC_ObjDist": 1,
|
||||||
|
"ACCMode": 2 if enabled and long_override else 1 if enabled else 0,
|
||||||
|
"StopReq": 1 if stopping else 0,
|
||||||
|
}),
|
||||||
|
("SCC14", {
|
||||||
|
"ACC_ObjRelSpd": 0,
|
||||||
|
"ObjValid": 0,
|
||||||
|
"ObjStatus": 2 if hud_control.leadVisible and enabled else 1 if hud_control.leadVisible else 0,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
|
||||||
|
if use_fca and not (CP.flags & HyundaiFlags.CAMERA_SCC):
|
||||||
|
# These values reproduce the stock status bytes without requesting AEB/FCA actuation.
|
||||||
|
message_values.append(("FCA11", {
|
||||||
|
"cr_vsm_deccmd": 255,
|
||||||
|
"cf_vsm_deccmdact": 0,
|
||||||
|
}))
|
||||||
|
|
||||||
|
for name, values in message_values:
|
||||||
|
values["COUNTER"] = idx % 0xF
|
||||||
|
values["CHECKSUM"] = create_checksum_can_canfd_blended(packer, bus, name, values)
|
||||||
|
commands.append(packer.make_can_msg(name, bus, values))
|
||||||
|
|
||||||
|
return commands
|
||||||
|
|
||||||
|
|
||||||
|
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP,
|
||||||
|
main_cruise_enabled=True):
|
||||||
commands = []
|
commands = []
|
||||||
|
|
||||||
scc11_values = {
|
scc11_values = {
|
||||||
"MainMode_ACC": 1,
|
"MainMode_ACC": int(bool(main_cruise_enabled)),
|
||||||
"TauGapSet": hud_control.leadDistanceBars,
|
"TauGapSet": hud_control.leadDistanceBars,
|
||||||
"VSetDis": set_speed if enabled else 0,
|
"VSetDis": set_speed if enabled else 0,
|
||||||
"AliveCounterACC": idx % 0x10,
|
"AliveCounterACC": idx % 0x10,
|
||||||
@@ -324,17 +380,27 @@ def create_frt_radar_opt(packer):
|
|||||||
return packer.make_can_msg("FRT_RADAR11", 0, frt_radar11_values)
|
return packer.make_can_msg("FRT_RADAR11", 0, frt_radar11_values)
|
||||||
|
|
||||||
|
|
||||||
def create_radar_aux_messages(packer, CAN, frame):
|
def create_radar_aux_messages(packer, CAN, frame, hda2=False):
|
||||||
commands = []
|
commands = []
|
||||||
|
|
||||||
for addr, freq, values in (
|
message_specs = (
|
||||||
|
("RADAR_0x363", 2, {"FCA_ESA": 1}),
|
||||||
|
("RADAR_0x398", 5, {"BYTE4": 0x80, "BYTE5": 0x5D}),
|
||||||
|
("RADAR_0x399", 5, {"BYTE2": 0x02}),
|
||||||
|
("RADAR_0x39a", 5, {"BYTE7": 0xFF}),
|
||||||
|
("RADAR_0x39b", 5, {}),
|
||||||
|
("RADAR_0x39c", 5, {"BYTE5": 0xE0, "BYTE6": 0x79}),
|
||||||
|
("RADAR_0x43a", 20, {"BYTE2": 0x07}),
|
||||||
|
) if hda2 else (
|
||||||
("RADAR_0x363", 2, {"FCA_ESA": 1}),
|
("RADAR_0x363", 2, {"FCA_ESA": 1}),
|
||||||
("RADAR_0x398", 5, {"BYTE4": 0x80, "BYTE5": 0x10}),
|
("RADAR_0x398", 5, {"BYTE4": 0x80, "BYTE5": 0x10}),
|
||||||
):
|
)
|
||||||
|
|
||||||
|
for addr, freq, values in message_specs:
|
||||||
if frame % freq != 0:
|
if frame % freq != 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
msg_values = values | {"COUNTER": frame % 0x10}
|
msg_values = values | {"COUNTER": frame % (0xF if hda2 else 0x10)}
|
||||||
msg_values["CHECKSUM"] = create_checksum_can_canfd_blended(packer, CAN.ECAN, addr, msg_values)
|
msg_values["CHECKSUM"] = create_checksum_can_canfd_blended(packer, CAN.ECAN, addr, msg_values)
|
||||||
commands.append(packer.make_can_msg(addr, CAN.ECAN, msg_values))
|
commands.append(packer.make_can_msg(addr, CAN.ECAN, msg_values))
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import numpy as np
|
|||||||
from opendbc.car import CanBusBase, CanData
|
from opendbc.car import CanBusBase, CanData
|
||||||
from opendbc.car.common.conversions import Conversions as CV
|
from opendbc.car.common.conversions import Conversions as CV
|
||||||
from opendbc.car.crc import CRC16_XMODEM
|
from opendbc.car.crc import CRC16_XMODEM
|
||||||
from opendbc.car.hyundai.values import HyundaiFlags, CAR
|
from opendbc.car.hyundai.values import HyundaiFlags, CAR, CANFD_ALT_BUTTONS_RESUME_CAR
|
||||||
|
|
||||||
|
|
||||||
def _set_value(msg: bytearray, sig, ival: int) -> None:
|
def _set_value(msg: bytearray, sig, ival: int) -> None:
|
||||||
@@ -63,6 +63,61 @@ def _update_checksum(packer, address: int, dat: bytearray) -> None:
|
|||||||
_set_value(dat, sig_checksum, checksum)
|
_set_value(dat, sig_checksum, checksum)
|
||||||
|
|
||||||
|
|
||||||
|
def _set_little_endian_bits(dat: bytearray, lsb: int, size: int, value: int) -> None:
|
||||||
|
"""Write the legacy HDA-II field layout without changing the generated DBC aliases."""
|
||||||
|
value &= (1 << size) - 1
|
||||||
|
bit = lsb
|
||||||
|
remaining = size
|
||||||
|
while remaining:
|
||||||
|
byte = bit // 8
|
||||||
|
shift = bit % 8
|
||||||
|
chunk_size = min(remaining, 8 - shift)
|
||||||
|
mask = ((1 << chunk_size) - 1) << shift
|
||||||
|
dat[byte] = (dat[byte] & ~mask) | ((value & ((1 << chunk_size) - 1)) << shift)
|
||||||
|
value >>= chunk_size
|
||||||
|
bit += chunk_size
|
||||||
|
remaining -= chunk_size
|
||||||
|
|
||||||
|
|
||||||
|
def _create_gv70_lka_status_msg(packer, CAN, message_name: str, bus: int, enabled: bool,
|
||||||
|
lat_active: bool, apply_torque: int):
|
||||||
|
values = {
|
||||||
|
"LKA_MODE": 2,
|
||||||
|
"LKA_ICON": 2 if enabled else 1,
|
||||||
|
"TORQUE_REQUEST": apply_torque,
|
||||||
|
"STEER_REQ": 1 if lat_active else 0,
|
||||||
|
"LKA_ASSIST": 0,
|
||||||
|
"STEER_MODE": 0,
|
||||||
|
"DAMP_FACTOR": 100,
|
||||||
|
}
|
||||||
|
address, raw, _ = packer.make_can_msg(message_name, bus, values)
|
||||||
|
dat = bytearray(raw)
|
||||||
|
|
||||||
|
legacy_fields = (
|
||||||
|
(24, 3, 2),
|
||||||
|
(27, 3, 0),
|
||||||
|
(30, 2, 0),
|
||||||
|
(32, 2, 0),
|
||||||
|
(34, 2, 0),
|
||||||
|
(36, 2, 0),
|
||||||
|
(38, 3, 2 if enabled else 1),
|
||||||
|
(52, 2, 1 if lat_active else 0),
|
||||||
|
(54, 2, 0),
|
||||||
|
(56, 1, 0),
|
||||||
|
(60, 4, 0),
|
||||||
|
(80, 2, 0),
|
||||||
|
)
|
||||||
|
for lsb, size, value in legacy_fields:
|
||||||
|
_set_little_endian_bits(dat, lsb, size, value)
|
||||||
|
|
||||||
|
_set_little_endian_bits(dat, 64 if message_name == "LKAS" else 104, 8, 100)
|
||||||
|
if message_name == "LKAS":
|
||||||
|
_set_little_endian_bits(dat, 84, 3, 0)
|
||||||
|
|
||||||
|
_update_checksum(packer, address, dat)
|
||||||
|
return address, bytes(dat), bus
|
||||||
|
|
||||||
|
|
||||||
def _create_angle_lfa_msg(packer, CAN, values, apply_angle: float, lat_active: bool, torque_reduction_gain: float):
|
def _create_angle_lfa_msg(packer, CAN, values, apply_angle: float, lat_active: bool, torque_reduction_gain: float):
|
||||||
address = packer.dbc.name_to_msg["LFA"].address
|
address = packer.dbc.name_to_msg["LFA"].address
|
||||||
dat = packer.pack(address, values)
|
dat = packer.pack(address, values)
|
||||||
@@ -100,6 +155,14 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
|
|||||||
lfa_base_values=None, lkas_base_values=None, lka_icon=None):
|
lfa_base_values=None, lkas_base_values=None, lka_icon=None):
|
||||||
if lka_icon is None:
|
if lka_icon is None:
|
||||||
lka_icon = 2 if enabled else 1
|
lka_icon = 2 if enabled else 1
|
||||||
|
|
||||||
|
if CP.carFingerprint == CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN and CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||||
|
ret = []
|
||||||
|
if CP.openpilotLongitudinalControl:
|
||||||
|
ret.append(_create_gv70_lka_status_msg(packer, CAN, "LFA", CAN.ECAN, enabled, lat_active, apply_torque))
|
||||||
|
ret.append(_create_gv70_lka_status_msg(packer, CAN, "LKAS", CAN.ACAN, enabled, lat_active, apply_torque))
|
||||||
|
return ret
|
||||||
|
|
||||||
angle_lkas_alt = CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT
|
angle_lkas_alt = CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT
|
||||||
|
|
||||||
control_values = {
|
control_values = {
|
||||||
@@ -117,6 +180,8 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
|
|||||||
else:
|
else:
|
||||||
lkas_values = copy.copy(control_values)
|
lkas_values = copy.copy(control_values)
|
||||||
lkas_values["LKA_AVAILABLE"] = 0
|
lkas_values["LKA_AVAILABLE"] = 0
|
||||||
|
if CP.carFingerprint in (CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN):
|
||||||
|
lkas_values["DAMP_FACTOR"] = 100
|
||||||
|
|
||||||
if lfa_base_values:
|
if lfa_base_values:
|
||||||
# Preserve stock UI/status fields and only override the actuation-relevant signals.
|
# Preserve stock UI/status fields and only override the actuation-relevant signals.
|
||||||
@@ -190,7 +255,7 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
|
|||||||
ret = []
|
ret = []
|
||||||
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||||
lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS"
|
lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS"
|
||||||
if CP.openpilotLongitudinalControl:
|
if CP.openpilotLongitudinalControl and not CP.flags & HyundaiFlags.CAN_CANFD_BLENDED:
|
||||||
ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values))
|
ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values))
|
||||||
ret.append(packer.make_can_msg(lkas_msg, CAN.ACAN, lkas_values))
|
ret.append(packer.make_can_msg(lkas_msg, CAN.ACAN, lkas_values))
|
||||||
else:
|
else:
|
||||||
@@ -241,16 +306,27 @@ def create_suppress_lfa(packer, CAN, lfa_block_msg, lka_steering_alt):
|
|||||||
|
|
||||||
|
|
||||||
def create_buttons(packer, CP, CAN, cnt, btn=0, base_values=None, left_paddle=False, right_paddle=False):
|
def create_buttons(packer, CP, CAN, cnt, btn=0, base_values=None, left_paddle=False, right_paddle=False):
|
||||||
values = {k: v for k, v in base_values.items() if k not in ("_CHECKSUM", "COUNTER")} if base_values else {}
|
values = {k: v for k, v in base_values.items() if k not in ("CHECKSUM", "_CHECKSUM", "COUNTER")} if base_values else {}
|
||||||
values.update({
|
values.update({
|
||||||
"COUNTER": cnt,
|
"COUNTER": cnt,
|
||||||
"SET_ME_1": 1,
|
"SET_ME_1": 1,
|
||||||
"CRUISE_BUTTONS": btn,
|
"CRUISE_BUTTONS": btn,
|
||||||
"LEFT_PADDLE": int(left_paddle),
|
|
||||||
"RIGHT_PADDLE": int(right_paddle),
|
|
||||||
})
|
})
|
||||||
|
if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS and CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR):
|
||||||
|
values.update({
|
||||||
|
"LEFT_PADDLE": int(left_paddle),
|
||||||
|
"RIGHT_PADDLE": int(right_paddle),
|
||||||
|
})
|
||||||
|
|
||||||
bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_LKA_STEERING else CAN.CAM
|
bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_LKA_STEERING else CAN.CAM
|
||||||
|
if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS and CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR:
|
||||||
|
address, dat, bus = packer.make_can_msg("CRUISE_BUTTONS_ALT", bus, values)
|
||||||
|
dat = bytearray(dat)
|
||||||
|
checksum = hkg_can_fd_checksum(address, None, dat)
|
||||||
|
dat[0] = checksum & 0xFF
|
||||||
|
dat[1] = (checksum >> 8) & 0xFF
|
||||||
|
return address, bytes(dat), bus
|
||||||
|
|
||||||
return packer.make_can_msg("CRUISE_BUTTONS", bus, values)
|
return packer.make_can_msg("CRUISE_BUTTONS", bus, values)
|
||||||
|
|
||||||
|
|
||||||
@@ -750,7 +826,7 @@ def create_fca_warning_light(packer, CAN, frame):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def create_adrv_messages(packer, CAN, frame):
|
def create_adrv_messages(packer, CAN, frame, blended_hda2=False):
|
||||||
# messages needed to car happy after disabling
|
# messages needed to car happy after disabling
|
||||||
# the ADAS Driving ECU to do longitudinal control
|
# the ADAS Driving ECU to do longitudinal control
|
||||||
|
|
||||||
@@ -760,6 +836,9 @@ def create_adrv_messages(packer, CAN, frame):
|
|||||||
}
|
}
|
||||||
ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
|
ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
|
||||||
|
|
||||||
|
if blended_hda2:
|
||||||
|
return ret
|
||||||
|
|
||||||
ret.extend(create_fca_warning_light(packer, CAN, frame))
|
ret.extend(create_fca_warning_light(packer, CAN, frame))
|
||||||
|
|
||||||
if frame % 5 == 0:
|
if frame % 5 == 0:
|
||||||
@@ -843,6 +922,7 @@ def hkg_can_fd_checksum(address: int, sig, d: bytearray) -> int:
|
|||||||
# brake, and accelerator bits are updated for the radar heartbeat.
|
# brake, and accelerator bits are updated for the radar heartbeat.
|
||||||
_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000020000fcff000000000020000055ff000068000000")
|
_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000020000fcff000000000020000055ff000068000000")
|
||||||
_KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("00000000ff006f00e80400001201030055ffff0000000000")
|
_KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("00000000ff006f00e80400001201030055ffff0000000000")
|
||||||
|
_HYUNDAI_IONIQ_5_PE_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000000000000000000000ff1fffff55ffff00a8000000")
|
||||||
# Neutral bodies verified across stock and successful suppression routes. Only
|
# Neutral bodies verified across stock and successful suppression routes. Only
|
||||||
# rolling integrity fields and the decoded state above are changed at runtime.
|
# rolling integrity fields and the decoded state above are changed at runtime.
|
||||||
_CCNC_ADRV_TEMPLATES = {
|
_CCNC_ADRV_TEMPLATES = {
|
||||||
@@ -859,6 +939,19 @@ _CCNC_ADRV_TEMPLATES = {
|
|||||||
0x1E0: bytes.fromhex("00000002000000000000000000000000"),
|
0x1E0: bytes.fromhex("00000002000000000000000000000000"),
|
||||||
0x38C: bytes.fromhex("000000f71f000000000000000000000000000000000000000000000000000000"),
|
0x38C: bytes.fromhex("000000f71f000000000000000000000000000000000000000000000000000000"),
|
||||||
},
|
},
|
||||||
|
CAR.HYUNDAI_IONIQ_5_PE: {
|
||||||
|
0x160: bytes.fromhex("0000000000000000fffc0100a8001000"),
|
||||||
|
0x1DA: bytes.fromhex("0000002200010000000000000000000000000000000000000000000000000000"),
|
||||||
|
0x1EA: bytes.fromhex("000000080000000000000000000000ff000000000000000000000000000f0f00"),
|
||||||
|
0x200: bytes.fromhex("00000014401b0000"),
|
||||||
|
0x345: bytes.fromhex("0000001500560000"),
|
||||||
|
0x161: bytes.fromhex("0000000000000000c0fff0c003000040000000000000000000ff000000000000"),
|
||||||
|
0x162: bytes.fromhex("0000002700000000c0ff00000000000000000000000000000000000000000000"),
|
||||||
|
0x1BA: bytes.fromhex("00000000000000880200000000000000000100000000000f"),
|
||||||
|
0x1E5: bytes.fromhex("00000000000000000000220200000080"),
|
||||||
|
0x1E0: bytes.fromhex("00000002000000000000000000000000"),
|
||||||
|
0x38C: bytes.fromhex("000000f79f000000000000000000000000000000000000000000000000000000"),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
_CCNC_ADRV_PERIODS = {
|
_CCNC_ADRV_PERIODS = {
|
||||||
CAR.KIA_EV9: {
|
CAR.KIA_EV9: {
|
||||||
@@ -870,12 +963,26 @@ _CCNC_ADRV_PERIODS = {
|
|||||||
0x1E0: 5,
|
0x1E0: 5,
|
||||||
0x38C: 20,
|
0x38C: 20,
|
||||||
},
|
},
|
||||||
|
CAR.HYUNDAI_IONIQ_5_PE: {
|
||||||
|
0x160: 2,
|
||||||
|
0x1DA: 100,
|
||||||
|
0x1EA: 5,
|
||||||
|
0x200: 5,
|
||||||
|
0x345: 20,
|
||||||
|
0x1E0: 5,
|
||||||
|
0x38C: 20,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool,
|
def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool,
|
||||||
car_fingerprint=None) -> CanData:
|
car_fingerprint=None) -> CanData:
|
||||||
template = _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE if car_fingerprint == CAR.KIA_EV9 else _ACCEL_BRAKE_ALT_TEMPLATE
|
if car_fingerprint == CAR.KIA_EV9:
|
||||||
|
template = _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE
|
||||||
|
elif car_fingerprint == CAR.HYUNDAI_IONIQ_5_PE:
|
||||||
|
template = _HYUNDAI_IONIQ_5_PE_ACCEL_BRAKE_ALT_TEMPLATE
|
||||||
|
else:
|
||||||
|
template = _ACCEL_BRAKE_ALT_TEMPLATE
|
||||||
d = bytearray(template)
|
d = bytearray(template)
|
||||||
d[2] = counter & 0xFF # COUNTER (bit 16, 8-bit)
|
d[2] = counter & 0xFF # COUNTER (bit 16, 8-bit)
|
||||||
d[4] = (d[4] & ~0x01) | (0x01 if brake_pressed else 0x00) # BRAKE_PRESSED (bit 32)
|
d[4] = (d[4] & ~0x01) | (0x01 if brake_pressed else 0x00) # BRAKE_PRESSED (bit 32)
|
||||||
|
|||||||
@@ -9,15 +9,18 @@ from opendbc.car.hyundai.values import HyundaiFlags, CAR, CarControllerParams, \
|
|||||||
RADAR_LIVE_LONGITUDINAL_CAR, \
|
RADAR_LIVE_LONGITUDINAL_CAR, \
|
||||||
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, \
|
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, \
|
||||||
LEGACY_LONGITUDINAL_CAR, \
|
LEGACY_LONGITUDINAL_CAR, \
|
||||||
|
CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR, \
|
||||||
HyundaiStarPilotSafetyFlags, \
|
HyundaiStarPilotSafetyFlags, \
|
||||||
hyundai_cancel_button_enables_cruise, \
|
hyundai_cancel_button_enables_cruise, \
|
||||||
kia_ev6_gt_line_longitudinal_tuning
|
kia_ev6_gt_line_longitudinal_tuning, \
|
||||||
|
KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID
|
||||||
from opendbc.car.hyundai.radar_interface import get_radar_track_config, radar_tracks_available
|
from opendbc.car.hyundai.radar_interface import get_radar_track_config, radar_tracks_available
|
||||||
from opendbc.car.interfaces import CarInterfaceBase, ACCEL_MIN
|
from opendbc.car.interfaces import CarInterfaceBase, ACCEL_MIN
|
||||||
from opendbc.car.disable_ecu import disable_ecu, ecu_log
|
from opendbc.car.disable_ecu import disable_ecu, ecu_log
|
||||||
from opendbc.car.hyundai.carcontroller import CarController
|
from opendbc.car.hyundai.carcontroller import CarController
|
||||||
from opendbc.car.hyundai.carstate import CarState
|
from opendbc.car.hyundai.carstate import CarState
|
||||||
from opendbc.car.hyundai.radar_interface import RadarInterface
|
from opendbc.car.hyundai.radar_interface import RadarInterface
|
||||||
|
from openpilot.starpilot.common.testing_grounds import testing_ground
|
||||||
|
|
||||||
ButtonType = structs.CarState.ButtonEvent.Type
|
ButtonType = structs.CarState.ButtonEvent.Type
|
||||||
Ecu = structs.CarParams.Ecu
|
Ecu = structs.CarParams.Ecu
|
||||||
@@ -28,6 +31,7 @@ ENABLE_BUTTONS = (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.can
|
|||||||
# Track when ECU disable happened - used to permanently suppress CAN errors from disabled ECU
|
# Track when ECU disable happened - used to permanently suppress CAN errors from disabled ECU
|
||||||
ECU_DISABLE_TIMESTAMP = 0.0
|
ECU_DISABLE_TIMESTAMP = 0.0
|
||||||
KONA_NON_SCC_FCA_RADAR_ADDR = 0x602
|
KONA_NON_SCC_FCA_RADAR_ADDR = 0x602
|
||||||
|
KIA_EV9_ACCEL_MAX = 2.2
|
||||||
|
|
||||||
|
|
||||||
def apply_platform_longitudinal_params(ret: structs.CarParams) -> None:
|
def apply_platform_longitudinal_params(ret: structs.CarParams) -> None:
|
||||||
@@ -61,6 +65,25 @@ def apply_ecu_disable_failure_fallback(CP: structs.CarParams, params) -> None:
|
|||||||
CP.pcmCruise = True
|
CP.pcmCruise = True
|
||||||
|
|
||||||
|
|
||||||
|
def egmp_in_ready_state(can_recv, bus: int, timeout_s: float = 0.5) -> bool:
|
||||||
|
accelerator_addr = 0x35
|
||||||
|
ready_bit_mask = 0x40
|
||||||
|
deadline = time.monotonic() + timeout_s
|
||||||
|
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
try:
|
||||||
|
can_packets = can_recv(wait_for_one=True)
|
||||||
|
except Exception:
|
||||||
|
break
|
||||||
|
|
||||||
|
for packet in can_packets:
|
||||||
|
for msg in packet:
|
||||||
|
if msg.address == accelerator_addr and msg.src == bus and len(msg.dat) > 3 and msg.dat[3] & ready_bit_mask:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def detect_kona_non_scc_radar_fca(candidate, fingerprint, car_fw) -> bool:
|
def detect_kona_non_scc_radar_fca(candidate, fingerprint, car_fw) -> bool:
|
||||||
if candidate != CAR.HYUNDAI_KONA_NON_SCC:
|
if candidate != CAR.HYUNDAI_KONA_NON_SCC:
|
||||||
return False
|
return False
|
||||||
@@ -80,11 +103,13 @@ class CarInterface(CarInterfaceBase):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_pid_accel_limits(CP, current_speed, cruise_speed):
|
def get_pid_accel_limits(CP, current_speed, cruise_speed):
|
||||||
return ACCEL_MIN, CarControllerParams.ACCEL_MAX
|
accel_max = KIA_EV9_ACCEL_MAX if CP.carFingerprint == CAR.KIA_EV9 else CarControllerParams.ACCEL_MAX
|
||||||
|
return ACCEL_MIN, accel_max
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def apply_post_fingerprint_params(CP: structs.CarParams, candidate, fingerprint, car_fw) -> None:
|
def apply_post_fingerprint_params(CP: structs.CarParams, candidate, fingerprint, car_fw) -> None:
|
||||||
if kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin):
|
gt_line_testing_ground = testing_ground.use(KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID)
|
||||||
|
if kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin, gt_line_testing_ground):
|
||||||
apply_kia_ev6_gt_line_longitudinal_params(CP)
|
apply_kia_ev6_gt_line_longitudinal_params(CP)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -97,6 +122,10 @@ class CarInterface(CarInterfaceBase):
|
|||||||
# "LFA steering" if camera directly sends LFA to the MDPS
|
# "LFA steering" if camera directly sends LFA to the MDPS
|
||||||
cam_can = CanBus(None, fingerprint).CAM
|
cam_can = CanBus(None, fingerprint).CAM
|
||||||
lka_steering = 0x50 in fingerprint[cam_can] or 0x110 in fingerprint[cam_can]
|
lka_steering = 0x50 in fingerprint[cam_can] or 0x110 in fingerprint[cam_can]
|
||||||
|
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
|
||||||
|
lka_steering = Ecu.adas in [fw.ecu for fw in car_fw] or 0x50 in fingerprint[cam_can]
|
||||||
|
if lka_steering:
|
||||||
|
ret.flags |= HyundaiFlags.CANFD_LKA_STEERING.value
|
||||||
CAN = CanBus(None, fingerprint, lka_steering)
|
CAN = CanBus(None, fingerprint, lka_steering)
|
||||||
|
|
||||||
if ret.flags & HyundaiFlags.CANFD:
|
if ret.flags & HyundaiFlags.CANFD:
|
||||||
@@ -123,7 +152,8 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.flags |= HyundaiFlags.CANFD_LKA_STEERING_ALT.value
|
ret.flags |= HyundaiFlags.CANFD_LKA_STEERING_ALT.value
|
||||||
# This HDA II Carnival uses the alternate 0x1AA cruise-button frame even
|
# This HDA II Carnival uses the alternate 0x1AA cruise-button frame even
|
||||||
# though other LKA-steering platforms use 0x1CF.
|
# though other LKA-steering platforms use 0x1CF.
|
||||||
if candidate == CAR.KIA_CARNIVAL_2025 and 0x1aa in fingerprint[CAN.ECAN] and 0x1cf not in fingerprint[CAN.ECAN]:
|
if candidate in (CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN) and \
|
||||||
|
0x1aa in fingerprint[CAN.ECAN] and 0x1cf not in fingerprint[CAN.ECAN]:
|
||||||
ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
|
ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
|
||||||
else:
|
else:
|
||||||
# no LKA steering
|
# no LKA steering
|
||||||
@@ -165,12 +195,17 @@ class CarInterface(CarInterfaceBase):
|
|||||||
# panda safety or the carcontroller; the MDPS tolerating held torque at 0 speed
|
# panda safety or the carcontroller; the MDPS tolerating held torque at 0 speed
|
||||||
# is being validated on-road.
|
# is being validated on-road.
|
||||||
ret.steerAtStandstill = True
|
ret.steerAtStandstill = True
|
||||||
|
if candidate == CAR.HYUNDAI_IONIQ_5_PE:
|
||||||
|
ret.steerAtStandstill = True
|
||||||
if ret.flags & HyundaiFlags.CCNC and not ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
if ret.flags & HyundaiFlags.CCNC and not ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||||
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CCNC.value
|
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CCNC.value
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Shared configuration for non CAN-FD cars
|
# Shared configuration for non CAN-FD cars
|
||||||
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR or candidate in LEGACY_LONGITUDINAL_CAR
|
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR or candidate in LEGACY_LONGITUDINAL_CAR
|
||||||
|
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED and ret.flags & HyundaiFlags.CANFD_LKA_STEERING and \
|
||||||
|
candidate not in CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR:
|
||||||
|
ret.alphaLongitudinalAvailable = False
|
||||||
ret.enableBsm = 0x58b in fingerprint[CAN.ECAN]
|
ret.enableBsm = 0x58b in fingerprint[CAN.ECAN]
|
||||||
|
|
||||||
# Send LFA message on cars with HDA
|
# Send LFA message on cars with HDA
|
||||||
@@ -195,13 +230,20 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_REFRESH_MSGS.value
|
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_REFRESH_MSGS.value
|
||||||
|
|
||||||
# These cars expose an LKAS/LFA steering-wheel button that StarPilot can customize.
|
# These cars expose an LKAS/LFA steering-wheel button that StarPilot can customize.
|
||||||
if 0x391 in fingerprint[0] or ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
|
if 0x391 in fingerprint[0] or 0x50C in fingerprint[0] or ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
|
||||||
ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value
|
ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value
|
||||||
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
|
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
|
||||||
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_CANFD_BLENDED.value
|
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_CANFD_BLENDED.value
|
||||||
|
if ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||||
|
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_LKA_STEERING.value
|
||||||
if hyundai_cancel_button_enables_cruise(candidate):
|
if hyundai_cancel_button_enables_cruise(candidate):
|
||||||
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANCEL_BTN_ENABLE.value
|
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANCEL_BTN_ENABLE.value
|
||||||
|
|
||||||
|
if 0x2AA in fingerprint[0]:
|
||||||
|
ret.minSteerSpeed = 0.0
|
||||||
|
ret.flags &= ~HyundaiFlags.MIN_STEER_32_MPH.value
|
||||||
|
ret.steerAtStandstill = True
|
||||||
|
|
||||||
# Common lateral control setup
|
# Common lateral control setup
|
||||||
|
|
||||||
ret.centerToFront = ret.wheelbase * 0.4
|
ret.centerToFront = ret.wheelbase * 0.4
|
||||||
@@ -261,8 +303,8 @@ class CarInterface(CarInterfaceBase):
|
|||||||
|
|
||||||
if candidate == CAR.HYUNDAI_ELANTRA_2021:
|
if candidate == CAR.HYUNDAI_ELANTRA_2021:
|
||||||
ret.longitudinalActuatorDelay = 0.22
|
ret.longitudinalActuatorDelay = 0.22
|
||||||
ret.stopAccel = -1.5
|
ret.stopAccel = -0.85
|
||||||
ret.stoppingDecelRate = 0.5
|
ret.stoppingDecelRate = 0.35
|
||||||
|
|
||||||
if candidate == CAR.HYUNDAI_ELANTRA_HEV_2024:
|
if candidate == CAR.HYUNDAI_ELANTRA_HEV_2024:
|
||||||
ret.longitudinalActuatorDelay = 0.22
|
ret.longitudinalActuatorDelay = 0.22
|
||||||
@@ -270,6 +312,17 @@ class CarInterface(CarInterfaceBase):
|
|||||||
if candidate == CAR.HYUNDAI_IONIQ_6:
|
if candidate == CAR.HYUNDAI_IONIQ_6:
|
||||||
ret.longitudinalActuatorDelay = 0.6
|
ret.longitudinalActuatorDelay = 0.6
|
||||||
|
|
||||||
|
if candidate == CAR.HYUNDAI_SANTA_FE_2022:
|
||||||
|
ret.longitudinalActuatorDelay = 0.4
|
||||||
|
ret.longitudinalTuning.kpBP = [0.0, 8.0, 20.0, 35.0]
|
||||||
|
ret.longitudinalTuning.kpV = [0.20, 0.17, 0.12, 0.08]
|
||||||
|
ret.longitudinalTuning.kiBP = [0.0, 8.0, 20.0, 35.0]
|
||||||
|
ret.longitudinalTuning.kiV = [0.02, 0.03, 0.05, 0.07]
|
||||||
|
|
||||||
|
if candidate == CAR.HYUNDAI_IONIQ_5_PE:
|
||||||
|
ret.longitudinalActuatorDelay = 0.35
|
||||||
|
ret.vEgoStarting = 0.4
|
||||||
|
|
||||||
if candidate == CAR.KIA_EV9 and ret.openpilotLongitudinalControl:
|
if candidate == CAR.KIA_EV9 and ret.openpilotLongitudinalControl:
|
||||||
apply_kia_ev9_longitudinal_params(ret)
|
apply_kia_ev9_longitudinal_params(ret)
|
||||||
|
|
||||||
@@ -306,35 +359,42 @@ class CarInterface(CarInterfaceBase):
|
|||||||
|
|
||||||
ecu_log(f"=== init() called: opLong={CP.openpilotLongitudinalControl}, flags=0x{CP.flags:x}, safetyParam={CP.safetyConfigs[-1].safetyParam} ===")
|
ecu_log(f"=== init() called: opLong={CP.openpilotLongitudinalControl}, flags=0x{CP.flags:x}, safetyParam={CP.safetyConfigs[-1].safetyParam} ===")
|
||||||
|
|
||||||
if CP.openpilotLongitudinalControl and not (CP.flags & (HyundaiFlags.CANFD_CAMERA_SCC | HyundaiFlags.CAMERA_SCC)):
|
if CP.openpilotLongitudinalControl and not (CP.flags & (HyundaiFlags.NON_SCC | HyundaiFlags.CANFD_CAMERA_SCC | HyundaiFlags.CAMERA_SCC)):
|
||||||
addr, bus = 0x7d0, CanBus(CP).ECAN if CP.flags & (HyundaiFlags.CANFD | HyundaiFlags.CAN_CANFD_BLENDED) else 0
|
addr, bus = 0x7d0, CanBus(CP).ECAN if CP.flags & (HyundaiFlags.CANFD | HyundaiFlags.CAN_CANFD_BLENDED) else 0
|
||||||
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value:
|
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value:
|
||||||
addr, bus = 0x730, CanBus(CP).ECAN
|
addr, bus = 0x730, CanBus(CP).ECAN
|
||||||
|
|
||||||
# Try ECU disable. If it succeeds (IGN-ON mode), enable longitudinal.
|
skip_disable_ecu = False
|
||||||
# If it fails (READY mode returns NRC 0x22, or timeout), strip LONG safety flag
|
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and egmp_in_ready_state(can_recv, bus):
|
||||||
# so panda forwards stock SCC messages normally (lateral-only mode).
|
apply_ecu_disable_failure_fallback(CP, params)
|
||||||
ecu_log(f"=== ECU DISABLE attempt: addr=0x{addr:x}, bus={bus} ===")
|
ecu_log(f"=== ECU DISABLE SKIPPED - READY detected, safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
|
||||||
ecu_disabled = disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control,
|
skip_disable_ecu = True
|
||||||
reset=bool(CP.flags & HyundaiFlags.CAN_CANFD_BLENDED))
|
|
||||||
|
|
||||||
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
|
if not skip_disable_ecu:
|
||||||
# Ioniq 6: track success/failure to auto-switch between openpilot long and stock ACC
|
# Try ECU disable. If it succeeds (IGN-ON mode), enable longitudinal.
|
||||||
if ecu_disabled:
|
# If it fails (READY mode returns NRC 0x22, or timeout), strip LONG safety flag
|
||||||
ECU_DISABLE_TIMESTAMP = time.monotonic()
|
# so panda forwards stock SCC messages normally (lateral-only mode).
|
||||||
params.put_bool("EcuDisableFailed", False)
|
ecu_log(f"=== ECU DISABLE attempt: addr=0x{addr:x}, bus={bus} ===")
|
||||||
params.put_bool("ExperimentalMode", True)
|
ecu_disabled = disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control,
|
||||||
ecu_log("=== ECU DISABLE SUCCESS - Longitudinal + Experimental ENABLED ===")
|
reset=bool(CP.flags & HyundaiFlags.CAN_CANFD_BLENDED))
|
||||||
|
|
||||||
|
if CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_IONIQ_5_PE):
|
||||||
|
# Track success/failure to auto-switch between openpilot long and stock ACC
|
||||||
|
if ecu_disabled:
|
||||||
|
ECU_DISABLE_TIMESTAMP = time.monotonic()
|
||||||
|
params.put_bool("EcuDisableFailed", False)
|
||||||
|
params.put_bool("ExperimentalMode", True)
|
||||||
|
ecu_log("=== ECU DISABLE SUCCESS - Longitudinal + Experimental ENABLED ===")
|
||||||
|
else:
|
||||||
|
apply_ecu_disable_failure_fallback(CP, params)
|
||||||
|
ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
|
||||||
else:
|
else:
|
||||||
apply_ecu_disable_failure_fallback(CP, params)
|
if ecu_disabled:
|
||||||
ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
|
params.put_bool("EcuDisableFailed", False)
|
||||||
else:
|
ecu_log("=== ECU DISABLE SUCCESS ===")
|
||||||
if ecu_disabled:
|
else:
|
||||||
params.put_bool("EcuDisableFailed", False)
|
apply_ecu_disable_failure_fallback(CP, params)
|
||||||
ecu_log("=== ECU DISABLE SUCCESS ===")
|
ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
|
||||||
else:
|
|
||||||
apply_ecu_disable_failure_fallback(CP, params)
|
|
||||||
ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
|
|
||||||
|
|
||||||
# for blinkers
|
# for blinkers
|
||||||
if CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
if CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -45,8 +45,12 @@ class CarControllerParams:
|
|||||||
self.STEER_DRIVER_MULTIPLIER = 2
|
self.STEER_DRIVER_MULTIPLIER = 2
|
||||||
self.STEER_THRESHOLD = 100
|
self.STEER_THRESHOLD = 100
|
||||||
if vEgoRaw < 15.0: # below ~34 mph - more aggressive for tight turns
|
if vEgoRaw < 15.0: # below ~34 mph - more aggressive for tight turns
|
||||||
self.STEER_DELTA_UP = 10
|
if CP.carFingerprint == CAR.KIA_CARNIVAL_HEV_4TH_GEN:
|
||||||
self.STEER_DELTA_DOWN = 8
|
self.STEER_DELTA_UP = 2
|
||||||
|
self.STEER_DELTA_DOWN = 3
|
||||||
|
else:
|
||||||
|
self.STEER_DELTA_UP = 10
|
||||||
|
self.STEER_DELTA_DOWN = 8
|
||||||
else:
|
else:
|
||||||
self.STEER_DELTA_UP = 2
|
self.STEER_DELTA_UP = 2
|
||||||
self.STEER_DELTA_DOWN = 3
|
self.STEER_DELTA_DOWN = 3
|
||||||
@@ -77,11 +81,14 @@ class CarControllerParams:
|
|||||||
self.STEER_DELTA_DOWN = 3
|
self.STEER_DELTA_DOWN = 3
|
||||||
|
|
||||||
elif CP.flags & HyundaiFlags.CAN_CANFD_BLENDED:
|
elif CP.flags & HyundaiFlags.CAN_CANFD_BLENDED:
|
||||||
self.STEER_MAX = 404
|
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||||
self.STEER_DRIVER_ALLOWANCE = 50
|
self.STEER_MAX = 384
|
||||||
self.STEER_THRESHOLD = 150
|
else:
|
||||||
self.STEER_DELTA_UP = 2
|
self.STEER_MAX = 404
|
||||||
self.STEER_DELTA_DOWN = 3
|
self.STEER_DRIVER_ALLOWANCE = 50
|
||||||
|
self.STEER_THRESHOLD = 150
|
||||||
|
self.STEER_DELTA_UP = 2
|
||||||
|
self.STEER_DELTA_DOWN = 3
|
||||||
|
|
||||||
# Default for most HKG
|
# Default for most HKG
|
||||||
else:
|
else:
|
||||||
@@ -108,12 +115,15 @@ class HyundaiSafetyFlags(IntFlag):
|
|||||||
|
|
||||||
|
|
||||||
class HyundaiStarPilotSafetyFlags(IntFlag):
|
class HyundaiStarPilotSafetyFlags(IntFlag):
|
||||||
|
AOL_MAIN_LKAS_ON_ENGAGE = 128
|
||||||
|
AOL_MAIN_LKAS_SYNC = 32
|
||||||
HAS_LDA_BUTTON = 1024
|
HAS_LDA_BUTTON = 1024
|
||||||
AOL_LKAS_ON_ENGAGE = 2048
|
AOL_LKAS_ON_ENGAGE = 2048
|
||||||
|
|
||||||
|
|
||||||
class HyundaiStarPilotFlags(IntFlag):
|
class HyundaiStarPilotFlags(IntFlag):
|
||||||
SPEED_LIMIT_AVAILABLE = 1
|
SPEED_LIMIT_AVAILABLE = 1
|
||||||
|
MAIN_CRUISE_STATE_TRACKING = 2 ** 2
|
||||||
|
|
||||||
|
|
||||||
class HyundaiFlags(IntFlag):
|
class HyundaiFlags(IntFlag):
|
||||||
@@ -476,8 +486,12 @@ class CAR(Platforms):
|
|||||||
[
|
[
|
||||||
HyundaiCarDocs("Hyundai Palisade (without HDA II) 2023-25", "Highway Driving Assist",
|
HyundaiCarDocs("Hyundai Palisade (without HDA II) 2023-25", "Highway Driving Assist",
|
||||||
car_parts=CarParts.common([CarHarness.hyundai_a])),
|
car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
HyundaiCarDocs("Hyundai Palisade (with HDA II) 2023-25", "Highway Driving Assist II",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_r])),
|
||||||
HyundaiCarDocs("Kia Telluride (without HDA II) 2023-25", "Highway Driving Assist",
|
HyundaiCarDocs("Kia Telluride (without HDA II) 2023-25", "Highway Driving Assist",
|
||||||
car_parts=CarParts.common([CarHarness.hyundai_l])),
|
car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||||
|
HyundaiCarDocs("Kia Telluride (with HDA II) 2023-24", "Highway Driving Assist II",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_p])),
|
||||||
],
|
],
|
||||||
HYUNDAI_PALISADE.specs,
|
HYUNDAI_PALISADE.specs,
|
||||||
flags=HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.CAN_CANFD_BLENDED | HyundaiFlags.RADAR_SCC,
|
flags=HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.CAN_CANFD_BLENDED | HyundaiFlags.RADAR_SCC,
|
||||||
@@ -513,8 +527,8 @@ class CAR(Platforms):
|
|||||||
car_parts=CarParts.common([CarHarness.hyundai_q]))
|
car_parts=CarParts.common([CarHarness.hyundai_q]))
|
||||||
],
|
],
|
||||||
HYUNDAI_IONIQ_5.specs,
|
HYUNDAI_IONIQ_5.specs,
|
||||||
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
|
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING | HyundaiFlags.CCNC,
|
||||||
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
|
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
|
||||||
)
|
)
|
||||||
HYUNDAI_IONIQ_5_N = HyundaiCanFDPlatformConfig(
|
HYUNDAI_IONIQ_5_N = HyundaiCanFDPlatformConfig(
|
||||||
[HyundaiCarDocs("Hyundai Ioniq 5 N (with HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_s]))],
|
[HyundaiCarDocs("Hyundai Ioniq 5 N (with HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_s]))],
|
||||||
@@ -863,6 +877,16 @@ class CAR(Platforms):
|
|||||||
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
|
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
|
||||||
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
|
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
|
||||||
)
|
)
|
||||||
|
GENESIS_GV70_2026 = HyundaiCanFDPlatformConfig(
|
||||||
|
[
|
||||||
|
HyundaiCarDocs("Genesis GV70 (3.5T Sport Prestige Trim, with HDA II & LFA2) 2026",
|
||||||
|
"Highway Driving Assist II & Lane Follow Assist 2",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_m])),
|
||||||
|
],
|
||||||
|
GENESIS_GV70_1ST_GEN.specs,
|
||||||
|
flags=HyundaiFlags.CANFD_ANGLE_STEERING,
|
||||||
|
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
|
||||||
|
)
|
||||||
GENESIS_G80 = HyundaiPlatformConfig(
|
GENESIS_G80 = HyundaiPlatformConfig(
|
||||||
[HyundaiCarDocs("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))],
|
[HyundaiCarDocs("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))],
|
||||||
CarSpecs(mass=2060, wheelbase=3.01, steerRatio=16.5),
|
CarSpecs(mass=2060, wheelbase=3.01, steerRatio=16.5),
|
||||||
@@ -921,6 +945,11 @@ class CAR(Platforms):
|
|||||||
HYUNDAI_KONA_EV.specs,
|
HYUNDAI_KONA_EV.specs,
|
||||||
flags=HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS,
|
flags=HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS,
|
||||||
)
|
)
|
||||||
|
KIA_RAY_EV = HyundaiNonSccPlatformConfig(
|
||||||
|
[HyundaiNonSccCarDocs("Kia Ray EV 2025", car_parts=CarParts.common([CarHarness.hyundai_h]))],
|
||||||
|
CarSpecs(mass=1295, wheelbase=2.52, steerRatio=14.5),
|
||||||
|
flags=HyundaiFlags.EV | HyundaiFlags.CHECKSUM_CRC8,
|
||||||
|
)
|
||||||
KIA_CEED_PHEV_2022_NON_SCC = HyundaiNonSccPlatformConfig(
|
KIA_CEED_PHEV_2022_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||||
[HyundaiNonSccCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_i]))],
|
[HyundaiNonSccCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_i]))],
|
||||||
CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
|
CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
|
||||||
@@ -959,32 +988,27 @@ CANCEL_BUTTON_ENABLE_CARS = frozenset({
|
|||||||
CAR.HYUNDAI_PALISADE_2023,
|
CAR.HYUNDAI_PALISADE_2023,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR = frozenset({
|
||||||
|
CAR.HYUNDAI_PALISADE_2023,
|
||||||
|
})
|
||||||
|
|
||||||
KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES = frozenset({
|
KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES = frozenset({
|
||||||
"C4DLC",
|
"C4DLC",
|
||||||
})
|
})
|
||||||
|
KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID = "5"
|
||||||
|
|
||||||
|
|
||||||
# These classic HKG platforms publish the LKAS button on CLU13 over the alt bus.
|
ALT_BUS_LDA_BUTTON_CARS = frozenset()
|
||||||
# Keep G90 excluded until its alt-bus path is route-proven without the recent
|
ALT_BUS_LDA_BUTTON_SWL_STAT_CARS = frozenset()
|
||||||
# engage/disengage regression.
|
|
||||||
ALT_BUS_LDA_BUTTON_CARS = frozenset({
|
|
||||||
CAR.HYUNDAI_SONATA,
|
|
||||||
})
|
|
||||||
|
|
||||||
# On these Sonata layouts the alt-bus LKAS button pulses through the CLU13
|
|
||||||
# steering-wheel-status field instead of the dedicated LKAS bit.
|
|
||||||
ALT_BUS_LDA_BUTTON_SWL_STAT_CARS = frozenset({
|
|
||||||
CAR.HYUNDAI_SONATA,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
def hyundai_cancel_button_enables_cruise(car_fingerprint) -> bool:
|
def hyundai_cancel_button_enables_cruise(car_fingerprint) -> bool:
|
||||||
return car_fingerprint in CANCEL_BUTTON_ENABLE_CARS
|
return car_fingerprint in CANCEL_BUTTON_ENABLE_CARS
|
||||||
|
|
||||||
|
|
||||||
def kia_ev6_gt_line_longitudinal_tuning(car_fingerprint, vin: str) -> bool:
|
def kia_ev6_gt_line_longitudinal_tuning(car_fingerprint, vin: str, testing_ground_active: bool = False) -> bool:
|
||||||
return car_fingerprint == CAR.KIA_EV6 and isinstance(vin, str) and \
|
vin_match = isinstance(vin, str) and len(vin) == 17 and vin[3:8] in KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES
|
||||||
len(vin) == 17 and vin[3:8] in KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES
|
return car_fingerprint == CAR.KIA_EV6 and (vin_match or testing_ground_active)
|
||||||
|
|
||||||
|
|
||||||
def get_platform_codes(fw_versions: list[bytes]) -> set[tuple[bytes, bytes | None]]:
|
def get_platform_codes(fw_versions: list[bytes]) -> set[tuple[bytes, bytes | None]]:
|
||||||
@@ -1037,7 +1061,7 @@ def match_fw_to_car_fuzzy(live_fw_versions, vin, offline_fw_versions) -> set[str
|
|||||||
if not any(found_platform_code in expected_platform_codes for found_platform_code in found_platform_codes):
|
if not any(found_platform_code in expected_platform_codes for found_platform_code in found_platform_codes):
|
||||||
break
|
break
|
||||||
|
|
||||||
if ecu[0] in DATE_FW_ECUS:
|
if ecu[0] in DATE_FW_ECUS and candidate not in DATELESS_FUZZY_CARS:
|
||||||
# If ECU can have a FW date, require it to exist
|
# If ECU can have a FW date, require it to exist
|
||||||
# (this excludes candidates in the database without dates)
|
# (this excludes candidates in the database without dates)
|
||||||
if not len(expected_dates) or not len(found_dates):
|
if not len(expected_dates) or not len(found_dates):
|
||||||
@@ -1076,7 +1100,7 @@ PART_NUMBER_FW_PATTERN = re.compile(b'(?<=[0-9][.,][0-9]{2} )([0-9]{5}[-/]?[A-Z]
|
|||||||
# We've seen both ICE and hybrid for these platforms, and they have hybrid descriptors (e.g. MQ4 vs MQ4H)
|
# We've seen both ICE and hybrid for these platforms, and they have hybrid descriptors (e.g. MQ4 vs MQ4H)
|
||||||
CANFD_FUZZY_WHITELIST = {CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KIA_K8_HEV_1ST_GEN,
|
CANFD_FUZZY_WHITELIST = {CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KIA_K8_HEV_1ST_GEN,
|
||||||
CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN,
|
CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN,
|
||||||
CAR.KIA_SORENTO_HEV_4TH_GEN_LFA2}
|
CAR.KIA_SORENTO_HEV_4TH_GEN_LFA2, CAR.GENESIS_GV70_2026}
|
||||||
|
|
||||||
# List of ECUs expected to have platform codes, camera and radar should exist on all cars
|
# List of ECUs expected to have platform codes, camera and radar should exist on all cars
|
||||||
# TODO: use abs, it has the platform code and part number on many platforms
|
# TODO: use abs, it has the platform code and part number on many platforms
|
||||||
@@ -1085,6 +1109,8 @@ PLATFORM_CODE_ECUS = [Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps]
|
|||||||
# TODO: there are date codes in the ABS firmware versions in hex
|
# TODO: there are date codes in the ABS firmware versions in hex
|
||||||
DATE_FW_ECUS = [Ecu.fwdCamera]
|
DATE_FW_ECUS = [Ecu.fwdCamera]
|
||||||
|
|
||||||
|
DATELESS_FUZZY_CARS = {CAR.HYUNDAI_KONA_NON_SCC}
|
||||||
|
|
||||||
# Note: an ECU on CAN FD cars may sometimes send 0x30080aaaaaaaaaaa (flow control continue) while we
|
# Note: an ECU on CAN FD cars may sometimes send 0x30080aaaaaaaaaaa (flow control continue) while we
|
||||||
# are attempting to query ECUs. This currently does not seem to affect fingerprinting from the camera
|
# are attempting to query ECUs. This currently does not seem to affect fingerprinting from the camera
|
||||||
FW_QUERY_CONFIG = FwQueryConfig(
|
FW_QUERY_CONFIG = FwQueryConfig(
|
||||||
@@ -1173,13 +1199,14 @@ CANFD_RADAR_SCC_CAR = CAR.with_flags(HyundaiFlags.RADAR_SCC) # TODO: merge with
|
|||||||
|
|
||||||
# CAN-FD cars with ADAS ECUs that work with the communication-control path.
|
# CAN-FD cars with ADAS ECUs that work with the communication-control path.
|
||||||
CANFD_SECURITYACCESS_CAR = {
|
CANFD_SECURITYACCESS_CAR = {
|
||||||
CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_KONA_EV_2ND_GEN, CAR.KIA_EV9,
|
CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_5_PE, CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_KONA_EV_2ND_GEN, CAR.KIA_EV9,
|
||||||
}
|
}
|
||||||
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) - CANFD_SECURITYACCESS_CAR # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
|
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) - CANFD_SECURITYACCESS_CAR # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
|
||||||
CANFD_ANGLE_LONGITUDINAL_CAR = {CAR.KIA_EV9}
|
CANFD_ANGLE_LONGITUDINAL_CAR = {CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE}
|
||||||
CANFD_CORNER_RADAR_BSM_CAR = {CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9}
|
CANFD_ALT_BUTTONS_RESUME_CAR = {CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN}
|
||||||
|
CANFD_CORNER_RADAR_BSM_CAR = {CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_IONIQ_5_PE, CAR.KIA_EV9}
|
||||||
CANFD_RADAR_LIVE_LONGITUDINAL_CAR = {
|
CANFD_RADAR_LIVE_LONGITUDINAL_CAR = {
|
||||||
CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV6, CAR.KIA_EV9, CAR.GENESIS_GV60_EV_1ST_GEN,
|
CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_5_PE, CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV6, CAR.KIA_EV9, CAR.GENESIS_GV60_EV_1ST_GEN,
|
||||||
}
|
}
|
||||||
RADAR_LIVE_LONGITUDINAL_CAR = CANFD_RADAR_LIVE_LONGITUDINAL_CAR | {
|
RADAR_LIVE_LONGITUDINAL_CAR = CANFD_RADAR_LIVE_LONGITUDINAL_CAR | {
|
||||||
CAR.HYUNDAI_IONIQ,
|
CAR.HYUNDAI_IONIQ,
|
||||||
@@ -1207,6 +1234,9 @@ NON_SCC_CAR = CAR.with_flags(HyundaiFlags.NON_SCC)
|
|||||||
# HyundaiFlags.CANFD_RADAR_SCC | HyundaiFlags.CANFD_NO_RADAR_DISABLE | )
|
# HyundaiFlags.CANFD_RADAR_SCC | HyundaiFlags.CANFD_NO_RADAR_DISABLE | )
|
||||||
UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.LEGACY) | CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL)
|
UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.LEGACY) | CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL)
|
||||||
|
|
||||||
LEGACY_LONGITUDINAL_CAR = {CAR.KIA_XCEED_PHEV}
|
LEGACY_LONGITUDINAL_CAR = {
|
||||||
|
CAR.GENESIS_G80,
|
||||||
|
CAR.KIA_XCEED_PHEV,
|
||||||
|
}
|
||||||
|
|
||||||
DBC = CAR.create_dbc_map()
|
DBC = CAR.create_dbc_map()
|
||||||
|
|||||||
@@ -187,12 +187,18 @@ class CarInterfaceBase(ABC):
|
|||||||
ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase)
|
ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase)
|
||||||
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, ret.tireStiffnessFactor)
|
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, ret.tireStiffnessFactor)
|
||||||
|
|
||||||
toggles_to_check = ("force_torque_controller", "nnff", "nnff_lite")
|
force_torque_controller = bool(getattr(starpilot_toggles, "force_torque_controller", False))
|
||||||
|
toggles_to_check = ("nnff", "nnff_lite")
|
||||||
modified_civic_force_torque = (
|
modified_civic_force_torque = (
|
||||||
candidate == HONDA.HONDA_CIVIC_BOSCH and
|
candidate == HONDA.HONDA_CIVIC_BOSCH and
|
||||||
bool(ret.flags & HondaFlags.EPS_MODIFIED)
|
bool(ret.flags & HondaFlags.EPS_MODIFIED)
|
||||||
)
|
)
|
||||||
|
# ForceTorqueController converts PID-based paths to torque control. It must
|
||||||
|
# not reinitialize cars that already selected torque control: those paths
|
||||||
|
# may have vehicle-specific torque tuning applied in their interface.
|
||||||
|
force_torque_conversion = force_torque_controller and ret.lateralTuning.which() != "torque"
|
||||||
if ret.steerControlType != structs.CarParams.SteerControlType.angle and (
|
if ret.steerControlType != structs.CarParams.SteerControlType.angle and (
|
||||||
|
force_torque_conversion or
|
||||||
any(getattr(starpilot_toggles, toggle, False) for toggle in toggles_to_check) or
|
any(getattr(starpilot_toggles, toggle, False) for toggle in toggles_to_check) or
|
||||||
modified_civic_force_torque
|
modified_civic_force_torque
|
||||||
):
|
):
|
||||||
@@ -213,9 +219,6 @@ class CarInterfaceBase(ABC):
|
|||||||
|
|
||||||
if platform not in MOCK:
|
if platform not in MOCK:
|
||||||
if platform in CHRYSLER:
|
if platform in CHRYSLER:
|
||||||
if candidate == CHRYSLER.RAM_HD_5TH_GEN:
|
|
||||||
if 570 not in fingerprint[0]:
|
|
||||||
fp_ret.flags |= ChryslerStarPilotFlags.RAM_HD_ALT_BUTTONS.value
|
|
||||||
if 0x4FF in fingerprint[0]:
|
if 0x4FF in fingerprint[0]:
|
||||||
fp_ret.flags |= ChryslerStarPilotFlags.NO_MIN_STEERING_SPEED.value
|
fp_ret.flags |= ChryslerStarPilotFlags.NO_MIN_STEERING_SPEED.value
|
||||||
CP.minSteerSpeed = 0.
|
CP.minSteerSpeed = 0.
|
||||||
@@ -238,11 +241,14 @@ class CarInterfaceBase(ABC):
|
|||||||
fp_ret.flags |= HyundaiStarPilotFlags.SPEED_LIMIT_AVAILABLE.value
|
fp_ret.flags |= HyundaiStarPilotFlags.SPEED_LIMIT_AVAILABLE.value
|
||||||
|
|
||||||
fp_ret.redneckCruiseAvailable = bool(CP.flags & HyundaiFlags.NON_SCC) and not bool(CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS)
|
fp_ret.redneckCruiseAvailable = bool(CP.flags & HyundaiFlags.NON_SCC) and not bool(CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS)
|
||||||
if fp_ret.redneckCruiseAvailable and params.get_bool("RedneckCruise") and \
|
if fp_ret.redneckCruiseAvailable and params.get_bool("RedneckCruise"):
|
||||||
not CP.openpilotLongitudinalControl:
|
|
||||||
fp_ret.pcmCruiseSpeed = False
|
fp_ret.pcmCruiseSpeed = False
|
||||||
|
CP.openpilotLongitudinalControl = True
|
||||||
|
|
||||||
hyundai_has_lda_button = (
|
if candidate == HYUNDAI.HYUNDAI_ELANTRA_HEV_2024 and CP.openpilotLongitudinalControl:
|
||||||
|
fp_ret.flags |= HyundaiStarPilotFlags.MAIN_CRUISE_STATE_TRACKING.value
|
||||||
|
|
||||||
|
hyundai_has_lda_button = not (CP.flags & HyundaiFlags.CANFD) and (
|
||||||
0x391 in fingerprint[0] or
|
0x391 in fingerprint[0] or
|
||||||
0x50C in fingerprint[0] or
|
0x50C in fingerprint[0] or
|
||||||
candidate in ALT_BUS_LDA_BUTTON_CARS or
|
candidate in ALT_BUS_LDA_BUTTON_CARS or
|
||||||
@@ -251,9 +257,25 @@ class CarInterfaceBase(ABC):
|
|||||||
if hyundai_has_lda_button:
|
if hyundai_has_lda_button:
|
||||||
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value
|
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value
|
||||||
|
|
||||||
# LKASButtonControl == 9 means BUTTON_FUNCTIONS["AOL_TOGGLE"] in starpilot_variables.
|
if getattr(starpilot_toggles, "always_on_lateral_lkas", False):
|
||||||
if params.get_bool("AlwaysOnLateral") and params.get_int("LKASButtonControl") == 9:
|
|
||||||
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
|
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
|
||||||
|
|
||||||
|
if candidate in (HYUNDAI.HYUNDAI_ELANTRA_HEV_2024, HYUNDAI.HYUNDAI_SONATA_HYBRID) and \
|
||||||
|
getattr(starpilot_toggles, "always_on_lateral_main", False):
|
||||||
|
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_MAIN_LKAS_ON_ENGAGE.value
|
||||||
|
if candidate == HYUNDAI.HYUNDAI_SONATA_HYBRID:
|
||||||
|
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
|
||||||
|
|
||||||
|
# The refresh Elantra's safety mapping comes from the resolved Galaxy
|
||||||
|
# toggle above, not from this legacy persisted-parameter fallback.
|
||||||
|
if candidate != HYUNDAI.HYUNDAI_ELANTRA_HEV_2024 and \
|
||||||
|
params.get_bool("AlwaysOnLateral") and params.get_int("LKASButtonControl") == 9:
|
||||||
|
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
|
||||||
|
|
||||||
|
if candidate == HYUNDAI.HYUNDAI_SONATA_HYBRID and getattr(starpilot_toggles, "always_on_lateral_lkas", False) and \
|
||||||
|
getattr(starpilot_toggles, "main_cruise_aol_toggle", False):
|
||||||
|
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_MAIN_LKAS_SYNC.value
|
||||||
|
|
||||||
elif platform in TOYOTA:
|
elif platform in TOYOTA:
|
||||||
fp_ret.canUsePedal = not CP.autoResumeSng
|
fp_ret.canUsePedal = not CP.autoResumeSng
|
||||||
fp_ret.canUseSDSU = candidate not in UNSUPPORTED_DSU_CAR and candidate not in TSS2_CAR
|
fp_ret.canUseSDSU = candidate not in UNSUPPORTED_DSU_CAR and candidate not in TSS2_CAR
|
||||||
@@ -264,7 +286,7 @@ class CarInterfaceBase(ABC):
|
|||||||
if 0x2FF in fingerprint[0] or (0x2AA in fingerprint[0] and candidate in NO_DSU_CAR):
|
if 0x2FF in fingerprint[0] or (0x2AA in fingerprint[0] and candidate in NO_DSU_CAR):
|
||||||
fp_ret.flags |= ToyotaStarPilotFlags.SMART_DSU.value
|
fp_ret.flags |= ToyotaStarPilotFlags.SMART_DSU.value
|
||||||
|
|
||||||
if candidate == TOYOTA.TOYOTA_PRIUS:
|
if candidate in (TOYOTA.TOYOTA_PRIUS, TOYOTA.TOYOTA_PRIUS_RETROFIT):
|
||||||
if 0x23 in fingerprint[0]:
|
if 0x23 in fingerprint[0]:
|
||||||
fp_ret.flags |= ToyotaStarPilotFlags.ZSS.value
|
fp_ret.flags |= ToyotaStarPilotFlags.ZSS.value
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import math
|
import math
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from opendbc.car import structs, rate_limit, DT_CTRL
|
from opendbc.car import ACCELERATION_DUE_TO_GRAVITY, structs, rate_limit, DT_CTRL
|
||||||
from opendbc.car.vehicle_model import VehicleModel
|
from opendbc.car.vehicle_model import VehicleModel
|
||||||
|
|
||||||
FRICTION_THRESHOLD = 0.3
|
FRICTION_THRESHOLD = 0.3
|
||||||
@@ -10,6 +10,12 @@ FRICTION_THRESHOLD = 0.3
|
|||||||
ISO_LATERAL_ACCEL = 3.0 # m/s^2
|
ISO_LATERAL_ACCEL = 3.0 # m/s^2
|
||||||
ISO_LATERAL_JERK = 5.0 # m/s^3
|
ISO_LATERAL_JERK = 5.0 # m/s^3
|
||||||
|
|
||||||
|
# Common angle/curvature safety limits. The road-roll allowance keeps the
|
||||||
|
# controller and panda limits aligned on normally banked roads.
|
||||||
|
AVERAGE_ROAD_ROLL = 0.06
|
||||||
|
MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL)
|
||||||
|
MAX_LATERAL_JERK = 3.0 + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AngleSteeringLimits:
|
class AngleSteeringLimits:
|
||||||
@@ -24,6 +30,29 @@ class AngleSteeringLimits:
|
|||||||
MAX_ANGLE_RATE: float = math.inf
|
MAX_ANGLE_RATE: float = math.inf
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CurvatureSteeringLimits:
|
||||||
|
CURVATURE_MAX: float
|
||||||
|
MAX_LATERAL_ACCEL: float = MAX_LATERAL_ACCEL
|
||||||
|
MAX_LATERAL_JERK: float = MAX_LATERAL_JERK
|
||||||
|
|
||||||
|
def apply_limits(self, apply_curvature: float, apply_curvature_last: float, v_ego: float, curvature: float,
|
||||||
|
lat_active: bool, steer_step: int) -> float:
|
||||||
|
"""Apply lateral acceleration and jerk constraints to curvature."""
|
||||||
|
v_ego = max(v_ego, 1)
|
||||||
|
|
||||||
|
max_curvature = self.MAX_LATERAL_ACCEL / (v_ego ** 2)
|
||||||
|
new_apply_curvature = float(np.clip(apply_curvature, -max_curvature, max_curvature))
|
||||||
|
|
||||||
|
max_jerk = (self.MAX_LATERAL_JERK / (v_ego ** 2)) * (steer_step * DT_CTRL)
|
||||||
|
new_apply_curvature = float(np.clip(new_apply_curvature, apply_curvature_last - max_jerk, apply_curvature_last + max_jerk))
|
||||||
|
|
||||||
|
if not lat_active:
|
||||||
|
new_apply_curvature = curvature
|
||||||
|
|
||||||
|
return float(np.clip(new_apply_curvature, -self.CURVATURE_MAX, self.CURVATURE_MAX))
|
||||||
|
|
||||||
|
|
||||||
def apply_driver_steer_torque_limits(apply_torque: int, apply_torque_last: int, driver_torque: float, LIMITS, steer_max: int = None):
|
def apply_driver_steer_torque_limits(apply_torque: int, apply_torque_last: int, driver_torque: float, LIMITS, steer_max: int = None):
|
||||||
# some safety modes utilize a dynamic max steer
|
# some safety modes utilize a dynamic max steer
|
||||||
if steer_max is None:
|
if steer_max is None:
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from opendbc.car.nissan import nissancan
|
|||||||
from opendbc.car.nissan.values import CAR, CarControllerParams
|
from opendbc.car.nissan.values import CAR, CarControllerParams
|
||||||
|
|
||||||
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
||||||
|
LongCtrlState = structs.CarControl.Actuators.LongControlState
|
||||||
|
|
||||||
|
|
||||||
class CarController(CarControllerBase):
|
class CarController(CarControllerBase):
|
||||||
@@ -28,6 +29,34 @@ class CarController(CarControllerBase):
|
|||||||
|
|
||||||
can_sends = []
|
can_sends = []
|
||||||
|
|
||||||
|
if self.CP.openpilotLongitudinalControl and self.car_fingerprint == CAR.NISSAN_LEAF:
|
||||||
|
accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
|
||||||
|
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||||
|
brake_mode = CC.longActive and (accel < CarControllerParams.PROPILOT_ACCEL_MIN or stopping)
|
||||||
|
|
||||||
|
if CC.longActive:
|
||||||
|
if brake_mode:
|
||||||
|
raw_accel = CarControllerParams.PROPILOT_BRAKE_RAW
|
||||||
|
else:
|
||||||
|
propulsion_accel = float(np.clip(accel, CarControllerParams.PROPILOT_ACCEL_MIN,
|
||||||
|
CarControllerParams.PROPILOT_ACCEL_MAX))
|
||||||
|
raw_accel = round(propulsion_accel * CarControllerParams.PROPILOT_ACCEL_SCALE +
|
||||||
|
CarControllerParams.PROPILOT_ACCEL_OFFSET)
|
||||||
|
else:
|
||||||
|
raw_accel = CarControllerParams.PROPILOT_INACTIVE_RAW
|
||||||
|
|
||||||
|
brake_pressure = round(max(0.0, -accel - 1.0) * CarControllerParams.BRAKE_GAIN) if brake_mode else 0
|
||||||
|
if stopping and CS.out.vEgo < self.CP.vEgoStopping:
|
||||||
|
brake_pressure = CarControllerParams.BRAKE_MAX
|
||||||
|
brake_pressure = int(np.clip(brake_pressure, 0, CarControllerParams.BRAKE_MAX))
|
||||||
|
|
||||||
|
can_sends.append(nissancan.create_accel_command(raw_accel, self.frame, CC.longActive))
|
||||||
|
can_sends.append(nissancan.create_brake_command(brake_pressure, self.frame,
|
||||||
|
CC.longActive and brake_pressure > 0, brake_mode))
|
||||||
|
|
||||||
|
if self.frame % 100 == 0:
|
||||||
|
can_sends.append(nissancan.create_leaf_adas_tester_present())
|
||||||
|
|
||||||
### STEER ###
|
### STEER ###
|
||||||
steer_hud_alert = 1 if hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0
|
steer_hud_alert = 1 if hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0
|
||||||
|
|
||||||
@@ -64,7 +93,8 @@ class CarController(CarControllerBase):
|
|||||||
# We now cancel by making propilot think the seatbelt is unlatched,
|
# We now cancel by making propilot think the seatbelt is unlatched,
|
||||||
# this generates a beep and a warning message every time you disengage
|
# this generates a beep and a warning message every time you disengage
|
||||||
if self.CP.carFingerprint in (CAR.NISSAN_LEAF, CAR.NISSAN_LEAF_IC) and self.frame % 2 == 0:
|
if self.CP.carFingerprint in (CAR.NISSAN_LEAF, CAR.NISSAN_LEAF_IC) and self.frame % 2 == 0:
|
||||||
can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg, pcm_cancel_cmd))
|
can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg,
|
||||||
|
pcm_cancel_cmd and not self.CP.openpilotLongitudinalControl))
|
||||||
|
|
||||||
can_sends.append(nissancan.create_steering_control(
|
can_sends.append(nissancan.create_steering_control(
|
||||||
self.packer, self.apply_angle_last, self.frame, CC.latActive, lkas_max_torque))
|
self.packer, self.apply_angle_last, self.frame, CC.latActive, lkas_max_torque))
|
||||||
@@ -82,6 +112,8 @@ class CarController(CarControllerBase):
|
|||||||
|
|
||||||
new_actuators = actuators.as_builder()
|
new_actuators = actuators.as_builder()
|
||||||
new_actuators.steeringAngleDeg = self.apply_angle_last
|
new_actuators.steeringAngleDeg = self.apply_angle_last
|
||||||
|
if self.CP.openpilotLongitudinalControl:
|
||||||
|
new_actuators.accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
|
||||||
|
|
||||||
self.frame += 1
|
self.frame += 1
|
||||||
return new_actuators, can_sends
|
return new_actuators, can_sends
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ class CarState(CarStateBase):
|
|||||||
self.distance_button = 0
|
self.distance_button = 0
|
||||||
|
|
||||||
self.lkas_button = 0
|
self.lkas_button = 0
|
||||||
|
self.set_button = 0
|
||||||
|
self.res_button = 0
|
||||||
|
self.cancel_button = 0
|
||||||
|
|
||||||
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
|
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
|
||||||
cp = can_parsers[Bus.pt]
|
cp = can_parsers[Bus.pt]
|
||||||
@@ -131,6 +134,17 @@ class CarState(CarStateBase):
|
|||||||
|
|
||||||
buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||||
|
|
||||||
|
if self.CP.openpilotLongitudinalControl and self.CP.carFingerprint == CAR.NISSAN_LEAF:
|
||||||
|
prev_set_button = self.set_button
|
||||||
|
prev_res_button = self.res_button
|
||||||
|
prev_cancel_button = self.cancel_button
|
||||||
|
self.set_button = int(cp.vl["CRUISE_THROTTLE"]["SET_BUTTON"])
|
||||||
|
self.res_button = int(cp.vl["CRUISE_THROTTLE"]["RES_BUTTON"])
|
||||||
|
self.cancel_button = int(cp.vl["CRUISE_THROTTLE"]["CANCEL_BUTTON"])
|
||||||
|
buttonEvents += create_button_events(self.set_button, prev_set_button, {1: ButtonType.decelCruise})
|
||||||
|
buttonEvents += create_button_events(self.res_button, prev_res_button, {1: ButtonType.accelCruise})
|
||||||
|
buttonEvents += create_button_events(self.cancel_button, prev_cancel_button, {1: ButtonType.cancel})
|
||||||
|
|
||||||
fp_ret = custom.StarPilotCarState.new_message()
|
fp_ret = custom.StarPilotCarState.new_message()
|
||||||
|
|
||||||
self.prev_lkas_button = self.lkas_button
|
self.prev_lkas_button = self.lkas_button
|
||||||
|
|||||||
@@ -1,14 +1,124 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
from opendbc.car import get_safety_config, structs
|
from opendbc.car import get_safety_config, structs
|
||||||
|
from opendbc.car.disable_ecu import disable_ecu, ecu_log
|
||||||
from opendbc.car.interfaces import CarInterfaceBase
|
from opendbc.car.interfaces import CarInterfaceBase
|
||||||
|
from opendbc.car.isotp_parallel_query import IsoTpParallelQuery
|
||||||
from opendbc.car.nissan.carcontroller import CarController
|
from opendbc.car.nissan.carcontroller import CarController
|
||||||
from opendbc.car.nissan.carstate import CarState
|
from opendbc.car.nissan.carstate import CarState
|
||||||
from opendbc.car.nissan.values import CAR, NissanSafetyFlags
|
from opendbc.car.nissan.values import CAR, CarControllerParams, NissanSafetyFlags, \
|
||||||
|
NISSAN_DIAGNOSTIC_REQUEST_KWP, NISSAN_DIAGNOSTIC_RESPONSE_KWP, NISSAN_RX_OFFSET
|
||||||
|
|
||||||
|
|
||||||
|
LEAF_ADAS_ECU_ADDR = 0x707
|
||||||
|
LEAF_ADAS_ECU_BUS = 0
|
||||||
|
LEAF_ADAS_COMMAND_BUS = 1
|
||||||
|
LEAF_ADAS_COMMAND_ADDRS = frozenset((0x1C3, 0x2B0))
|
||||||
|
LEAF_2025_SV_PLUS_CAMERA_FW = b'6WK2CDB\x04\x18\x00\x00\x00\x00\x00R=1\x18\x99\x10\x00\x00\x00\x80'
|
||||||
|
LEAF_2025_SV_PLUS_ALPHA_LONG_ENABLED = False
|
||||||
|
|
||||||
|
LEAF_KWP_EXTENDED_REQUEST = b"\x10\xC0"
|
||||||
|
LEAF_KWP_EXTENDED_RESPONSE = b"\x50\xC0"
|
||||||
|
LEAF_KWP_DISABLE_NORMAL_TX_NO_RESPONSE = b"\x28\x02"
|
||||||
|
|
||||||
|
LEAF_KWP_TAKEOVER_SESSIONS = (
|
||||||
|
(LEAF_KWP_EXTENDED_REQUEST, LEAF_KWP_EXTENDED_RESPONSE),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def is_leaf_2025_sv_plus_longitudinal(candidate, car_fw):
|
||||||
|
return LEAF_2025_SV_PLUS_ALPHA_LONG_ENABLED and candidate == CAR.NISSAN_LEAF and any(
|
||||||
|
fw.address == LEAF_ADAS_ECU_ADDR and bytes(fw.fwVersion) == LEAF_2025_SV_PLUS_CAMERA_FW
|
||||||
|
for fw in car_fw
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def leaf_adas_commands_silent(can_recv, settle_time=0.05, observe_time=0.15):
|
||||||
|
"""Confirm the stock ADAS command sender stopped while bus 1 is still observable."""
|
||||||
|
if can_recv is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Let already-published CAN batches age out, then discard everything queued
|
||||||
|
# before the communication-control response.
|
||||||
|
time.sleep(settle_time)
|
||||||
|
can_recv()
|
||||||
|
|
||||||
|
saw_adas_bus_traffic = False
|
||||||
|
deadline = time.monotonic() + observe_time
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
packets = can_recv(wait_for_one=True)
|
||||||
|
for packet in packets:
|
||||||
|
for msg in packet:
|
||||||
|
if msg.src != LEAF_ADAS_COMMAND_BUS:
|
||||||
|
continue
|
||||||
|
saw_adas_bus_traffic = True
|
||||||
|
if msg.address in LEAF_ADAS_COMMAND_ADDRS:
|
||||||
|
ecu_log(f"Nissan Leaf ADAS TX still active: {hex(msg.address)} on bus {msg.src}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
ecu_log(f"Nissan Leaf ADAS TX silence verification exception: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not saw_adas_bus_traffic:
|
||||||
|
ecu_log("Nissan Leaf ADAS TX silence could not be verified: no bus 1 traffic observed")
|
||||||
|
return saw_adas_bus_traffic
|
||||||
|
|
||||||
|
|
||||||
|
def leaf_adas_commands_present(can_recv, settle_time=0.05, observe_time=0.15):
|
||||||
|
"""Confirm the stock ADAS command sender resumed on bus 1."""
|
||||||
|
if can_recv is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
time.sleep(settle_time)
|
||||||
|
can_recv()
|
||||||
|
|
||||||
|
deadline = time.monotonic() + observe_time
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
for packet in can_recv(wait_for_one=True):
|
||||||
|
if any(msg.src == LEAF_ADAS_COMMAND_BUS and msg.address in LEAF_ADAS_COMMAND_ADDRS for msg in packet):
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
ecu_log(f"Nissan Leaf ADAS TX recovery verification exception: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
ecu_log("Nissan Leaf ADAS normal TX recovery could not be verified")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def restore_leaf_adas_tx(can_recv, can_send):
|
||||||
|
"""Return to the confirmed KWP default session and verify normal TX resumes."""
|
||||||
|
if can_recv is None or can_send is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
ecu_log("Nissan Leaf ADAS TX restore using KWP default session 1081")
|
||||||
|
query = IsoTpParallelQuery(
|
||||||
|
can_send, can_recv, LEAF_ADAS_ECU_BUS, [LEAF_ADAS_ECU_ADDR],
|
||||||
|
[NISSAN_DIAGNOSTIC_REQUEST_KWP], [NISSAN_DIAGNOSTIC_RESPONSE_KWP],
|
||||||
|
response_offset=NISSAN_RX_OFFSET,
|
||||||
|
)
|
||||||
|
if query.get_data(0.2) and leaf_adas_commands_present(can_recv):
|
||||||
|
ecu_log("Nissan Leaf ADAS normal TX restored and command traffic confirmed")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
ecu_log(f"Nissan Leaf ADAS TX restore exception: {e}")
|
||||||
|
|
||||||
|
ecu_log("Nissan Leaf ADAS normal TX restore was not confirmed")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class CarInterface(CarInterfaceBase):
|
class CarInterface(CarInterfaceBase):
|
||||||
CarState = CarState
|
CarState = CarState
|
||||||
CarController = CarController
|
CarController = CarController
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_pid_accel_limits(CP, current_speed, cruise_speed):
|
||||||
|
if CP.carFingerprint == CAR.NISSAN_LEAF and CP.openpilotLongitudinalControl:
|
||||||
|
return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX
|
||||||
|
return CarInterfaceBase.get_pid_accel_limits(CP, current_speed, cruise_speed)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
|
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
|
||||||
ret.brand = "nissan"
|
ret.brand = "nissan"
|
||||||
@@ -22,8 +132,56 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
||||||
ret.radarUnavailable = True
|
ret.radarUnavailable = True
|
||||||
|
|
||||||
|
ret.alphaLongitudinalAvailable = is_leaf_2025_sv_plus_longitudinal(candidate, car_fw)
|
||||||
|
ret.openpilotLongitudinalControl = alpha_long and ret.alphaLongitudinalAvailable
|
||||||
|
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
||||||
|
|
||||||
|
if ret.openpilotLongitudinalControl:
|
||||||
|
ret.safetyConfigs[0].safetyParam |= NissanSafetyFlags.LONG_CONTROL.value
|
||||||
|
ret.autoResumeSng = True
|
||||||
|
ret.stopAccel = -2.0
|
||||||
|
ret.vEgoStopping = 0.5
|
||||||
|
ret.vEgoStarting = 0.5
|
||||||
|
ret.stoppingDecelRate = 0.8
|
||||||
|
|
||||||
if candidate == CAR.NISSAN_ALTIMA:
|
if candidate == CAR.NISSAN_ALTIMA:
|
||||||
# Altima has EPS on C-CAN unlike the others that have it on V-CAN
|
# Altima has EPS on C-CAN unlike the others that have it on V-CAN
|
||||||
ret.safetyConfigs[0].safetyParam |= NissanSafetyFlags.ALT_EPS_BUS.value
|
ret.safetyConfigs[0].safetyParam |= NissanSafetyFlags.ALT_EPS_BUS.value
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def init(CP, can_recv, can_send):
|
||||||
|
if not (CP.openpilotLongitudinalControl and CP.alphaLongitudinalAvailable and CP.carFingerprint == CAR.NISSAN_LEAF):
|
||||||
|
return
|
||||||
|
|
||||||
|
from openpilot.common.params import Params
|
||||||
|
params = Params()
|
||||||
|
ecu_disabled = False
|
||||||
|
for diag_request, diag_response in LEAF_KWP_TAKEOVER_SESSIONS:
|
||||||
|
ecu_log(f"Nissan Leaf ADAS takeover using KWP session {diag_request.hex()}")
|
||||||
|
ecu_disabled = disable_ecu(can_recv, can_send, bus=LEAF_ADAS_ECU_BUS, addr=LEAF_ADAS_ECU_ADDR,
|
||||||
|
com_cont_req=LEAF_KWP_DISABLE_NORMAL_TX_NO_RESPONSE, require_response=False, retry=1,
|
||||||
|
diag_request=diag_request, diag_response=diag_response, response_offset=NISSAN_RX_OFFSET)
|
||||||
|
if ecu_disabled:
|
||||||
|
break
|
||||||
|
|
||||||
|
takeover_confirmed = ecu_disabled and leaf_adas_commands_silent(can_recv)
|
||||||
|
params.put_bool("EcuDisableFailed", not takeover_confirmed)
|
||||||
|
if takeover_confirmed:
|
||||||
|
ecu_log("Nissan Leaf ADAS TX disable and command silence confirmed; experimental longitudinal control enabled")
|
||||||
|
else:
|
||||||
|
# A response can be lost after the ECU accepts 0x28. Always attempt to
|
||||||
|
# restore stock transmission before falling back to stock longitudinal.
|
||||||
|
restore_leaf_adas_tx(can_recv, can_send)
|
||||||
|
CP.safetyConfigs[-1].safetyParam &= ~NissanSafetyFlags.LONG_CONTROL.value
|
||||||
|
CP.openpilotLongitudinalControl = False
|
||||||
|
CP.pcmCruise = True
|
||||||
|
ecu_log("Nissan Leaf ADAS takeover was not confirmed; falling back to stock longitudinal control")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def deinit(CP, can_recv, can_send):
|
||||||
|
if not (CP.openpilotLongitudinalControl and CP.alphaLongitudinalAvailable and CP.carFingerprint == CAR.NISSAN_LEAF):
|
||||||
|
return
|
||||||
|
|
||||||
|
restore_leaf_adas_tx(can_recv, can_send)
|
||||||
|
|||||||
@@ -1,10 +1,48 @@
|
|||||||
import crcmod
|
import crcmod
|
||||||
|
from opendbc.car.can_definitions import CanData
|
||||||
from opendbc.car.nissan.values import CAR
|
from opendbc.car.nissan.values import CAR
|
||||||
|
|
||||||
# TODO: add this checksum to the CANPacker
|
# TODO: add this checksum to the CANPacker
|
||||||
nissan_checksum = crcmod.mkCrcFun(0x11d, initCrc=0x00, rev=False, xorOut=0xff)
|
nissan_checksum = crcmod.mkCrcFun(0x11d, initCrc=0x00, rev=False, xorOut=0xff)
|
||||||
|
|
||||||
|
|
||||||
|
def create_leaf_adas_tester_present():
|
||||||
|
"""KWP2000 tester-present with a response requested, for the 2025 Leaf ADAS ECU."""
|
||||||
|
return CanData(0x707, b"\x02\x3E\x01\x00\x00\x00\x00\x00", 0)
|
||||||
|
|
||||||
|
|
||||||
|
def create_accel_command(raw_command, frame, active):
|
||||||
|
"""Build the Leaf ADAS propulsion/regen request (0x2B0)."""
|
||||||
|
raw_command = int(raw_command)
|
||||||
|
raw12, fraction = divmod(raw_command, 4)
|
||||||
|
inverse = (~raw12) & 0xFFF
|
||||||
|
|
||||||
|
dat = bytes([
|
||||||
|
((inverse & 0xF) << 4) | ((inverse >> 4) & 0xF),
|
||||||
|
(raw12 >> 4) & 0xFF,
|
||||||
|
(((inverse >> 8) & 0xF) << 4) | (raw12 & 0xF),
|
||||||
|
0xAC, # normal ADAS ownership state; stock briefly uses 0x6C while handing control back
|
||||||
|
0x5B if active else 0x1B,
|
||||||
|
0x00,
|
||||||
|
((frame & 0xF) << 4) | 0xE,
|
||||||
|
(fraction << 2) | ((~fraction) & 0x3),
|
||||||
|
])
|
||||||
|
return CanData(0x2B0, dat, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def create_brake_command(pressure, frame, active, brake_mode):
|
||||||
|
"""Build the Leaf ADAS friction-brake request (0x1C3), with pressure in 0.5-count units."""
|
||||||
|
pressure = int(pressure)
|
||||||
|
dat = bytearray(8)
|
||||||
|
dat[0] = (pressure >> 4) & 0x3F
|
||||||
|
dat[1] = (pressure & 0xF) << 4
|
||||||
|
dat[4] = 0x64
|
||||||
|
dat[5] = (0x80 if active else 0) | (0x04 if brake_mode else 0) | (frame & 0x3)
|
||||||
|
dat[6] = 0xFF
|
||||||
|
dat[7] = (0x01 + 0xC3 + sum(dat[:7])) & 0xFF
|
||||||
|
return CanData(0x1C3, bytes(dat), 1)
|
||||||
|
|
||||||
|
|
||||||
def create_steering_control(packer, apply_torque, frame, steer_on, lkas_max_torque):
|
def create_steering_control(packer, apply_torque, frame, steer_on, lkas_max_torque):
|
||||||
values = {
|
values = {
|
||||||
"COUNTER": frame % 0x10,
|
"COUNTER": frame % 0x10,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user