mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-06-11 21:05:54 +08:00
Compare commits
301 Commits
ev9-new
...
feature/de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e78b361444 | ||
|
|
74540873bf | ||
|
|
f3ef8ff6ec | ||
|
|
79a4f25f77 | ||
|
|
efef671a3f | ||
|
|
ded6049301 | ||
|
|
51f5193ec5 | ||
|
|
5db7dbee6b | ||
|
|
aab08b8527 | ||
|
|
4c8ed80304 | ||
|
|
3615b1a203 | ||
|
|
b41ace34cc | ||
|
|
b9d584245f | ||
|
|
6bd47c4eec | ||
|
|
43eefed514 | ||
|
|
f1d703e6e4 | ||
|
|
a598d385f2 | ||
|
|
92707e8912 | ||
|
|
fb87ba681a | ||
|
|
6a00ac9cd0 | ||
|
|
0a2fd7bd61 | ||
|
|
1490a24378 | ||
|
|
a2761ba731 | ||
|
|
cdc801c3c1 | ||
|
|
9f1a4569d1 | ||
|
|
d1caf29f7d | ||
|
|
d78c9c26f6 | ||
|
|
05ba480e02 | ||
|
|
f3c1427027 | ||
|
|
d7d4523e49 | ||
|
|
a08a29d5e6 | ||
|
|
490c53e2dc | ||
|
|
976655b599 | ||
|
|
2105344725 | ||
|
|
8dec4ea5d7 | ||
|
|
1e3f6599bd | ||
|
|
658444ca77 | ||
|
|
b934aa37d4 | ||
|
|
cab57a00d0 | ||
|
|
049193b178 | ||
|
|
84b934033c | ||
|
|
87ff98dc7c | ||
|
|
e45fc5e84b | ||
|
|
6c8b2290fa | ||
|
|
9dba62e686 | ||
|
|
5c4ceb7b39 | ||
|
|
6a3d0e090c | ||
|
|
3707efff6b | ||
|
|
b4cc9e68d1 | ||
|
|
9cb4d3d75e | ||
|
|
1034dbd37c | ||
|
|
39d4148c70 | ||
|
|
ffcbdc8c43 | ||
|
|
bad6103ce7 | ||
|
|
75cc300480 | ||
|
|
447f279f83 | ||
|
|
c4efe2f973 | ||
|
|
63ba5e864f | ||
|
|
6b3f75bbf0 | ||
|
|
4268d7a19c | ||
|
|
245605dc55 | ||
|
|
e674bc1355 | ||
|
|
6c046e5aa3 | ||
|
|
05f7519628 | ||
|
|
b33677c0dc | ||
|
|
b8065d3138 | ||
|
|
98a2b85529 | ||
|
|
a2859090d8 | ||
|
|
a6bfb9919d | ||
|
|
ce318e9c40 | ||
|
|
27d882cc0a | ||
|
|
45de2f7f19 | ||
|
|
531893d1c5 | ||
|
|
e15974345b | ||
|
|
b413f3de47 | ||
|
|
65853f0111 | ||
|
|
ea4554526e | ||
|
|
e652f435f9 | ||
|
|
5ce03e6ecf | ||
|
|
e607cbe5a2 | ||
|
|
5d8fd36022 | ||
|
|
4055efdf4b | ||
|
|
da79b6d494 | ||
|
|
45c8f5c9d5 | ||
|
|
34bbdf4d7f | ||
|
|
3748fdc355 | ||
|
|
2382f1cab0 | ||
|
|
e11b239b2e | ||
|
|
de8806cdfd | ||
|
|
5a28b0c9fe | ||
|
|
313a3d81e0 | ||
|
|
7627432830 | ||
|
|
cc1b233277 | ||
|
|
029a601674 | ||
|
|
982674b4a7 | ||
|
|
96d73fe2b3 | ||
|
|
a307a08591 | ||
|
|
e6177c49aa | ||
|
|
ed39aaddbc | ||
|
|
bab2d776b6 | ||
|
|
4bbb697998 | ||
|
|
002a37cdc4 | ||
|
|
43e43849ad | ||
|
|
efb44aeecd | ||
|
|
c70d3db1e6 | ||
|
|
309304a352 | ||
|
|
65d667e60e | ||
|
|
27ce30587a | ||
|
|
715a38fd6a | ||
|
|
124c75a94f | ||
|
|
b8229ebca6 | ||
|
|
0990212edc | ||
|
|
ecb4026269 | ||
|
|
2413f73108 | ||
|
|
75c9db260f | ||
|
|
b511fb7245 | ||
|
|
46e435f124 | ||
|
|
5c6c438bcb | ||
|
|
c55ef3ae1b | ||
|
|
2b9bd8dc36 | ||
|
|
05700433d8 | ||
|
|
a40ab9a69b | ||
|
|
a2628fe4f6 | ||
|
|
d21e351003 | ||
|
|
47c8ac2431 | ||
|
|
bf2731b470 | ||
|
|
01998f864d | ||
|
|
d2846741bc | ||
|
|
6d12ade231 | ||
|
|
dd37a35b59 | ||
|
|
e785026a98 | ||
|
|
4525659a7e | ||
|
|
2fca845153 | ||
|
|
988fc477eb | ||
|
|
ad67bdc853 | ||
|
|
6ad4ebdae6 | ||
|
|
c3bba7431a | ||
|
|
ed56ac52f4 | ||
|
|
d59e514209 | ||
|
|
31b3897418 | ||
|
|
f0abacbc59 | ||
|
|
3177142bfc | ||
|
|
4a04819d96 | ||
|
|
b95140666b | ||
|
|
42871f7a9d | ||
|
|
cac8527115 | ||
|
|
89e385b692 | ||
|
|
61b9d81ba6 | ||
|
|
4fbf7a81b4 | ||
|
|
f50d7a1842 | ||
|
|
4ef46251a7 | ||
|
|
7f669ec1e7 | ||
|
|
1be2643dfd | ||
|
|
db0ce99c01 | ||
|
|
4879e2f5ec | ||
|
|
70f8225efc | ||
|
|
6ed459d7cd | ||
|
|
8c4f5f1ff4 | ||
|
|
0798ebab07 | ||
|
|
141a7f5f72 | ||
|
|
ba3acbce0a | ||
|
|
425f5ebb2e | ||
|
|
1779a76d3c | ||
|
|
a4ef5ad982 | ||
|
|
bc65c8bef7 | ||
|
|
290383128e | ||
|
|
f9952d7cb7 | ||
|
|
d0f590b55e | ||
|
|
7ddaf52b2b | ||
|
|
a51ed062ca | ||
|
|
17d292c773 | ||
|
|
8c3f8064b2 | ||
|
|
b791d4ed55 | ||
|
|
1a8dd310ae | ||
|
|
cce0f14976 | ||
|
|
d5aa4ba997 | ||
|
|
564914c3a4 | ||
|
|
a0a1635c55 | ||
|
|
bb407ae9bf | ||
|
|
d7087d312c | ||
|
|
17b3092e76 | ||
|
|
977b164dd3 | ||
|
|
767880ffaf | ||
|
|
3abe1c9168 | ||
|
|
8801d1eb8e | ||
|
|
7e5a84b897 | ||
|
|
c51e74e6af | ||
|
|
c392b2b269 | ||
|
|
213b977774 | ||
|
|
f1837b8502 | ||
|
|
3e7240516e | ||
|
|
403d77ff3f | ||
|
|
9fe4d7ecc7 | ||
|
|
8d7315fa28 | ||
|
|
3e4be4a393 | ||
|
|
d08fd25784 | ||
|
|
4730a192b1 | ||
|
|
5f10529a88 | ||
|
|
bc67effb6d | ||
|
|
c9961f1590 | ||
|
|
d58b0f403f | ||
|
|
837eea06a4 | ||
|
|
485ac32250 | ||
|
|
5c38aeae0b | ||
|
|
177bfc9ba7 | ||
|
|
155f9ee3b9 | ||
|
|
073887221d | ||
|
|
36453f2014 | ||
|
|
2792ce472a | ||
|
|
4e6cc1f3bc | ||
|
|
f5764c2edf | ||
|
|
027023a7ff | ||
|
|
da980312d9 | ||
|
|
1a3f86a542 | ||
|
|
ac255742b6 | ||
|
|
d15d56b161 | ||
|
|
429b461eae | ||
|
|
ce3c55c691 | ||
|
|
afde2771f8 | ||
|
|
01c5dbdc4c | ||
|
|
c3bfd17028 | ||
|
|
bba3c39e2f | ||
|
|
4a60eb50e5 | ||
|
|
2f2b13382b | ||
|
|
9ccc5cc3ea | ||
|
|
898b7f28a8 | ||
|
|
72a4e0970a | ||
|
|
acd46aa94b | ||
|
|
7329128325 | ||
|
|
402ee444b7 | ||
|
|
5b99c8b185 | ||
|
|
b29117c02a | ||
|
|
56aa07844a | ||
|
|
d5f5887830 | ||
|
|
9e6656fd2e | ||
|
|
04ddb10c1d | ||
|
|
8edeb458d4 | ||
|
|
ec044790fb | ||
|
|
1b92f6ba3b | ||
|
|
b434043db7 | ||
|
|
d0f11e59ad | ||
|
|
1b7066eb12 | ||
|
|
8ee28e4f79 | ||
|
|
19f3cfd3d7 | ||
|
|
d6ec84c068 | ||
|
|
e682957101 | ||
|
|
c13f159a77 | ||
|
|
8970a7aa5b | ||
|
|
f84d27c4ee | ||
|
|
c12c22eac7 | ||
|
|
5b1bfc26db | ||
|
|
0b1d97fc72 | ||
|
|
9c58fa1020 | ||
|
|
ee5c1c4507 | ||
|
|
993c4a0d2a | ||
|
|
63f0237e7a | ||
|
|
a3ab6db7eb | ||
|
|
3a64efe52f | ||
|
|
3966599e9d | ||
|
|
0e264e1b05 | ||
|
|
3717a111af | ||
|
|
262d17ead2 | ||
|
|
0bfa9fca88 | ||
|
|
cd73feec57 | ||
|
|
bd49be185f | ||
|
|
37e493ce0d | ||
|
|
e114dc5a6f | ||
|
|
ad537fcb89 | ||
|
|
cf74e6416c | ||
|
|
7592669d74 | ||
|
|
a20d7a4279 | ||
|
|
e4fc6ffe7a | ||
|
|
cf30110d65 | ||
|
|
a48d43ec2b | ||
|
|
c8fe86c552 | ||
|
|
952354c847 | ||
|
|
fffa98ee85 | ||
|
|
c69cd934af | ||
|
|
437663ff98 | ||
|
|
8b54fb8372 | ||
|
|
0f74e0f760 | ||
|
|
4cccd07fd6 | ||
|
|
b42c997f83 | ||
|
|
6aaa245e65 | ||
|
|
705dd83a2f | ||
|
|
8132fe9f0e | ||
|
|
5dc5b6accb | ||
|
|
cc1bfcf12e | ||
|
|
bd6d207c8a | ||
|
|
777ff8dcb4 | ||
|
|
9446dd60d1 | ||
|
|
1deae82f12 | ||
|
|
0649653947 | ||
|
|
ab65b19ba5 | ||
|
|
36f8192612 | ||
|
|
4b66cd0577 | ||
|
|
ad742515f1 | ||
|
|
2426354d72 | ||
|
|
cf55992c26 | ||
|
|
3da0dfd47f | ||
|
|
6edaf619bf |
3
.codespellignore
Normal file
3
.codespellignore
Normal file
@@ -0,0 +1,3 @@
|
||||
Wen
|
||||
REGIST
|
||||
PullRequest
|
||||
3
.github/CODEOWNERS
vendored
Normal file
3
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
* @sunnypilot/dev-internal
|
||||
/.github/ @devtekve @sunnyhaibin
|
||||
/release/ci/ @devtekve @sunnyhaibin
|
||||
2
.github/labeler.yaml
vendored
2
.github/labeler.yaml
vendored
@@ -24,4 +24,4 @@ multilanguage:
|
||||
|
||||
autonomy:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: "{selfdrive/modeld/models/**,selfdrive/test/process_replay/model_replay_ref_commit}"
|
||||
- any-glob-to-all-files: "{selfdrive/modeld/models/**,selfdrive/test/process_replay/model_replay_ref_commit,sunnypilot/modeld*/models/**}"
|
||||
|
||||
43
.github/release-drafter.yml
vendored
Normal file
43
.github/release-drafter.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
exclude-labels:
|
||||
- 'no-changelog'
|
||||
categories:
|
||||
- title: '🚀 Features'
|
||||
labels:
|
||||
- 'feature'
|
||||
- 'enhancement'
|
||||
- title: '🐛 Bug Fixes'
|
||||
collapse-after: 5
|
||||
labels:
|
||||
- 'fix'
|
||||
- 'bugfix'
|
||||
- 'bug'
|
||||
- title: '🧰 Maintenance'
|
||||
collapse-after: 5
|
||||
label: 'chore'
|
||||
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
|
||||
change-title-escapes: '\<*_&'
|
||||
replacers:
|
||||
- search: '/[Ss][Uu][Nn][Nn][Yy][Pp][Ii][Ll][Oo][Tt]/g'
|
||||
replace: 'sunnypilot'
|
||||
- search: '/\b[Ss][Pp]\b/g'
|
||||
replace: 'SP'
|
||||
version-resolver:
|
||||
major:
|
||||
labels:
|
||||
- 'major'
|
||||
minor:
|
||||
labels:
|
||||
- 'minor'
|
||||
patch:
|
||||
labels:
|
||||
- 'patch'
|
||||
default: patch
|
||||
name-template: 'v$RESOLVED_VERSION 🚀'
|
||||
tag-template: 'v$RESOLVED_VERSION'
|
||||
version-template: "0.$MAJOR.$MINOR.$PATCH" # The day OP becomes v1, we need to bump this
|
||||
tag-prefix: "v0." # The day OP becomes v1, we need to bump this
|
||||
prerelease-identifier: "staging"
|
||||
template: |
|
||||
## Changes
|
||||
|
||||
$CHANGES
|
||||
11
.github/workflows/auto_pr_review.yaml
vendored
11
.github/workflows/auto_pr_review.yaml
vendored
@@ -1,7 +1,7 @@
|
||||
name: "PR review"
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened, synchronize, edited, edited]
|
||||
types: [opened, reopened, synchronize, edited]
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
# Check PR target branch
|
||||
- name: check branch
|
||||
uses: Vankka/pr-target-branch-action@def32ec9d93514138d6ac0132ee62e120a72aed5
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
@@ -37,17 +37,16 @@ jobs:
|
||||
# Welcome comment
|
||||
- name: "First timers PR"
|
||||
uses: actions/first-interaction@v1
|
||||
if: github.event.pull_request.head.repo.full_name != 'commaai/openpilot'
|
||||
if: github.event.pull_request.head.repo.full_name != 'sunnypilot/sunnypilot'
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
pr-message: |
|
||||
<!-- _(run_id **${{ github.run_id }}**)_ -->
|
||||
Thanks for contributing to openpilot! In order for us to review your PR as quickly as possible, check the following:
|
||||
* Convert your PR to a draft unless it's ready to review
|
||||
* Read the [contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md)
|
||||
* Read the [contributing docs](https://github.com/sunnypilot/sunnypilot/blob/master/docs/CONTRIBUTING.md)
|
||||
* Before marking as "ready for review", ensure:
|
||||
* the goal is clearly stated in the description
|
||||
* all the tests are passing
|
||||
* the change is [something we merge](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md#what-gets-merged)
|
||||
* the change is [something we merge](https://github.com/sunnypilot/sunnypilot/blob/master/docs/CONTRIBUTING.md#what-gets-merged)
|
||||
* include a route or your device' dongle ID if relevant
|
||||
|
||||
|
||||
4
.github/workflows/badges.yaml
vendored
4
.github/workflows/badges.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
badges:
|
||||
name: create badges
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
git checkout --orphan badges
|
||||
git rm -rf --cached .
|
||||
git config user.email "badge-researcher@comma.ai"
|
||||
git config user.email "badge-researcher@sunnypilot.ai"
|
||||
git config user.name "Badge Researcher"
|
||||
|
||||
git add translation_badge.svg
|
||||
|
||||
77
.github/workflows/cereal_validation.yaml
vendored
Normal file
77
.github/workflows/cereal_validation.yaml
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
name: cereal validation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- master-new
|
||||
pull_request:
|
||||
paths:
|
||||
- 'cereal/**'
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
run_number:
|
||||
default: '1'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
group: cereal-validation-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PYTHONWARNINGS: error
|
||||
BASE_IMAGE: openpilot-base
|
||||
BUILD: selfdrive/test/docker_build.sh base
|
||||
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
|
||||
|
||||
jobs:
|
||||
generate_cereal_artifact:
|
||||
name: Generate cereal validation artifacts
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: Build openpilot
|
||||
run: ${{ env.RUN }} "scons -j$(nproc) cereal"
|
||||
- name: Generate the log file
|
||||
run: |
|
||||
${{ env.RUN }} "cereal/messaging/tests/validate_sp_cereal_upstream.py -g -f schema_instances.bin" && \
|
||||
ls -la
|
||||
ls -la cereal/messaging/tests
|
||||
- name: 'Prepare artifact'
|
||||
run: |
|
||||
mkdir -p "cereal/messaging/tests/cereal_validations"
|
||||
cp cereal/messaging/tests/validate_sp_cereal_upstream.py "cereal/messaging/tests/cereal_validations/validate_sp_cereal_upstream.py"
|
||||
cp schema_instances.bin "cereal/messaging/tests/cereal_validations/schema_instances.bin"
|
||||
- name: 'Upload Artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cereal_validations
|
||||
path: cereal/messaging/tests/cereal_validations
|
||||
|
||||
validate_cereal_with_upstream:
|
||||
name: Validate cereal with Upstream
|
||||
runs-on: ubuntu-24.04
|
||||
needs: generate_cereal_artifact
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'commaai/openpilot'
|
||||
submodules: true
|
||||
ref: "refs/heads/master"
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: Build openpilot
|
||||
run: ${{ env.RUN }} "scons -j$(nproc) cereal"
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cereal_validations
|
||||
path: cereal/messaging/tests/cereal_validations
|
||||
- name: 'Run the validation'
|
||||
run: |
|
||||
chmod +x cereal/messaging/tests/cereal_validations/validate_sp_cereal_upstream.py
|
||||
${{ env.RUN }} "cereal/messaging/tests/cereal_validations/validate_sp_cereal_upstream.py -r -f cereal/messaging/tests/cereal_validations/schema_instances.bin"
|
||||
4
.github/workflows/ci_weekly_report.yaml
vendored
4
.github/workflows/ci_weekly_report.yaml
vendored
@@ -15,7 +15,7 @@ env:
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
ci_runs: ${{ steps.ci_runs_setup.outputs.matrix }}
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}}
|
||||
uses: commaai/openpilot/.github/workflows/ci_weekly_run.yaml@master
|
||||
uses: sunnypilot/sunnypilot/.github/workflows/ci_weekly_run.yaml@master
|
||||
with:
|
||||
run_number: ${{ matrix.run_number }}
|
||||
|
||||
|
||||
2
.github/workflows/ci_weekly_run.yaml
vendored
2
.github/workflows/ci_weekly_run.yaml
vendored
@@ -12,6 +12,6 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
selfdrive_tests:
|
||||
uses: commaai/openpilot/.github/workflows/selfdrive_tests.yaml@master
|
||||
uses: sunnypilot/sunnypilot/.github/workflows/selfdrive_tests.yaml@master
|
||||
with:
|
||||
run_number: ${{ inputs.run_number }}
|
||||
|
||||
@@ -15,7 +15,7 @@ runs:
|
||||
scons -j$(nproc) --cache-populate"
|
||||
- name: Save scons cache
|
||||
uses: actions/cache/save@v4
|
||||
if: github.ref == 'refs/heads/master'
|
||||
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new')
|
||||
with:
|
||||
path: .ci_cache/scons_cache
|
||||
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
|
||||
6
.github/workflows/docs.yaml
vendored
6
.github/workflows/docs.yaml
vendored
@@ -35,13 +35,13 @@ jobs:
|
||||
|
||||
# Push to docs.comma.ai
|
||||
- uses: actions/checkout@v4
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
||||
with:
|
||||
path: openpilot-docs
|
||||
ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }}
|
||||
repository: commaai/openpilot-docs
|
||||
repository: sunnypilot/sunnypilot-docs
|
||||
- name: Push
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
||||
run: |
|
||||
set -x
|
||||
|
||||
|
||||
72
.github/workflows/lfs-maintenance.yaml
vendored
Normal file
72
.github/workflows/lfs-maintenance.yaml
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
name: Sync comma's LFS
|
||||
|
||||
env:
|
||||
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
|
||||
LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Runs at 00:00 UTC every day
|
||||
push:
|
||||
branches:
|
||||
- 'master-new'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master-new'
|
||||
workflow_dispatch: # enables manual triggering
|
||||
inputs:
|
||||
upstream_branch:
|
||||
default: 'master'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
# Skip if PR is in draft mode
|
||||
if: (github.event_name != 'pull_request' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false)) && !github.event.pull_request.head.repo.fork
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'commaai/openpilot'
|
||||
ref: ${{ inputs.upstream_branch }}
|
||||
|
||||
- name: LFS Fetch
|
||||
run: |
|
||||
git lfs fetch
|
||||
|
||||
- name: Set up Git
|
||||
run: |
|
||||
git config --global user.name 'GitHub Action'
|
||||
git config --global user.email 'action@github.com'
|
||||
|
||||
- name: Set up SSH
|
||||
uses: webfactory/ssh-agent@v0.9.0
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
|
||||
- name: Add GitLab public keys
|
||||
run: |
|
||||
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Ensure branch
|
||||
run: |
|
||||
if git symbolic-ref -q HEAD >/dev/null; then
|
||||
echo "Already on a branch, proceeding with push"
|
||||
else
|
||||
echo "Detached HEAD state detected, creating temporary branch"
|
||||
git checkout -b temp_branch
|
||||
fi
|
||||
|
||||
- name: Update LFS Config
|
||||
run: |
|
||||
echo '[lfs]' > .lfsconfig
|
||||
echo ' url = ${{ env.LFS_URL }}' >> .lfsconfig
|
||||
echo ' pushurl = ${{ env.LFS_PUSH_URL }}' >> .lfsconfig
|
||||
echo ' locksverify = false' >> .lfsconfig
|
||||
|
||||
- name: Push LFS
|
||||
id: sync-and-commit
|
||||
run: |
|
||||
git lfs ls-files -l
|
||||
git lfs push --all origin
|
||||
2
.github/workflows/prebuilt.yaml
vendored
2
.github/workflows/prebuilt.yaml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
build_prebuilt:
|
||||
name: build prebuilt
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
env:
|
||||
PUSH_IMAGE: true
|
||||
permissions:
|
||||
|
||||
29
.github/workflows/release-drafter.yml
vendored
Normal file
29
.github/workflows/release-drafter.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: Release Drafter
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master-new
|
||||
- master
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request_target:
|
||||
types: [opened, reopened, synchronize]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update_release_draft:
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@v6
|
||||
with:
|
||||
config-name: release-drafter.yml
|
||||
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
container:
|
||||
image: ghcr.io/commaai/openpilot-base:latest
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
permissions:
|
||||
checks: read
|
||||
contents: write
|
||||
|
||||
2
.github/workflows/repo-maintenance.yaml
vendored
2
.github/workflows/repo-maintenance.yaml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/commaai/openpilot-base:latest
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
60
.github/workflows/selfdrive_tests.yaml
vendored
60
.github/workflows/selfdrive_tests.yaml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- master-new
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
@@ -14,10 +15,11 @@ on:
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
group: selfdrive-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||
group: selfdrive-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REPORT_NAME: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && 'master' || github.event.number }}
|
||||
PYTHONWARNINGS: error
|
||||
BASE_IMAGE: openpilot-base
|
||||
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
||||
@@ -31,10 +33,10 @@ env:
|
||||
|
||||
jobs:
|
||||
build_release:
|
||||
if: github.repository == 'commaai/openpilot' # build_release blocked for the time being to only comma as we may have a different process.
|
||||
name: build release
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
- 'ubuntu-24.04'
|
||||
env:
|
||||
STRIPPED_DIR: /tmp/releasepilot
|
||||
steps:
|
||||
@@ -52,7 +54,7 @@ jobs:
|
||||
run: TARGET_DIR=$STRIPPED_DIR release/build_devel.sh
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: Check submodules
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
timeout-minutes: 3
|
||||
run: release/check-submodules.sh
|
||||
- name: Build openpilot and run checks
|
||||
@@ -68,8 +70,7 @@ jobs:
|
||||
|
||||
build:
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
- 'ubuntu-24.04'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -85,34 +86,53 @@ jobs:
|
||||
|
||||
build_mac:
|
||||
name: build macOS
|
||||
runs-on: ${{ github.repository == 'commaai/openpilot' && 'namespace-profile-macos-8x14' || 'macos-latest' }}
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-macos-8x14' || 'macos-latest' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
|
||||
- name: Homebrew cache
|
||||
uses: ./.github/workflows/auto-cache
|
||||
with:
|
||||
path: ~/Library/Caches/Homebrew
|
||||
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
brew-macos-${{ env.CACHE_COMMIT_DATE }}
|
||||
brew-macos
|
||||
- name: Install dependencies
|
||||
run: ./tools/mac_setup.sh
|
||||
env:
|
||||
# package install has DeprecationWarnings
|
||||
PYTHONWARNINGS: default
|
||||
- name: Save Homebrew cache
|
||||
uses: actions/cache/save@v4
|
||||
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new')
|
||||
with:
|
||||
path: ~/Library/Caches/Homebrew
|
||||
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
- run: git lfs pull
|
||||
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
|
||||
- name: Getting scons cache
|
||||
uses: ./.github/workflows/auto-cache
|
||||
with:
|
||||
path: /tmp/scons_cache
|
||||
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}
|
||||
scons-${{ runner.arch }}-macos
|
||||
- name: Building openpilot
|
||||
run: . .venv/bin/activate && scons -j$(nproc)
|
||||
- name: Save scons cache
|
||||
uses: actions/cache/save@v4
|
||||
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new')
|
||||
with:
|
||||
path: /tmp/scons_cache
|
||||
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
|
||||
static_analysis:
|
||||
name: static analysis
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
- 'ubuntu-latest'
|
||||
env:
|
||||
PYTHONWARNINGS: default
|
||||
steps:
|
||||
@@ -127,8 +147,7 @@ jobs:
|
||||
unit_tests:
|
||||
name: unit tests
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
- 'ubuntu-24.04'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -153,9 +172,9 @@ jobs:
|
||||
|
||||
process_replay:
|
||||
name: process replay
|
||||
if: github.repository == 'commaai/openpilot' # disable process_replay for forks
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
- 'ubuntu-24.04'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -207,8 +226,7 @@ jobs:
|
||||
test_cars:
|
||||
name: cars
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
- 'ubuntu-24.04'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -299,8 +317,7 @@ jobs:
|
||||
simulator_driving:
|
||||
name: simulator driving
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
- 'ubuntu-24.04'
|
||||
if: (github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -321,8 +338,7 @@ jobs:
|
||||
# This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml
|
||||
name: Create UI Report
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
- 'ubuntu-24.04'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -337,7 +353,7 @@ jobs:
|
||||
- name: Build openpilot
|
||||
run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||
- name: Create Test Report
|
||||
timeout-minutes: ${{ ((steps.frames-cache.outputs.cache-hit == 'true') && 1 || 3) }}
|
||||
timeout-minutes: ${{ ((steps.frames-cache.outputs.cache-hit == 'true') && 2 || 4) }}
|
||||
run: >
|
||||
${{ env.RUN }} "PYTHONWARNINGS=ignore &&
|
||||
source selfdrive/test/setup_xvfb.sh &&
|
||||
@@ -346,5 +362,5 @@ jobs:
|
||||
- name: Upload Test Report
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
||||
name: ${{ env.REPORT_NAME }}
|
||||
path: selfdrive/ui/tests/test_ui/report_1/screenshots
|
||||
|
||||
2
.github/workflows/setup/action.yaml
vendored
2
.github/workflows/setup/action.yaml
vendored
@@ -19,7 +19,7 @@ runs:
|
||||
- shell: bash
|
||||
name: No retries!
|
||||
run: |
|
||||
if [ "${{ github.run_attempt }}" -gt 1 ]; then
|
||||
if [ "${{ github.run_attempt }}" -gt ${{ github.event.pull_request.head.repo.fork && github.event.pull_request.author_association == 'NONE' && 2 || 1}} ]; then
|
||||
echo -e "\033[0;31m##################################################"
|
||||
echo -e "\033[0;31m Retries not allowed! Fix the flaky test! "
|
||||
echo -e "\033[0;31m##################################################\033[0m"
|
||||
|
||||
2
.github/workflows/stale.yaml
vendored
2
.github/workflows/stale.yaml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
stale-pr-message: 'This PR has had no activity for ${{ env.DAYS_BEFORE_PR_STALE }} days. It will be automatically closed in ${{ env.DAYS_BEFORE_PR_CLOSE }} days if there is no activity.'
|
||||
close-pr-message: 'This PR has been automatically closed due to inactivity. Feel free to re-open once activity resumes.'
|
||||
stale-pr-label: stale
|
||||
delete-branch: ${{ github.event.pull_request.head.repo.full_name == 'commaai/openpilot' }} # only delete branches on the main repo
|
||||
delete-branch: ${{ github.event.pull_request.head.repo.full_name == 'sunnypilot/sunnypilot' }} # only delete branches on the main repo
|
||||
exempt-pr-labels: "ignore stale,needs testing" # if wip or it needs testing from the community, don't mark as stale
|
||||
days-before-pr-stale: ${{ env.DAYS_BEFORE_PR_STALE }}
|
||||
days-before-pr-close: ${{ env.DAYS_BEFORE_PR_CLOSE }}
|
||||
|
||||
133
.github/workflows/sunnypilot-build-model.yaml
vendored
Normal file
133
.github/workflows/sunnypilot-build-model.yaml
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
name: Build Model from Upstream
|
||||
|
||||
env:
|
||||
BUILD_DIR: "/data/openpilot"
|
||||
OUTPUT_DIR: ${{ github.workspace }}/output
|
||||
SCONS_CACHE_DIR: ${{ github.workspace }}/release/ci/scons_cache
|
||||
UPSTREAM_REPO: "commaai/openpilot"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
upstream_branch:
|
||||
description: 'Upstream branch to build from'
|
||||
required: true
|
||||
default: 'master'
|
||||
type: string
|
||||
custom_name:
|
||||
description: 'Custom name for the model'
|
||||
required: false
|
||||
type: string
|
||||
file_name:
|
||||
description: 'File name prefix for the model files'
|
||||
required: false
|
||||
type: string
|
||||
is_20hz:
|
||||
description: 'Is this a 20Hz model'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
|
||||
run-name: Build model [${{ inputs.custom_name || inputs.upstream_branch }}] from ref [${{ inputs.upstream_branch }}]
|
||||
|
||||
jobs:
|
||||
build_model:
|
||||
runs-on: self-hosted
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ env.UPSTREAM_REPO }}
|
||||
ref: ${{ github.event.inputs.upstream_branch }}
|
||||
submodules: recursive
|
||||
|
||||
- run: git lfs pull
|
||||
|
||||
- name: Cache SCons
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{env.SCONS_CACHE_DIR}}
|
||||
key: scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}-model-${{ github.sha }}
|
||||
# Note: GitHub Actions enforces cache isolation between different build sources (PR builds, workflow dispatches, etc.)
|
||||
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
|
||||
restore-keys: |
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}-model
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_NEW_BRANCH }}-model
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_BRANCH }}-model
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_NEW_BRANCH }}
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_BRANCH }}
|
||||
scons-${{ runner.os }}-${{ runner.arch }}
|
||||
|
||||
- name: Setup build environment
|
||||
run: |
|
||||
mkdir -p "${BUILD_DIR}/"
|
||||
sudo find $BUILD_DIR/ -mindepth 1 -delete
|
||||
echo "Starting build stage..."
|
||||
echo "Building from: ${{ env.UPSTREAM_REPO }} branch: ${{ github.event.inputs.upstream_branch }}"
|
||||
|
||||
- name: Patch SConstruct to pass arbitrary cache
|
||||
run: |
|
||||
sed -i.bak 's#cache_dir =#default_cache_dir =#' ${{ github.workspace }}/SConstruct
|
||||
printf '/default_cache_dir/a\\\ncache_dir = ARGUMENTS.get("cache_dir", default_cache_dir)\n' | sed -i.bak -f - ${{ github.workspace }}/SConstruct
|
||||
cat ${{ github.workspace }}/SConstruct
|
||||
|
||||
- name: Build Model
|
||||
run: |
|
||||
source /etc/profile
|
||||
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
||||
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
||||
scons -j$(nproc) cache_dir=${{ env.SCONS_CACHE_DIR }} ${{ github.workspace }}/selfdrive/modeld
|
||||
|
||||
- name: Prepare Output
|
||||
run: |
|
||||
sudo rm -rf ${OUTPUT_DIR}
|
||||
mkdir -p ${OUTPUT_DIR}
|
||||
|
||||
# Copy the model files
|
||||
rsync -avm \
|
||||
--include='*.dlc' \
|
||||
--include='*.thneed' \
|
||||
--include='*.pkl' \
|
||||
--include='*.onnx' \
|
||||
--exclude='*' \
|
||||
--delete-excluded \
|
||||
--chown=comma:comma \
|
||||
./selfdrive/modeld/models/ ${OUTPUT_DIR}/
|
||||
|
||||
# Rename files if file_name is provided
|
||||
if [ ! -z "${{ inputs.file_name }}" ]; then
|
||||
mv ${OUTPUT_DIR}/supercombo.thneed ${OUTPUT_DIR}/supercombo-${{ inputs.file_name }}.thneed
|
||||
mv ${OUTPUT_DIR}/supercombo_metadata.pkl ${OUTPUT_DIR}/supercombo-${{ inputs.file_name }}_metadata.pkl
|
||||
fi
|
||||
|
||||
# Calculate SHA256 hashes
|
||||
HASH=$(sha256sum ${OUTPUT_DIR}/supercombo*.thneed | cut -d' ' -f1)
|
||||
METADATA_HASH=$(sha256sum ${OUTPUT_DIR}/supercombo*_metadata.pkl | cut -d' ' -f1)
|
||||
|
||||
# Create metadata.json
|
||||
cat > ${OUTPUT_DIR}/metadata.json << EOF
|
||||
{
|
||||
"display_name": "${{ inputs.custom_name || inputs.upstream_branch }}",
|
||||
"full_name": "${{ inputs.file_name || 'default' }}",
|
||||
"is_20hz": ${{ inputs.is_20hz || false }},
|
||||
"files": {
|
||||
"drive_model": {
|
||||
"file_name": "$(basename ${OUTPUT_DIR}/supercombo*.thneed)",
|
||||
"sha256": "${HASH}"
|
||||
},
|
||||
"metadata": {
|
||||
"file_name": "$(basename ${OUTPUT_DIR}/supercombo*_metadata.pkl)",
|
||||
"sha256": "${METADATA_HASH}"
|
||||
}
|
||||
},
|
||||
"ref": "${{ inputs.upstream_branch }}",
|
||||
"build_time": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
}
|
||||
|
||||
- name: Upload Build Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: model-${{ github.event.inputs.custom_name || github.event.inputs.upstream_branch }}-${{ github.run_number }}
|
||||
path: ${{ env.OUTPUT_DIR }}
|
||||
271
.github/workflows/sunnypilot-build-prebuilt.yaml
vendored
Normal file
271
.github/workflows/sunnypilot-build-prebuilt.yaml
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
name: sunnypilot prebuilt action
|
||||
|
||||
env:
|
||||
BUILD_DIR: "/data/openpilot"
|
||||
OUTPUT_DIR: ${{ github.workspace }}/output
|
||||
CI_DIR: ${{ github.workspace }}/release/ci
|
||||
SCONS_CACHE_DIR: ${{ github.workspace }}/release/ci/scons_cache
|
||||
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
||||
|
||||
# Branch configurations
|
||||
MASTER_BRANCH: "master"
|
||||
MASTER_NEW_BRANCH: "master-new"
|
||||
DEV_C3_SOURCE_BRANCH: "master-dev-c3-new"
|
||||
|
||||
# Target branch configurations
|
||||
STAGING_TARGET_BRANCH: "staging-c3-new"
|
||||
DEV_TARGET_BRANCH: "dev-c3-new"
|
||||
RELEASE_TARGET_BRANCH: "release-c3-new"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, master-new, master-dev-c3-new ]
|
||||
tags: [ '*' ]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
extra_version:
|
||||
description: 'Extra version identifier'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
jobs:
|
||||
build:
|
||||
concurrency:
|
||||
group: build-${{ github.head_ref || github.ref_name }}
|
||||
cancel-in-progress: false
|
||||
runs-on: self-hosted
|
||||
outputs:
|
||||
new_branch: ${{ steps.set-env.outputs.new_branch }}
|
||||
version: ${{ steps.set-env.outputs.version }}
|
||||
extra_version_identifier: ${{ steps.set-env.outputs.extra_version_identifier }}
|
||||
commit_sha: ${{ steps.set-env.outputs.commit_sha }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- run: git lfs pull
|
||||
|
||||
- name: Cache SCons
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{env.SCONS_CACHE_DIR}}
|
||||
key: scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}-${{ github.sha }}
|
||||
# Note: GitHub Actions enforces cache isolation between different build sources (PR builds, workflow dispatches, etc.)
|
||||
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
|
||||
restore-keys: |
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_NEW_BRANCH }}
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_BRANCH }}
|
||||
scons-${{ runner.os }}-${{ runner.arch }}
|
||||
|
||||
- name: Set Configuration
|
||||
run: |
|
||||
if [[ "${{ github.ref_name }}" == "${{ env.DEV_C3_SOURCE_BRANCH }}" ]]; then
|
||||
# Dev configuration
|
||||
echo "BRANCH_TYPE=dev" >> $GITHUB_ENV
|
||||
echo "NEW_BRANCH=${{ env.DEV_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||||
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
||||
echo "EXTRA_VERSION_IDENTIFIER=${{ github.run_number }}" >> $GITHUB_ENV
|
||||
|
||||
elif [[ "${{ github.ref_name }}" == "${{ env.MASTER_BRANCH }}" || "${{ github.ref_name }}" == "${{ env.MASTER_NEW_BRANCH }}" ]]; then
|
||||
# Master configuration
|
||||
echo "BRANCH_TYPE=master" >> $GITHUB_ENV
|
||||
echo "NEW_BRANCH=${{ env.STAGING_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||||
echo "EXTRA_VERSION_IDENTIFIER=staging" >> $GITHUB_ENV
|
||||
echo "VERSION=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g')-staging" >> $GITHUB_ENV
|
||||
|
||||
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||||
# Tag configuration
|
||||
echo "BRANCH_TYPE=tag" >> $GITHUB_ENV
|
||||
echo "NEW_BRANCH=${{ env.RELEASE_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||||
echo "EXTRA_VERSION_IDENTIFIER=release" >> $GITHUB_ENV
|
||||
echo "VERSION=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g')-release" >> $GITHUB_ENV
|
||||
|
||||
else
|
||||
# Feature branch configuration
|
||||
echo "BRANCH_TYPE=dispatch" >> $GITHUB_ENV
|
||||
echo "NEW_BRANCH=${{ github.head_ref || github.ref_name }}-prebuilt" >> $GITHUB_ENV
|
||||
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Set environment variables
|
||||
id: set-env
|
||||
run: |
|
||||
# Write to GITHUB_OUTPUT from environment variables
|
||||
echo "new_branch=$NEW_BRANCH" >> $GITHUB_OUTPUT
|
||||
[[ ! -z "$EXTRA_VERSION_IDENTIFIER" ]] && echo "extra_version_identifier=$EXTRA_VERSION_IDENTIFIER" >> $GITHUB_OUTPUT
|
||||
[[ ! -z "$VERSION" ]] && echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "commit_sha=${{ github.sha }}" >> $GITHUB_OUTPUT
|
||||
|
||||
# Set up common environment
|
||||
source /etc/profile;
|
||||
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
||||
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
||||
printenv >> $GITHUB_ENV
|
||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||||
cat $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Setup build environment
|
||||
run: |
|
||||
mkdir -p "${BUILD_DIR}/"
|
||||
sudo find $BUILD_DIR/ -mindepth 1 -delete
|
||||
echo "Starting build stage..."
|
||||
echo "BUILD_DIR: ${BUILD_DIR}"
|
||||
echo "CI_DIR: ${CI_DIR}"
|
||||
echo "VERSION: ${{ steps.set-env.outputs.version }}"
|
||||
echo "UV_PROJECT_ENVIRONMENT: ${UV_PROJECT_ENVIRONMENT}"
|
||||
echo "VIRTUAL_ENV: ${VIRTUAL_ENV}"
|
||||
echo "-------"
|
||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||||
printenv
|
||||
fi
|
||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --disable
|
||||
|
||||
- name: Build Main Project
|
||||
run: |
|
||||
export PYTHONPATH="$BUILD_DIR"
|
||||
./release/release_files.py | sort | uniq | rsync -rRl${RUNNER_DEBUG:+v} --files-from=- . $BUILD_DIR/
|
||||
cd $BUILD_DIR
|
||||
sed -i '/from .board.jungle import PandaJungle, PandaJungleDFU/s/^/#/' panda/__init__.py
|
||||
scons -j$(nproc) cache_dir=${{env.SCONS_CACHE_DIR}} --minimal
|
||||
touch ${BUILD_DIR}/prebuilt
|
||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||||
ls -la ${BUILD_DIR}
|
||||
fi
|
||||
|
||||
- name: Prepare Output
|
||||
run: |
|
||||
sudo rm -rf ${OUTPUT_DIR}
|
||||
mkdir -p ${OUTPUT_DIR}
|
||||
rsync -am${RUNNER_DEBUG:+v} \
|
||||
--include='**/panda/board/' \
|
||||
--include='**/panda/board/obj' \
|
||||
--include='**/panda/board/obj/panda.bin.signed' \
|
||||
--include='**/panda/board/obj/panda_h7.bin.signed' \
|
||||
--include='**/panda/board/obj/bootstub.panda.bin' \
|
||||
--include='**/panda/board/obj/bootstub.panda_h7.bin' \
|
||||
--exclude='.sconsign.dblite' \
|
||||
--exclude='*.a' \
|
||||
--exclude='*.o' \
|
||||
--exclude='*.os' \
|
||||
--exclude='*.pyc' \
|
||||
--exclude='moc_*' \
|
||||
--exclude='*.cc' \
|
||||
--exclude='Jenkinsfile' \
|
||||
--exclude='supercombo.onnx' \
|
||||
--exclude='**/panda/board/*' \
|
||||
--exclude='**/panda/board/obj/**' \
|
||||
--exclude='**/panda/certs/' \
|
||||
--exclude='**/panda/crypto/' \
|
||||
--exclude='**/release/' \
|
||||
--exclude='**/.github/' \
|
||||
--exclude='**/selfdrive/ui/replay/' \
|
||||
--exclude='**/__pycache__/' \
|
||||
--exclude='**/selfdrive/ui/*.h' \
|
||||
--exclude='**/selfdrive/ui/**/*.h' \
|
||||
--exclude='**/selfdrive/ui/qt/offroad/sunnypilot/' \
|
||||
--exclude='${{env.SCONS_CACHE_DIR}}' \
|
||||
--exclude='**/.git/' \
|
||||
--exclude='**/SConstruct' \
|
||||
--exclude='**/SConscript' \
|
||||
--exclude='**/.venv/' \
|
||||
--delete-excluded \
|
||||
--chown=comma:comma \
|
||||
${BUILD_DIR}/ ${OUTPUT_DIR}/
|
||||
|
||||
- name: 'Tar.gz files'
|
||||
run: |
|
||||
tar czf prebuilt.tar.gz -C ${{ env.OUTPUT_DIR }} .
|
||||
ls -la prebuilt.tar.gz
|
||||
|
||||
- name: 'Upload Artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: prebuilt
|
||||
path: prebuilt.tar.gz
|
||||
|
||||
- name: Re-enable powersave
|
||||
if: always()
|
||||
run: |
|
||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
|
||||
|
||||
publish:
|
||||
concurrency:
|
||||
group: publish-${{ github.head_ref || github.ref_name }}
|
||||
cancel-in-progress: true
|
||||
if: ${{ github.event_name != 'pull_request' || github.event_name == 'pull_request' && github.event.pull_request.draft }}
|
||||
needs: build
|
||||
runs-on: ubuntu-24.04
|
||||
environment: ${{ contains(fromJSON(vars.AUTO_DEPLOY_PREBUILT_BRANCHES), github.head_ref || github.ref_name) && 'auto-deploy' || 'feature-branch' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: prebuilt
|
||||
|
||||
- name: Untar prebuilt
|
||||
run: |
|
||||
mkdir -p ${{ env.OUTPUT_DIR }}
|
||||
tar xzf prebuilt.tar.gz -C ${{ env.OUTPUT_DIR }}
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --global user.name "github-actions[bot]"
|
||||
|
||||
- name: Publish to Public Repository
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo '${{ toJSON(needs.build.outputs) }}'
|
||||
ls -la ${{ env.OUTPUT_DIR }}
|
||||
|
||||
${{ env.CI_DIR }}/publish.sh \
|
||||
"${{ github.workspace }}" \
|
||||
"${{ env.OUTPUT_DIR }}" \
|
||||
"${{ needs.build.outputs.new_branch }}" \
|
||||
"${{ needs.build.outputs.version }}" \
|
||||
"https://x-access-token:${{github.token}}@github.com/sunnypilot/sunnypilot.git" \
|
||||
"-${{ needs.build.outputs.extra_version_identifier }}"
|
||||
|
||||
echo ""
|
||||
echo "---- ℹ️ To update the list of branches that auto deploy prebuilts -----"
|
||||
echo ""
|
||||
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/AUTO_DEPLOY_PREBUILT_BRANCHES"
|
||||
echo "2. Current value: ${{ vars.AUTO_DEPLOY_PREBUILT_BRANCHES }}"
|
||||
echo "3. Update as needed (JSON array with no spaces)"
|
||||
|
||||
notify:
|
||||
needs: [ build, publish ]
|
||||
runs-on: ubuntu-24.04
|
||||
if: success()
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Alpine Linux environment
|
||||
uses: jirutka/setup-alpine@v1.2.0
|
||||
with:
|
||||
packages: 'jq gettext curl'
|
||||
|
||||
- name: Send Discord Notification
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ contains(fromJSON(vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES), github.head_ref || github.ref_name) && secrets.DISCORD_DEV_FEEDBACK_CHANNEL_WEBHOOK || secrets.DISCORD_DEV_PRIVATE_CHANNEL_WEBHOOK }}
|
||||
run: |
|
||||
TEMPLATE='${{ vars.DISCORD_GENERAL_UPDATE_NOTICE }}'
|
||||
export EXTRA_VERSION_IDENTIFIER="${{ needs.build.outputs.extra_version_identifier }}"
|
||||
export VERSION="${{ needs.build.outputs.version }}"
|
||||
export branch_name=${{ github.head_ref || github.ref_name }}
|
||||
export new_branch=${{ needs.build.outputs.new_branch }}
|
||||
export extra_version_identifier=${{ needs.build.outputs.extra_version_identifier || github.run_number}}
|
||||
echo ${TEMPLATE} | envsubst | jq -c '.' | tee payload.json
|
||||
curl -X POST -H "Content-Type: application/json" -d @payload.json $DISCORD_WEBHOOK
|
||||
|
||||
echo ""
|
||||
echo "---- ℹ️ To update the list of branches that notify to dev-feedback -----"
|
||||
echo ""
|
||||
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/DEV_FEEDBACK_NOTIFICATION_BRANCHES"
|
||||
echo "2. Current value: ${{ vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES }}"
|
||||
echo "3. Update as needed (JSON array with no spaces)"
|
||||
shell: alpine.sh {0}
|
||||
193
.github/workflows/sunnypilot-master-dev-c3-prep.yaml
vendored
Normal file
193
.github/workflows/sunnypilot-master-dev-c3-prep.yaml
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
name: Nightly Branch Reset and PR Squash
|
||||
|
||||
env:
|
||||
DEFAULT_SOURCE_BRANCH: "master-new"
|
||||
DEFAULT_TARGET_BRANCH: "nightly"
|
||||
PR_LABEL: "dev-c3"
|
||||
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
|
||||
LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
source_branch:
|
||||
description: 'Source branch to reset from'
|
||||
required: true
|
||||
default: 'master-new'
|
||||
type: string
|
||||
target_branch:
|
||||
description: 'Target branch to reset and squash into'
|
||||
required: true
|
||||
default: 'master-dev-c3-new'
|
||||
type: string
|
||||
# schedule:
|
||||
# - cron: '0 0 * * *' # Run at midnight UTC for nightly
|
||||
|
||||
jobs:
|
||||
reset-and-squash:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for all branches
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global user.name 'github-actions[bot]'
|
||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
|
||||
- name: Set up SSH
|
||||
uses: webfactory/ssh-agent@v0.9.0
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
|
||||
- name: Add GitLab public keys
|
||||
run: |
|
||||
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install PyGithub
|
||||
|
||||
- name: Check branches exist
|
||||
run: |
|
||||
# Check if source branch exists
|
||||
if ! git ls-remote --heads origin ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }} | grep -q "${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"; then
|
||||
echo "Source branch ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }} does not exist!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure we have the latest source branch
|
||||
git fetch origin ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
|
||||
|
||||
# Check if target branch exists
|
||||
if ! git ls-remote --heads origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} | grep -q "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"; then
|
||||
echo "Target branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} does not exist, creating it from ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"
|
||||
git checkout -b ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} origin/${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
|
||||
git push origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}
|
||||
else
|
||||
# Fetch target branch if it exists
|
||||
git fetch origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}
|
||||
fi
|
||||
|
||||
- name: Reset target branch
|
||||
run: |
|
||||
echo "Resetting ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} to match ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"
|
||||
# Delete if exists and recreate pointing to source
|
||||
git branch -D ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} || true
|
||||
git branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} origin/${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
|
||||
|
||||
- name: Get PRs to squash
|
||||
id: get-prs
|
||||
run: |
|
||||
# Use GitHub API to get PRs with specific label, ordered by creation date
|
||||
PR_LIST=$(gh api graphql -f query='
|
||||
query($label:String!) {
|
||||
search(query: $label, type:ISSUE, first:100) {
|
||||
nodes {
|
||||
... on PullRequest {
|
||||
number
|
||||
headRefName
|
||||
title
|
||||
createdAt
|
||||
labels(last:10) {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
headRepository {
|
||||
name
|
||||
nameWithOwner
|
||||
url
|
||||
isFork
|
||||
}
|
||||
commits(last: 1) {
|
||||
nodes {
|
||||
commit {
|
||||
statusCheckRollup {
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}' -F label="is:pr is:open label:${PR_LABEL} sort:created-asc")
|
||||
|
||||
echo "PR_LIST=${PR_LIST}" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Process PRs
|
||||
run: |
|
||||
cp ${{ github.workspace }}/release/ci/squash_and_merge.py /tmp/squash_and_merge.py && \
|
||||
chmod +x /tmp/squash_and_merge.py && \
|
||||
python3 ${{ github.workspace }}/release/ci/squash_and_merge_prs.py \
|
||||
--pr-data '${{ steps.get-prs.outputs.PR_LIST }}' \
|
||||
--target-branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} \
|
||||
--squash-script-path '/tmp/squash_and_merge.py'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Update LFS Config
|
||||
run: |
|
||||
echo '[lfs]' > .lfsconfig
|
||||
echo ' url = ${{ env.LFS_URL }}' >> .lfsconfig
|
||||
echo ' pushurl = ${{ env.LFS_PUSH_URL }}' >> .lfsconfig
|
||||
echo ' locksverify = false' >> .lfsconfig
|
||||
|
||||
- name: Push changes if there are diffs
|
||||
id: push-changes # Add an id so we can reference this step
|
||||
run: |
|
||||
TARGET_BRANCH="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
|
||||
|
||||
# Fetch the latest from remote
|
||||
git fetch origin $TARGET_BRANCH
|
||||
|
||||
# Check for diffs between local and remote
|
||||
if git diff $TARGET_BRANCH origin/$TARGET_BRANCH --quiet; then
|
||||
echo "No changes to push - local and remote branches are identical"
|
||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If we get here, there are diffs, so push
|
||||
if ! git push origin $TARGET_BRANCH --force; then
|
||||
echo "Failed to push changes to $TARGET_BRANCH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Branch $TARGET_BRANCH has been reset and updated with squashed PRs"
|
||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Trigger and wait for selfdrive tests
|
||||
if: steps.push-changes.outputs.has_changes == 'true'
|
||||
run: |
|
||||
echo "Triggering selfdrive tests..."
|
||||
gh workflow run selfdrive_tests.yaml --ref "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
|
||||
|
||||
echo "Sleeping for 120s to give plenty of time for the action to start and then we wait"
|
||||
sleep 120
|
||||
|
||||
echo "Getting latest run ID..."
|
||||
RUN_ID=$(gh run list --workflow=selfdrive_tests.yaml --branch="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}" --limit=1 --json databaseId --jq '.[0].databaseId')
|
||||
|
||||
echo "Watching run ID: $RUN_ID"
|
||||
gh run watch "$RUN_ID"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Trigger prebuilt workflow
|
||||
if: success() && steps.push-changes.outputs.has_changes == 'true'
|
||||
run: |
|
||||
gh workflow run sunnypilot-build-prebuilt.yaml --ref "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
38
.github/workflows/ui_preview.yaml
vendored
38
.github/workflows/ui_preview.yaml
vendored
@@ -3,23 +3,25 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- master-new
|
||||
pull_request_target:
|
||||
types: [assigned, opened, synchronize, reopened, edited]
|
||||
branches:
|
||||
- 'master'
|
||||
- 'master-new'
|
||||
paths:
|
||||
- 'selfdrive/ui/**'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
UI_JOB_NAME: "Create UI Report"
|
||||
REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
||||
SHA: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.sha || github.event.pull_request.head.sha }}
|
||||
REPORT_NAME: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && 'master' || github.event.number }}
|
||||
SHA: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && github.sha || github.event.pull_request.head.sha }}
|
||||
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}"
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
name: preview
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
@@ -58,13 +60,13 @@ jobs:
|
||||
- name: Getting master ui
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: commaai/ci-artifacts
|
||||
repository: sunnypilot/ci-artifacts
|
||||
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
|
||||
path: ${{ github.workspace }}/master_ui
|
||||
ref: openpilot_master_ui
|
||||
|
||||
- name: Saving new master ui
|
||||
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && github.event_name == 'push'
|
||||
working-directory: ${{ github.workspace }}/master_ui
|
||||
run: |
|
||||
git checkout --orphan=new_master_ui
|
||||
@@ -82,7 +84,7 @@ jobs:
|
||||
if: github.event_name == 'pull_request_target'
|
||||
id: find_diff
|
||||
run: >-
|
||||
sudo apt-get install -y imagemagick
|
||||
sudo apt-get update && sudo apt-get install -y imagemagick
|
||||
|
||||
scenes=$(find ${{ github.workspace }}/pr_ui/*.png -type f -printf "%f\n" | cut -d '.' -f 1 | grep -v 'pair_device')
|
||||
A=($scenes)
|
||||
@@ -93,8 +95,20 @@ jobs:
|
||||
|
||||
for ((i=0; i<${#A[*]}; i=i+1));
|
||||
do
|
||||
# Check if the master file exists
|
||||
if [ ! -f "${{ github.workspace }}/master_ui/${A[$i]}.png" ]; then
|
||||
# This is a new file in PR UI that doesn't exist in master
|
||||
DIFF="${DIFF}<details open>"
|
||||
DIFF="${DIFF}<summary>${A[$i]} : \$\${\\color{cyan}\\text{NEW}}\$\$</summary>"
|
||||
DIFF="${DIFF}<table>"
|
||||
|
||||
if ! compare -fuzz 2% -highlight-color DeepSkyBlue1 -lowlight-color Black -compose Src ${{ github.workspace }}/master_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png; then
|
||||
DIFF="${DIFF}<tr>"
|
||||
DIFF="${DIFF} <td> <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
||||
DIFF="${DIFF}</tr>"
|
||||
|
||||
DIFF="${DIFF}</table>"
|
||||
DIFF="${DIFF}</details>"
|
||||
elif ! compare -fuzz 2% -highlight-color DeepSkyBlue1 -lowlight-color Black -compose Src ${{ github.workspace }}/master_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png; then
|
||||
convert ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png -transparent black mask.png
|
||||
composite mask.png ${{ github.workspace }}/master_ui/${A[$i]}.png composite_diff.png
|
||||
convert -delay 100 ${{ github.workspace }}/master_ui/${A[$i]}.png composite_diff.png -loop 0 ${{ github.workspace }}/pr_ui/${A[$i]}_diff.gif
|
||||
@@ -106,13 +120,13 @@ jobs:
|
||||
DIFF="${DIFF}<table>"
|
||||
|
||||
DIFF="${DIFF}<tr>"
|
||||
DIFF="${DIFF} <td> master <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_master_ref.png\"> </td>"
|
||||
DIFF="${DIFF} <td> proposed <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
||||
DIFF="${DIFF} <td> master <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_master_ref.png\"> </td>"
|
||||
DIFF="${DIFF} <td> proposed <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
||||
DIFF="${DIFF}</tr>"
|
||||
|
||||
DIFF="${DIFF}<tr>"
|
||||
DIFF="${DIFF} <td> diff <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_diff.png\"> </td>"
|
||||
DIFF="${DIFF} <td> composite diff <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_diff.gif\"> </td>"
|
||||
DIFF="${DIFF} <td> diff <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_diff.png\"> </td>"
|
||||
DIFF="${DIFF} <td> composite diff <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_diff.gif\"> </td>"
|
||||
DIFF="${DIFF}</tr>"
|
||||
|
||||
DIFF="${DIFF}</table>"
|
||||
@@ -125,7 +139,7 @@ jobs:
|
||||
if [[ $INDEX -eq 0 ]]; then
|
||||
TABLE="${TABLE}<tr>"
|
||||
fi
|
||||
TABLE="${TABLE} <td> <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
||||
TABLE="${TABLE} <td> <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
||||
if [[ $INDEX -eq 1 || $(($i + 1)) -eq ${#A[*]} ]]; then
|
||||
TABLE="${TABLE}</tr>"
|
||||
fi
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -75,6 +75,9 @@ comma*.sh
|
||||
selfdrive/modeld/thneed/compile
|
||||
selfdrive/modeld/models/*.thneed
|
||||
selfdrive/modeld/models/*.pkl
|
||||
sunnypilot/modeld*/thneed/compile
|
||||
sunnypilot/modeld*/models/*.thneed
|
||||
sunnypilot/modeld*/models/*.pkl
|
||||
|
||||
*.bz2
|
||||
*.zst
|
||||
@@ -104,3 +107,8 @@ Pipfile
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
|
||||
### JetBrains ###
|
||||
!.idea/customTargets.xml
|
||||
!.idea/tools/*
|
||||
!.run/*
|
||||
|
||||
13
.gitmodules
vendored
13
.gitmodules
vendored
@@ -1,18 +1,21 @@
|
||||
[submodule "panda"]
|
||||
path = panda
|
||||
url = ../../commaai/panda.git
|
||||
url = https://github.com/sunnyhaibin/panda.git
|
||||
[submodule "opendbc"]
|
||||
path = opendbc_repo
|
||||
url = ../../commaai/opendbc.git
|
||||
url = https://github.com/sunnypilot/opendbc.git
|
||||
[submodule "msgq"]
|
||||
path = msgq_repo
|
||||
url = ../../commaai/msgq.git
|
||||
url = https://github.com/sunnypilot/msgq.git
|
||||
[submodule "rednose_repo"]
|
||||
path = rednose_repo
|
||||
url = ../../commaai/rednose.git
|
||||
url = https://github.com/commaai/rednose.git
|
||||
[submodule "teleoprtc_repo"]
|
||||
path = teleoprtc_repo
|
||||
url = ../../commaai/teleoprtc
|
||||
url = https://github.com/commaai/teleoprtc
|
||||
[submodule "tinygrad"]
|
||||
path = tinygrad_repo
|
||||
url = https://github.com/commaai/tinygrad.git
|
||||
[submodule "sunnypilot/neural_network_data"]
|
||||
path = sunnypilot/neural_network_data
|
||||
url = https://github.com/sunnypilot/neural-network-data.git
|
||||
|
||||
25
.idea/customTargets.xml
generated
Normal file
25
.idea/customTargets.xml
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CLionExternalBuildManager">
|
||||
<target id="a62f99e8-5ec4-434c-8122-49efed5af108" name="uv Scons Build Debug" defaultType="TOOL">
|
||||
<configuration id="b93ec964-16e5-4962-a12e-3ed360ce8f02" name="uv Scons Build Debug">
|
||||
<build type="TOOL">
|
||||
<tool actionId="Tool_External Tools_uv Scons Build Debug" />
|
||||
</build>
|
||||
<clean type="TOOL">
|
||||
<tool actionId="Tool_External Tools_uv Scons Clean" />
|
||||
</clean>
|
||||
</configuration>
|
||||
</target>
|
||||
<target id="edd8ad9d-183b-467c-a355-0d9a0ecab026" name="uv Scons Build Release" defaultType="TOOL">
|
||||
<configuration id="09523339-5ce3-4223-ab9e-904f38ad7752" name="uv Scons Build Release">
|
||||
<build type="TOOL">
|
||||
<tool actionId="Tool_External Tools_uv Scons Build Release" />
|
||||
</build>
|
||||
<clean type="TOOL">
|
||||
<tool actionId="Tool_External Tools_uv Scons Clean" />
|
||||
</clean>
|
||||
</configuration>
|
||||
</target>
|
||||
</component>
|
||||
</project>
|
||||
23
.idea/tools/External Tools.xml
generated
Normal file
23
.idea/tools/External Tools.xml
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
<toolSet name="External Tools">
|
||||
<tool name="uv Scons Build Debug" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
||||
<exec>
|
||||
<option name="COMMAND" value="bash" />
|
||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) --compile_db --ccflags=\"-fno-inline\""" />
|
||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||
</exec>
|
||||
</tool>
|
||||
<tool name="uv Scons Clean" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
||||
<exec>
|
||||
<option name="COMMAND" value="bash" />
|
||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -c" " />
|
||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||
</exec>
|
||||
</tool>
|
||||
<tool name="uv Scons Build Release" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
||||
<exec>
|
||||
<option name="COMMAND" value="bash" />
|
||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) --compile_db" " />
|
||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||
</exec>
|
||||
</tool>
|
||||
</toolSet>
|
||||
@@ -1,4 +1,4 @@
|
||||
[lfs]
|
||||
url = https://gitlab.com/commaai/openpilot-lfs.git/info/lfs
|
||||
pushurl = ssh://git@gitlab.com/commaai/openpilot-lfs.git
|
||||
url = https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs
|
||||
pushurl = ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git
|
||||
locksverify = false
|
||||
|
||||
4
.lfsconfig-comma
Normal file
4
.lfsconfig-comma
Normal file
@@ -0,0 +1,4 @@
|
||||
[lfs]
|
||||
url = https://gitlab.com/commaai/openpilot-lfs.git/info/lfs
|
||||
pushurl = ssh://git@gitlab.com/commaai/openpilot-lfs.git
|
||||
locksverify = false
|
||||
10
.run/Build Debug.run.xml
Normal file
10
.run/Build Debug.run.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Build Debug" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/selfdrive/ui" PASS_PARENT_ENVS_2="true" PROJECT_NAME="sunnypilot" TARGET_NAME="uv Scons Build Debug" CONFIG_NAME="uv Scons Build Debug" RUN_PATH="ui">
|
||||
<envs>
|
||||
<env name="QT_DBL_CLICK_DIST" value="150" />
|
||||
</envs>
|
||||
<method v="2">
|
||||
<option name="CLION.EXTERNAL.BUILD" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
10
.run/Build Release.run.xml
Normal file
10
.run/Build Release.run.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Build Release" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/selfdrive/ui" PASS_PARENT_ENVS_2="true" PROJECT_NAME="sunnypilot" TARGET_NAME="uv Scons Build Release" CONFIG_NAME="uv Scons Build Release" RUN_PATH="ui">
|
||||
<envs>
|
||||
<env name="QT_DBL_CLICK_DIST" value="150" />
|
||||
</envs>
|
||||
<method v="2">
|
||||
<option name="CLION.EXTERNAL.BUILD" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Custom MIT License
|
||||
|
||||
Copyright (c) 2024, Haibin Wen, SUNNYPILOT LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to view and modify the Software, subject to the following conditions:
|
||||
|
||||
1. **Permission Required**: Permission Required for Commercial, For-Profit, or Closed Source Use: Use of the Software, in whole or in part, for any commercial purposes, for-profit projects, or in closed source projects requires explicit written permission from the original author(s).
|
||||
|
||||
2. **Redistribution**: Any redistribution of the Software, modified or unmodified, must retain this license notice and the following acknowledgment:
|
||||
"This software is licensed under a custom license requiring permission for use."
|
||||
|
||||
3. **Visibility**: Any project that uses the Software must visibly mention the following acknowledgment:
|
||||
"This project uses software from Haibin Wen and SUNNYPILOT LLC and is licensed under a custom license requiring permission for use."
|
||||
|
||||
4. **No Warranty**: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Contact sunnypilot Support <support@sunnypilot.ai> for permission requests.
|
||||
|
||||
---
|
||||
|
||||
Haibin Wen, SUNNYPILOT LLC
|
||||
188
README.md
188
README.md
@@ -1,107 +1,119 @@
|
||||
<div align="center" style="text-align: center;">
|
||||

|
||||
|
||||
<h1>openpilot</h1>
|
||||
## 🌞 What is sunnypilot?
|
||||
[sunnypilot](https://github.com/sunnyhaibin/sunnypilot) is a fork of comma.ai's openpilot, an open source driver assistance system. sunnypilot offers the user a unique driving experience for over 300+ supported car makes and models with modified behaviors of driving assist engagements. sunnypilot complies with comma.ai's safety rules as accurately as possible.
|
||||
|
||||
<p>
|
||||
<b>openpilot is an operating system for robotics.</b>
|
||||
<br>
|
||||
Currently, it upgrades the driver assistance system in 275+ supported cars.
|
||||
</p>
|
||||
## 💭 Join our Discord
|
||||
Join the official sunnypilot Discord server to stay up to date with all the latest features and be a part of shaping the future of sunnypilot!
|
||||
* https://discord.gg/sunnypilot
|
||||
|
||||
<h3>
|
||||
<a href="https://docs.comma.ai">Docs</a>
|
||||
<span> · </span>
|
||||
<a href="https://docs.comma.ai/contributing/roadmap/">Roadmap</a>
|
||||
<span> · </span>
|
||||
<a href="https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md">Contribute</a>
|
||||
<span> · </span>
|
||||
<a href="https://discord.comma.ai">Community</a>
|
||||
<span> · </span>
|
||||
<a href="https://comma.ai/shop">Try it on a comma 3X</a>
|
||||
</h3>
|
||||
 
|
||||
|
||||
Quick start: `bash <(curl -fsSL openpilot.comma.ai)`
|
||||
## Documentation
|
||||
https://docs.sunnypilot.ai/ is your one stop shop for everything from features to installation to FAQ about the sunnypilot
|
||||
|
||||

|
||||
[](https://codecov.io/gh/commaai/openpilot)
|
||||
[](LICENSE)
|
||||
[](https://x.com/comma_ai)
|
||||
[](https://discord.comma.ai)
|
||||
## 🚘 Running on a dedicated device in a car
|
||||
* A supported device to run this software
|
||||
* a [comma three](https://comma.ai/shop/products/three) or a [C3X](https://comma.ai/shop/comma-3x)
|
||||
* This software
|
||||
* One of [the 300+ supported cars](https://github.com/commaai/openpilot/blob/master/docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run sunnypilot.
|
||||
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car
|
||||
|
||||
</div>
|
||||
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="https://youtu.be/NmBfgOanCyk" title="Video By Greer Viau"><img src="https://github.com/commaai/openpilot/assets/8762862/2f7112ae-f748-4f39-b617-fabd689c3772"></a></td>
|
||||
<td><a href="https://youtu.be/VHKyqZ7t8Gw" title="Video By Logan LeGrand"><img src="https://github.com/commaai/openpilot/assets/8762862/92351544-2833-40d7-9e0b-7ef7ae37ec4c"></a></td>
|
||||
<td><a href="https://youtu.be/SUIZYzxtMQs" title="A drive to Taco Bell"><img src="https://github.com/commaai/openpilot/assets/8762862/05ceefc5-2628-439c-a9b2-89ce77dc6f63"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
## Installation
|
||||
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `release-c3` branch.
|
||||
|
||||
* sunnypilot not installed or you installed a version before 0.8.17?
|
||||
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
|
||||
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
|
||||
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```release-c3.sunnypilot.ai```.
|
||||
4. Complete the rest of the installation following the onscreen instructions.
|
||||
|
||||
* sunnypilot already installed and you installed a version after 0.8.17?
|
||||
1. On the comma three, go to `Settings` ▶️ `Software`.
|
||||
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
|
||||
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
|
||||
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `release-c3`
|
||||
|
||||
| Branch | Installation URL |
|
||||
|:------------:|:--------------------------------:|
|
||||
| `release-c3` | https://release-c3.sunnypilot.ai |
|
||||
| `staging-c3` | https://staging-c3.sunnypilot.ai |
|
||||
| `dev-c3` | https://dev-c3.sunnypilot.ai |
|
||||
|
||||
### If you want to use our newest branches (our rewrite)
|
||||
> [!TIP]
|
||||
>You can see the rewrite state on our [rewrite project board](https://github.com/orgs/sunnypilot/projects/2), and to install the new branches, you can use the following links
|
||||
|
||||
|
||||
Using openpilot in a car
|
||||
------
|
||||
> [!IMPORTANT]
|
||||
> It is recommended to [re-flash AGNOS](https://flash.comma.ai/) if you intend to downgrade from the new branches.
|
||||
> You can still restore the latest sunnylink backup made on the old branches.
|
||||
|
||||
To use openpilot in a car, you need four things:
|
||||
1. **Supported Device:** a comma 3/3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x).
|
||||
2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version.
|
||||
3. **Supported Car:** Ensure that you have one of [the 275+ supported cars](docs/CARS.md).
|
||||
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car.
|
||||
| Branch | Installation URL |
|
||||
|:----------------:|:---------------------------------------------:|
|
||||
| `staging-c3-new` | `https://staging-c3-new.sunnypilot.ai` |
|
||||
| `dev-c3-new` | `https://dev-c3-new.sunnypilot.ai` |
|
||||
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
||||
| `release-c3-new` | **Not yet available**. |
|
||||
|
||||
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup). Note that it's possible to run openpilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play.
|
||||
> [!TIP]
|
||||
> Do you require further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
|
||||
|
||||
### Branches
|
||||
| branch | URL | description |
|
||||
|------------------|----------------------------------------|-------------------------------------------------------------------------------------|
|
||||
| `release3` | openpilot.comma.ai | This is openpilot's release branch. |
|
||||
| `release3-staging` | openpilot-test.comma.ai | This is the staging branch for releases. Use it to get new releases slightly early. |
|
||||
| `nightly` | openpilot-nightly.comma.ai | This is the bleeding edge development branch. Do not expect this to be stable. |
|
||||
| `nightly-dev` | installer.comma.ai/commaai/nightly-dev | Same as nightly, but includes experimental development features for some cars. |
|
||||
## 🎆 Pull Requests
|
||||
We welcome both pull requests and issues on GitHub. Bug fixes are encouraged.
|
||||
|
||||
To start developing openpilot
|
||||
------
|
||||
Pull requests should be against the most current `master-new` branch.
|
||||
|
||||
openpilot is developed by [comma](https://comma.ai/) and by users like you. We welcome both pull requests and issues on [GitHub](http://github.com/commaai/openpilot).
|
||||
## 📊 User Data
|
||||
|
||||
* Join the [community Discord](https://discord.comma.ai)
|
||||
* Check out [the contributing docs](docs/CONTRIBUTING.md)
|
||||
* Check out the [openpilot tools](tools/)
|
||||
* Read about the [development workflow](docs/WORKFLOW.md)
|
||||
* Code documentation lives at https://docs.comma.ai
|
||||
* Information about running openpilot lives on the [community wiki](https://github.com/commaai/openpilot/wiki)
|
||||
By default, sunnypilot uploads the driving data to comma servers. You can also access your data through [comma connect](https://connect.comma.ai/).
|
||||
|
||||
Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs#open-positions) and offers lots of [bounties](https://comma.ai/bounties) for external contributors.
|
||||
sunnypilot is open source software. The user is free to disable data collection if they wish to do so.
|
||||
|
||||
Safety and Testing
|
||||
----
|
||||
|
||||
* openpilot observes [ISO26262](https://en.wikipedia.org/wiki/ISO_26262) guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
|
||||
* openpilot has software-in-the-loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit.
|
||||
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
|
||||
* panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
|
||||
* Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
|
||||
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
|
||||
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
|
||||
|
||||
Licensing
|
||||
------
|
||||
|
||||
openpilot is released under the MIT license. Some parts of the software are released under other licenses as specified.
|
||||
|
||||
Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys’ fees and costs) which arise out of, relate to or result from any use of this software by user.
|
||||
|
||||
**THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
|
||||
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
|
||||
NO WARRANTY EXPRESSED OR IMPLIED.**
|
||||
|
||||
User Data and comma Account
|
||||
------
|
||||
|
||||
By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone.
|
||||
|
||||
openpilot is open source software: the user is free to disable data collection if they wish to do so.
|
||||
|
||||
openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
|
||||
sunnypilot logs the road-facing camera, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
|
||||
The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
|
||||
|
||||
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
|
||||
By using this software, you understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
|
||||
|
||||
## Licensing
|
||||
|
||||
sunnypilot is released under the [MIT License](LICENSE). This repository includes original work as well as significant portions of code derived from [openpilot by comma.ai](https://github.com/commaai/openpilot), which is also released under the MIT license with additional disclaimers.
|
||||
|
||||
The original openpilot license notice, including comma.ai’s indemnification and alpha software disclaimer, is reproduced below as required:
|
||||
|
||||
> openpilot is released under the MIT license. Some parts of the software are released under other licenses as specified.
|
||||
>
|
||||
> Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys’ fees and costs) which arise out of, relate to or result from any use of this software by user.
|
||||
>
|
||||
> **THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
|
||||
> YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
|
||||
> NO WARRANTY EXPRESSED OR IMPLIED.**
|
||||
|
||||
For full license terms, please see the [`LICENSE`](LICENSE) file.
|
||||
|
||||
## 💰 Support sunnypilot
|
||||
If you find any of the features useful, consider becoming a [sponsor on GitHub](https://github.com/sponsors/sunnyhaibin) to support future feature development and improvements.
|
||||
|
||||
|
||||
By becoming a sponsor, you will gain access to exclusive content, early access to new features, and the opportunity to directly influence the project's development.
|
||||
|
||||
|
||||
<h3>GitHub Sponsor</h3>
|
||||
|
||||
<a href="https://github.com/sponsors/sunnyhaibin">
|
||||
<img src="https://user-images.githubusercontent.com/47793918/244135584-9800acbd-69fd-4b2b-bec9-e5fa2d85c817.png" alt="Become a Sponsor" width="300" style="max-width: 100%; height: auto;">
|
||||
</a>
|
||||
<br>
|
||||
|
||||
<h3>PayPal</h3>
|
||||
|
||||
<a href="https://paypal.me/sunnyhaibin0850" target="_blank">
|
||||
<img src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" alt="PayPal this" title="PayPal - The safer, easier way to pay online!" border="0" />
|
||||
</a>
|
||||
<br></br>
|
||||
|
||||
Your continuous love and support are greatly appreciated! Enjoy 🥰
|
||||
|
||||
<span>-</span> Jason, Founder of sunnypilot
|
||||
|
||||
25
SConstruct
25
SConstruct
@@ -70,6 +70,12 @@ AddOption('--minimal',
|
||||
default=os.path.exists(File('#.lfsconfig').abspath), # minimal by default on release branch (where there's no LFS)
|
||||
help='the minimum build to run openpilot. no tests, tools, etc.')
|
||||
|
||||
AddOption('--stock-ui',
|
||||
action='store_true',
|
||||
dest='stock_ui',
|
||||
default=False,
|
||||
help='Build stock openpilot UI instead of sunnypilot UI')
|
||||
|
||||
## Architecture name breakdown (arch)
|
||||
## - larch64: linux tici aarch64
|
||||
## - aarch64: linux pc aarch64
|
||||
@@ -107,6 +113,7 @@ if arch == "larch64":
|
||||
]
|
||||
|
||||
libpath += [
|
||||
"#third_party/snpe/larch64",
|
||||
"#third_party/libyuv/larch64/lib",
|
||||
"/usr/lib/aarch64-linux-gnu"
|
||||
]
|
||||
@@ -145,6 +152,14 @@ else:
|
||||
"/usr/local/lib",
|
||||
]
|
||||
|
||||
if arch == "x86_64":
|
||||
libpath += [
|
||||
f"#third_party/snpe/{arch}"
|
||||
]
|
||||
rpath += [
|
||||
Dir(f"#third_party/snpe/{arch}").abspath,
|
||||
]
|
||||
|
||||
if GetOption('asan'):
|
||||
ccflags = ["-fsanitize=address", "-fno-omit-frame-pointer"]
|
||||
ldflags = ["-fsanitize=address"]
|
||||
@@ -159,6 +174,10 @@ else:
|
||||
if arch != "Darwin":
|
||||
ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"]
|
||||
|
||||
if not GetOption('stock_ui'):
|
||||
cflags += ["-DSUNNYPILOT"]
|
||||
cxxflags += ["-DSUNNYPILOT"]
|
||||
|
||||
ccflags_option = GetOption('ccflags')
|
||||
if ccflags_option:
|
||||
ccflags += ccflags_option.split(' ')
|
||||
@@ -188,6 +207,7 @@ env = Environment(
|
||||
"#third_party/libyuv/include",
|
||||
"#third_party/json11",
|
||||
"#third_party/linux/include",
|
||||
"#third_party/snpe/include",
|
||||
"#third_party",
|
||||
"#msgq",
|
||||
],
|
||||
@@ -223,7 +243,8 @@ if GetOption('compile_db'):
|
||||
env.CompilationDatabase('compile_commands.json')
|
||||
|
||||
# Setup cache dir
|
||||
cache_dir = '/data/scons_cache' if AGNOS else '/tmp/scons_cache'
|
||||
default_cache_dir = '/data/scons_cache' if AGNOS else '/tmp/scons_cache'
|
||||
cache_dir = ARGUMENTS.get('cache_dir', default_cache_dir)
|
||||
CacheDir(cache_dir)
|
||||
Clean(["."], cache_dir)
|
||||
|
||||
@@ -370,6 +391,8 @@ SConscript(['third_party/SConscript'])
|
||||
|
||||
SConscript(['selfdrive/SConscript'])
|
||||
|
||||
SConscript(['sunnypilot/SConscript'])
|
||||
|
||||
if Dir('#tools/cabana/').exists() and GetOption('extras'):
|
||||
SConscript(['tools/replay/SConscript'])
|
||||
if arch != "larch64":
|
||||
|
||||
@@ -10,25 +10,197 @@ $Cxx.namespace("cereal");
|
||||
# DO rename the structs
|
||||
# DON'T change the identifier (e.g. @0x81c2f05a394cf4af)
|
||||
|
||||
struct CustomReserved0 @0x81c2f05a394cf4af {
|
||||
struct ModularAssistiveDrivingSystem {
|
||||
state @0 :ModularAssistiveDrivingSystemState;
|
||||
enabled @1 :Bool;
|
||||
active @2 :Bool;
|
||||
available @3 :Bool;
|
||||
|
||||
enum ModularAssistiveDrivingSystemState {
|
||||
disabled @0;
|
||||
paused @1;
|
||||
enabled @2;
|
||||
softDisabling @3;
|
||||
overriding @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomReserved1 @0xaedffd8f31e7b55d {
|
||||
struct SelfdriveStateSP @0x81c2f05a394cf4af {
|
||||
mads @0 :ModularAssistiveDrivingSystem;
|
||||
}
|
||||
|
||||
struct CustomReserved2 @0xf35cc4560bbf6ec2 {
|
||||
struct ModelManagerSP @0xaedffd8f31e7b55d {
|
||||
activeBundle @0 :ModelBundle;
|
||||
selectedBundle @1 :ModelBundle;
|
||||
availableBundles @2 :List(ModelBundle);
|
||||
|
||||
struct DownloadUri {
|
||||
uri @0 :Text;
|
||||
sha256 @1 :Text;
|
||||
}
|
||||
|
||||
enum Type {
|
||||
drive @0;
|
||||
navigation @1;
|
||||
metadata @2;
|
||||
}
|
||||
|
||||
struct Model {
|
||||
fullName @0 :Text;
|
||||
fileName @1 :Text;
|
||||
downloadUri @2 :DownloadUri;
|
||||
downloadProgress @3 :DownloadProgress;
|
||||
type @4 :Type;
|
||||
}
|
||||
|
||||
enum DownloadStatus {
|
||||
notDownloading @0;
|
||||
downloading @1;
|
||||
downloaded @2;
|
||||
cached @3;
|
||||
failed @4;
|
||||
}
|
||||
|
||||
struct DownloadProgress {
|
||||
status @0 :DownloadStatus;
|
||||
progress @1 :Float32;
|
||||
eta @2 :UInt32;
|
||||
}
|
||||
|
||||
enum Runner {
|
||||
snpe @0;
|
||||
tinygrad @1;
|
||||
stock @2;
|
||||
}
|
||||
|
||||
struct ModelBundle {
|
||||
index @0 :UInt32;
|
||||
internalName @1 :Text;
|
||||
displayName @2 :Text;
|
||||
models @3 :List(Model);
|
||||
status @4 :DownloadStatus;
|
||||
generation @5 :UInt32;
|
||||
environment @6 :Text;
|
||||
runner @7 :Runner;
|
||||
is20hz @8 :Bool;
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomReserved3 @0xda96579883444c35 {
|
||||
struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
||||
dec @0 :DynamicExperimentalControl;
|
||||
|
||||
struct DynamicExperimentalControl {
|
||||
state @0 :DynamicExperimentalControlState;
|
||||
enabled @1 :Bool;
|
||||
active @2 :Bool;
|
||||
|
||||
enum DynamicExperimentalControlState {
|
||||
acc @0;
|
||||
blended @1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomReserved4 @0x80ae746ee2596b11 {
|
||||
struct OnroadEventSP @0xda96579883444c35 {
|
||||
events @0 :List(Event);
|
||||
|
||||
struct Event {
|
||||
name @0 :EventName;
|
||||
|
||||
# event types
|
||||
enable @1 :Bool;
|
||||
noEntry @2 :Bool;
|
||||
warning @3 :Bool; # alerts presented only when enabled or soft disabling
|
||||
userDisable @4 :Bool;
|
||||
softDisable @5 :Bool;
|
||||
immediateDisable @6 :Bool;
|
||||
preEnable @7 :Bool;
|
||||
permanent @8 :Bool; # alerts presented regardless of openpilot state
|
||||
overrideLateral @10 :Bool;
|
||||
overrideLongitudinal @9 :Bool;
|
||||
}
|
||||
|
||||
enum EventName {
|
||||
lkasEnable @0;
|
||||
lkasDisable @1;
|
||||
manualSteeringRequired @2;
|
||||
manualLongitudinalRequired @3;
|
||||
silentLkasEnable @4;
|
||||
silentLkasDisable @5;
|
||||
silentBrakeHold @6;
|
||||
silentWrongGear @7;
|
||||
silentReverseGear @8;
|
||||
silentDoorOpen @9;
|
||||
silentSeatbeltNotLatched @10;
|
||||
silentParkBrake @11;
|
||||
controlsMismatchLateral @12;
|
||||
hyundaiRadarTracksConfirmed @13;
|
||||
experimentalModeSwitched @14;
|
||||
wrongCarModeAlertOnly @15;
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomReserved5 @0xa5cd762cd951a455 {
|
||||
struct CarParamsSP @0x80ae746ee2596b11 {
|
||||
flags @0 :UInt32; # flags for car specific quirks in sunnypilot
|
||||
safetyParam @1 : Int16; # flags for sunnypilot's custom safety flags
|
||||
|
||||
neuralNetworkLateralControl @2 :NeuralNetworkLateralControl;
|
||||
|
||||
struct NeuralNetworkLateralControl {
|
||||
model @0 :Model;
|
||||
fuzzyFingerprint @1 :Bool;
|
||||
|
||||
struct Model {
|
||||
path @0 :Text;
|
||||
name @1 :Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomReserved6 @0xf98d843bfd7004a3 {
|
||||
struct CarControlSP @0xa5cd762cd951a455 {
|
||||
mads @0 :ModularAssistiveDrivingSystem;
|
||||
}
|
||||
|
||||
struct BackupManagerSP @0xf98d843bfd7004a3 {
|
||||
backupStatus @0 :Status;
|
||||
restoreStatus @1 :Status;
|
||||
backupProgress @2 :Float32;
|
||||
restoreProgress @3 :Float32;
|
||||
lastError @4 :Text;
|
||||
currentBackup @5 :BackupInfo;
|
||||
backupHistory @6 :List(BackupInfo);
|
||||
|
||||
enum Status {
|
||||
idle @0;
|
||||
inProgress @1;
|
||||
completed @2;
|
||||
failed @3;
|
||||
}
|
||||
|
||||
struct Version {
|
||||
major @0 :UInt16;
|
||||
minor @1 :UInt16;
|
||||
patch @2 :UInt16;
|
||||
build @3 :UInt16;
|
||||
branch @4 :Text;
|
||||
}
|
||||
|
||||
struct MetadataEntry {
|
||||
key @0 :Text;
|
||||
value @1 :Text;
|
||||
tags @2 :List(Text);
|
||||
}
|
||||
|
||||
struct BackupInfo {
|
||||
deviceId @0 :Text;
|
||||
version @1 :UInt32;
|
||||
config @2 :Text;
|
||||
isEncrypted @3 :Bool;
|
||||
createdAt @4 :Text; # ISO timestamp
|
||||
updatedAt @5 :Text; # ISO timestamp
|
||||
sunnypilotVersion @6 :Version;
|
||||
backupMetadata @7 :List(MetadataEntry);
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomReserved7 @0xb86e6369214c01c8 {
|
||||
|
||||
@@ -1586,6 +1586,10 @@ struct UbloxGnss {
|
||||
svId @0 :UInt8;
|
||||
gnssId @1 :UInt8;
|
||||
flagsBitfield @2 :UInt32;
|
||||
cno @3 :UInt8;
|
||||
elevationDeg @4 :Int8;
|
||||
azimuthDeg @5 :Int16;
|
||||
pseudorangeResidual @6 :Float32;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2274,6 +2278,21 @@ struct LiveTorqueParametersData {
|
||||
useParams @12 :Bool;
|
||||
}
|
||||
|
||||
struct LiveDelayData {
|
||||
lateralDelay @0 :Float32;
|
||||
validBlocks @1 :Int32;
|
||||
status @2 :Status;
|
||||
|
||||
lateralDelayEstimate @3 :Float32;
|
||||
points @4 :List(Float32);
|
||||
|
||||
enum Status {
|
||||
unestimated @0;
|
||||
estimated @1;
|
||||
invalid @2;
|
||||
}
|
||||
}
|
||||
|
||||
struct LiveMapDataDEPRECATED {
|
||||
speedLimitValid @0 :Bool;
|
||||
speedLimit @1 :Float32;
|
||||
@@ -2504,6 +2523,7 @@ struct Event {
|
||||
gnssMeasurements @91 :GnssMeasurements;
|
||||
liveParameters @61 :LiveParametersData;
|
||||
liveTorqueParameters @94 :LiveTorqueParametersData;
|
||||
liveDelay @146 : LiveDelayData;
|
||||
cameraOdometry @63 :CameraOdometry;
|
||||
thumbnail @66: Thumbnail;
|
||||
onroadEvents @134: List(OnroadEvent);
|
||||
@@ -2576,13 +2596,13 @@ struct Event {
|
||||
# DO change the name of the field and struct
|
||||
# DON'T change the ID (e.g. @107)
|
||||
# DON'T change which struct it points to
|
||||
customReserved0 @107 :Custom.CustomReserved0;
|
||||
customReserved1 @108 :Custom.CustomReserved1;
|
||||
customReserved2 @109 :Custom.CustomReserved2;
|
||||
customReserved3 @110 :Custom.CustomReserved3;
|
||||
customReserved4 @111 :Custom.CustomReserved4;
|
||||
customReserved5 @112 :Custom.CustomReserved5;
|
||||
customReserved6 @113 :Custom.CustomReserved6;
|
||||
selfdriveStateSP @107 :Custom.SelfdriveStateSP;
|
||||
modelManagerSP @108 :Custom.ModelManagerSP;
|
||||
longitudinalPlanSP @109 :Custom.LongitudinalPlanSP;
|
||||
onroadEventsSP @110 :Custom.OnroadEventSP;
|
||||
carParamsSP @111 :Custom.CarParamsSP;
|
||||
carControlSP @112 :Custom.CarControlSP;
|
||||
backupManagerSP @113 :Custom.BackupManagerSP;
|
||||
customReserved7 @114 :Custom.CustomReserved7;
|
||||
customReserved8 @115 :Custom.CustomReserved8;
|
||||
customReserved9 @116 :Custom.CustomReserved9;
|
||||
|
||||
222
cereal/messaging/tests/validate_sp_cereal_upstream.py
Executable file
222
cereal/messaging/tests/validate_sp_cereal_upstream.py
Executable file
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import sys
|
||||
from typing import Any, List, Tuple
|
||||
|
||||
DEBUG = False
|
||||
|
||||
|
||||
def print_debug(string: str) -> None:
|
||||
if DEBUG:
|
||||
print(string)
|
||||
|
||||
|
||||
def create_schema_instance(struct: Any, prop: Tuple[str, Any]) -> Any:
|
||||
"""
|
||||
Create a new instance of a schema type, handling different field types.
|
||||
|
||||
Args:
|
||||
struct: The Cap'n Proto schema structure
|
||||
prop: A tuple containing the field name and field metadata
|
||||
|
||||
Returns:
|
||||
A new initialized schema instance
|
||||
"""
|
||||
struct_instance = struct.new_message()
|
||||
field_name, field_metadata = prop
|
||||
|
||||
try:
|
||||
field_type = field_metadata.proto.slot.type.which()
|
||||
|
||||
# Initialize different types of fields
|
||||
if field_type in ('list', 'text', 'data'):
|
||||
struct_instance.init(field_name, 1)
|
||||
print_debug(f"Initialized list/text/data field: {field_name}")
|
||||
elif field_type in ('struct', 'object'):
|
||||
struct_instance.init(field_name)
|
||||
print_debug(f"Initialized struct/object field: {field_name}")
|
||||
|
||||
return struct_instance
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error creating instance for {field_name}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def get_schema_fields(schema_struct: Any) -> List[Tuple[str, Any]]:
|
||||
"""
|
||||
Retrieve all fields from a given schema structure.
|
||||
|
||||
Args:
|
||||
schema_struct: The Cap'n Proto schema structure
|
||||
|
||||
Returns:
|
||||
A list of field names and their metadata
|
||||
"""
|
||||
try:
|
||||
# Get all fields from the schema
|
||||
schema_fields = list(schema_struct.schema.fields.items())
|
||||
|
||||
print_debug("Discovered schema fields:")
|
||||
for field_name, field_metadata in schema_fields:
|
||||
print_debug(f"- {field_name}")
|
||||
|
||||
return schema_fields
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error retrieving schema fields: {e}")
|
||||
return []
|
||||
|
||||
|
||||
def generate_schema_instances(schema_struct: Any) -> List[Any]:
|
||||
"""
|
||||
Generate instances for all fields in a given schema.
|
||||
|
||||
Args:
|
||||
schema_struct: The Cap'n Proto schema structure
|
||||
|
||||
Returns:
|
||||
A list of schema instances
|
||||
"""
|
||||
schema_fields = get_schema_fields(schema_struct)
|
||||
instances = []
|
||||
|
||||
for field_prop in schema_fields:
|
||||
try:
|
||||
instance = create_schema_instance(schema_struct, field_prop)
|
||||
if instance is not None:
|
||||
instances.append(instance)
|
||||
except Exception as e:
|
||||
print(f"Skipping field due to error: {e}")
|
||||
|
||||
print(f"Generated {len(instances)} schema instances")
|
||||
return instances
|
||||
|
||||
|
||||
def persist_instances(instances: List[Any], filename: str) -> None:
|
||||
"""
|
||||
Write schema instances to a binary file.
|
||||
|
||||
Args:
|
||||
instances: List of schema instances
|
||||
filename: Output file path
|
||||
"""
|
||||
try:
|
||||
with open(filename, 'wb') as f:
|
||||
for instance in instances:
|
||||
f.write(instance.to_bytes())
|
||||
|
||||
print(f"Successfully wrote {len(instances)} instances to {filename}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error persisting instances: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def read_instances(filename: str, schema_type: Any) -> List[Any]:
|
||||
"""
|
||||
Read schema instances from a binary file.
|
||||
|
||||
Args:
|
||||
filename: Input file path
|
||||
schema_type: The schema type to use for reading
|
||||
|
||||
Returns:
|
||||
A list of read schema instances
|
||||
"""
|
||||
try:
|
||||
with open(filename, 'rb') as f:
|
||||
data = f.read()
|
||||
|
||||
instances = list(schema_type.read_multiple_bytes(data))
|
||||
|
||||
print(f"Read {len(instances)} instances from {filename}")
|
||||
return instances
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error reading instances: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def compare_schemas(original_instances: List[Any], read_instances: List[Any]) -> bool:
|
||||
"""
|
||||
Compare original and read-back instances to detect potential breaking changes.
|
||||
|
||||
Args:
|
||||
original_instances: List of originally generated instances
|
||||
read_instances: List of instances read back from file
|
||||
|
||||
Returns:
|
||||
Boolean indicating whether schemas appear compatible
|
||||
"""
|
||||
if len(original_instances) != len(read_instances):
|
||||
print("❌ Schema Compatibility Warning: Instance count mismatch")
|
||||
return False
|
||||
|
||||
compatible = True
|
||||
for struct in read_instances:
|
||||
try:
|
||||
getattr(struct, struct.which()) # Attempting to access the field to validate readability
|
||||
except Exception as e:
|
||||
print(f"❌ Structural change detected: {struct.which()} is not readable.\nFull error: {e}")
|
||||
compatible = False
|
||||
|
||||
return compatible
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
CLI entry point for schema compatibility testing.
|
||||
"""
|
||||
# Setup argument parser
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Cap\'n Proto Schema Compatibility Testing Tool',
|
||||
epilog='Test schema compatibility by generating and reading back instances.'
|
||||
)
|
||||
|
||||
# Add mutually exclusive group for generation or reading mode
|
||||
mode_group = parser.add_mutually_exclusive_group(required=True)
|
||||
mode_group.add_argument('-g', '--generate', action='store_true',
|
||||
help='Generate schema instances')
|
||||
mode_group.add_argument('-r', '--read', action='store_true',
|
||||
help='Read and validate schema instances')
|
||||
|
||||
# Common arguments
|
||||
parser.add_argument('-f', '--file',
|
||||
default='schema_instances.bin',
|
||||
help='Output/input binary file (default: schema_instances.bin)')
|
||||
|
||||
# Parse arguments
|
||||
args = parser.parse_args()
|
||||
|
||||
# Import the schema dynamically
|
||||
try:
|
||||
from cereal import log
|
||||
schema_type = log.Event
|
||||
except ImportError:
|
||||
print("Error: Unable to import schema. Ensure 'cereal' is installed.")
|
||||
sys.exit(1)
|
||||
|
||||
# Execute based on mode
|
||||
if args.generate:
|
||||
print("🔧 Generating Schema Instances")
|
||||
instances = generate_schema_instances(schema_type)
|
||||
persist_instances(instances, args.file)
|
||||
print("✅ Instance generation complete")
|
||||
|
||||
elif args.read:
|
||||
print("🔍 Reading and Validating Schema Instances")
|
||||
generated_instances = generate_schema_instances(schema_type)
|
||||
read_back_instances = read_instances(args.file, schema_type)
|
||||
|
||||
# Compare schemas
|
||||
if compare_schemas(generated_instances, read_back_instances):
|
||||
print("✅ Schema Compatibility: No breaking changes detected")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("❌ Potential Schema Breaking Changes Detected")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -74,6 +74,15 @@ _services: dict[str, tuple] = {
|
||||
"userFlag": (True, 0., 1),
|
||||
"microphone": (True, 10., 10),
|
||||
|
||||
# sunnypilot
|
||||
"modelManagerSP": (False, 1., 1),
|
||||
"backupManagerSP": (False, 1., 1),
|
||||
"selfdriveStateSP": (True, 100., 10),
|
||||
"longitudinalPlanSP": (True, 20., 10),
|
||||
"onroadEventsSP": (True, 1., 1),
|
||||
"carParamsSP": (True, 0.02, 1),
|
||||
"carControlSP": (True, 100., 10),
|
||||
|
||||
# debug
|
||||
"uiDebug": (True, 0., 1),
|
||||
"testJoystick": (True, 0.),
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import jwt
|
||||
import os
|
||||
import requests
|
||||
from datetime import datetime, timedelta, UTC
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
from openpilot.system.version import get_version
|
||||
|
||||
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
|
||||
|
||||
class Api:
|
||||
def __init__(self, dongle_id):
|
||||
self.dongle_id = dongle_id
|
||||
with open(Paths.persist_root()+'/comma/id_rsa') as f:
|
||||
self.private_key = f.read()
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
return self.request('GET', *args, **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
return self.request('POST', *args, **kwargs)
|
||||
|
||||
def request(self, method, endpoint, timeout=None, access_token=None, **params):
|
||||
return api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params)
|
||||
|
||||
def get_token(self, expiry_hours=1):
|
||||
now = datetime.now(UTC).replace(tzinfo=None)
|
||||
payload = {
|
||||
'identity': self.dongle_id,
|
||||
'nbf': now,
|
||||
'iat': now,
|
||||
'exp': now + timedelta(hours=expiry_hours)
|
||||
}
|
||||
token = jwt.encode(payload, self.private_key, algorithm='RS256')
|
||||
if isinstance(token, bytes):
|
||||
token = token.decode('utf8')
|
||||
return token
|
||||
|
||||
|
||||
def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
|
||||
headers = {}
|
||||
if access_token is not None:
|
||||
headers['Authorization'] = "JWT " + access_token
|
||||
|
||||
headers['User-Agent'] = "openpilot-" + get_version()
|
||||
|
||||
return requests.request(method, API_HOST + "/" + endpoint, timeout=timeout, headers=headers, params=params)
|
||||
22
common/api/__init__.py
Normal file
22
common/api/__init__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from openpilot.common.api.comma_connect import CommaConnectApi
|
||||
|
||||
|
||||
class Api:
|
||||
def __init__(self, dongle_id):
|
||||
self.service = CommaConnectApi(dongle_id)
|
||||
|
||||
def request(self, method, endpoint, **params):
|
||||
return self.service.request(method, endpoint, **params)
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
return self.service.get(*args, **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
return self.service.post(*args, **kwargs)
|
||||
|
||||
def get_token(self, expiry_hours=1):
|
||||
return self.service.get_token(expiry_hours)
|
||||
|
||||
|
||||
def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
|
||||
return CommaConnectApi(None).api_get(endpoint, method, timeout, access_token, **params)
|
||||
56
common/api/base.py
Normal file
56
common/api/base.py
Normal file
@@ -0,0 +1,56 @@
|
||||
import jwt
|
||||
import requests
|
||||
import unicodedata
|
||||
from datetime import datetime, timedelta, UTC
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
from openpilot.system.version import get_version
|
||||
|
||||
|
||||
class BaseApi:
|
||||
def __init__(self, dongle_id, api_host, user_agent="openpilot-"):
|
||||
self.dongle_id = dongle_id
|
||||
self.api_host = api_host
|
||||
self.user_agent = user_agent
|
||||
with open(f'{Paths.persist_root()}/comma/id_rsa') as f:
|
||||
self.private_key = f.read()
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
return self.request('GET', *args, **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
return self.request('POST', *args, **kwargs)
|
||||
|
||||
def request(self, method, endpoint, timeout=None, access_token=None, **params):
|
||||
return self.api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params)
|
||||
|
||||
def _get_token(self, expiry_hours=1, **extra_payload):
|
||||
now = datetime.now(UTC).replace(tzinfo=None)
|
||||
payload = {
|
||||
'identity': self.dongle_id,
|
||||
'nbf': now,
|
||||
'iat': now,
|
||||
'exp': now + timedelta(hours=expiry_hours),
|
||||
**extra_payload
|
||||
}
|
||||
token = jwt.encode(payload, self.private_key, algorithm='RS256')
|
||||
if isinstance(token, bytes):
|
||||
token = token.decode('utf8')
|
||||
return token
|
||||
|
||||
def get_token(self, expiry_hours=1):
|
||||
return self._get_token(expiry_hours)
|
||||
|
||||
def remove_non_ascii_chars(self, text):
|
||||
normalized_text = unicodedata.normalize('NFD', text)
|
||||
ascii_encoded_text = normalized_text.encode('ascii', 'ignore')
|
||||
return ascii_encoded_text.decode()
|
||||
|
||||
def api_get(self, endpoint, method='GET', timeout=None, access_token=None, json=None, **params):
|
||||
headers = {}
|
||||
if access_token is not None:
|
||||
headers['Authorization'] = "JWT " + access_token
|
||||
|
||||
version = self.remove_non_ascii_chars(get_version())
|
||||
headers['User-Agent'] = self.user_agent + version
|
||||
|
||||
return requests.request(method, f"{self.api_host}/{endpoint}", timeout=timeout, headers=headers, json=json, params=params)
|
||||
11
common/api/comma_connect.py
Normal file
11
common/api/comma_connect.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import os
|
||||
|
||||
from openpilot.common.api.base import BaseApi
|
||||
|
||||
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
|
||||
|
||||
|
||||
class CommaConnectApi(BaseApi):
|
||||
def __init__(self, dongle_id):
|
||||
super().__init__(dongle_id, API_HOST)
|
||||
self.user_agent = "openpilot-"
|
||||
1
common/model.h
Normal file
1
common/model.h
Normal file
@@ -0,0 +1 @@
|
||||
#define DEFAULT_MODEL "Filet o Fish (Default)"
|
||||
@@ -103,10 +103,12 @@ Params::~Params() {
|
||||
assert(queue.empty());
|
||||
}
|
||||
|
||||
std::vector<std::string> Params::allKeys() const {
|
||||
std::vector<std::string> Params::allKeys(ParamKeyType type) const {
|
||||
std::vector<std::string> ret;
|
||||
for (auto &p : keys) {
|
||||
ret.push_back(p.first);
|
||||
if (type == ALL || (p.second & type)) {
|
||||
ret.push_back(p.first);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ enum ParamKeyType {
|
||||
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
|
||||
DONT_LOG = 0x20,
|
||||
DEVELOPMENT_ONLY = 0x40,
|
||||
BACKUP = 0x80,
|
||||
ALL = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
@@ -27,7 +28,7 @@ public:
|
||||
Params(const Params&) = delete;
|
||||
Params& operator=(const Params&) = delete;
|
||||
|
||||
std::vector<std::string> allKeys() const;
|
||||
std::vector<std::string> allKeys(ParamKeyType type = ALL) const;
|
||||
bool checkKey(const std::string &key);
|
||||
ParamKeyType getKeyType(const std::string &key);
|
||||
inline std::string getParamPath(const std::string &key = {}) {
|
||||
|
||||
@@ -27,35 +27,35 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"CurrentBootlog", PERSISTENT},
|
||||
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"DisablePowerDown", PERSISTENT},
|
||||
{"DisableUpdates", PERSISTENT},
|
||||
{"DisengageOnAccelerator", PERSISTENT},
|
||||
{"DisablePowerDown", PERSISTENT | BACKUP},
|
||||
{"DisableUpdates", PERSISTENT | BACKUP},
|
||||
{"DisengageOnAccelerator", PERSISTENT | BACKUP},
|
||||
{"DongleId", PERSISTENT},
|
||||
{"DoReboot", CLEAR_ON_MANAGER_START},
|
||||
{"DoShutdown", CLEAR_ON_MANAGER_START},
|
||||
{"DoUninstall", CLEAR_ON_MANAGER_START},
|
||||
{"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY},
|
||||
{"ExperimentalMode", PERSISTENT},
|
||||
{"ExperimentalModeConfirmed", PERSISTENT},
|
||||
{"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY | BACKUP},
|
||||
{"ExperimentalMode", PERSISTENT | BACKUP},
|
||||
{"ExperimentalModeConfirmed", PERSISTENT | BACKUP},
|
||||
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"ForcePowerDown", PERSISTENT},
|
||||
{"GitBranch", PERSISTENT},
|
||||
{"GitCommit", PERSISTENT},
|
||||
{"GitCommitDate", PERSISTENT},
|
||||
{"GitDiff", PERSISTENT},
|
||||
{"GithubSshKeys", PERSISTENT},
|
||||
{"GithubUsername", PERSISTENT},
|
||||
{"GithubSshKeys", PERSISTENT | BACKUP},
|
||||
{"GithubUsername", PERSISTENT | BACKUP},
|
||||
{"GitRemote", PERSISTENT},
|
||||
{"GsmApn", PERSISTENT},
|
||||
{"GsmMetered", PERSISTENT},
|
||||
{"GsmRoaming", PERSISTENT},
|
||||
{"GsmApn", PERSISTENT | BACKUP},
|
||||
{"GsmMetered", PERSISTENT | BACKUP},
|
||||
{"GsmRoaming", PERSISTENT | BACKUP},
|
||||
{"HardwareSerial", PERSISTENT},
|
||||
{"HasAcceptedTerms", PERSISTENT},
|
||||
{"InstallDate", PERSISTENT},
|
||||
{"IsDriverViewEnabled", CLEAR_ON_MANAGER_START},
|
||||
{"IsEngaged", PERSISTENT},
|
||||
{"IsLdwEnabled", PERSISTENT},
|
||||
{"IsMetric", PERSISTENT},
|
||||
{"IsLdwEnabled", PERSISTENT | BACKUP},
|
||||
{"IsMetric", PERSISTENT | BACKUP},
|
||||
{"IsOffroad", CLEAR_ON_MANAGER_START},
|
||||
{"IsOnroad", PERSISTENT},
|
||||
{"IsRhdDetected", PERSISTENT},
|
||||
@@ -63,7 +63,7 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
||||
{"IsTestedBranch", CLEAR_ON_MANAGER_START},
|
||||
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"LanguageSetting", PERSISTENT},
|
||||
{"LanguageSetting", PERSISTENT | BACKUP},
|
||||
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
|
||||
{"LastGPSPosition", PERSISTENT},
|
||||
{"LastManagerExitReason", CLEAR_ON_MANAGER_START},
|
||||
@@ -75,7 +75,7 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"LiveTorqueParameters", PERSISTENT | DONT_LOG},
|
||||
{"LocationFilterInitialState", PERSISTENT},
|
||||
{"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"LongitudinalPersonality", PERSISTENT},
|
||||
{"LongitudinalPersonality", PERSISTENT | BACKUP},
|
||||
{"NetworkMetered", PERSISTENT},
|
||||
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
@@ -91,17 +91,17 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
|
||||
{"OpenpilotEnabledToggle", PERSISTENT},
|
||||
{"OpenpilotEnabledToggle", PERSISTENT | BACKUP},
|
||||
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"PandaSignatures", CLEAR_ON_MANAGER_START},
|
||||
{"PrimeType", PERSISTENT},
|
||||
{"RecordFront", PERSISTENT},
|
||||
{"RecordFront", PERSISTENT | BACKUP},
|
||||
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
|
||||
{"SecOCKey", PERSISTENT | DONT_LOG},
|
||||
{"SecOCKey", PERSISTENT | DONT_LOG}, // Candidate for | BACKUP
|
||||
{"RouteCount", PERSISTENT},
|
||||
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"SshEnabled", PERSISTENT},
|
||||
{"SshEnabled", PERSISTENT | BACKUP},
|
||||
{"TermsVersion", PERSISTENT},
|
||||
{"TrainingVersion", PERSISTENT},
|
||||
{"UbloxAvailable", PERSISTENT},
|
||||
@@ -117,4 +117,55 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterLastFetchTime", PERSISTENT},
|
||||
{"Version", PERSISTENT},
|
||||
|
||||
// --- sunnypilot params --- //
|
||||
{"ApiCache_DriveStats", PERSISTENT},
|
||||
{"AutoLaneChangeBsmDelay", PERSISTENT},
|
||||
{"AutoLaneChangeTimer", PERSISTENT},
|
||||
{"CarParamsSP", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"CarParamsSPCache", CLEAR_ON_MANAGER_START},
|
||||
{"CarParamsSPPersistent", PERSISTENT},
|
||||
{"CarPlatformBundle", PERSISTENT},
|
||||
{"EnableGithubRunner", PERSISTENT | BACKUP},
|
||||
{"MaxTimeOffroad", PERSISTENT | BACKUP},
|
||||
{"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"OffroadMode", CLEAR_ON_MANAGER_START},
|
||||
{"OffroadMode_Status", CLEAR_ON_MANAGER_START},
|
||||
{"QuietMode", PERSISTENT | BACKUP},
|
||||
|
||||
// MADS params
|
||||
{"Mads", PERSISTENT | BACKUP},
|
||||
{"MadsMainCruiseAllowed", PERSISTENT | BACKUP},
|
||||
{"MadsPauseLateralOnBrake", PERSISTENT | BACKUP},
|
||||
{"MadsUnifiedEngagementMode", PERSISTENT | BACKUP},
|
||||
|
||||
// Model Manager params
|
||||
{"ModelManager_ActiveBundle", PERSISTENT},
|
||||
{"ModelManager_DownloadIndex", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"ModelManager_LastSyncTime", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"ModelManager_ModelsCache", PERSISTENT | BACKUP},
|
||||
|
||||
// Neural Network Lateral Control
|
||||
{"NeuralNetworkLateralControl", PERSISTENT | BACKUP},
|
||||
|
||||
// sunnylink params
|
||||
{"EnableSunnylinkUploader", PERSISTENT | BACKUP},
|
||||
{"LastSunnylinkPingTime", CLEAR_ON_MANAGER_START},
|
||||
{"SunnylinkCache_Roles", PERSISTENT},
|
||||
{"SunnylinkCache_Users", PERSISTENT},
|
||||
{"SunnylinkDongleId", PERSISTENT},
|
||||
{"SunnylinkdPid", PERSISTENT},
|
||||
{"SunnylinkEnabled", PERSISTENT},
|
||||
|
||||
// Backup Manager params
|
||||
{"BackupManager_CreateBackup", PERSISTENT},
|
||||
{"BackupManager_RestoreVersion", PERSISTENT},
|
||||
|
||||
// sunnypilot car specific params
|
||||
{"HyundaiRadarTracks", PERSISTENT},
|
||||
{"HyundaiRadarTracksConfirmed", PERSISTENT},
|
||||
{"HyundaiRadarTracksPersistent", PERSISTENT},
|
||||
{"HyundaiRadarTracksToggle", PERSISTENT},
|
||||
|
||||
{"DynamicExperimentalControl", PERSISTENT},
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@ cdef extern from "common/params.h":
|
||||
CLEAR_ON_ONROAD_TRANSITION
|
||||
CLEAR_ON_OFFROAD_TRANSITION
|
||||
DEVELOPMENT_ONLY
|
||||
BACKUP
|
||||
ALL
|
||||
|
||||
cdef cppclass c_Params "Params":
|
||||
@@ -25,7 +26,7 @@ cdef extern from "common/params.h":
|
||||
bool checkKey(string) nogil
|
||||
string getParamPath(string) nogil
|
||||
void clearAll(ParamKeyType)
|
||||
vector[string] allKeys()
|
||||
vector[string] allKeys(ParamKeyType)
|
||||
|
||||
|
||||
def ensure_bytes(v):
|
||||
@@ -119,5 +120,5 @@ cdef class Params:
|
||||
cdef string key_bytes = ensure_bytes(key)
|
||||
return self.p.getParamPath(key_bytes).decode("utf-8")
|
||||
|
||||
def all_keys(self):
|
||||
return self.p.allKeys()
|
||||
def all_keys(self, type=ParamKeyType.ALL):
|
||||
return self.p.allKeys(type)
|
||||
|
||||
@@ -18,6 +18,7 @@ collect_ignore = [
|
||||
collect_ignore_glob = [
|
||||
"selfdrive/debug/*.py",
|
||||
"selfdrive/modeld/*.py",
|
||||
"sunnypilot/modeld*/*.py",
|
||||
]
|
||||
|
||||
|
||||
|
||||
590
docs/CARS.md
590
docs/CARS.md
@@ -8,308 +8,308 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|
||||
|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|
|
||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=ILX 2016-19">Buy Here</a></sub></details>||
|
||||
|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2019-21">Buy Here</a></sub></details>||
|
||||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 2014-19">Buy Here</a></sub></details>||
|
||||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>||
|
||||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q2 2018">Buy Here</a></sub></details>||
|
||||
|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q3 2019-23">Buy Here</a></sub></details>||
|
||||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=RS3 2018">Buy Here</a></sub></details>||
|
||||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=S3 2015-17">Buy Here</a></sub></details>||
|
||||
|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=ILX 2016-19">Buy Here</a></sub></details>||
|
||||
|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2016-18">Buy Here</a></sub></details>||
|
||||
|Acura|RDX 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2019-21">Buy Here</a></sub></details>||
|
||||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 2014-19">Buy Here</a></sub></details>||
|
||||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>||
|
||||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q2 2018">Buy Here</a></sub></details>||
|
||||
|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q3 2019-23">Buy Here</a></sub></details>||
|
||||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=RS3 2018">Buy Here</a></sub></details>||
|
||||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=S3 2015-17">Buy Here</a></sub></details>||
|
||||
|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 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Bolt EUV 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Chevrolet|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 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Bolt EV 2022-23">Buy Here</a></sub></details>||
|
||||
|Chevrolet|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 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=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 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Silverado 1500 2020-21">Buy Here</a></sub></details>||
|
||||
|Chevrolet|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 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Trailblazer 2021-22">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica 2019-20">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica Hybrid 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica Hybrid 2019-24">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica 2017-18">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica 2019-20">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica 2021-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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica Hybrid 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chrysler&model=Pacifica Hybrid 2019-24">Buy Here</a></sub></details>||
|
||||
|comma|body|All|openpilot|0 mph|0 mph|[](##)|[](##)|None||
|
||||
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=CUPRA&model=Ateca 2018-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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Dodge&model=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 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Bronco Sport 2021-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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Escape 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Escape Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Escape Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Explorer 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Explorer 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 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=F-150 2021-23">Buy Here</a></sub></details>||
|
||||
|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 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=F-150 Hybrid 2021-23">Buy Here</a></sub></details>||
|
||||
|Ford|Focus 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Focus 2018">Buy Here</a></sub></details>||
|
||||
|Ford|Focus Hybrid 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Focus Hybrid 2018">Buy Here</a></sub></details>||
|
||||
|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Kuga 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Kuga Hybrid 2020-22|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Kuga Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Kuga Plug-in Hybrid 2020-22|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Kuga Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Maverick 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 2022">Buy Here</a></sub></details>||
|
||||
|Ford|Maverick 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 2023-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 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 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 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick Hybrid 2023-24">Buy Here</a></sub></details>||
|
||||
|Ford|Mustang Mach-E 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Mustang Mach-E 2021-23">Buy Here</a></sub></details>||
|
||||
|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 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Ranger 2024">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G70 2018">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G70 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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G70 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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G80 2017">Buy Here</a></sub></details>||
|
||||
|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G80 2018-19">Buy Here</a></sub></details>||
|
||||
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G80 (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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G90 2017-20">Buy Here</a></sub></details>||
|
||||
|Genesis|GV60 (Advanced Trim) 2023[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV60 (Advanced Trim) 2023">Buy Here</a></sub></details>||
|
||||
|Genesis|GV60 (Performance Trim) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV60 (Performance Trim) 2022-23">Buy Here</a></sub></details>||
|
||||
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV70 (2.5T Trim, without HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV70 (3.5T Trim, without HDA II) 2022-23">Buy Here</a></sub></details>||
|
||||
|Genesis|GV70 Electrified (Australia Only) 2022[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV70 Electrified (Australia Only) 2022">Buy Here</a></sub></details>||
|
||||
|Genesis|GV70 Electrified (with HDA II) 2023-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV70 Electrified (with HDA II) 2023-24">Buy Here</a></sub></details>||
|
||||
|Genesis|GV80 2023[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV80 2023">Buy Here</a></sub></details>||
|
||||
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=CUPRA&model=Ateca 2018-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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Dodge&model=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 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Bronco Sport 2021-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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Escape 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Escape Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Escape Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Explorer 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Explorer 2020-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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Explorer 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 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=F-150 2021-23">Buy Here</a></sub></details>||
|
||||
|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 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=F-150 Hybrid 2021-23">Buy Here</a></sub></details>||
|
||||
|Ford|Focus 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Focus 2018">Buy Here</a></sub></details>||
|
||||
|Ford|Focus Hybrid 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Focus Hybrid 2018">Buy Here</a></sub></details>||
|
||||
|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Kuga 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Kuga Hybrid 2020-22|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Kuga Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Kuga Plug-in Hybrid 2020-22|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Kuga Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Maverick 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 2022">Buy Here</a></sub></details>||
|
||||
|Ford|Maverick 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 2023-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 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 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 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick Hybrid 2023-24">Buy Here</a></sub></details>||
|
||||
|Ford|Mustang Mach-E 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Mustang Mach-E 2021-23">Buy Here</a></sub></details>||
|
||||
|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 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Ranger 2024">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G70 2018">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G70 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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G70 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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G80 2017">Buy Here</a></sub></details>||
|
||||
|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G80 2018-19">Buy Here</a></sub></details>||
|
||||
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G80 (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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=G90 2017-20">Buy Here</a></sub></details>||
|
||||
|Genesis|GV60 (Advanced Trim) 2023[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV60 (Advanced Trim) 2023">Buy Here</a></sub></details>||
|
||||
|Genesis|GV60 (Performance Trim) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV60 (Performance Trim) 2022-23">Buy Here</a></sub></details>||
|
||||
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV70 (2.5T Trim, without HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV70 (3.5T Trim, without HDA II) 2022-23">Buy Here</a></sub></details>||
|
||||
|Genesis|GV70 Electrified (Australia Only) 2022[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV70 Electrified (Australia Only) 2022">Buy Here</a></sub></details>||
|
||||
|Genesis|GV70 Electrified (with HDA II) 2023-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV70 Electrified (with HDA II) 2023-24">Buy Here</a></sub></details>||
|
||||
|Genesis|GV80 2023[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Genesis&model=GV80 2023">Buy Here</a></sub></details>||
|
||||
|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=GMC&model=Sierra 1500 2020-21">Buy Here</a></sub></details>|<a href="https://youtu.be/5HbNoBLzRwE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Honda|Accord 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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Accord 2018-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=mrUwlj3Mi58" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Honda|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Accord Hybrid 2018-22">Buy Here</a></sub></details>||
|
||||
|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic 2016-18">Buy Here</a></sub></details>|<a href="https://youtu.be/-IkImTe1NYE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Honda|Civic 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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=4Iz1Mz5LGF8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Honda|Civic 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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic 2022-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-21|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic Hatchback 2017-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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic Hatchback 2022-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|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=CR-V 2015-16">Buy Here</a></sub></details>||
|
||||
|Honda|CR-V 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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=CR-V 2017-22">Buy Here</a></sub></details>||
|
||||
|Honda|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=CR-V Hybrid 2017-22">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=e 2020">Buy Here</a></sub></details>||
|
||||
|Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Fit 2018-20">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Freed 2020">Buy Here</a></sub></details>||
|
||||
|Honda|HR-V 2019-22|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=HR-V 2019-22">Buy Here</a></sub></details>||
|
||||
|Honda|HR-V 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=HR-V 2023">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Insight 2019-22">Buy Here</a></sub></details>||
|
||||
|Honda|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Inspire 2018">Buy Here</a></sub></details>||
|
||||
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Odyssey 2018-20">Buy Here</a></sub></details>||
|
||||
|Honda|Passport 2019-23|All|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Passport 2019-23">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Pilot 2016-22">Buy Here</a></sub></details>||
|
||||
|Honda|Ridgeline 2017-25|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Azera 2022">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Azera Hybrid 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Azera Hybrid 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Azera Hybrid 2020">Buy Here</a></sub></details>||
|
||||
|Hyundai|Custin 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Custin 2023">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra 2017-18">Buy Here</a></sub></details>||
|
||||
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=i30 2017-19">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (Southeast Asia and Europe only) 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (with HDA II) 2022-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (with HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (without HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (without HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 6 (with HDA II) 2023-24[<sup>5</sup>](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 6 (with HDA II) 2023-24">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2020">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2017-19">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2020-22">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona 2020">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona 2022|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona 2022">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric 2018-21">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Hybrid 2020">Buy Here</a></sub></details>||
|
||||
|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Santa Cruz 2022-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Cruz 2022-24">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe 2019-20">Buy Here</a></sub></details>|<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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Sonata Hybrid 2020-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Staria 2023[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson 2021">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson 2022[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson 2022">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson 2023-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson 2023-24">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson Diesel 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson Hybrid 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson Hybrid 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson Plug-in Hybrid 2024[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson Plug-in Hybrid 2024">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Veloster 2019-20">Buy Here</a></sub></details>||
|
||||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Jeep&model=Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Jeep&model=Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Carnival 2022-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|Carnival (China only) 2023[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival (China only) 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Ceed 2019-21">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (Southeast Asia only) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (with HDA II) 2022-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (without HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (without HDA II) 2022-24">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Forte 2019-21">Buy Here</a></sub></details>||
|
||||
|Kia|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Forte 2022-23">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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=K5 2021-24">Buy Here</a></sub></details>||
|
||||
|Kia|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=K5 Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Kia|K8 Hybrid (with HDA II) 2023[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=K8 Hybrid (with HDA II) 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Niro EV 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2020">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Niro EV 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2021">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Niro EV 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2022">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Niro EV 2023[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2018|All|Stock|10 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Hybrid 2018">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Hybrid 2021">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Hybrid 2022">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2023[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Hybrid 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2018-19|All|Stock|10 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Plug-in Hybrid 2018-19">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2020|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Plug-in Hybrid 2020">Buy Here</a></sub></details>||
|
||||
|Kia|Niro 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 D connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Plug-in Hybrid 2021">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Plug-in Hybrid 2022">Buy Here</a></sub></details>||
|
||||
|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Optima 2017">Buy Here</a></sub></details>||
|
||||
|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Optima 2019-20">Buy Here</a></sub></details>||
|
||||
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Optima Hybrid 2019">Buy Here</a></sub></details>||
|
||||
|Kia|Seltos 2021|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Seltos 2021">Buy Here</a></sub></details>||
|
||||
|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Sorento 2021-23[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento 2021-23">Buy Here</a></sub></details>||
|
||||
|Kia|Sorento Hybrid 2021-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento Hybrid 2021-23">Buy Here</a></sub></details>||
|
||||
|Kia|Sorento Plug-in Hybrid 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|
||||
|Kia|Sportage 2023-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sportage 2023-24">Buy Here</a></sub></details>||
|
||||
|Kia|Sportage Hybrid 2023[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sportage Hybrid 2023">Buy Here</a></sub></details>||
|
||||
|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Stinger 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Stinger 2022-23">Buy Here</a></sub></details>||
|
||||
|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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Telluride 2020-22">Buy Here</a></sub></details>||
|
||||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=CT Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES 2019-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES 2019-24">Buy Here</a></sub></details>||
|
||||
|Lexus|ES Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES Hybrid 2019-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES Hybrid 2019-25">Buy Here</a></sub></details>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Lexus|GS F 2016|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=GS F 2016">Buy Here</a></sub></details>||
|
||||
|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=IS 2017-19">Buy Here</a></sub></details>||
|
||||
|Lexus|IS 2022-23|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=IS 2022-23">Buy Here</a></sub></details>||
|
||||
|Lexus|LC 2024|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=LC 2024">Buy Here</a></sub></details>||
|
||||
|Lexus|NX 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX 2018-19">Buy Here</a></sub></details>||
|
||||
|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX 2020-21">Buy Here</a></sub></details>||
|
||||
|Lexus|NX Hybrid 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX Hybrid 2018-19">Buy Here</a></sub></details>||
|
||||
|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX Hybrid 2020-21">Buy Here</a></sub></details>||
|
||||
|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RC 2018-20">Buy Here</a></sub></details>||
|
||||
|Lexus|RX 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX 2016">Buy Here</a></sub></details>||
|
||||
|Lexus|RX 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX 2017-19">Buy Here</a></sub></details>||
|
||||
|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX 2020-22">Buy Here</a></sub></details>||
|
||||
|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX Hybrid 2016">Buy Here</a></sub></details>||
|
||||
|Lexus|RX Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX Hybrid 2017-19">Buy Here</a></sub></details>||
|
||||
|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Lexus|UX Hybrid 2019-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=UX Hybrid 2019-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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lincoln&model=Aviator 2020-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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lincoln&model=Aviator Plug-in Hybrid 2020-24">Buy Here</a></sub></details>||
|
||||
|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=eTGE 2020-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,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=TGE 2017-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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-5 2022-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 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Altima 2019-20">Buy Here</a></sub></details>||
|
||||
|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Leaf 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Rogue 2018-20">Buy Here</a></sub></details>||
|
||||
|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=X-Trail 2017">Buy Here</a></sub></details>||
|
||||
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ram connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ram&model=1500 2019-24">Buy Here</a></sub></details>||
|
||||
|Rivian|R1S 2022-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Rivian&model=R1S 2022-24">Buy Here</a></sub></details>||
|
||||
|Rivian|R1T 2022-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Rivian&model=R1T 2022-24">Buy Here</a></sub></details>||
|
||||
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=SEAT&model=Ateca 2016-23">Buy Here</a></sub></details>||
|
||||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=SEAT&model=Leon 2014-20">Buy Here</a></sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|Subaru|Legacy 2020-22|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Subaru B connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Legacy 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|Subaru|Outback 2020-22|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Subaru B connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Outback 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|Škoda|Fabia 2022-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Fabia 2022-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Škoda|Kamiq 2021-23[<sup>10,12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kamiq 2021-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Škoda|Karoq 2019-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Karoq 2019-23">Buy Here</a></sub></details>||
|
||||
|Škoda|Kodiaq 2017-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kodiaq 2017-23">Buy Here</a></sub></details>||
|
||||
|Škoda|Octavia 2015-19[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia 2015-19">Buy Here</a></sub></details>||
|
||||
|Škoda|Octavia RS 2016[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia RS 2016">Buy Here</a></sub></details>||
|
||||
|Škoda|Octavia Scout 2017-19[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia Scout 2017-19">Buy Here</a></sub></details>||
|
||||
|Škoda|Scala 2020-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Scala 2020-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Škoda|Superb 2015-22[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Superb 2015-22">Buy Here</a></sub></details>||
|
||||
|Tesla|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 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Tesla&model=Model 3 (with HW3) 2019-23">Buy Here</a></sub></details>||
|
||||
|Tesla|Model 3 (with HW4) 2024[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Tesla&model=Model 3 (with HW4) 2024">Buy Here</a></sub></details>||
|
||||
|Tesla|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 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Tesla&model=Model Y (with HW3) 2020-23">Buy Here</a></sub></details>||
|
||||
|Tesla|Model Y (with HW4) 2024[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Tesla&model=Model Y (with HW4) 2024">Buy Here</a></sub></details>||
|
||||
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Alphard 2019-20">Buy Here</a></sub></details>||
|
||||
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Alphard Hybrid 2021">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2016">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2017-18">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2019-21">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2022">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon Hybrid 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon Hybrid 2019-21">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon Hybrid 2022">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR 2017-20">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR 2021">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR Hybrid 2017-20">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR Hybrid 2021-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR Hybrid 2021-22">Buy Here</a></sub></details>||
|
||||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>9</sup>](#footnotes)|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>9</sup>](#footnotes)|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry 2021-24">Buy Here</a></sub></details>||
|
||||
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry Hybrid 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry Hybrid 2021-24">Buy Here</a></sub></details>||
|
||||
|Toyota|Corolla 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla 2017-19">Buy Here</a></sub></details>||
|
||||
|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla 2020-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Cross (Non-US only) 2020-23">Buy Here</a></sub></details>||
|
||||
|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Cross Hybrid (Non-US only) 2020-22">Buy Here</a></sub></details>||
|
||||
|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hatchback 2019-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Toyota|Corolla Hybrid (South America only) 2020-23|All|openpilot|17 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hybrid (South America only) 2020-23">Buy Here</a></sub></details>||
|
||||
|Toyota|Highlander 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander 2017-19">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=0wS0wXSLzoo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander 2020-23">Buy Here</a></sub></details>||
|
||||
|Toyota|Highlander Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander Hybrid 2017-19">Buy Here</a></sub></details>||
|
||||
|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander Hybrid 2020-23">Buy Here</a></sub></details>||
|
||||
|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Mirai 2021">Buy Here</a></sub></details>||
|
||||
|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius 2016">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Prius 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius 2017-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius 2021-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=J58TvCpUd4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Prius Prime 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius Prime 2017-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius Prime 2021-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=J58TvCpUd4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius v 2017">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2016">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2017-18">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=wJxjDd42gGA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2022">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2023-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2023-24">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2016">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2019-21">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 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|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon 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,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas 2018-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas Cross Sport 2020-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=California 2021-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Caravelle 2020">Buy Here</a></sub></details>||
|
||||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Crafter 2017-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,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Crafter 2018-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,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Golf 2014-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf 2015-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf Alltrack 2015-19">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTD 2015-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTE 2015-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTI 2015-21">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf R 2015-19">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf SportsVan 2015-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Grand California 2019-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,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta 2018-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta GLI 2021-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Passat 2015-22[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat 2015-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat Alltrack 2015-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat GTE 2015-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Polo 2018-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=T-Cross 2021">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Volkswagen|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=T-Roc 2018-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Taos 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Taos 2022-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont 2018-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont Cross Sport 2021-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont X 2021-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Tiguan 2018-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Tiguan eHybrid 2021-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Touran 2016-23">Buy Here</a></sub></details>||
|
||||
|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Accord 2018-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=mrUwlj3Mi58" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Honda|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Accord Hybrid 2018-22">Buy Here</a></sub></details>||
|
||||
|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic 2016-18">Buy Here</a></sub></details>|<a href="https://youtu.be/-IkImTe1NYE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Honda|Civic 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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=4Iz1Mz5LGF8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Honda|Civic 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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic 2022-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-21|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic Hatchback 2017-21">Buy Here</a></sub></details>||
|
||||
|Honda|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Civic Hatchback 2022-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|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=CR-V 2015-16">Buy Here</a></sub></details>||
|
||||
|Honda|CR-V 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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=CR-V 2017-22">Buy Here</a></sub></details>||
|
||||
|Honda|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=CR-V Hybrid 2017-22">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=e 2020">Buy Here</a></sub></details>||
|
||||
|Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Fit 2018-20">Buy Here</a></sub></details>||
|
||||
|Honda|Freed 2020|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Freed 2020">Buy Here</a></sub></details>||
|
||||
|Honda|HR-V 2019-22|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=HR-V 2019-22">Buy Here</a></sub></details>||
|
||||
|Honda|HR-V 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=HR-V 2023">Buy Here</a></sub></details>||
|
||||
|Honda|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Insight 2019-22">Buy Here</a></sub></details>||
|
||||
|Honda|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Inspire 2018">Buy Here</a></sub></details>||
|
||||
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Odyssey 2018-20">Buy Here</a></sub></details>||
|
||||
|Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Passport 2019-25">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Pilot 2016-22">Buy Here</a></sub></details>||
|
||||
|Honda|Ridgeline 2017-25|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Honda&model=Ridgeline 2017-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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Azera 2022">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Azera Hybrid 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Azera Hybrid 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Azera Hybrid 2020">Buy Here</a></sub></details>||
|
||||
|Hyundai|Custin 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Custin 2023">Buy Here</a></sub></details>||
|
||||
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra 2017-18">Buy Here</a></sub></details>||
|
||||
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra GT 2017-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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Genesis 2015-16">Buy Here</a></sub></details>||
|
||||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=i30 2017-19">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (Southeast Asia and Europe only) 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (with HDA II) 2022-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (with HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (without HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (without HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 6 (with HDA II) 2023-24[<sup>5</sup>](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 6 (with HDA II) 2023-24">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2020">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2017-19">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona 2020">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona 2022|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona 2022">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric 2018-21">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Hybrid 2020">Buy Here</a></sub></details>||
|
||||
|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Santa Cruz 2022-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Cruz 2022-24">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe 2019-20">Buy Here</a></sub></details>|<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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Sonata 2018-19">Buy Here</a></sub></details>||
|
||||
|Hyundai|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Sonata Hybrid 2020-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Staria 2023[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson 2021">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson 2022[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson 2022">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson 2023-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson 2023-24">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson Diesel 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson Hybrid 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson Hybrid 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson Plug-in Hybrid 2024[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Tucson Plug-in Hybrid 2024">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Veloster 2019-20">Buy Here</a></sub></details>||
|
||||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Jeep&model=Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Jeep&model=Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Carnival 2022-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|Carnival (China only) 2023[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival (China only) 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Ceed 2019-21">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (Southeast Asia only) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (with HDA II) 2022-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (without HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (without HDA II) 2022-24">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Forte 2019-21">Buy Here</a></sub></details>||
|
||||
|Kia|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Forte 2022-23">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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=K5 2021-24">Buy Here</a></sub></details>||
|
||||
|Kia|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=K5 Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Kia|K8 Hybrid (with HDA II) 2023[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=K8 Hybrid (with HDA II) 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Niro EV 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2020">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Niro EV 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2021">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Niro EV 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2022">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Niro EV 2023-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro EV 2023-24">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2018|All|Stock|10 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Hybrid 2018">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Hybrid 2021">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Hybrid 2022">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2023[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Hybrid 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2018-19|All|Stock|10 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Plug-in Hybrid 2018-19">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2020|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Plug-in Hybrid 2020">Buy Here</a></sub></details>||
|
||||
|Kia|Niro 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 D connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Plug-in Hybrid 2021">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Niro Plug-in Hybrid 2022">Buy Here</a></sub></details>||
|
||||
|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Optima 2017">Buy Here</a></sub></details>||
|
||||
|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Optima 2019-20">Buy Here</a></sub></details>||
|
||||
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Optima Hybrid 2019">Buy Here</a></sub></details>||
|
||||
|Kia|Seltos 2021|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Seltos 2021">Buy Here</a></sub></details>||
|
||||
|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Sorento 2021-23[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento 2021-23">Buy Here</a></sub></details>||
|
||||
|Kia|Sorento Hybrid 2021-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento Hybrid 2021-23">Buy Here</a></sub></details>||
|
||||
|Kia|Sorento Plug-in Hybrid 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|
||||
|Kia|Sportage 2023-24[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sportage 2023-24">Buy Here</a></sub></details>||
|
||||
|Kia|Sportage Hybrid 2023[<sup>5</sup>](#footnotes)|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Sportage Hybrid 2023">Buy Here</a></sub></details>||
|
||||
|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Stinger 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Stinger 2022-23">Buy Here</a></sub></details>||
|
||||
|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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Telluride 2020-22">Buy Here</a></sub></details>||
|
||||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=CT Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES 2019-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES 2019-24">Buy Here</a></sub></details>||
|
||||
|Lexus|ES Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES Hybrid 2019-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES Hybrid 2019-25">Buy Here</a></sub></details>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Lexus|GS F 2016|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=GS F 2016">Buy Here</a></sub></details>||
|
||||
|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=IS 2017-19">Buy Here</a></sub></details>||
|
||||
|Lexus|IS 2022-23|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=IS 2022-23">Buy Here</a></sub></details>||
|
||||
|Lexus|LC 2024|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=LC 2024">Buy Here</a></sub></details>||
|
||||
|Lexus|NX 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX 2018-19">Buy Here</a></sub></details>||
|
||||
|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX 2020-21">Buy Here</a></sub></details>||
|
||||
|Lexus|NX Hybrid 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX Hybrid 2018-19">Buy Here</a></sub></details>||
|
||||
|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=NX Hybrid 2020-21">Buy Here</a></sub></details>||
|
||||
|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RC 2018-20">Buy Here</a></sub></details>||
|
||||
|Lexus|RX 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX 2016">Buy Here</a></sub></details>||
|
||||
|Lexus|RX 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX 2017-19">Buy Here</a></sub></details>||
|
||||
|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX 2020-22">Buy Here</a></sub></details>||
|
||||
|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX Hybrid 2016">Buy Here</a></sub></details>||
|
||||
|Lexus|RX Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX Hybrid 2017-19">Buy Here</a></sub></details>||
|
||||
|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=RX Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Lexus|UX Hybrid 2019-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=UX Hybrid 2019-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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lincoln&model=Aviator 2020-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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lincoln&model=Aviator Plug-in Hybrid 2020-24">Buy Here</a></sub></details>||
|
||||
|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=eTGE 2020-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,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=TGE 2017-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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-5 2022-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 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Altima 2019-20">Buy Here</a></sub></details>||
|
||||
|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Leaf 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Rogue 2018-20">Buy Here</a></sub></details>||
|
||||
|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=X-Trail 2017">Buy Here</a></sub></details>||
|
||||
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ram connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ram&model=1500 2019-24">Buy Here</a></sub></details>||
|
||||
|Rivian|R1S 2022-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Rivian&model=R1S 2022-24">Buy Here</a></sub></details>||
|
||||
|Rivian|R1T 2022-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Rivian&model=R1T 2022-24">Buy Here</a></sub></details>||
|
||||
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=SEAT&model=Ateca 2016-23">Buy Here</a></sub></details>||
|
||||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=SEAT&model=Leon 2014-20">Buy Here</a></sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|Subaru|Legacy 2020-22|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Subaru B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Legacy 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|Subaru|Outback 2020-22|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Subaru B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=Outback 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|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 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Subaru&model=XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|
||||
|Škoda|Fabia 2022-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Fabia 2022-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Škoda|Kamiq 2021-23[<sup>10,12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kamiq 2021-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Škoda|Karoq 2019-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Karoq 2019-23">Buy Here</a></sub></details>||
|
||||
|Škoda|Kodiaq 2017-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kodiaq 2017-23">Buy Here</a></sub></details>||
|
||||
|Škoda|Octavia 2015-19[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia 2015-19">Buy Here</a></sub></details>||
|
||||
|Škoda|Octavia RS 2016[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia RS 2016">Buy Here</a></sub></details>||
|
||||
|Škoda|Octavia Scout 2017-19[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia Scout 2017-19">Buy Here</a></sub></details>||
|
||||
|Škoda|Scala 2020-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Scala 2020-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Škoda|Superb 2015-22[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Superb 2015-22">Buy Here</a></sub></details>||
|
||||
|Tesla|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 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Tesla&model=Model 3 (with HW3) 2019-23">Buy Here</a></sub></details>||
|
||||
|Tesla|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 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Tesla&model=Model 3 (with HW4) 2024-25">Buy Here</a></sub></details>||
|
||||
|Tesla|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 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Tesla&model=Model Y (with HW3) 2020-23">Buy Here</a></sub></details>||
|
||||
|Tesla|Model Y (with HW4) 2024[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Tesla&model=Model Y (with HW4) 2024">Buy Here</a></sub></details>||
|
||||
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Alphard 2019-20">Buy Here</a></sub></details>||
|
||||
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Alphard Hybrid 2021">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2016">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2017-18">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2019-21">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon 2022">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon Hybrid 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon Hybrid 2019-21">Buy Here</a></sub></details>||
|
||||
|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Avalon Hybrid 2022">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR 2017-20">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR 2021">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR Hybrid 2017-20">Buy Here</a></sub></details>||
|
||||
|Toyota|C-HR Hybrid 2021-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=C-HR Hybrid 2021-22">Buy Here</a></sub></details>||
|
||||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>9</sup>](#footnotes)|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>9</sup>](#footnotes)|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry 2021-24">Buy Here</a></sub></details>||
|
||||
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry Hybrid 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Camry Hybrid 2021-24">Buy Here</a></sub></details>||
|
||||
|Toyota|Corolla 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla 2017-19">Buy Here</a></sub></details>||
|
||||
|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla 2020-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Cross (Non-US only) 2020-23">Buy Here</a></sub></details>||
|
||||
|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Cross Hybrid (Non-US only) 2020-22">Buy Here</a></sub></details>||
|
||||
|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hatchback 2019-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Toyota|Corolla Hybrid (South America only) 2020-23|All|openpilot|17 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hybrid (South America only) 2020-23">Buy Here</a></sub></details>||
|
||||
|Toyota|Highlander 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander 2017-19">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=0wS0wXSLzoo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander 2020-23">Buy Here</a></sub></details>||
|
||||
|Toyota|Highlander Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander Hybrid 2017-19">Buy Here</a></sub></details>||
|
||||
|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander Hybrid 2020-23">Buy Here</a></sub></details>||
|
||||
|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Mirai 2021">Buy Here</a></sub></details>||
|
||||
|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius 2016">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Prius 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius 2017-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius 2021-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=J58TvCpUd4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Prius Prime 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius Prime 2017-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius Prime 2021-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=J58TvCpUd4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Prius v 2017">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2016">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2017-18">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=wJxjDd42gGA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2022">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 2023-25">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2016">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2019-21">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 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|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon 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,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas 2018-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas Cross Sport 2020-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=California 2021-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Caravelle 2020">Buy Here</a></sub></details>||
|
||||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Crafter 2017-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,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Crafter 2018-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,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Golf 2014-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf 2015-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf Alltrack 2015-19">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTD 2015-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTE 2015-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTI 2015-21">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf R 2015-19">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf SportsVan 2015-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Grand California 2019-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,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta 2018-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta GLI 2021-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Passat 2015-22[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat 2015-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat Alltrack 2015-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat GTE 2015-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Polo 2018-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=T-Cross 2021">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|
||||
|Volkswagen|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=T-Roc 2018-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Taos 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Taos 2022-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont 2018-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont Cross Sport 2021-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont X 2021-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Tiguan 2018-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Tiguan eHybrid 2021-23">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Touran 2016-23">Buy Here</a></sub></details>||
|
||||
|
||||
### Footnotes
|
||||
<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 />
|
||||
|
||||
@@ -31,13 +31,3 @@ cd system/loggerd && pytest .
|
||||
# run the linter
|
||||
op lint
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Automated Testing
|
||||
|
||||
All PRs and commits are automatically checked by GitHub Actions. Check out `.github/workflows/` for what GitHub Actions runs. Any new tests should be added to GitHub Actions.
|
||||
|
||||
### Code Style and Linting
|
||||
|
||||
Code is automatically checked for style by GitHub Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.
|
||||
|
||||
@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
|
||||
export VECLIB_MAXIMUM_THREADS=1
|
||||
|
||||
if [ -z "$AGNOS_VERSION" ]; then
|
||||
export AGNOS_VERSION="11.11"
|
||||
export AGNOS_VERSION="11.13"
|
||||
fi
|
||||
|
||||
export STAGING_ROOT="/data/safe_staging"
|
||||
|
||||
Submodule msgq_repo updated: ad9020c430...a144e41d5f
Submodule opendbc_repo updated: 3db676c5cc...d2002787f6
1
openpilot/sunnypilot
Symbolic link
1
openpilot/sunnypilot
Symbolic link
@@ -0,0 +1 @@
|
||||
../sunnypilot
|
||||
2
panda
2
panda
Submodule panda updated: 998ac9d5d8...4fab184d5f
@@ -26,7 +26,7 @@ dependencies = [
|
||||
"pycapnp",
|
||||
"Cython",
|
||||
"setuptools",
|
||||
"numpy < 2.0.0",
|
||||
"numpy >=2.0, <2.2", # Linting issues with mypy in 2.2
|
||||
|
||||
# body / webrtcd
|
||||
"aiohttp",
|
||||
@@ -163,6 +163,7 @@ testpaths = [
|
||||
"tools/replay",
|
||||
"tools/cabana",
|
||||
"cereal/messaging/tests",
|
||||
"sunnypilot",
|
||||
]
|
||||
|
||||
[tool.codespell]
|
||||
|
||||
Submodule rednose_repo updated: 05fd60278a...8b86052919
@@ -74,6 +74,7 @@ find . -name '__pycache__' -delete
|
||||
rm -rf .sconsign.dblite Jenkinsfile release/
|
||||
rm selfdrive/modeld/models/driving_vision.onnx
|
||||
rm selfdrive/modeld/models/driving_policy.onnx
|
||||
rm sunnypilot/modeld*/models/supercombo.onnx
|
||||
|
||||
find third_party/ -name '*x86*' -exec rm -r {} +
|
||||
find third_party/ -name '*Darwin*' -exec rm -r {} +
|
||||
|
||||
262
release/ci/install_github_runner.sh
Executable file
262
release/ci/install_github_runner.sh
Executable file
@@ -0,0 +1,262 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Default values
|
||||
DEFAULT_REPO_URL="https://github.com/sunnypilot"
|
||||
START_AT_BOOT=false
|
||||
RESTORE_MODE=false
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--start-at-boot)
|
||||
START_AT_BOOT=true
|
||||
shift
|
||||
;;
|
||||
--token)
|
||||
GITHUB_TOKEN="$2"
|
||||
shift 2
|
||||
;;
|
||||
--repo)
|
||||
REPO_URL="$2"
|
||||
shift 2
|
||||
;;
|
||||
--restore)
|
||||
RESTORE_MODE=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
if [ -z "$GITHUB_TOKEN" ]; then
|
||||
GITHUB_TOKEN="$1"
|
||||
elif [ -z "$REPO_URL" ]; then
|
||||
REPO_URL="$1"
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Determine BASE_DIR based on mount point
|
||||
if mountpoint -q /data/media; then
|
||||
BASE_DIR="/data/media/0/github"
|
||||
else
|
||||
BASE_DIR="/data/github"
|
||||
fi
|
||||
|
||||
# Constants
|
||||
RUNNER_USER="github-runner"
|
||||
USER_GROUPS="comma,gpu,gpio,sudo"
|
||||
RUNNER_DIR="${BASE_DIR}/runner"
|
||||
BUILDS_DIR="${BASE_DIR}/builds"
|
||||
LOGS_DIR="${BASE_DIR}/logs"
|
||||
CACHE_DIR="${BASE_DIR}/cache"
|
||||
OPENPILOT_DIR="${BASE_DIR}/openpilot"
|
||||
|
||||
# Basic utility functions (no dependencies)
|
||||
remount_rw() {
|
||||
sudo mount -o remount,rw /
|
||||
}
|
||||
|
||||
remount_ro() {
|
||||
sync || true # Try to sync but continue even if it fails
|
||||
sudo mount -o remount,ro / # Always try to remount as read-only
|
||||
}
|
||||
|
||||
# Always ensure we try to remount as read-only on exit
|
||||
trap remount_ro EXIT
|
||||
|
||||
setup_runner_user() {
|
||||
sudo useradd --comment 'GitHub Runner' --create-home --home-dir ${BASE_DIR} ${RUNNER_USER} --shell /bin/bash -G ${USER_GROUPS} || sudo usermod -aG ${USER_GROUPS} ${RUNNER_USER}
|
||||
}
|
||||
|
||||
create_sudoers_entry() {
|
||||
sudo grep -qxF "${RUNNER_USER} ALL=(ALL) NOPASSWD: ALL" /etc/sudoers || echo "${RUNNER_USER} ALL=(ALL) NOPASSWD: ALL" | sudo tee -a /etc/sudoers
|
||||
}
|
||||
|
||||
set_directory_permissions() {
|
||||
sudo chown -R ${RUNNER_USER}:comma "$BASE_DIR"
|
||||
sudo chmod -R g+rwx "$BASE_DIR"
|
||||
sudo find "$BASE_DIR" -type d -exec chmod g+s {} +
|
||||
}
|
||||
|
||||
setup_directories() {
|
||||
echo "Creating necessary directories..."
|
||||
sudo mkdir -p "$RUNNER_DIR" "$BUILDS_DIR" "$LOGS_DIR" "$CACHE_DIR" "$OPENPILOT_DIR"
|
||||
mkdir -p "/data/openpilot"
|
||||
sudo chown -R comma:comma "/data/openpilot"
|
||||
sync
|
||||
}
|
||||
|
||||
wipe_bash_logout() {
|
||||
export BASE_DIR
|
||||
sudo -u ${RUNNER_USER} bash -c "touch ${BASE_DIR}/.bash_logout"
|
||||
sudo -u ${RUNNER_USER} bash -c "truncate -s 0 '${BASE_DIR}/.bash_logout'"
|
||||
}
|
||||
|
||||
# System configuration functions (depends on basic utility functions)
|
||||
setup_system_configs() {
|
||||
echo "Setting up system configurations..."
|
||||
remount_rw
|
||||
setup_runner_user
|
||||
create_sudoers_entry
|
||||
remount_ro
|
||||
set_directory_permissions
|
||||
wipe_bash_logout
|
||||
}
|
||||
|
||||
# Runner setup functions
|
||||
install_runner() {
|
||||
echo "Downloading and setting up runner..."
|
||||
cd "$RUNNER_DIR"
|
||||
curl -o actions-runner-linux-arm64-2.322.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.322.0/actions-runner-linux-arm64-2.322.0.tar.gz
|
||||
sudo -u ${RUNNER_USER} tar -xzf ./actions-runner-linux-arm64-2.322.0.tar.gz
|
||||
sudo rm ./actions-runner-linux-arm64-2.322.0.tar.gz
|
||||
sudo chmod +x ./config.sh
|
||||
}
|
||||
|
||||
configure_runner() {
|
||||
remount_rw
|
||||
echo "Configuring runner..."
|
||||
cd "$RUNNER_DIR"
|
||||
sudo -u ${RUNNER_USER} ./config.sh --url "$REPO_URL" --token "$GITHUB_TOKEN" --name $(hostname) --runnergroup "tici-tizi" --labels "tici" --work "$BUILDS_DIR" --unattended
|
||||
remount_ro
|
||||
}
|
||||
|
||||
create_service_template() {
|
||||
echo "Creating service template..."
|
||||
cat <<EOL > "$RUNNER_DIR/bin/actions.runner.service.template"
|
||||
[Unit]
|
||||
Description={{Description}}
|
||||
After=network-online.target nss-lookup.target time-sync.target
|
||||
Wants=network-online.target nss-lookup.target time-sync.target
|
||||
StartLimitInterval=5
|
||||
StartLimitBurst=10
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
ExecStart=/usr/bin/unshare -m -- /bin/bash -c 'mount --bind ${OPENPILOT_DIR} /data/openpilot && setpriv --reuid={{User}} --regid={{User}} --init-groups env HOME=${BASE_DIR} USER={{User}} LOGNAME={{User}} MAIL=/var/mail/{{User}} {{RunnerRoot}}/runsvc.sh'
|
||||
WorkingDirectory={{RunnerRoot}}
|
||||
KillMode=process
|
||||
KillSignal=SIGTERM
|
||||
TimeoutStopSec=5min
|
||||
Restart=always
|
||||
RestartSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
}
|
||||
|
||||
install_service() {
|
||||
remount_rw
|
||||
echo "Installing systemd service..."
|
||||
cd "$RUNNER_DIR"
|
||||
sudo ./svc.sh install $RUNNER_USER
|
||||
|
||||
if [ "$START_AT_BOOT" = false ]; then
|
||||
local service_name
|
||||
if [ -f "${RUNNER_DIR}/.service" ]; then
|
||||
service_name=$(cat "${RUNNER_DIR}/.service")
|
||||
else
|
||||
service_name="actions.runner.sunnypilot.$(uname -n)"
|
||||
fi
|
||||
sudo systemctl disable "${service_name}"
|
||||
fi
|
||||
remount_ro
|
||||
}
|
||||
|
||||
check_restore_prerequisites() {
|
||||
local needs_restore=false
|
||||
local can_restore=false
|
||||
local service_name=""
|
||||
|
||||
# Check if base runner directory exists
|
||||
if [ ! -d "${RUNNER_DIR}" ]; then
|
||||
echo "ERROR: Runner directory ${RUNNER_DIR} does not exist"
|
||||
echo "This directory is required for restore operations"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# First check if we have the required files for restoration
|
||||
if [ -f "${RUNNER_DIR}/.credentials" ] && [ -f "${RUNNER_DIR}/.service" ]; then
|
||||
can_restore=true
|
||||
service_name=$(cat "${RUNNER_DIR}/.service")
|
||||
echo "Found required runner configuration files"
|
||||
else
|
||||
echo "Missing required runner configuration files"
|
||||
echo "Required: .credentials and .service files in ${RUNNER_DIR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Then check if restoration is needed (if either service or user is missing)
|
||||
if ! systemctl list-unit-files "${service_name}" &>/dev/null; then
|
||||
echo "Service ${service_name} not found in systemd"
|
||||
needs_restore=true
|
||||
fi
|
||||
|
||||
if ! id "${RUNNER_USER}" &>/dev/null; then
|
||||
echo "User ${RUNNER_USER} does not exist"
|
||||
needs_restore=true
|
||||
fi
|
||||
|
||||
# Only proceed if we can restore AND need to restore
|
||||
if [ "$can_restore" = true ] && [ "$needs_restore" = true ]; then
|
||||
echo "Restoration is needed and possible"
|
||||
return 0
|
||||
else
|
||||
if [ "$needs_restore" = false ]; then
|
||||
echo "System is already properly configured (user and service exist)"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
perform_restore() {
|
||||
echo "Starting runner restoration..."
|
||||
setup_directories
|
||||
setup_system_configs
|
||||
install_service
|
||||
echo "Runner restoration completed successfully"
|
||||
}
|
||||
|
||||
perform_install() {
|
||||
echo "Starting fresh installation..."
|
||||
setup_directories
|
||||
setup_system_configs
|
||||
install_runner
|
||||
set_directory_permissions
|
||||
create_service_template
|
||||
configure_runner
|
||||
install_service
|
||||
echo "Installation completed successfully"
|
||||
}
|
||||
|
||||
main() {
|
||||
if [ "$RESTORE_MODE" = true ]; then
|
||||
echo "Running in restore mode - will only restore system configurations..."
|
||||
check_restore_prerequisites
|
||||
perform_restore
|
||||
else
|
||||
# Check required arguments for normal installation
|
||||
if [ -z "$GITHUB_TOKEN" ]; then
|
||||
echo "Usage: $0 [--start-at-boot] [--token <github_token>] [--repo <repository_url>] [--restore]"
|
||||
echo "Required argument (except for --restore): github_token"
|
||||
echo "Optional arguments:"
|
||||
echo " --start-at-boot Enable auto-start at boot (default: false)"
|
||||
echo " --repo Repository URL (default: ${DEFAULT_REPO_URL})"
|
||||
echo " --restore Restore existing runner configuration"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set repository URL if not provided
|
||||
REPO_URL="${REPO_URL:-$DEFAULT_REPO_URL}"
|
||||
perform_install
|
||||
fi
|
||||
|
||||
echo "Starting runner service..."
|
||||
cd "$RUNNER_DIR"
|
||||
sudo ./svc.sh start
|
||||
}
|
||||
|
||||
main
|
||||
78
release/ci/publish.sh
Executable file
78
release/ci/publish.sh
Executable file
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
|
||||
cd $DIR
|
||||
|
||||
# Take parameters as arguments
|
||||
SOURCE_DIR=$1
|
||||
OUTPUT_DIR=$2
|
||||
DEV_BRANCH=$3
|
||||
VERSION=$4
|
||||
GIT_ORIGIN=$5
|
||||
EXTRA_VERSION_IDENTIFIER=$6
|
||||
|
||||
# Check parameters
|
||||
if [ -z "$SOURCE_DIR" ] || [ -z "$OUTPUT_DIR" ]; then
|
||||
echo "Error: No source or output directory provided."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$DEV_BRANCH" ] || [ -z "$VERSION" ]; then
|
||||
echo "Error: No dev branch or version provided."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$GIT_ORIGIN" ]; then
|
||||
echo "Error: No GIT_ORIGIN provided"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# "Tagging"
|
||||
echo "#define COMMA_VERSION \"$VERSION\"" > ${OUTPUT_DIR}/common/version.h
|
||||
|
||||
## set git identity
|
||||
#source $DIR/identity.sh
|
||||
#export GIT_SSH_COMMAND="ssh -i /data/gitkey"
|
||||
|
||||
echo "[-] Setting up repo T=$SECONDS"
|
||||
cd $OUTPUT_DIR
|
||||
git init
|
||||
|
||||
# set git username/password
|
||||
#source /data/identity.sh
|
||||
|
||||
git rm -rf $OUTPUT_DIR/.git || true # Doing cleanup, but it might fail if the .git doesn't exist or not allowed to delete
|
||||
git remote remove origin || true # ensure cleanup
|
||||
git remote add origin $GIT_ORIGIN
|
||||
#git push origin -d $DEV_BRANCH || true # Ensuring we delete the remote branch if it exists as we are wiping it out
|
||||
git fetch origin $DEV_BRANCH || (git checkout -b $DEV_BRANCH && git commit --allow-empty -m "sunnypilot v$VERSION release" && git push -u origin $DEV_BRANCH)
|
||||
|
||||
echo "[-] committing version $VERSION T=$SECONDS"
|
||||
git add -f .
|
||||
git commit -a -m "sunnypilot v$VERSION release"
|
||||
git branch --set-upstream-to=origin/$DEV_BRANCH
|
||||
|
||||
# include source commit hash and build date in commit
|
||||
GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD)
|
||||
DATETIME=$(date '+%Y-%m-%dT%H:%M:%S')
|
||||
SP_VERSION=$(cat $SOURCE_DIR/common/version.h | awk -F\" '{print $2}')
|
||||
|
||||
# Add built files to git
|
||||
git add -f .
|
||||
if [ "$EXTRA_VERSION_IDENTIFIER" = "-release" ] || [ "$EXTRA_VERSION_IDENTIFIER" = "-staging" ]; then
|
||||
export VERSION=${VERSION%"$EXTRA_VERSION_IDENTIFIER"}
|
||||
git commit --amend -m "sunnypilot v$VERSION"
|
||||
else
|
||||
git commit --amend -m "sunnypilot v$VERSION
|
||||
version: sunnypilot v$SP_VERSION release
|
||||
date: $DATETIME
|
||||
master commit: $GIT_HASH
|
||||
"
|
||||
fi
|
||||
git branch -m $DEV_BRANCH
|
||||
|
||||
# Push!
|
||||
echo "[-] pushing T=$SECONDS"
|
||||
git push -f origin $DEV_BRANCH
|
||||
54
release/ci/squash_and_merge.py
Executable file
54
release/ci/squash_and_merge.py
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
import subprocess
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
|
||||
def run_git_command(command, check=True):
|
||||
"""
|
||||
Runs a git command and returns the trimmed stdout output.
|
||||
Exits the script if the command fails.
|
||||
"""
|
||||
print(f"Running: {' '.join(command)}")
|
||||
result = subprocess.run(command, capture_output=True, text=True)
|
||||
if check and result.returncode != 0:
|
||||
print(result.stdout.strip())
|
||||
print(result.stderr.strip())
|
||||
sys.exit(result.returncode)
|
||||
return result.stdout.strip()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Merge multiple branches with squash merges.")
|
||||
parser.add_argument("--base", required=True, help="The base branch name from which the target branch will be created.")
|
||||
parser.add_argument("--target", required=True, help="The target branch name to merge into.")
|
||||
parser.add_argument("--title", required=False, help="Title for the commit")
|
||||
|
||||
parser.add_argument("branches", nargs="+", help="List of branch names to merge into the target branch.")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Checkout the base branch to ensure a common starting point.
|
||||
run_git_command(["git", "checkout", args.base])
|
||||
|
||||
# Check if the target branch exists. If not, create it from the base branch.
|
||||
branch_list = run_git_command(["git", "branch"], check=False)
|
||||
branch_names = [line.strip("* ").strip() for line in branch_list.splitlines()]
|
||||
if args.target in branch_names:
|
||||
run_git_command(["git", "checkout", args.target])
|
||||
else:
|
||||
run_git_command(["git", "checkout", "-b", args.target])
|
||||
|
||||
# Iterate over each branch, merging it with a squash merge.
|
||||
for branch in args.branches:
|
||||
print(f"Merging branch '{branch}' with a squash merge.")
|
||||
# Merge the branch without creating a merge commit.
|
||||
run_git_command(["git", "merge", "--squash", branch])
|
||||
# Commit the squashed changes with an appropriate message.
|
||||
commit_message = args.title or f"Squashed merge of branch '{branch}'"
|
||||
run_git_command(["git", "commit", "-m", commit_message])
|
||||
|
||||
print(f"All branches have been merged with squashed commits into '{args.target}'.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
206
release/ci/squash_and_merge_prs.py
Executable file
206
release/ci/squash_and_merge_prs.py
Executable file
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
TRUST_FORK_LABEL = "trust-fork-pr"
|
||||
|
||||
def setup_argument_parser():
|
||||
parser = argparse.ArgumentParser(description='Process and squash GitHub PRs')
|
||||
parser.add_argument('--pr-data', type=str, help='PR data in JSON format')
|
||||
parser.add_argument('--source-branch', type=str, default='master-new',
|
||||
help='Source branch for merging')
|
||||
parser.add_argument('--target-branch', type=str, default='master-dev-c3-new-test',
|
||||
help='Target branch for merging')
|
||||
parser.add_argument('--squash-script-path', type=str, required=True,
|
||||
help='Path to the squash_and_merge.py script')
|
||||
return parser
|
||||
|
||||
|
||||
def validate_squash_script(script_path):
|
||||
if not os.path.isfile(script_path):
|
||||
raise FileNotFoundError(f"Squash script not found at: {script_path}")
|
||||
if not os.access(script_path, os.X_OK):
|
||||
raise PermissionError(f"Squash script is not executable: {script_path}")
|
||||
|
||||
|
||||
def sort_prs_by_creation(pr_data):
|
||||
"""Sort PRs by creation date"""
|
||||
nodes = (pr_data.get('data', {}).get('search', {}).get('nodes', []))
|
||||
|
||||
return sorted(
|
||||
nodes,
|
||||
key=lambda x: datetime.fromisoformat(x.get('createdAt', '').replace('Z', '+00:00'))
|
||||
)
|
||||
|
||||
|
||||
def add_pr_comments(pr_number, comments: list[str]):
|
||||
"""Adds or updates a comment with multiple comments to a PR using gh cli"""
|
||||
comment = "\n___\n".join(comments)
|
||||
_add_pr_comment(pr_number, comment)
|
||||
|
||||
|
||||
def _add_pr_comment(pr_number, comment):
|
||||
"""Add or update a comment to a PR using gh cli"""
|
||||
title = "## Squash and Merge"
|
||||
|
||||
try:
|
||||
full_comment = f"{title}\n\n{comment}"
|
||||
subprocess.run(
|
||||
['gh', 'pr', 'comment', '--edit-last', '--create-if-none', f"#{pr_number}", '--body', full_comment],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Failed to add/update comment on PR #{pr_number}: {e.stderr}")
|
||||
except json.JSONDecodeError:
|
||||
print(f"Failed to parse comments data for PR #{pr_number}")
|
||||
|
||||
|
||||
def validate_pr(pr):
|
||||
"""Validate a PR and return (is_valid, skip_reason)"""
|
||||
pr_number = pr.get('number', 'UNKNOWN')
|
||||
branch = pr.get('headRefName', '')
|
||||
|
||||
if not branch:
|
||||
return False, f"missing branch name for PR #{pr_number}"
|
||||
|
||||
# Check if checks have passed
|
||||
commits = pr.get('commits', {}).get('nodes', [])
|
||||
if not commits:
|
||||
return False, "no commit data found"
|
||||
|
||||
status = commits[0].get('commit', {}).get('statusCheckRollup', {})
|
||||
if not status or status.get('state') != 'SUCCESS':
|
||||
return False, "not all checks have passed"
|
||||
|
||||
# Check for merge conflicts
|
||||
merge_status = subprocess.run(['gh', 'pr', 'view', str(pr_number), '--json', 'mergeable,mergeStateStatus'],
|
||||
capture_output=True, text=True)
|
||||
merge_data = json.loads(merge_status.stdout)
|
||||
if not merge_data.get('mergeable'):
|
||||
return False, "merge conflicts detected"
|
||||
|
||||
# if (mergeStateStatus := merge_data.get('mergeStateStatus')) == "BEHIND":
|
||||
# return False, f"branch is `{mergeStateStatus}`"
|
||||
|
||||
return True, None
|
||||
|
||||
|
||||
def process_pr(pr_data, source_branch, target_branch, squash_script_path):
|
||||
try:
|
||||
nodes = sort_prs_by_creation(pr_data)
|
||||
if not nodes:
|
||||
print("No PRs to squash")
|
||||
return 0
|
||||
|
||||
print(f"Deleting target branch {target_branch}")
|
||||
subprocess.run(['git', 'branch', '-D', target_branch], check=False)
|
||||
subprocess.run(['git', 'branch', target_branch, f'origin/{source_branch}'], check=True)
|
||||
success_count = 0
|
||||
for pr in nodes:
|
||||
pr_comments = []
|
||||
try:
|
||||
pr_number = pr.get('number', 'UNKNOWN')
|
||||
branch = pr.get('headRefName', '')
|
||||
title = pr.get('title', '')
|
||||
head_repository = pr.get('headRepository', {})
|
||||
pr_labels = pr.get('labels', {}).get('nodes', [])
|
||||
is_fork = head_repository.get('isFork', False)
|
||||
trust_fork = any(label.get('name') == TRUST_FORK_LABEL for label in pr_labels)
|
||||
is_valid, skip_reason = validate_pr(pr)
|
||||
origin = "origin" if not head_repository.get('isFork', False) else head_repository.get('nameWithOwner', 'origin')
|
||||
|
||||
if is_fork and trust_fork:
|
||||
print(f"Removing label `{TRUST_FORK_LABEL}` from PR #{pr_number} as it is being processed")
|
||||
subprocess.run(['gh', 'pr', 'edit', str(pr_number), '--remove-label', TRUST_FORK_LABEL], check=True)
|
||||
pr_comments.append(f"ℹ️️ This PR is from a fork. The `{TRUST_FORK_LABEL}` label was removed as it is being processed right now.")
|
||||
print(f"Adding remote {origin} for PR #{pr_number}")
|
||||
subprocess.run(['git', 'remote', 'add', origin, head_repository.get('url')], check=False)
|
||||
|
||||
if is_fork and not trust_fork:
|
||||
pr_comments.append(
|
||||
f"⚠️ This PR is from a fork. Please add the `{TRUST_FORK_LABEL}` label to include it in the squash." +
|
||||
"\n**Note**: The label is removed after the squash is done and must be added again for the next execution for security reasons."
|
||||
)
|
||||
continue
|
||||
|
||||
if not is_valid:
|
||||
print(f"Warning: {skip_reason} for PR #{pr_number}, skipping")
|
||||
pr_comments.append(f"⚠️ This PR was skipped in the automated `{target_branch}` squash because **{skip_reason}**.")
|
||||
continue
|
||||
|
||||
# Fetch PR branch
|
||||
subprocess.run(['git', 'fetch', origin, branch], check=True)
|
||||
# Delete branch if it exists (ignore errors if it doesn't)
|
||||
subprocess.run(['git', 'branch', '-D', branch], check=False)
|
||||
# Create new branch pointing to origin's branch
|
||||
subprocess.run(['git', 'branch', branch, f'{origin}/{branch}'], check=True)
|
||||
|
||||
# Run squash script
|
||||
result = subprocess.run([
|
||||
squash_script_path,
|
||||
'--target', target_branch,
|
||||
'--base', source_branch,
|
||||
'--title', f"{title} (PR-{pr_number})",
|
||||
branch,
|
||||
], capture_output=True, text=True)
|
||||
|
||||
print(result.stdout)
|
||||
if result.returncode == 0:
|
||||
print(f"Successfully processed PR #{pr_number}")
|
||||
success_count += 1
|
||||
continue
|
||||
|
||||
print(f"Error processing PR #{pr_number}:")
|
||||
print(f"Command failed with exit code {result.returncode}")
|
||||
output = result.stdout
|
||||
print(f"Error output: {output}")
|
||||
pr_comments.append(f"⚠️ Error during automated `{target_branch}` squash:\n```\n{output}\n```")
|
||||
subprocess.run(['git', 'reset', '--hard'], check=True)
|
||||
continue
|
||||
except Exception as e:
|
||||
print(f"Unexpected error processing PR #{pr_number}: {str(e)}")
|
||||
pr_comments.append(f"⚠️ Unexpected error during automated `{target_branch}` squash:\n```\n{str(e)}\n```")
|
||||
subprocess.run(['git', 'reset', '--hard'], check=True)
|
||||
continue
|
||||
finally:
|
||||
if pr_comments:
|
||||
add_pr_comments(pr_number, pr_comments) # This "commits" all the comments generated on this run before leaving loop on continue.
|
||||
|
||||
return success_count
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
print(f"Error in process_pr: {str(e)}")
|
||||
print("Full traceback:")
|
||||
print(traceback.format_exc())
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
parser = setup_argument_parser()
|
||||
try:
|
||||
args = parser.parse_args()
|
||||
validate_squash_script(args.squash_script_path)
|
||||
pr_data_json = json.loads(args.pr_data)
|
||||
|
||||
# Process the PRs
|
||||
success_count = process_pr(pr_data_json, args.source_branch, args.target_branch, args.squash_script_path)
|
||||
print(f"Successfully processed {success_count} PRs")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fatal error: {str(e)}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
66
release/ci/uninstall_github_runner.sh
Executable file
66
release/ci/uninstall_github_runner.sh
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
# Determine BASE_DIR based on mount point
|
||||
if mountpoint -q /data/media; then
|
||||
GITHUB_BASE_DIR="/data/media/0/github"
|
||||
else
|
||||
GITHUB_BASE_DIR="/data/github"
|
||||
fi
|
||||
|
||||
# Define directories and user
|
||||
BIN_DIR="$GITHUB_BASE_DIR/bin"
|
||||
BUILDS_DIR="$GITHUB_BASE_DIR/builds"
|
||||
OPENPILOT_DIR="$GITHUB_BASE_DIR/openpilot"
|
||||
LOGS_DIR="$GITHUB_BASE_DIR/logs"
|
||||
CACHE_DIR="$GITHUB_BASE_DIR/cache"
|
||||
RUNNER_USERNAME="github-runner"
|
||||
# Define the systemd service name
|
||||
SERVICE_NAME="github-runner"
|
||||
USER_GROUPS="comma,gpu,gpio,sudo"
|
||||
|
||||
# Function to stop and disable the systemd service
|
||||
stop_and_uninstall_service() {
|
||||
cd $GITHUB_BASE_DIR/runner
|
||||
sudo ./svc.sh stop
|
||||
sudo ./svc.sh uninstall
|
||||
}
|
||||
|
||||
# Function to remove the systemd service file
|
||||
remove_runner() {
|
||||
cd $GITHUB_BASE_DIR/runner
|
||||
sudo rm .runner
|
||||
sudo su -c './config.sh remove' github-runner
|
||||
}
|
||||
|
||||
# Function to delete the Github Runner directories
|
||||
delete_directories() {
|
||||
sudo rm -rf "$BIN_DIR/github-runner"
|
||||
sudo rm -rf "$GITHUB_BASE_DIR" "$BIN_DIR" "$BUILDS_DIR" "$LOGS_DIR" "$CACHE_DIR" "$OPENPILOT_DIR"
|
||||
}
|
||||
|
||||
# Function to remove the Github Runner user
|
||||
delete_user() {
|
||||
for group in ${USER_GROUPS//,/ }
|
||||
do
|
||||
sudo gpasswd -d ${RUNNER_USERNAME} ${group}
|
||||
done
|
||||
sudo userdel -r ${RUNNER_USERNAME}
|
||||
}
|
||||
|
||||
# Function to remove sudoers entry
|
||||
remove_sudoers_entry() {
|
||||
sudo sed -i.bak "/${RUNNER_USERNAME} ALL=(ALL) NOPASSWD: ALL/d" /etc/sudoers
|
||||
}
|
||||
|
||||
# Make filesystem writable
|
||||
sudo mount -o remount rw /
|
||||
|
||||
# Ensure filesystem is remounted as read-only on script exit
|
||||
trap "sudo mount -o remount ro /" EXIT
|
||||
|
||||
# Call functions
|
||||
stop_and_uninstall_service
|
||||
remove_runner
|
||||
delete_directories
|
||||
delete_user
|
||||
remove_sudoers_entry
|
||||
# End of uninstall script
|
||||
@@ -23,6 +23,7 @@ blacklist = [
|
||||
whitelist: list[str] = [
|
||||
]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for f in Path(ROOT).rglob("**/*"):
|
||||
if not (f.is_file() or f.is_symlink()):
|
||||
|
||||
@@ -16,7 +16,7 @@ CRUMB=$(curl -s --cookie-jar $COOKIE_JAR 'https://jenkins.comma.life/crumbIssuer
|
||||
FIRST_LOOP=1
|
||||
|
||||
function loop() {
|
||||
JENKINS_BRANCH="__jenkins_loop_${BRANCH}"
|
||||
JENKINS_BRANCH="__jenkins_loop_${BRANCH}_$(date +%s)"
|
||||
API_ROUTE="https://jenkins.comma.life/job/openpilot/job/$JENKINS_BRANCH"
|
||||
|
||||
for run in $(seq 1 $((RUNS / 2))); do
|
||||
|
||||
@@ -13,7 +13,7 @@ cd $ROOT
|
||||
|
||||
FAILED=0
|
||||
|
||||
IGNORED_FILES="uv\.lock|docs\/CARS.md"
|
||||
IGNORED_FILES="uv\.lock|docs\/CARS.md|LICENSE\.md"
|
||||
IGNORED_DIRS="^third_party.*|^msgq.*|^msgq_repo.*|^opendbc.*|^opendbc_repo.*|^cereal.*|^panda.*|^rednose.*|^rednose_repo.*|^tinygrad.*|^tinygrad_repo.*|^teleoprtc.*|^teleoprtc_repo.*"
|
||||
|
||||
function run() {
|
||||
@@ -56,7 +56,7 @@ function run_tests() {
|
||||
|
||||
if [[ -z "$FAST" ]]; then
|
||||
run "mypy" mypy $PYTHON_FILES
|
||||
run "codespell" codespell $ALL_FILES
|
||||
run "codespell" codespell $ALL_FILES --ignore-words=$ROOT/.codespellignore
|
||||
fi
|
||||
|
||||
return $FAILED
|
||||
|
||||
27
scripts/manage-powersave.py
Executable file
27
scripts/manage-powersave.py
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import multiprocessing
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Control power saving mode')
|
||||
parser.add_argument('--enable', action='store_true', help='Enable power saving mode')
|
||||
parser.add_argument('--disable', action='store_true', help='Disable power saving mode')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.enable and args.disable:
|
||||
parser.error("Cannot specify both --enable and --disable")
|
||||
elif not (args.enable or args.disable):
|
||||
parser.error("Must specify either --enable or --disable")
|
||||
|
||||
print(f"Number of CPU cores available before: [{multiprocessing.cpu_count()}]")
|
||||
HARDWARE.set_power_save(args.enable)
|
||||
|
||||
state = "enabled" if args.enable else "disabled"
|
||||
print(f"Power save mode set to: [{state}]")
|
||||
print(f"Number of CPU cores available now: [{multiprocessing.cpu_count()}]")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,11 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from cereal import car, log
|
||||
from cereal import car, log, custom
|
||||
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper
|
||||
@@ -21,6 +22,10 @@ from opendbc.safety import ALTERNATIVE_EXPERIENCE
|
||||
from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp
|
||||
from openpilot.selfdrive.car.cruise import VCruiseHelper
|
||||
from openpilot.selfdrive.car.car_specific import MockCarState
|
||||
from openpilot.selfdrive.car.helpers import convert_carControlSP, convert_to_capnp
|
||||
|
||||
from openpilot.sunnypilot.mads.helpers import set_alternative_experience, set_car_specific_params
|
||||
from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfaces
|
||||
|
||||
REPLAY = "REPLAY" in os.environ
|
||||
|
||||
@@ -63,11 +68,13 @@ class Car:
|
||||
CI: CarInterfaceBase
|
||||
RI: RadarInterfaceBase
|
||||
CP: car.CarParams
|
||||
CP_SP: structs.CarParamsSP
|
||||
CP_SP_capnp: custom.CarParamsSP
|
||||
|
||||
def __init__(self, CI=None, RI=None) -> None:
|
||||
self.can_sock = messaging.sub_sock('can', timeout=20)
|
||||
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'])
|
||||
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'liveTracks'])
|
||||
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'] + ['carControlSP'])
|
||||
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'liveTracks'] + ['carParamsSP'])
|
||||
|
||||
self.can_rcv_cum_timeout_counter = 0
|
||||
|
||||
@@ -98,14 +105,18 @@ class Car:
|
||||
with car.CarParams.from_bytes(cached_params_raw) as _cached_params:
|
||||
cached_params = _cached_params
|
||||
|
||||
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), experimental_long_allowed, num_pandas, cached_params)
|
||||
self.RI = interfaces[self.CI.CP.carFingerprint].RadarInterface(self.CI.CP)
|
||||
fixed_fingerprint = json.loads(self.params.get("CarPlatformBundle", encoding='utf-8') or "{}").get("platform", None)
|
||||
|
||||
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), experimental_long_allowed, num_pandas, cached_params, fixed_fingerprint)
|
||||
sunnypilot_interfaces.setup_interfaces(self.CI.CP, self.CI.CP_SP, self.params)
|
||||
self.RI = interfaces[self.CI.CP.carFingerprint].RadarInterface(self.CI.CP, self.CI.CP_SP)
|
||||
self.CP = self.CI.CP
|
||||
self.CP_SP = self.CI.CP_SP
|
||||
|
||||
# continue onto next fingerprinting step in pandad
|
||||
self.params.put_bool("FirmwareQueryDone", True)
|
||||
else:
|
||||
self.CI, self.CP = CI, CI.CP
|
||||
self.CI, self.CP, self.CP_SP = CI, CI.CP, CI.CP_SP
|
||||
self.RI = RI
|
||||
|
||||
# set alternative experiences from parameters
|
||||
@@ -114,6 +125,13 @@ class Car:
|
||||
if not disengage_on_accelerator:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
|
||||
|
||||
# mads
|
||||
set_alternative_experience(self.CP, self.params)
|
||||
set_car_specific_params(self.CP, self.CP_SP, self.params)
|
||||
|
||||
# Dynamic Experimental Control
|
||||
self.dynamic_experimental_control = self.params.get_bool("DynamicExperimentalControl")
|
||||
|
||||
openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle")
|
||||
|
||||
controller_available = self.CI.CC is not None and openpilot_enabled_toggle and not self.CP.dashcamOnly
|
||||
@@ -156,6 +174,14 @@ class Car:
|
||||
self.params.put_nonblocking("CarParamsCache", cp_bytes)
|
||||
self.params.put_nonblocking("CarParamsPersistent", cp_bytes)
|
||||
|
||||
# Write CarParamsSP for controls
|
||||
# convert to pycapnp representation for caching and logging
|
||||
self.CP_SP_capnp = convert_to_capnp(self.CP_SP)
|
||||
cp_sp_bytes = self.CP_SP_capnp.to_bytes()
|
||||
self.params.put("CarParamsSP", cp_sp_bytes)
|
||||
self.params.put_nonblocking("CarParamsSPCache", cp_sp_bytes)
|
||||
self.params.put_nonblocking("CarParamsSPPersistent", cp_sp_bytes)
|
||||
|
||||
self.mock_carstate = MockCarState()
|
||||
self.v_cruise_helper = VCruiseHelper(self.CP)
|
||||
|
||||
@@ -165,6 +191,9 @@ class Car:
|
||||
# card is driven by can recv, expected at 100Hz
|
||||
self.rk = Ratekeeper(100, print_delay_threshold=None)
|
||||
|
||||
# log fingerprint in sentry
|
||||
sunnypilot_interfaces.log_fingerprint(self.CP)
|
||||
|
||||
def state_update(self) -> tuple[car.CarState, structs.RadarDataT | None]:
|
||||
"""carState update loop, driven by can"""
|
||||
|
||||
@@ -193,7 +222,7 @@ class Car:
|
||||
self.v_cruise_helper.update_v_cruise(CS, self.sm['carControl'].enabled, self.is_metric)
|
||||
if self.sm['carControl'].enabled and not self.CC_prev.enabled:
|
||||
# Use CarState w/ buttons from the step selfdrived enables on
|
||||
self.v_cruise_helper.initialize_v_cruise(self.CS_prev, self.experimental_mode)
|
||||
self.v_cruise_helper.initialize_v_cruise(self.CS_prev, self.experimental_mode, self.dynamic_experimental_control)
|
||||
|
||||
# TODO: mirror the carState.cruiseState struct?
|
||||
CS.vCruise = float(self.v_cruise_helper.v_cruise_kph)
|
||||
@@ -231,20 +260,28 @@ class Car:
|
||||
tracks_msg.liveTracks = RD
|
||||
self.pm.send('liveTracks', tracks_msg)
|
||||
|
||||
def controls_update(self, CS: car.CarState, CC: car.CarControl):
|
||||
# carParamsSP - logged every 50 seconds (> 1 per segment)
|
||||
if self.sm.frame % int(50. / DT_CTRL) == 0:
|
||||
cp_sp_send = messaging.new_message('carParamsSP')
|
||||
cp_sp_send.valid = True
|
||||
cp_sp_send.carParamsSP = self.CP_SP_capnp
|
||||
self.pm.send('carParamsSP', cp_sp_send)
|
||||
|
||||
def controls_update(self, CS: car.CarState, CC: car.CarControl, CC_SP: custom.CarControlSP):
|
||||
"""control update loop, driven by carControl"""
|
||||
|
||||
if not self.initialized_prev:
|
||||
# Initialize CarInterface, once controls are ready
|
||||
# TODO: this can make us miss at least a few cycles when doing an ECU knockout
|
||||
self.CI.init(self.CP, *self.can_callbacks)
|
||||
self.CI.init(self.CP, self.CP_SP, *self.can_callbacks)
|
||||
sunnypilot_interfaces.init_interfaces(self.CP, self.CP_SP, self.params, *self.can_callbacks)
|
||||
# signal pandad to switch to car safety mode
|
||||
self.params.put_bool_nonblocking("ControlsReady", True)
|
||||
|
||||
if self.sm.all_alive(['carControl']):
|
||||
# send car controls over can
|
||||
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
|
||||
self.last_actuators_output, can_sends = self.CI.apply(CC, now_nanos)
|
||||
self.last_actuators_output, can_sends = self.CI.apply(CC, convert_carControlSP(CC_SP), now_nanos)
|
||||
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))
|
||||
|
||||
self.CC_prev = CC
|
||||
@@ -257,7 +294,7 @@ class Car:
|
||||
initialized = (not any(e.name == EventName.selfdriveInitializing for e in self.sm['onroadEvents']) and
|
||||
self.sm.seen['onroadEvents'])
|
||||
if not self.CP.passive and initialized:
|
||||
self.controls_update(CS, self.sm['carControl'])
|
||||
self.controls_update(CS, self.sm['carControl'], self.sm['carControlSP'])
|
||||
|
||||
self.initialized_prev = initialized
|
||||
self.CS_prev = CS
|
||||
@@ -266,6 +303,10 @@ class Car:
|
||||
while not evt.is_set():
|
||||
self.is_metric = self.params.get_bool("IsMetric")
|
||||
self.experimental_mode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl
|
||||
|
||||
# sunnypilot
|
||||
self.dynamic_experimental_control = self.params.get_bool("DynamicExperimentalControl")
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
def card_thread(self):
|
||||
|
||||
@@ -123,12 +123,13 @@ class VCruiseHelper:
|
||||
self.button_timers[b.type.raw] = 1 if b.pressed else 0
|
||||
self.button_change_states[b.type.raw] = {"standstill": CS.cruiseState.standstill, "enabled": enabled}
|
||||
|
||||
def initialize_v_cruise(self, CS, experimental_mode: bool) -> None:
|
||||
def initialize_v_cruise(self, CS, experimental_mode: bool, dynamic_experimental_control: bool) -> None:
|
||||
# initializing is handled by the PCM
|
||||
if self.CP.pcmCruise:
|
||||
return
|
||||
|
||||
initial = V_CRUISE_INITIAL_EXPERIMENTAL_MODE if experimental_mode else V_CRUISE_INITIAL
|
||||
initial_experimental_mode = experimental_mode and not dynamic_experimental_control
|
||||
initial = V_CRUISE_INITIAL_EXPERIMENTAL_MODE if initial_experimental_mode else V_CRUISE_INITIAL
|
||||
|
||||
if any(b.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for b in CS.buttonEvents) and self.v_cruise_initialized:
|
||||
self.v_cruise_kph = self.v_cruise_kph_last
|
||||
|
||||
59
selfdrive/car/helpers.py
Normal file
59
selfdrive/car/helpers.py
Normal file
@@ -0,0 +1,59 @@
|
||||
import capnp
|
||||
from typing import Any
|
||||
|
||||
from cereal import custom
|
||||
from opendbc.car import structs
|
||||
|
||||
_FIELDS = '__dataclass_fields__' # copy of dataclasses._FIELDS
|
||||
|
||||
|
||||
def is_dataclass(obj):
|
||||
"""Similar to dataclasses.is_dataclass without instance type check checking"""
|
||||
return hasattr(obj, _FIELDS)
|
||||
|
||||
|
||||
def _asdictref_inner(obj) -> dict[str, Any] | Any:
|
||||
if is_dataclass(obj):
|
||||
ret = {}
|
||||
for field in getattr(obj, _FIELDS): # similar to dataclasses.fields()
|
||||
ret[field] = _asdictref_inner(getattr(obj, field))
|
||||
return ret
|
||||
elif isinstance(obj, (tuple, list)):
|
||||
return type(obj)(_asdictref_inner(v) for v in obj)
|
||||
else:
|
||||
return obj
|
||||
|
||||
|
||||
def asdictref(obj) -> dict[str, Any]:
|
||||
"""
|
||||
Similar to dataclasses.asdict without recursive type checking and copy.deepcopy
|
||||
Note that the resulting dict will contain references to the original struct as a result
|
||||
"""
|
||||
if not is_dataclass(obj):
|
||||
raise TypeError("asdictref() should be called on dataclass instances")
|
||||
|
||||
return _asdictref_inner(obj)
|
||||
|
||||
|
||||
def convert_to_capnp(struct: structs.CarParamsSP) -> capnp.lib.capnp._DynamicStructBuilder:
|
||||
struct_dict = asdictref(struct)
|
||||
|
||||
if isinstance(struct, structs.CarParamsSP):
|
||||
struct_capnp = custom.CarParamsSP.new_message(**struct_dict)
|
||||
else:
|
||||
raise ValueError(f"Unsupported struct type: {type(struct)}")
|
||||
|
||||
return struct_capnp
|
||||
|
||||
|
||||
def convert_carControlSP(struct: capnp.lib.capnp._DynamicStructReader) -> structs.CarControlSP:
|
||||
# TODO: recursively handle any car struct as needed
|
||||
def remove_deprecated(s: dict) -> dict:
|
||||
return {k: v for k, v in s.items() if not k.endswith('DEPRECATED')}
|
||||
|
||||
struct_dict = struct.to_dict()
|
||||
struct_dataclass = structs.CarControlSP(**remove_deprecated({k: v for k, v in struct_dict.items() if not isinstance(k, dict)}))
|
||||
|
||||
struct_dataclass.mads = structs.ModularAssistiveDrivingSystem(**remove_deprecated(struct_dict.get('mads', {})))
|
||||
|
||||
return struct_dataclass
|
||||
@@ -4,7 +4,7 @@ import hypothesis.strategies as st
|
||||
from hypothesis import Phase, given, settings
|
||||
from parameterized import parameterized
|
||||
|
||||
from cereal import car
|
||||
from cereal import car, custom
|
||||
from opendbc.car import DT_CTRL
|
||||
from opendbc.car.car_helpers import interfaces
|
||||
from opendbc.car.structs import CarParams
|
||||
@@ -12,12 +12,15 @@ from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface_args
|
||||
from opendbc.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS
|
||||
from opendbc.car.mock.values import CAR as MOCK
|
||||
from opendbc.car.values import PLATFORMS
|
||||
from openpilot.selfdrive.car.helpers import convert_carControlSP
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
||||
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
||||
from openpilot.selfdrive.test.fuzzy_generation import FuzzyGenerator
|
||||
|
||||
from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfaces
|
||||
|
||||
ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()}
|
||||
ALL_ECUS |= {ecu for config in FW_QUERY_CONFIGS.values() for ecu in config.extra_ecus}
|
||||
|
||||
@@ -40,9 +43,13 @@ class TestCarInterfaces:
|
||||
|
||||
car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'],
|
||||
experimental_long=args['experimental_long'], docs=False)
|
||||
car_params_sp = CarInterface.get_params_sp(car_params, car_name, args['fingerprints'], args['car_fw'],
|
||||
experimental_long=args['experimental_long'], docs=False)
|
||||
sunnypilot_interfaces.setup_interfaces(car_params, car_params_sp)
|
||||
car_params = car_params.as_reader()
|
||||
car_interface = CarInterface(car_params)
|
||||
car_interface = CarInterface(car_params, car_params_sp)
|
||||
assert car_params
|
||||
assert car_params_sp
|
||||
assert car_interface
|
||||
|
||||
assert car_params.mass > 1
|
||||
@@ -69,13 +76,16 @@ class TestCarInterfaces:
|
||||
assert not math.isnan(tune.torque.friction) and tune.torque.friction > 0
|
||||
|
||||
cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True)
|
||||
cc_sp_msg = FuzzyGenerator.get_random_msg(data.draw, custom.CarControlSP, real_floats=True)
|
||||
# Run car interface
|
||||
now_nanos = 0
|
||||
CC = car.CarControl.new_message(**cc_msg)
|
||||
CC = CC.as_reader()
|
||||
CC_SP = custom.CarControlSP.new_message(**cc_sp_msg)
|
||||
CC_SP = convert_carControlSP(CC_SP.as_reader())
|
||||
for _ in range(10):
|
||||
car_interface.update([])
|
||||
car_interface.apply(CC, now_nanos)
|
||||
car_interface.apply(CC, CC_SP, now_nanos)
|
||||
now_nanos += DT_CTRL * 1e9 # 10 ms
|
||||
|
||||
CC = car.CarControl.new_message(**cc_msg)
|
||||
@@ -85,7 +95,7 @@ class TestCarInterfaces:
|
||||
CC = CC.as_reader()
|
||||
for _ in range(10):
|
||||
car_interface.update([])
|
||||
car_interface.apply(CC, now_nanos)
|
||||
car_interface.apply(CC, CC_SP, now_nanos)
|
||||
now_nanos += DT_CTRL * 1e9 # 10ms
|
||||
|
||||
# Test controller initialization
|
||||
@@ -93,8 +103,8 @@ class TestCarInterfaces:
|
||||
# hypothesis also slows down significantly with just one more message draw
|
||||
LongControl(car_params)
|
||||
if car_params.steerControlType == CarParams.SteerControlType.angle:
|
||||
LatControlAngle(car_params, car_interface)
|
||||
LatControlAngle(car_params, car_params_sp, car_interface)
|
||||
elif car_params.lateralTuning.which() == 'pid':
|
||||
LatControlPID(car_params, car_interface)
|
||||
LatControlPID(car_params, car_params_sp, car_interface)
|
||||
elif car_params.lateralTuning.which() == 'torque':
|
||||
LatControlTorque(car_params, car_interface)
|
||||
LatControlTorque(car_params, car_params_sp, car_interface)
|
||||
|
||||
@@ -57,16 +57,16 @@ class TestVCruiseHelper:
|
||||
for _ in range(2):
|
||||
self.v_cruise_helper.update_v_cruise(car.CarState(cruiseState={"available": False}), enabled=False, is_metric=False)
|
||||
|
||||
def enable(self, v_ego, experimental_mode):
|
||||
def enable(self, v_ego, experimental_mode, dynamic_experimental_control):
|
||||
# Simulates user pressing set with a current speed
|
||||
self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=v_ego), experimental_mode)
|
||||
self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=v_ego), experimental_mode, dynamic_experimental_control)
|
||||
|
||||
def test_adjust_speed(self):
|
||||
"""
|
||||
Asserts speed changes on falling edges of buttons.
|
||||
"""
|
||||
|
||||
self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False)
|
||||
self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False, False)
|
||||
|
||||
for btn in (ButtonType.accelCruise, ButtonType.decelCruise):
|
||||
for pressed in (True, False):
|
||||
@@ -90,7 +90,7 @@ class TestVCruiseHelper:
|
||||
CS.buttonEvents = [ButtonEvent(type=ButtonType.decelCruise, pressed=pressed)]
|
||||
self.v_cruise_helper.update_v_cruise(CS, enabled=enabled, is_metric=False)
|
||||
if pressed:
|
||||
self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False)
|
||||
self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False, False)
|
||||
|
||||
# Expected diff on enabling. Speed should not change on falling edge of pressed
|
||||
assert not pressed == self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last
|
||||
@@ -100,7 +100,7 @@ class TestVCruiseHelper:
|
||||
Asserts we don't increment set speed if user presses resume/accel to exit cruise standstill.
|
||||
"""
|
||||
|
||||
self.enable(0, False)
|
||||
self.enable(0, False, False)
|
||||
|
||||
for standstill in (True, False):
|
||||
for pressed in (True, False):
|
||||
@@ -120,7 +120,7 @@ class TestVCruiseHelper:
|
||||
|
||||
for v_ego in np.linspace(0, 100, 101):
|
||||
self.reset_cruise_speed_state()
|
||||
self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False)
|
||||
self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False, False)
|
||||
|
||||
# first decrement speed, then perform gas pressed logic
|
||||
expected_v_cruise_kph = self.v_cruise_helper.v_cruise_kph - IMPERIAL_INCREMENT
|
||||
@@ -142,10 +142,11 @@ class TestVCruiseHelper:
|
||||
"""
|
||||
|
||||
for experimental_mode in (True, False):
|
||||
for v_ego in np.linspace(0, 100, 101):
|
||||
self.reset_cruise_speed_state()
|
||||
assert not self.v_cruise_helper.v_cruise_initialized
|
||||
for dynamic_experimental_control in (True, False):
|
||||
for v_ego in np.linspace(0, 100, 101):
|
||||
self.reset_cruise_speed_state()
|
||||
assert not self.v_cruise_helper.v_cruise_initialized
|
||||
|
||||
self.enable(float(v_ego), experimental_mode)
|
||||
assert V_CRUISE_INITIAL <= self.v_cruise_helper.v_cruise_kph <= V_CRUISE_MAX
|
||||
assert self.v_cruise_helper.v_cruise_initialized
|
||||
self.enable(float(v_ego), experimental_mode, dynamic_experimental_control)
|
||||
assert V_CRUISE_INITIAL <= self.v_cruise_helper.v_cruise_kph <= V_CRUISE_MAX
|
||||
assert self.v_cruise_helper.v_cruise_initialized
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import time
|
||||
import copy
|
||||
import os
|
||||
import pytest
|
||||
import random
|
||||
@@ -153,7 +154,9 @@ class TestCarModelBase(unittest.TestCase):
|
||||
|
||||
cls.CarInterface = interfaces[cls.platform]
|
||||
cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False)
|
||||
cls.CP_SP = cls.CarInterface.get_params_sp(cls.CP, cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False)
|
||||
assert cls.CP
|
||||
assert cls.CP_SP
|
||||
assert cls.CP.carFingerprint == cls.platform
|
||||
|
||||
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||
@@ -163,12 +166,15 @@ class TestCarModelBase(unittest.TestCase):
|
||||
del cls.can_msgs
|
||||
|
||||
def setUp(self):
|
||||
self.CI = self.CarInterface(self.CP.copy())
|
||||
self.CI = self.CarInterface(self.CP.copy(), copy.deepcopy(self.CP_SP))
|
||||
assert self.CI
|
||||
|
||||
# TODO: check safetyModel is in release panda build
|
||||
self.safety = libsafety_py.libsafety
|
||||
|
||||
safety_param_sp = self.CP_SP.safetyParam
|
||||
self.safety.set_current_safety_param_sp(safety_param_sp)
|
||||
|
||||
cfg = self.CP.safetyConfigs[-1]
|
||||
set_status = self.safety.set_safety_hooks(cfg.safetyModel.raw, cfg.safetyParam)
|
||||
self.assertEqual(0, set_status, f"failed to set safetyModel {cfg}")
|
||||
@@ -195,10 +201,11 @@ class TestCarModelBase(unittest.TestCase):
|
||||
can_invalid_cnt = 0
|
||||
can_valid = False
|
||||
CC = structs.CarControl().as_reader()
|
||||
CC_SP = structs.CarControlSP()
|
||||
|
||||
for i, msg in enumerate(self.can_msgs):
|
||||
CS = self.CI.update(msg)
|
||||
self.CI.apply(CC, msg[0])
|
||||
self.CI.apply(CC, CC_SP, msg[0])
|
||||
|
||||
if CS.canValid:
|
||||
can_valid = True
|
||||
@@ -210,7 +217,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
self.assertEqual(can_invalid_cnt, 0)
|
||||
|
||||
def test_radar_interface(self):
|
||||
RI = self.CarInterface.RadarInterface(self.CP)
|
||||
RI = self.CarInterface.RadarInterface(self.CP, self.CP_SP)
|
||||
assert RI
|
||||
|
||||
# Since OBD port is multiplexed to bus 1 (commonly radar bus) while fingerprinting,
|
||||
@@ -270,13 +277,13 @@ class TestCarModelBase(unittest.TestCase):
|
||||
if self.CP.notCar:
|
||||
self.skipTest("Skipping test for notCar")
|
||||
|
||||
def test_car_controller(car_control):
|
||||
def test_car_controller(car_control, car_control_sp):
|
||||
now_nanos = 0
|
||||
msgs_sent = 0
|
||||
CI = self.CarInterface(self.CP)
|
||||
CI = self.CarInterface(self.CP, self.CP_SP)
|
||||
for _ in range(round(10.0 / DT_CTRL)): # make sure we hit the slowest messages
|
||||
CI.update([])
|
||||
_, sendcan = CI.apply(car_control, now_nanos)
|
||||
_, sendcan = CI.apply(car_control, car_control_sp, now_nanos)
|
||||
|
||||
now_nanos += DT_CTRL * 1e9
|
||||
msgs_sent += len(sendcan)
|
||||
@@ -289,17 +296,18 @@ class TestCarModelBase(unittest.TestCase):
|
||||
|
||||
# Make sure we can send all messages while inactive
|
||||
CC = structs.CarControl()
|
||||
test_car_controller(CC.as_reader())
|
||||
CC_SP = structs.CarControlSP()
|
||||
test_car_controller(CC.as_reader(), CC_SP)
|
||||
|
||||
# Test cancel + general messages (controls_allowed=False & cruise_engaged=True)
|
||||
self.safety.set_cruise_engaged_prev(True)
|
||||
CC = structs.CarControl(cruiseControl=structs.CarControl.CruiseControl(cancel=True))
|
||||
test_car_controller(CC.as_reader())
|
||||
test_car_controller(CC.as_reader(), CC_SP)
|
||||
|
||||
# Test resume + general messages (controls_allowed=True & cruise_engaged=True)
|
||||
self.safety.set_controls_allowed(True)
|
||||
CC = structs.CarControl(cruiseControl=structs.CarControl.CruiseControl(resume=True))
|
||||
test_car_controller(CC.as_reader())
|
||||
test_car_controller(CC.as_reader(), CC_SP)
|
||||
|
||||
# Skip stdout/stderr capture with pytest, causes elevated memory usage
|
||||
@pytest.mark.nocapture
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import math
|
||||
from typing import SupportsFloat
|
||||
|
||||
from cereal import car, log
|
||||
from cereal import car, log, custom
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.params import Params
|
||||
@@ -12,7 +12,7 @@ from openpilot.common.swaglog import cloudlog
|
||||
from opendbc.car.car_helpers import interfaces
|
||||
from opendbc.car.vehicle_model import VehicleModel
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import clip_curvature
|
||||
from openpilot.selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED
|
||||
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle, STEER_ANGLE_SATURATION_THRESHOLD
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
||||
@@ -33,14 +33,20 @@ class Controls:
|
||||
self.CP = messaging.log_from_bytes(self.params.get("CarParams", block=True), car.CarParams)
|
||||
cloudlog.info("controlsd got CarParams")
|
||||
|
||||
self.CI = interfaces[self.CP.carFingerprint](self.CP)
|
||||
cloudlog.info("controlsd is waiting for CarParamsSP")
|
||||
self.CP_SP = messaging.log_from_bytes(self.params.get("CarParamsSP", block=True), custom.CarParamsSP)
|
||||
cloudlog.info("controlsd got CarParamsSP")
|
||||
|
||||
self.CI = interfaces[self.CP.carFingerprint](self.CP, self.CP_SP)
|
||||
|
||||
self.sm = messaging.SubMaster(['liveParameters', 'liveTorqueParameters', 'modelV2', 'selfdriveState',
|
||||
'liveCalibration', 'livePose', 'longitudinalPlan', 'carState', 'carOutput',
|
||||
'driverMonitoringState', 'onroadEvents', 'driverAssistance'], poll='selfdriveState')
|
||||
self.pm = messaging.PubMaster(['carControl', 'controlsState'])
|
||||
'driverMonitoringState', 'onroadEvents', 'driverAssistance'] + ['selfdriveStateSP'],
|
||||
poll='selfdriveState')
|
||||
self.pm = messaging.PubMaster(['carControl', 'controlsState'] + ['carControlSP'])
|
||||
|
||||
self.steer_limited_by_controls = False
|
||||
self.curvature = 0.0
|
||||
self.desired_curvature = 0.0
|
||||
|
||||
self.pose_calibrator = PoseCalibrator()
|
||||
@@ -50,11 +56,11 @@ class Controls:
|
||||
self.VM = VehicleModel(self.CP)
|
||||
self.LaC: LatControl
|
||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||
self.LaC = LatControlAngle(self.CP, self.CI)
|
||||
self.LaC = LatControlAngle(self.CP, self.CP_SP, self.CI)
|
||||
elif self.CP.lateralTuning.which() == 'pid':
|
||||
self.LaC = LatControlPID(self.CP, self.CI)
|
||||
self.LaC = LatControlPID(self.CP, self.CP_SP, self.CI)
|
||||
elif self.CP.lateralTuning.which() == 'torque':
|
||||
self.LaC = LatControlTorque(self.CP, self.CI)
|
||||
self.LaC = LatControlTorque(self.CP, self.CP_SP, self.CI)
|
||||
|
||||
def update(self):
|
||||
self.sm.update(15)
|
||||
@@ -73,6 +79,9 @@ class Controls:
|
||||
sr = max(lp.steerRatio, 0.1)
|
||||
self.VM.update_params(x, sr)
|
||||
|
||||
steer_angle_without_offset = math.radians(CS.steeringAngleDeg - lp.angleOffsetDeg)
|
||||
self.curvature = -self.VM.calc_curvature(steer_angle_without_offset, CS.vEgo, lp.roll)
|
||||
|
||||
# Update Torque Params
|
||||
if self.CP.lateralTuning.which() == 'torque':
|
||||
torque_params = self.sm['liveTorqueParameters']
|
||||
@@ -80,6 +89,8 @@ class Controls:
|
||||
self.LaC.update_live_torque_params(torque_params.latAccelFactorFiltered, torque_params.latAccelOffsetFiltered,
|
||||
torque_params.frictionCoefficientFiltered)
|
||||
|
||||
self.LaC.extension.update_model_v2(self.sm['modelV2'])
|
||||
|
||||
long_plan = self.sm['longitudinalPlan']
|
||||
model_v2 = self.sm['modelV2']
|
||||
|
||||
@@ -87,8 +98,16 @@ class Controls:
|
||||
CC.enabled = self.sm['selfdriveState'].enabled
|
||||
|
||||
# Check which actuators can be enabled
|
||||
standstill = abs(CS.vEgo) <= max(self.CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED) or CS.standstill
|
||||
CC.latActive = self.sm['selfdriveState'].active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and not standstill
|
||||
standstill = abs(CS.vEgo) <= max(self.CP.minSteerSpeed, 0.3) or CS.standstill
|
||||
|
||||
ss_sp = self.sm['selfdriveStateSP']
|
||||
if ss_sp.mads.available:
|
||||
_lat_active = ss_sp.mads.active
|
||||
else:
|
||||
_lat_active = self.sm['selfdriveState'].active
|
||||
|
||||
CC.latActive = _lat_active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
|
||||
(not standstill or self.CP.steerAtStandstill)
|
||||
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in self.sm['onroadEvents']) and self.CP.openpilotLongitudinalControl
|
||||
|
||||
actuators = CC.actuators
|
||||
@@ -109,7 +128,10 @@ class Controls:
|
||||
actuators.accel = float(self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop, pid_accel_limits))
|
||||
|
||||
# Steering PID loop and lateral MPC
|
||||
self.desired_curvature, curvature_limited = clip_curvature(CS.vEgo, self.desired_curvature, model_v2.action.desiredCurvature, lp.roll)
|
||||
# Reset desired curvature to current to avoid violating the limits on engage
|
||||
new_desired_curvature = model_v2.action.desiredCurvature if CC.latActive else self.curvature
|
||||
self.desired_curvature, curvature_limited = clip_curvature(CS.vEgo, self.desired_curvature, new_desired_curvature, lp.roll)
|
||||
|
||||
actuators.curvature = self.desired_curvature
|
||||
steer, steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp,
|
||||
self.steer_limited_by_controls, self.desired_curvature,
|
||||
@@ -126,9 +148,12 @@ class Controls:
|
||||
cloudlog.error(f"actuators.{p} not finite {actuators.to_dict()}")
|
||||
setattr(actuators, p, 0.0)
|
||||
|
||||
return CC, lac_log
|
||||
CC_SP = custom.CarControlSP.new_message()
|
||||
CC_SP.mads = ss_sp.mads
|
||||
|
||||
def publish(self, CC, lac_log):
|
||||
return CC, CC_SP, lac_log
|
||||
|
||||
def publish(self, CC, CC_SP, lac_log):
|
||||
CS = self.sm['carState']
|
||||
|
||||
# Orientation and angle rates can be useful for carcontroller
|
||||
@@ -174,10 +199,7 @@ class Controls:
|
||||
dat.valid = CS.canValid
|
||||
cs = dat.controlsState
|
||||
|
||||
lp = self.sm['liveParameters']
|
||||
steer_angle_without_offset = math.radians(CS.steeringAngleDeg - lp.angleOffsetDeg)
|
||||
cs.curvature = -self.VM.calc_curvature(steer_angle_without_offset, CS.vEgo, lp.roll)
|
||||
|
||||
cs.curvature = self.curvature
|
||||
cs.longitudinalPlanMonoTime = self.sm.logMonoTime['longitudinalPlan']
|
||||
cs.lateralPlanMonoTime = self.sm.logMonoTime['modelV2']
|
||||
cs.desiredCurvature = self.desired_curvature
|
||||
@@ -204,12 +226,18 @@ class Controls:
|
||||
cc_send.carControl = CC
|
||||
self.pm.send('carControl', cc_send)
|
||||
|
||||
# carControlSP
|
||||
cc_sp_send = messaging.new_message('carControlSP')
|
||||
cc_sp_send.valid = CS.canValid
|
||||
cc_sp_send.carControlSP = CC_SP
|
||||
self.pm.send('carControlSP', cc_sp_send)
|
||||
|
||||
def run(self):
|
||||
rk = Ratekeeper(100, print_delay_threshold=None)
|
||||
while True:
|
||||
self.update()
|
||||
CC, lac_log = self.state_control()
|
||||
self.publish(CC, lac_log)
|
||||
CC, CC_SP, lac_log = self.state_control()
|
||||
self.publish(CC, CC_SP, lac_log)
|
||||
rk.monitor_time()
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from cereal import log
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.realtime import DT_MDL
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.auto_lane_change import AutoLaneChangeController
|
||||
|
||||
LaneChangeState = log.LaneChangeState
|
||||
LaneChangeDirection = log.LaneChangeDirection
|
||||
@@ -39,8 +40,10 @@ class DesireHelper:
|
||||
self.keep_pulse_timer = 0.0
|
||||
self.prev_one_blinker = False
|
||||
self.desire = log.Desire.none
|
||||
self.alc = AutoLaneChangeController(self)
|
||||
|
||||
def update(self, carstate, lateral_active, lane_change_prob):
|
||||
self.alc.update_params()
|
||||
v_ego = carstate.vEgo
|
||||
one_blinker = carstate.leftBlinker != carstate.rightBlinker
|
||||
below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN
|
||||
@@ -67,10 +70,12 @@ class DesireHelper:
|
||||
blindspot_detected = ((carstate.leftBlindspot and self.lane_change_direction == LaneChangeDirection.left) or
|
||||
(carstate.rightBlindspot and self.lane_change_direction == LaneChangeDirection.right))
|
||||
|
||||
self.alc.update_lane_change(blindspot_detected, carstate.brakePressed)
|
||||
|
||||
if not one_blinker or below_lane_change_speed:
|
||||
self.lane_change_state = LaneChangeState.off
|
||||
self.lane_change_direction = LaneChangeDirection.none
|
||||
elif torque_applied and not blindspot_detected:
|
||||
elif (torque_applied or self.alc.auto_lane_change_allowed) and not blindspot_detected:
|
||||
self.lane_change_state = LaneChangeState.laneChangeStarting
|
||||
|
||||
# LaneChangeState.laneChangeStarting
|
||||
@@ -112,3 +117,5 @@ class DesireHelper:
|
||||
self.keep_pulse_timer = 0.0
|
||||
elif self.desire in (log.Desire.keepLeft, log.Desire.keepRight):
|
||||
self.desire = log.Desire.none
|
||||
|
||||
self.alc.update_state()
|
||||
|
||||
@@ -3,11 +3,9 @@ from abc import abstractmethod, ABC
|
||||
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
|
||||
MIN_LATERAL_CONTROL_SPEED = 0.3 # m/s
|
||||
|
||||
|
||||
class LatControl(ABC):
|
||||
def __init__(self, CP, CI):
|
||||
def __init__(self, CP, CP_SP, CI):
|
||||
self.sat_count_rate = 1.0 * DT_CTRL
|
||||
self.sat_limit = CP.steerLimitTimer
|
||||
self.sat_count = 0.
|
||||
|
||||
@@ -7,8 +7,8 @@ STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees
|
||||
|
||||
|
||||
class LatControlAngle(LatControl):
|
||||
def __init__(self, CP, CI):
|
||||
super().__init__(CP, CI)
|
||||
def __init__(self, CP, CP_SP, CI):
|
||||
super().__init__(CP, CP_SP, CI)
|
||||
self.sat_check_min_speed = 5.
|
||||
|
||||
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
|
||||
|
||||
@@ -6,8 +6,8 @@ from openpilot.common.pid import PIDController
|
||||
|
||||
|
||||
class LatControlPID(LatControl):
|
||||
def __init__(self, CP, CI):
|
||||
super().__init__(CP, CI)
|
||||
def __init__(self, CP, CP_SP, CI):
|
||||
super().__init__(CP, CP_SP, CI)
|
||||
self.pid = PIDController((CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV),
|
||||
(CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV),
|
||||
k_f=CP.lateralTuning.pid.kf, pos_limit=self.steer_max, neg_limit=-self.steer_max)
|
||||
|
||||
@@ -7,6 +7,8 @@ from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
||||
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
|
||||
from openpilot.common.pid import PIDController
|
||||
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.latcontrol_torque_ext import LatControlTorqueExt
|
||||
|
||||
# At higher speeds (25+mph) we can assume:
|
||||
# Lateral acceleration achieved by a specific car correlates to
|
||||
# torque applied to the steering rack. It does not correlate to
|
||||
@@ -23,8 +25,8 @@ LOW_SPEED_Y = [15, 13, 10, 5]
|
||||
|
||||
|
||||
class LatControlTorque(LatControl):
|
||||
def __init__(self, CP, CI):
|
||||
super().__init__(CP, CI)
|
||||
def __init__(self, CP, CP_SP, CI):
|
||||
super().__init__(CP, CP_SP, CI)
|
||||
self.torque_params = CP.lateralTuning.torque.as_builder()
|
||||
self.pid = PIDController(self.torque_params.kp, self.torque_params.ki,
|
||||
k_f=self.torque_params.kf, pos_limit=self.steer_max, neg_limit=-self.steer_max)
|
||||
@@ -32,6 +34,8 @@ class LatControlTorque(LatControl):
|
||||
self.use_steering_angle = self.torque_params.useSteeringAngle
|
||||
self.steering_angle_deadzone_deg = self.torque_params.steeringAngleDeadzoneDeg
|
||||
|
||||
self.extension = LatControlTorqueExt(self, CP, CP_SP)
|
||||
|
||||
def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction):
|
||||
self.torque_params.latAccelFactor = latAccelFactor
|
||||
self.torque_params.latAccelOffset = latAccelOffset
|
||||
@@ -73,6 +77,11 @@ class LatControlTorque(LatControl):
|
||||
desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, friction_compensation=True,
|
||||
gravity_adjusted=True)
|
||||
|
||||
# Lateral acceleration torque controller extension updates
|
||||
# Overrides stock ff and pid_log.error
|
||||
ff, pid_log = self.extension.update(CS, VM, params, ff, pid_log, setpoint, measurement, calibrated_pose, roll_compensation,
|
||||
desired_lateral_accel, actual_lateral_accel, lateral_accel_deadzone, gravity_adjusted_lateral_accel)
|
||||
|
||||
freeze_integrator = steer_limited_by_controls or CS.steeringPressed or CS.vEgo < 5
|
||||
output_torque = self.pid.update(pid_log.error,
|
||||
feedforward=ff,
|
||||
|
||||
@@ -15,6 +15,8 @@ from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, get_speed_
|
||||
from openpilot.selfdrive.car.cruise import V_CRUISE_MAX, V_CRUISE_UNSET
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.longitudinal_planner import LongitudinalPlannerSP
|
||||
|
||||
LON_MPC_STEP = 0.2 # first step is 0.2s
|
||||
A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6]
|
||||
A_CRUISE_MAX_BP = [0., 10.0, 25., 40.]
|
||||
@@ -65,10 +67,11 @@ def get_accel_from_plan(speeds, accels, action_t=DT_MDL, vEgoStopping=0.05):
|
||||
return a_target, should_stop
|
||||
|
||||
|
||||
class LongitudinalPlanner:
|
||||
class LongitudinalPlanner(LongitudinalPlannerSP):
|
||||
def __init__(self, CP, init_v=0.0, init_a=0.0, dt=DT_MDL):
|
||||
self.CP = CP
|
||||
self.mpc = LongitudinalMpc(dt=dt)
|
||||
LongitudinalPlannerSP.__init__(self, self.CP, self.mpc)
|
||||
self.fcw = False
|
||||
self.dt = dt
|
||||
self.allow_throttle = True
|
||||
@@ -106,7 +109,10 @@ class LongitudinalPlanner:
|
||||
return x, v, a, j, throttle_prob
|
||||
|
||||
def update(self, sm):
|
||||
LongitudinalPlannerSP.update(self, sm)
|
||||
self.mpc.mode = 'blended' if sm['selfdriveState'].experimentalMode else 'acc'
|
||||
if dec_mpc_mode := self.get_mpc_mode():
|
||||
self.mpc.mode = dec_mpc_mode
|
||||
|
||||
if len(sm['carControl'].orientationNED) == 3:
|
||||
accel_coast = get_coast_accel(sm['carControl'].orientationNED[1])
|
||||
@@ -208,3 +214,5 @@ class LongitudinalPlanner:
|
||||
longitudinalPlan.allowThrottle = bool(self.allow_throttle)
|
||||
|
||||
pm.send('longitudinalPlan', plan_send)
|
||||
|
||||
self.publish_longitudinal_plan_sp(sm, pm)
|
||||
|
||||
@@ -6,11 +6,13 @@ from opendbc.car.honda.values import CAR as HONDA
|
||||
from opendbc.car.toyota.values import CAR as TOYOTA
|
||||
from opendbc.car.nissan.values import CAR as NISSAN
|
||||
from opendbc.car.vehicle_model import VehicleModel
|
||||
from openpilot.selfdrive.car.helpers import convert_to_capnp
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle
|
||||
from openpilot.selfdrive.locationd.helpers import Pose
|
||||
from openpilot.common.mock.generators import generate_livePose
|
||||
from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfaces
|
||||
|
||||
|
||||
class TestLatControl:
|
||||
@@ -19,10 +21,13 @@ class TestLatControl:
|
||||
def test_saturation(self, car_name, controller):
|
||||
CarInterface = interfaces[car_name]
|
||||
CP = CarInterface.get_non_essential_params(car_name)
|
||||
CI = CarInterface(CP)
|
||||
CP_SP = CarInterface.get_non_essential_params_sp(CP, car_name)
|
||||
CI = CarInterface(CP, CP_SP)
|
||||
sunnypilot_interfaces.setup_interfaces(CP, CP_SP)
|
||||
CP_SP = convert_to_capnp(CP_SP)
|
||||
VM = VehicleModel(CP)
|
||||
|
||||
controller = controller(CP.as_reader(), CI)
|
||||
controller = controller(CP.as_reader(), CP_SP.as_reader(), CI)
|
||||
|
||||
CS = car.CarState.new_message()
|
||||
CS.vEgo = 30
|
||||
|
||||
@@ -18,7 +18,7 @@ def main():
|
||||
|
||||
ldw = LaneDepartureWarning()
|
||||
longitudinal_planner = LongitudinalPlanner(CP)
|
||||
pm = messaging.PubMaster(['longitudinalPlan', 'driverAssistance'])
|
||||
pm = messaging.PubMaster(['longitudinalPlan', 'driverAssistance', 'longitudinalPlanSP'])
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState'],
|
||||
poll='modelV2')
|
||||
|
||||
|
||||
@@ -5,13 +5,17 @@ from collections import deque
|
||||
from typing import Any
|
||||
|
||||
import capnp
|
||||
from cereal import messaging, log, car
|
||||
from cereal import messaging, log, car, custom
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_MDL, Priority, config_realtime_process
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.common.simple_kalman import KF1D
|
||||
|
||||
from opendbc.car import structs
|
||||
from opendbc.car.hyundai.values import HyundaiFlags
|
||||
from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
|
||||
|
||||
|
||||
# Default lead acceleration decay set to 50% at 1s
|
||||
_LEAD_ACCEL_TAU = 1.5
|
||||
@@ -157,7 +161,7 @@ def get_RadarState_from_vision(lead_msg: capnp._DynamicStructReader, v_ego: floa
|
||||
|
||||
|
||||
def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capnp._DynamicStructReader,
|
||||
model_v_ego: float, low_speed_override: bool = True) -> dict[str, Any]:
|
||||
model_v_ego: float, CP: structs.CarParams, CP_SP: structs.CarParamsSP, low_speed_override: bool = True) -> dict[str, Any]:
|
||||
# Determine leads, this is where the essential logic happens
|
||||
if len(tracks) > 0 and ready and lead_msg.prob > .5:
|
||||
track = match_vision_to_track(v_ego, lead_msg, tracks)
|
||||
@@ -167,6 +171,7 @@ def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capn
|
||||
lead_dict = {'status': False}
|
||||
if track is not None:
|
||||
lead_dict = track.get_RadarState(lead_msg.prob)
|
||||
lead_dict = get_custom_yrel(CP, CP_SP, lead_dict, lead_msg)
|
||||
elif (track is None) and ready and (lead_msg.prob > .5):
|
||||
lead_dict = get_RadarState_from_vision(lead_msg, v_ego, model_v_ego)
|
||||
|
||||
@@ -182,8 +187,20 @@ def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capn
|
||||
return lead_dict
|
||||
|
||||
|
||||
def get_custom_yrel(CP: structs.CarParams, CP_SP: structs.CarParamsSP, lead_dict: dict[str, Any],
|
||||
lead_msg: capnp._DynamicStructReader) -> dict[str, Any]:
|
||||
if CP.brand == "hyundai" and (CP_SP.flags & HyundaiFlagsSP.ENHANCED_SCC or
|
||||
CP.flags & (HyundaiFlags.CANFD_CAMERA_SCC | HyundaiFlags.CAMERA_SCC)):
|
||||
lead_dict['yRel'] = float(-lead_msg.y[0])
|
||||
|
||||
return lead_dict
|
||||
|
||||
|
||||
class RadarD:
|
||||
def __init__(self, delay: float = 0.0):
|
||||
def __init__(self, CP: structs.CarParams, CP_SP: structs.CarParams, delay: float = 0.0):
|
||||
self.CP = CP
|
||||
self.CP_SP = CP_SP
|
||||
|
||||
self.current_time = 0.0
|
||||
|
||||
self.tracks: dict[int, Track] = {}
|
||||
@@ -239,8 +256,8 @@ class RadarD:
|
||||
model_v_ego = self.v_ego
|
||||
leads_v3 = sm['modelV2'].leadsV3
|
||||
if len(leads_v3) > 1:
|
||||
self.radar_state.leadOne = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[0], model_v_ego, low_speed_override=True)
|
||||
self.radar_state.leadTwo = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[1], model_v_ego, low_speed_override=False)
|
||||
self.radar_state.leadOne = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[0], model_v_ego, self.CP, self.CP_SP, low_speed_override=True)
|
||||
self.radar_state.leadTwo = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[1], model_v_ego, self.CP, self.CP_SP, low_speed_override=False)
|
||||
|
||||
def publish(self, pm: messaging.PubMaster):
|
||||
assert self.radar_state is not None
|
||||
@@ -260,11 +277,15 @@ def main() -> None:
|
||||
CP = messaging.log_from_bytes(Params().get("CarParams", block=True), car.CarParams)
|
||||
cloudlog.info("radard got CarParams")
|
||||
|
||||
cloudlog.info("radard is waiting for CarParamsSP")
|
||||
CP_SP = messaging.log_from_bytes(Params().get("CarParamsSP", block=True), custom.CarParamsSP)
|
||||
cloudlog.info("radard got CarParamsSP")
|
||||
|
||||
# *** setup messaging
|
||||
sm = messaging.SubMaster(['modelV2', 'carState', 'liveTracks'], poll='modelV2')
|
||||
pm = messaging.PubMaster(['radarState'])
|
||||
|
||||
RD = RadarD(CP.radarDelay)
|
||||
RD = RadarD(CP, CP_SP, CP.radarDelay)
|
||||
|
||||
while 1:
|
||||
sm.update()
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import argparse
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from functools import partial
|
||||
from tqdm import tqdm
|
||||
from typing import NamedTuple
|
||||
from openpilot.tools.lib.logreader import LogReader
|
||||
from openpilot.selfdrive.locationd.models.pose_kf import EARTH_G
|
||||
@@ -20,14 +22,15 @@ class Event(NamedTuple):
|
||||
timestamp: float # relative to start of route (s)
|
||||
|
||||
|
||||
def find_events(lr: LogReader, qlog: bool = False) -> list[Event]:
|
||||
def find_events(lr: LogReader, extrapolate: bool = False, qlog: bool = False) -> list[Event]:
|
||||
min_lat_active = RLOG_MIN_LAT_ACTIVE // QLOG_DECIMATION if qlog else RLOG_MIN_LAT_ACTIVE
|
||||
min_steering_unpressed = RLOG_MIN_STEERING_UNPRESSED // QLOG_DECIMATION if qlog else RLOG_MIN_STEERING_UNPRESSED
|
||||
min_requesting_max = RLOG_MIN_REQUESTING_MAX // QLOG_DECIMATION if qlog else RLOG_MIN_REQUESTING_MAX
|
||||
|
||||
events = []
|
||||
# if we test with driver torque safety, max torque can be slightly noisy
|
||||
steer_threshold = 0.7 if extrapolate else 0.95
|
||||
|
||||
start_ts = 0
|
||||
events = []
|
||||
|
||||
# state tracking
|
||||
steering_unpressed = 0 # frames
|
||||
@@ -38,7 +41,9 @@ def find_events(lr: LogReader, qlog: bool = False) -> list[Event]:
|
||||
curvature = 0
|
||||
v_ego = 0
|
||||
roll = 0
|
||||
out_torque = 0
|
||||
|
||||
start_ts = 0
|
||||
for msg in lr:
|
||||
if msg.which() == 'carControl':
|
||||
if start_ts == 0:
|
||||
@@ -47,8 +52,8 @@ def find_events(lr: LogReader, qlog: bool = False) -> list[Event]:
|
||||
lat_active = lat_active + 1 if msg.carControl.latActive else 0
|
||||
|
||||
elif msg.which() == 'carOutput':
|
||||
# if we test with driver torque safety, max torque can be slightly noisy
|
||||
requesting_max = requesting_max + 1 if abs(msg.carOutput.actuatorsOutput.torque) > 0.95 else 0
|
||||
out_torque = msg.carOutput.actuatorsOutput.torque
|
||||
requesting_max = requesting_max + 1 if abs(out_torque) > steer_threshold else 0
|
||||
|
||||
elif msg.which() == 'carState':
|
||||
steering_unpressed = steering_unpressed + 1 if not msg.carState.steeringPressed else 0
|
||||
@@ -64,7 +69,8 @@ def find_events(lr: LogReader, qlog: bool = False) -> list[Event]:
|
||||
# TODO: record max lat accel at the end of the event, need to use the past lat accel as overriding can happen before we detect it
|
||||
requesting_max = 0
|
||||
|
||||
current_lateral_accel = curvature * v_ego ** 2 - roll * EARTH_G
|
||||
factor = 1 / abs(out_torque)
|
||||
current_lateral_accel = (curvature * v_ego ** 2 * factor) - roll * EARTH_G
|
||||
events.append(Event(current_lateral_accel, v_ego, roll, round((msg.logMonoTime - start_ts) * 1e-9, 2)))
|
||||
print(events[-1])
|
||||
|
||||
@@ -75,29 +81,38 @@ if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Find max lateral acceleration events",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
|
||||
parser.add_argument("route")
|
||||
parser.add_argument("route", nargs='+')
|
||||
parser.add_argument("-e", "--extrapolate", action="store_true", help="Extrapolates max lateral acceleration events linearly. " +
|
||||
"This option can be far less accurate.")
|
||||
args = parser.parse_args()
|
||||
|
||||
lr = LogReader(args.route, sort_by_time=True)
|
||||
qlog = args.route.endswith('/q')
|
||||
if qlog:
|
||||
print('WARNING: Treating route as qlog!')
|
||||
events = []
|
||||
for route in tqdm(args.route):
|
||||
try:
|
||||
lr = LogReader(route, sort_by_time=True)
|
||||
except Exception:
|
||||
print(f'Skipping {route}')
|
||||
continue
|
||||
|
||||
print('Finding events...')
|
||||
events = find_events(lr, qlog=qlog)
|
||||
qlog = route.endswith('/q')
|
||||
if qlog:
|
||||
print('WARNING: Treating route as qlog!')
|
||||
|
||||
print('Finding events...')
|
||||
events += lr.run_across_segments(8, partial(find_events, extrapolate=args.extrapolate, qlog=qlog), disable_tqdm=True)
|
||||
|
||||
print()
|
||||
print(f'Found {len(events)} events')
|
||||
|
||||
perc_left_accel = -np.percentile([-ev.lateral_accel for ev in events if ev.lateral_accel < 0], 90)
|
||||
perc_right_accel = np.percentile([ev.lateral_accel for ev in events if ev.lateral_accel > 0], 90)
|
||||
perc_left_accel = -np.percentile([-ev.lateral_accel for ev in events if ev.lateral_accel < 0] or [0], 90)
|
||||
perc_right_accel = np.percentile([ev.lateral_accel for ev in events if ev.lateral_accel > 0] or [0], 90)
|
||||
|
||||
CP = lr.first('carParams')
|
||||
|
||||
plt.ion()
|
||||
plt.clf()
|
||||
plt.suptitle(f'{CP.carFingerprint} - Max lateral acceleration events')
|
||||
plt.title(args.route)
|
||||
plt.title(', '.join(args.route))
|
||||
plt.scatter([ev.speed for ev in events], [ev.lateral_accel for ev in events], label='max lateral accel events')
|
||||
|
||||
plt.plot([0, 35], [3, 3], c='r', label='ISO 11270 - 3 m/s^2')
|
||||
|
||||
@@ -3,14 +3,25 @@ import time
|
||||
|
||||
from cereal import car, log, messaging
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.system.manager.process_config import managed_processes
|
||||
from openpilot.system.manager.process_config import managed_processes, is_snpe_model, is_tinygrad_model, is_stock_model
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
|
||||
if __name__ == "__main__":
|
||||
CP = car.CarParams(notCar=True, wheelbase=1, steerRatio=10)
|
||||
Params().put("CarParams", CP.to_bytes())
|
||||
params = Params()
|
||||
params.put("CarParams", CP.to_bytes())
|
||||
|
||||
procs = ['camerad', 'ui', 'modeld', 'calibrationd', 'plannerd', 'dmonitoringmodeld', 'dmonitoringd']
|
||||
if use_snpe_modeld := is_snpe_model(False, params, CP):
|
||||
print("Using SNPE modeld")
|
||||
if use_tinygrad_modeld := is_tinygrad_model(False, params, CP):
|
||||
print("Using TinyGrad modeld")
|
||||
if use_stock_modeld := is_stock_model(False, params, CP):
|
||||
print("Using stock modeld")
|
||||
|
||||
HARDWARE.set_power_save(False)
|
||||
|
||||
procs = ['camerad', 'ui', 'calibrationd', 'plannerd', 'dmonitoringmodeld', 'dmonitoringd']
|
||||
procs += ["modeld_snpe" if use_snpe_modeld else "modeld_tinygrad" if use_tinygrad_modeld else "modeld"]
|
||||
for p in procs:
|
||||
managed_processes[p].start()
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import capnp
|
||||
import numpy as np
|
||||
from typing import NoReturn
|
||||
|
||||
from cereal import log
|
||||
from cereal import log, car
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.params import Params
|
||||
@@ -258,16 +258,18 @@ def main() -> NoReturn:
|
||||
config_realtime_process([0, 1, 2, 3], 5)
|
||||
|
||||
pm = messaging.PubMaster(['liveCalibration'])
|
||||
sm = messaging.SubMaster(['cameraOdometry', 'carState', 'carParams'], poll='cameraOdometry')
|
||||
sm = messaging.SubMaster(['cameraOdometry', 'carState'], poll='cameraOdometry')
|
||||
|
||||
params_reader = Params()
|
||||
CP = messaging.log_from_bytes(params_reader.get("CarParams", block=True), car.CarParams)
|
||||
|
||||
calibrator = Calibrator(param_put=True)
|
||||
calibrator.not_car = CP.notCar
|
||||
|
||||
while 1:
|
||||
timeout = 0 if sm.frame == -1 else 100
|
||||
sm.update(timeout)
|
||||
|
||||
calibrator.not_car = sm['carParams'].notCar
|
||||
|
||||
if sm.updated['cameraOdometry']:
|
||||
calibrator.handle_v_ego(sm['carState'].vEgo)
|
||||
new_rpy = calibrator.handle_cam_odom(sm['cameraOdometry'].trans,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import capnp
|
||||
import numpy as np
|
||||
@@ -65,7 +64,7 @@ class LocationEstimator:
|
||||
self.observation_errors = {kind: np.zeros(3, dtype=np.float32) for kind in obs_kinds}
|
||||
|
||||
def reset(self, t: float, x_initial: np.ndarray = PoseKalman.initial_x, P_initial: np.ndarray = PoseKalman.initial_P):
|
||||
self.kf.reset(t, x_initial, P_initial)
|
||||
self.kf.init_state(x_initial, covs=P_initial, filter_time=t)
|
||||
|
||||
def _validate_sensor_source(self, source: log.SensorEventData.SensorSource):
|
||||
# some segments have two IMUs, ignore the second one
|
||||
@@ -186,8 +185,8 @@ class LocationEstimator:
|
||||
rot_device_noise = rot_device_std ** 2
|
||||
trans_device_noise = trans_device_std ** 2
|
||||
|
||||
cam_odo_rot_res = self.kf.predict_and_observe(t, ObservationKind.CAMERA_ODO_ROTATION, rot_device, rot_device_noise)
|
||||
cam_odo_trans_res = self.kf.predict_and_observe(t, ObservationKind.CAMERA_ODO_TRANSLATION, trans_device, trans_device_noise)
|
||||
cam_odo_rot_res = self.kf.predict_and_observe(t, ObservationKind.CAMERA_ODO_ROTATION, rot_device, np.array([np.diag(rot_device_noise)]))
|
||||
cam_odo_trans_res = self.kf.predict_and_observe(t, ObservationKind.CAMERA_ODO_TRANSLATION, trans_device, np.array([np.diag(trans_device_noise)]))
|
||||
self.camodo_yawrate_distribution = np.array([rot_device[2], rot_device_std[2]])
|
||||
if cam_odo_rot_res is not None:
|
||||
_, new_x, _, new_P, _, _, (cam_odo_rot_err,), _, _ = cam_odo_rot_res
|
||||
@@ -278,12 +277,13 @@ def main():
|
||||
input_invalid_threshold = {s: input_invalid_limit[s] - 0.5 for s in critcal_services}
|
||||
input_invalid_decay = {s: calculate_invalid_input_decay(input_invalid_limit[s], INPUT_INVALID_RECOVERY, SERVICE_LIST[s].frequency) for s in critcal_services}
|
||||
|
||||
initial_pose = params.get("LocationFilterInitialState")
|
||||
if initial_pose is not None:
|
||||
initial_pose = json.loads(initial_pose)
|
||||
x_initial = np.array(initial_pose["x"], dtype=np.float64)
|
||||
P_initial = np.diag(np.array(initial_pose["P"], dtype=np.float64))
|
||||
estimator.reset(None, x_initial, P_initial)
|
||||
initial_pose_data = params.get("LocationFilterInitialState")
|
||||
if initial_pose_data is not None:
|
||||
with log.Event.from_bytes(initial_pose_data) as lp_msg:
|
||||
filter_state = lp_msg.livePose.debugFilterState
|
||||
x_initial = np.array(filter_state.value, dtype=np.float64) if len(filter_state.value) != 0 else PoseKalman.initial_x
|
||||
P_initial = np.diag(np.array(filter_state.std, dtype=np.float64)) if len(filter_state.std) != 0 else PoseKalman.initial_P
|
||||
estimator.reset(None, x_initial, P_initial)
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
|
||||
@@ -160,19 +160,18 @@ class CarKalman(KalmanFilter):
|
||||
|
||||
gen_code(generated_dir, name, f_sym, dt, state_sym, obs_eqs, dim_state, dim_state, global_vars=global_vars)
|
||||
|
||||
def __init__(self, generated_dir, steer_ratio=15, stiffness_factor=1, angle_offset=0, P_initial=None):
|
||||
dim_state = self.initial_x.shape[0]
|
||||
dim_state_err = self.P_initial.shape[0]
|
||||
x_init = self.initial_x
|
||||
x_init[States.STEER_RATIO] = steer_ratio
|
||||
x_init[States.STIFFNESS] = stiffness_factor
|
||||
x_init[States.ANGLE_OFFSET] = angle_offset
|
||||
def __init__(self, generated_dir):
|
||||
dim_state, dim_state_err = CarKalman.initial_x.shape[0], CarKalman.P_initial.shape[0]
|
||||
self.filter = EKF_sym_pyx(generated_dir, CarKalman.name, CarKalman.Q, CarKalman.initial_x, CarKalman.P_initial,
|
||||
dim_state, dim_state_err, global_vars=CarKalman.global_vars, logger=cloudlog)
|
||||
|
||||
if P_initial is not None:
|
||||
self.P_initial = P_initial
|
||||
# init filter
|
||||
self.filter = EKF_sym_pyx(generated_dir, self.name, self.Q, self.initial_x, self.P_initial,
|
||||
dim_state, dim_state_err, global_vars=self.global_vars, logger=cloudlog)
|
||||
def set_globals(self, mass, rotational_inertia, center_to_front, center_to_rear, stiffness_front, stiffness_rear):
|
||||
self.filter.set_global("mass", mass)
|
||||
self.filter.set_global("rotational_inertia", rotational_inertia)
|
||||
self.filter.set_global("center_to_front", center_to_front)
|
||||
self.filter.set_global("center_to_rear", center_to_rear)
|
||||
self.filter.set_global("stiffness_front", stiffness_front)
|
||||
self.filter.set_global("stiffness_rear", stiffness_rear)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -5,6 +5,8 @@ import numpy as np
|
||||
|
||||
from openpilot.selfdrive.locationd.models.constants import ObservationKind
|
||||
|
||||
from rednose.helpers.kalmanfilter import KalmanFilter
|
||||
|
||||
if __name__=="__main__":
|
||||
import sympy as sp
|
||||
from rednose.helpers.ekf_sym import gen_code
|
||||
@@ -24,7 +26,7 @@ class States:
|
||||
ACCEL_BIAS = slice(15, 18) # Acceletometer bias in m/s**2
|
||||
|
||||
|
||||
class PoseKalman:
|
||||
class PoseKalman(KalmanFilter):
|
||||
name = "pose"
|
||||
|
||||
# state
|
||||
@@ -50,10 +52,10 @@ class PoseKalman:
|
||||
3**2, 3**2, 3**2,
|
||||
0.005**2, 0.005**2, 0.005**2])
|
||||
|
||||
obs_noise = {ObservationKind.PHONE_GYRO: np.array([0.025**2, 0.025**2, 0.025**2]),
|
||||
ObservationKind.PHONE_ACCEL: np.array([.5**2, .5**2, .5**2]),
|
||||
ObservationKind.CAMERA_ODO_TRANSLATION: np.array([0.5**2, 0.5**2, 0.5**2]),
|
||||
ObservationKind.CAMERA_ODO_ROTATION: np.array([0.05**2, 0.05**2, 0.05**2])}
|
||||
obs_noise = {ObservationKind.PHONE_GYRO: np.diag([0.025**2, 0.025**2, 0.025**2]),
|
||||
ObservationKind.PHONE_ACCEL: np.diag([.5**2, .5**2, .5**2]),
|
||||
ObservationKind.CAMERA_ODO_TRANSLATION: np.diag([0.5**2, 0.5**2, 0.5**2]),
|
||||
ObservationKind.CAMERA_ODO_ROTATION: np.diag([0.05**2, 0.05**2, 0.05**2])}
|
||||
|
||||
@staticmethod
|
||||
def generate_code(generated_dir):
|
||||
@@ -103,35 +105,6 @@ class PoseKalman:
|
||||
self.filter = EKF_sym_pyx(generated_dir, self.name, PoseKalman.Q, PoseKalman.initial_x, PoseKalman.initial_P,
|
||||
dim_state, dim_state_err, max_rewind_age=max_rewind_age)
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self.filter.state()
|
||||
|
||||
@property
|
||||
def P(self):
|
||||
return self.filter.covs()
|
||||
|
||||
@property
|
||||
def t(self):
|
||||
return self.filter.get_filter_time()
|
||||
|
||||
def predict_and_observe(self, t, kind, data, obs_noise=None):
|
||||
data = np.atleast_2d(data)
|
||||
if obs_noise is None:
|
||||
obs_noise = self.obs_noise[kind]
|
||||
R = self._get_R(len(data), obs_noise)
|
||||
return self.filter.predict_and_update_batch(t, kind, data, R)
|
||||
|
||||
def reset(self, t, x_init, P_init):
|
||||
self.filter.init_state(x_init, P_init, t)
|
||||
|
||||
def _get_R(self, n, obs_noise):
|
||||
dim = obs_noise.shape[0]
|
||||
R = np.zeros((n, dim, dim))
|
||||
for i in range(n):
|
||||
R[i, :, :] = np.diag(obs_noise)
|
||||
return R
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
generated_dir = sys.argv[2]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import math
|
||||
import json
|
||||
import numpy as np
|
||||
import capnp
|
||||
|
||||
import cereal.messaging as messaging
|
||||
from cereal import car, log
|
||||
@@ -13,12 +13,11 @@ from openpilot.selfdrive.locationd.models.constants import GENERATED_DIR
|
||||
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
|
||||
MAX_ANGLE_OFFSET_DELTA = 20 * DT_MDL # Max 20 deg/s
|
||||
ROLL_MAX_DELTA = math.radians(20.0) * DT_MDL # 20deg in 1 second is well within curvature limits
|
||||
ROLL_MIN, ROLL_MAX = math.radians(-10), math.radians(10)
|
||||
ROLL_LOWERED_MAX = math.radians(8)
|
||||
ROLL_STD_MAX = math.radians(1.5)
|
||||
ROLL_MAX_DELTA = np.radians(20.0) * DT_MDL # 20deg in 1 second is well within curvature limits
|
||||
ROLL_MIN, ROLL_MAX = np.radians(-10), np.radians(10)
|
||||
ROLL_LOWERED_MAX = np.radians(8)
|
||||
ROLL_STD_MAX = np.radians(1.5)
|
||||
LATERAL_ACC_SENSOR_THRESHOLD = 4.0
|
||||
OFFSET_MAX = 10.0
|
||||
OFFSET_LOWERED_MAX = 8.0
|
||||
@@ -26,40 +25,58 @@ MIN_ACTIVE_SPEED = 1.0
|
||||
LOW_ACTIVE_SPEED = 10.0
|
||||
|
||||
|
||||
class ParamsLearner:
|
||||
def __init__(self, CP, steer_ratio, stiffness_factor, angle_offset, P_initial=None):
|
||||
self.kf = CarKalman(GENERATED_DIR, steer_ratio, stiffness_factor, angle_offset, P_initial)
|
||||
class VehicleParamsLearner:
|
||||
def __init__(self, CP: car.CarParams, steer_ratio: float, stiffness_factor: float, angle_offset: float, P_initial: np.ndarray | None = None):
|
||||
self.kf = CarKalman(GENERATED_DIR)
|
||||
|
||||
self.kf.filter.set_global("mass", CP.mass)
|
||||
self.kf.filter.set_global("rotational_inertia", CP.rotationalInertia)
|
||||
self.kf.filter.set_global("center_to_front", CP.centerToFront)
|
||||
self.kf.filter.set_global("center_to_rear", CP.wheelbase - CP.centerToFront)
|
||||
self.kf.filter.set_global("stiffness_front", CP.tireStiffnessFront)
|
||||
self.kf.filter.set_global("stiffness_rear", CP.tireStiffnessRear)
|
||||
self.x_initial = CarKalman.initial_x.copy()
|
||||
self.x_initial[States.STEER_RATIO] = steer_ratio
|
||||
self.x_initial[States.STIFFNESS] = stiffness_factor
|
||||
self.x_initial[States.ANGLE_OFFSET] = angle_offset
|
||||
self.P_initial = P_initial if P_initial is not None else CarKalman.P_initial
|
||||
|
||||
self.active = False
|
||||
self.kf.set_globals(
|
||||
mass=CP.mass,
|
||||
rotational_inertia=CP.rotationalInertia,
|
||||
center_to_front=CP.centerToFront,
|
||||
center_to_rear=CP.wheelbase - CP.centerToFront,
|
||||
stiffness_front=CP.tireStiffnessFront,
|
||||
stiffness_rear=CP.tireStiffnessRear
|
||||
)
|
||||
|
||||
self.min_sr, self.max_sr = 0.5 * CP.steerRatio, 2.0 * CP.steerRatio
|
||||
|
||||
self.calibrator = PoseCalibrator()
|
||||
|
||||
self.speed = 0.0
|
||||
self.yaw_rate = 0.0
|
||||
self.yaw_rate_std = 0.0
|
||||
self.roll = 0.0
|
||||
self.steering_angle = 0.0
|
||||
self.observed_speed = 0.0
|
||||
self.observed_yaw_rate = 0.0
|
||||
self.observed_roll = 0.0
|
||||
|
||||
def handle_log(self, t, which, msg):
|
||||
self.avg_offset_valid = True
|
||||
self.total_offset_valid = True
|
||||
self.roll_valid = True
|
||||
|
||||
self.reset(None)
|
||||
|
||||
def reset(self, t: float | None):
|
||||
self.kf.init_state(self.x_initial, covs=self.P_initial, filter_time=t)
|
||||
|
||||
self.angle_offset, self.roll, self.active = np.degrees(self.x_initial[States.ANGLE_OFFSET].item()), 0.0, False
|
||||
self.avg_angle_offset = self.angle_offset
|
||||
|
||||
def handle_log(self, t: float, which: str, msg: capnp._DynamicStructReader):
|
||||
if which == 'livePose':
|
||||
device_pose = Pose.from_live_pose(msg)
|
||||
calibrated_pose = self.calibrator.build_calibrated_pose(device_pose)
|
||||
|
||||
yaw_rate, yaw_rate_std = calibrated_pose.angular_velocity.z, calibrated_pose.angular_velocity.z_std
|
||||
yaw_rate_valid = msg.angularVelocityDevice.valid
|
||||
yaw_rate_valid = yaw_rate_valid and 0 < self.yaw_rate_std < 10 # rad/s
|
||||
yaw_rate_valid = yaw_rate_valid and abs(self.yaw_rate) < 1 # rad/s
|
||||
if yaw_rate_valid:
|
||||
self.yaw_rate, self.yaw_rate_std = calibrated_pose.angular_velocity.z, calibrated_pose.angular_velocity.z_std
|
||||
else:
|
||||
yaw_rate_valid = yaw_rate_valid and 0 < yaw_rate_std < 10 # rad/s
|
||||
yaw_rate_valid = yaw_rate_valid and abs(yaw_rate) < 1 # rad/s
|
||||
if not yaw_rate_valid:
|
||||
# This is done to bound the yaw rate estimate when localizer values are invalid or calibrating
|
||||
self.yaw_rate, self.yaw_rate_std = 0.0, np.radians(10.0)
|
||||
yaw_rate, yaw_rate_std = 0.0, np.radians(10.0)
|
||||
self.observed_yaw_rate = yaw_rate
|
||||
|
||||
localizer_roll, localizer_roll_std = device_pose.orientation.x, device_pose.orientation.x_std
|
||||
localizer_roll_std = np.radians(1) if np.isnan(localizer_roll_std) else localizer_roll_std
|
||||
@@ -72,18 +89,18 @@ class ParamsLearner:
|
||||
# This is done to bound the road roll estimate when localizer values are invalid
|
||||
roll = 0.0
|
||||
roll_std = np.radians(10.0)
|
||||
self.roll = np.clip(roll, self.roll - ROLL_MAX_DELTA, self.roll + ROLL_MAX_DELTA)
|
||||
self.observed_roll = np.clip(roll, self.observed_roll - ROLL_MAX_DELTA, self.observed_roll + ROLL_MAX_DELTA)
|
||||
|
||||
if self.active:
|
||||
if msg.posenetOK:
|
||||
self.kf.predict_and_observe(t,
|
||||
ObservationKind.ROAD_FRAME_YAW_RATE,
|
||||
np.array([[-self.yaw_rate]]),
|
||||
np.array([np.atleast_2d(self.yaw_rate_std**2)]))
|
||||
np.array([[-self.observed_yaw_rate]]),
|
||||
np.array([np.atleast_2d(yaw_rate_std**2)]))
|
||||
|
||||
self.kf.predict_and_observe(t,
|
||||
ObservationKind.ROAD_ROLL,
|
||||
np.array([[self.roll]]),
|
||||
np.array([[self.observed_roll]]),
|
||||
np.array([np.atleast_2d(roll_std**2)]))
|
||||
self.kf.predict_and_observe(t, ObservationKind.ANGLE_OFFSET_FAST, np.array([[0]]))
|
||||
|
||||
@@ -99,20 +116,79 @@ class ParamsLearner:
|
||||
self.calibrator.feed_live_calib(msg)
|
||||
|
||||
elif which == 'carState':
|
||||
self.steering_angle = msg.steeringAngleDeg
|
||||
self.speed = msg.vEgo
|
||||
steering_angle = msg.steeringAngleDeg
|
||||
|
||||
in_linear_region = abs(self.steering_angle) < 45
|
||||
self.active = self.speed > MIN_ACTIVE_SPEED and in_linear_region
|
||||
in_linear_region = abs(steering_angle) < 45
|
||||
self.observed_speed = msg.vEgo
|
||||
self.active = self.observed_speed > MIN_ACTIVE_SPEED and in_linear_region
|
||||
|
||||
if self.active:
|
||||
self.kf.predict_and_observe(t, ObservationKind.STEER_ANGLE, np.array([[math.radians(msg.steeringAngleDeg)]]))
|
||||
self.kf.predict_and_observe(t, ObservationKind.ROAD_FRAME_X_SPEED, np.array([[self.speed]]))
|
||||
self.kf.predict_and_observe(t, ObservationKind.STEER_ANGLE, np.array([[np.radians(steering_angle)]]))
|
||||
self.kf.predict_and_observe(t, ObservationKind.ROAD_FRAME_X_SPEED, np.array([[self.observed_speed]]))
|
||||
|
||||
if not self.active:
|
||||
# Reset time when stopped so uncertainty doesn't grow
|
||||
self.kf.filter.set_filter_time(t)
|
||||
self.kf.filter.reset_rewind()
|
||||
self.kf.filter.set_filter_time(t) # type: ignore
|
||||
self.kf.filter.reset_rewind() # type: ignore
|
||||
|
||||
def get_msg(self, valid: bool, debug: bool = False) -> capnp._DynamicStructBuilder:
|
||||
x = self.kf.x
|
||||
P = np.sqrt(self.kf.P.diagonal())
|
||||
if not np.all(np.isfinite(x)):
|
||||
cloudlog.error("NaN in liveParameters estimate. Resetting to default values")
|
||||
self.reset(self.kf.t)
|
||||
x = self.kf.x
|
||||
|
||||
self.avg_angle_offset = np.clip(np.degrees(x[States.ANGLE_OFFSET].item()),
|
||||
self.avg_angle_offset - MAX_ANGLE_OFFSET_DELTA, self.avg_angle_offset + MAX_ANGLE_OFFSET_DELTA)
|
||||
self.angle_offset = np.clip(np.degrees(x[States.ANGLE_OFFSET].item() + x[States.ANGLE_OFFSET_FAST].item()),
|
||||
self.angle_offset - MAX_ANGLE_OFFSET_DELTA, self.angle_offset + MAX_ANGLE_OFFSET_DELTA)
|
||||
self.roll = np.clip(float(x[States.ROAD_ROLL].item()), self.roll - ROLL_MAX_DELTA, self.roll + ROLL_MAX_DELTA)
|
||||
roll_std = float(P[States.ROAD_ROLL].item())
|
||||
if self.active and self.observed_speed > LOW_ACTIVE_SPEED:
|
||||
# Account for the opposite signs of the yaw rates
|
||||
# At low speeds, bumping into a curb can cause the yaw rate to be very high
|
||||
sensors_valid = bool(abs(self.observed_speed * (x[States.YAW_RATE].item() + self.observed_yaw_rate)) < LATERAL_ACC_SENSOR_THRESHOLD)
|
||||
else:
|
||||
sensors_valid = True
|
||||
self.avg_offset_valid = check_valid_with_hysteresis(self.avg_offset_valid, self.avg_angle_offset, OFFSET_MAX, OFFSET_LOWERED_MAX)
|
||||
self.total_offset_valid = check_valid_with_hysteresis(self.total_offset_valid, self.angle_offset, OFFSET_MAX, OFFSET_LOWERED_MAX)
|
||||
self.roll_valid = check_valid_with_hysteresis(self.roll_valid, self.roll, ROLL_MAX, ROLL_LOWERED_MAX)
|
||||
|
||||
msg = messaging.new_message('liveParameters')
|
||||
|
||||
msg.valid = valid
|
||||
|
||||
liveParameters = msg.liveParameters
|
||||
liveParameters.posenetValid = True
|
||||
liveParameters.sensorValid = sensors_valid
|
||||
liveParameters.steerRatio = float(x[States.STEER_RATIO].item())
|
||||
liveParameters.stiffnessFactor = float(x[States.STIFFNESS].item())
|
||||
liveParameters.roll = float(self.roll)
|
||||
liveParameters.angleOffsetAverageDeg = float(self.avg_angle_offset)
|
||||
liveParameters.angleOffsetDeg = float(self.angle_offset)
|
||||
liveParameters.steerRatioValid = self.min_sr <= liveParameters.steerRatio <= self.max_sr
|
||||
liveParameters.stiffnessFactorValid = 0.2 <= liveParameters.stiffnessFactor <= 5.0
|
||||
liveParameters.angleOffsetAverageValid = bool(self.avg_offset_valid)
|
||||
liveParameters.angleOffsetValid = bool(self.total_offset_valid)
|
||||
liveParameters.valid = all((
|
||||
liveParameters.angleOffsetAverageValid,
|
||||
liveParameters.angleOffsetValid ,
|
||||
self.roll_valid,
|
||||
roll_std < ROLL_STD_MAX,
|
||||
liveParameters.stiffnessFactorValid,
|
||||
liveParameters.steerRatioValid,
|
||||
))
|
||||
liveParameters.steerRatioStd = float(P[States.STEER_RATIO].item())
|
||||
liveParameters.stiffnessFactorStd = float(P[States.STIFFNESS].item())
|
||||
liveParameters.angleOffsetAverageStd = float(P[States.ANGLE_OFFSET].item())
|
||||
liveParameters.angleOffsetFastStd = float(P[States.ANGLE_OFFSET_FAST].item())
|
||||
if debug:
|
||||
liveParameters.debugFilterState = log.LiveParametersData.FilterState.new_message()
|
||||
liveParameters.debugFilterState.value = x.tolist()
|
||||
liveParameters.debugFilterState.std = P.tolist()
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
def check_valid_with_hysteresis(current_valid: bool, val: float, threshold: float, lowered_threshold: float):
|
||||
@@ -123,6 +199,65 @@ def check_valid_with_hysteresis(current_valid: bool, val: float, threshold: floa
|
||||
return current_valid
|
||||
|
||||
|
||||
# TODO: Remove this function after few releases (added in 0.9.9)
|
||||
def migrate_cached_vehicle_params_if_needed(params_reader: Params):
|
||||
last_parameters_data = params_reader.get("LiveParameters")
|
||||
if last_parameters_data is None:
|
||||
return
|
||||
|
||||
try:
|
||||
last_parameters_dict = json.loads(last_parameters_data)
|
||||
last_parameters_msg = messaging.new_message('liveParameters')
|
||||
last_parameters_msg.liveParameters.valid = True
|
||||
last_parameters_msg.liveParameters.steerRatio = last_parameters_dict['steerRatio']
|
||||
last_parameters_msg.liveParameters.stiffnessFactor = last_parameters_dict['stiffnessFactor']
|
||||
last_parameters_msg.liveParameters.angleOffsetAverageDeg = last_parameters_dict['angleOffsetAverageDeg']
|
||||
params_reader.put("LiveParameters", last_parameters_msg.to_bytes())
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def retrieve_initial_vehicle_params(params_reader: Params, CP: car.CarParams, replay: bool, debug: bool):
|
||||
last_parameters_data = params_reader.get("LiveParameters")
|
||||
last_carparams_data = params_reader.get("CarParamsPrevRoute")
|
||||
|
||||
steer_ratio, stiffness_factor, angle_offset_deg, p_initial = CP.steerRatio, 1.0, 0.0, None
|
||||
|
||||
retrieve_success = False
|
||||
if last_parameters_data is not None and last_carparams_data is not None:
|
||||
try:
|
||||
with log.Event.from_bytes(last_parameters_data) as last_lp_msg, car.CarParams.from_bytes(last_carparams_data) as last_CP:
|
||||
lp = last_lp_msg.liveParameters
|
||||
# Check if car model matches
|
||||
if last_CP.carFingerprint != CP.carFingerprint:
|
||||
raise Exception("Car model mismatch")
|
||||
|
||||
# Check if starting values are sane
|
||||
min_sr, max_sr = 0.5 * CP.steerRatio, 2.0 * CP.steerRatio
|
||||
steer_ratio_sane = min_sr <= lp.steerRatio <= max_sr
|
||||
if not steer_ratio_sane:
|
||||
raise Exception(f"Invalid starting values found {lp}")
|
||||
|
||||
initial_filter_std = np.array(lp.debugFilterState.std)
|
||||
if debug and len(initial_filter_std) != 0:
|
||||
p_initial = np.diag(initial_filter_std)
|
||||
|
||||
steer_ratio, stiffness_factor, angle_offset_deg = lp.steerRatio, lp.stiffnessFactor, lp.angleOffsetAverageDeg
|
||||
retrieve_success = True
|
||||
except Exception as e:
|
||||
cloudlog.error(f"Failed to retrieve initial values: {e}")
|
||||
|
||||
if not replay:
|
||||
# When driving in wet conditions the stiffness can go down, and then be too low on the next drive
|
||||
# Without a way to detect this we have to reset the stiffness every drive
|
||||
stiffness_factor = 1.0
|
||||
|
||||
if not retrieve_success:
|
||||
cloudlog.info("Parameter learner resetting to default values")
|
||||
|
||||
return steer_ratio, stiffness_factor, angle_offset_deg, p_initial
|
||||
|
||||
|
||||
def main():
|
||||
config_realtime_process([0, 1, 2, 3], 5)
|
||||
|
||||
@@ -133,59 +268,12 @@ def main():
|
||||
sm = messaging.SubMaster(['livePose', 'liveCalibration', 'carState'], poll='livePose')
|
||||
|
||||
params_reader = Params()
|
||||
# wait for stats about the car to come in from controls
|
||||
cloudlog.info("paramsd is waiting for CarParams")
|
||||
CP = messaging.log_from_bytes(params_reader.get("CarParams", block=True), car.CarParams)
|
||||
cloudlog.info("paramsd got CarParams")
|
||||
|
||||
min_sr, max_sr = 0.5 * CP.steerRatio, 2.0 * CP.steerRatio
|
||||
migrate_cached_vehicle_params_if_needed(params_reader)
|
||||
|
||||
params = params_reader.get("LiveParameters")
|
||||
|
||||
# Check if car model matches
|
||||
if params is not None:
|
||||
params = json.loads(params)
|
||||
if params.get('carFingerprint', None) != CP.carFingerprint:
|
||||
cloudlog.info("Parameter learner found parameters for wrong car.")
|
||||
params = None
|
||||
|
||||
# Check if starting values are sane
|
||||
if params is not None:
|
||||
try:
|
||||
steer_ratio_sane = min_sr <= params['steerRatio'] <= max_sr
|
||||
if not steer_ratio_sane:
|
||||
cloudlog.info(f"Invalid starting values found {params}")
|
||||
params = None
|
||||
except Exception as e:
|
||||
cloudlog.info(f"Error reading params {params}: {str(e)}")
|
||||
params = None
|
||||
|
||||
# TODO: cache the params with the capnp struct
|
||||
if params is None:
|
||||
params = {
|
||||
'carFingerprint': CP.carFingerprint,
|
||||
'steerRatio': CP.steerRatio,
|
||||
'stiffnessFactor': 1.0,
|
||||
'angleOffsetAverageDeg': 0.0,
|
||||
}
|
||||
cloudlog.info("Parameter learner resetting to default values")
|
||||
|
||||
if not REPLAY:
|
||||
# When driving in wet conditions the stiffness can go down, and then be too low on the next drive
|
||||
# Without a way to detect this we have to reset the stiffness every drive
|
||||
params['stiffnessFactor'] = 1.0
|
||||
|
||||
pInitial = None
|
||||
if DEBUG:
|
||||
pInitial = np.array(params['debugFilterState']['std']) if 'debugFilterState' in params else None
|
||||
|
||||
learner = ParamsLearner(CP, params['steerRatio'], params['stiffnessFactor'], math.radians(params['angleOffsetAverageDeg']), pInitial)
|
||||
angle_offset_average = params['angleOffsetAverageDeg']
|
||||
angle_offset = angle_offset_average
|
||||
roll = 0.0
|
||||
avg_offset_valid = True
|
||||
total_offset_valid = True
|
||||
roll_valid = True
|
||||
steer_ratio, stiffness_factor, angle_offset_deg, pInitial = retrieve_initial_vehicle_params(params_reader, CP, REPLAY, DEBUG)
|
||||
learner = VehicleParamsLearner(CP, steer_ratio, stiffness_factor, np.radians(angle_offset_deg), pInitial)
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
@@ -196,72 +284,13 @@ def main():
|
||||
learner.handle_log(t, which, sm[which])
|
||||
|
||||
if sm.updated['livePose']:
|
||||
x = learner.kf.x
|
||||
P = np.sqrt(learner.kf.P.diagonal())
|
||||
if not all(map(math.isfinite, x)):
|
||||
cloudlog.error("NaN in liveParameters estimate. Resetting to default values")
|
||||
learner = ParamsLearner(CP, CP.steerRatio, 1.0, 0.0)
|
||||
x = learner.kf.x
|
||||
|
||||
angle_offset_average = np.clip(math.degrees(x[States.ANGLE_OFFSET].item()),
|
||||
angle_offset_average - MAX_ANGLE_OFFSET_DELTA, angle_offset_average + MAX_ANGLE_OFFSET_DELTA)
|
||||
angle_offset = np.clip(math.degrees(x[States.ANGLE_OFFSET].item() + x[States.ANGLE_OFFSET_FAST].item()),
|
||||
angle_offset - MAX_ANGLE_OFFSET_DELTA, angle_offset + MAX_ANGLE_OFFSET_DELTA)
|
||||
roll = np.clip(float(x[States.ROAD_ROLL].item()), roll - ROLL_MAX_DELTA, roll + ROLL_MAX_DELTA)
|
||||
roll_std = float(P[States.ROAD_ROLL].item())
|
||||
if learner.active and learner.speed > LOW_ACTIVE_SPEED:
|
||||
# Account for the opposite signs of the yaw rates
|
||||
# At low speeds, bumping into a curb can cause the yaw rate to be very high
|
||||
sensors_valid = bool(abs(learner.speed * (x[States.YAW_RATE].item() + learner.yaw_rate)) < LATERAL_ACC_SENSOR_THRESHOLD)
|
||||
else:
|
||||
sensors_valid = True
|
||||
avg_offset_valid = check_valid_with_hysteresis(avg_offset_valid, angle_offset_average, OFFSET_MAX, OFFSET_LOWERED_MAX)
|
||||
total_offset_valid = check_valid_with_hysteresis(total_offset_valid, angle_offset, OFFSET_MAX, OFFSET_LOWERED_MAX)
|
||||
roll_valid = check_valid_with_hysteresis(roll_valid, roll, ROLL_MAX, ROLL_LOWERED_MAX)
|
||||
|
||||
msg = messaging.new_message('liveParameters')
|
||||
|
||||
liveParameters = msg.liveParameters
|
||||
liveParameters.posenetValid = True
|
||||
liveParameters.sensorValid = sensors_valid
|
||||
liveParameters.steerRatio = float(x[States.STEER_RATIO].item())
|
||||
liveParameters.stiffnessFactor = float(x[States.STIFFNESS].item())
|
||||
liveParameters.roll = float(roll)
|
||||
liveParameters.angleOffsetAverageDeg = float(angle_offset_average)
|
||||
liveParameters.angleOffsetDeg = float(angle_offset)
|
||||
liveParameters.steerRatioValid = min_sr <= liveParameters.steerRatio <= max_sr
|
||||
liveParameters.stiffnessFactorValid = 0.2 <= liveParameters.stiffnessFactor <= 5.0
|
||||
liveParameters.angleOffsetAverageValid = bool(avg_offset_valid)
|
||||
liveParameters.angleOffsetValid = bool(total_offset_valid)
|
||||
liveParameters.valid = all((
|
||||
liveParameters.angleOffsetAverageValid,
|
||||
liveParameters.angleOffsetValid ,
|
||||
roll_valid,
|
||||
roll_std < ROLL_STD_MAX,
|
||||
liveParameters.stiffnessFactorValid,
|
||||
liveParameters.steerRatioValid,
|
||||
))
|
||||
liveParameters.steerRatioStd = float(P[States.STEER_RATIO].item())
|
||||
liveParameters.stiffnessFactorStd = float(P[States.STIFFNESS].item())
|
||||
liveParameters.angleOffsetAverageStd = float(P[States.ANGLE_OFFSET].item())
|
||||
liveParameters.angleOffsetFastStd = float(P[States.ANGLE_OFFSET_FAST].item())
|
||||
if DEBUG:
|
||||
liveParameters.debugFilterState = log.LiveParametersData.FilterState.new_message()
|
||||
liveParameters.debugFilterState.value = x.tolist()
|
||||
liveParameters.debugFilterState.std = P.tolist()
|
||||
|
||||
msg.valid = sm.all_checks()
|
||||
msg = learner.get_msg(sm.all_checks(), debug=DEBUG)
|
||||
|
||||
msg_dat = msg.to_bytes()
|
||||
if sm.frame % 1200 == 0: # once a minute
|
||||
params = {
|
||||
'carFingerprint': CP.carFingerprint,
|
||||
'steerRatio': liveParameters.steerRatio,
|
||||
'stiffnessFactor': liveParameters.stiffnessFactor,
|
||||
'angleOffsetAverageDeg': liveParameters.angleOffsetAverageDeg,
|
||||
}
|
||||
params_reader.put_nonblocking("LiveParameters", json.dumps(params))
|
||||
params_reader.put_nonblocking("LiveParameters", msg_dat)
|
||||
|
||||
pm.send('liveParameters', msg)
|
||||
pm.send('liveParameters', msg_dat)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
57
selfdrive/locationd/test/test_paramsd.py
Normal file
57
selfdrive/locationd/test/test_paramsd.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import random
|
||||
import numpy as np
|
||||
import json
|
||||
|
||||
from cereal import messaging
|
||||
from openpilot.selfdrive.locationd.paramsd import retrieve_initial_vehicle_params, migrate_cached_vehicle_params_if_needed
|
||||
from openpilot.selfdrive.locationd.models.car_kf import CarKalman
|
||||
from openpilot.selfdrive.locationd.test.test_locationd_scenarios import TEST_ROUTE
|
||||
from openpilot.selfdrive.test.process_replay.migration import migrate, migrate_carParams
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.tools.lib.logreader import LogReader
|
||||
|
||||
|
||||
def get_random_live_parameters(CP):
|
||||
msg = messaging.new_message("liveParameters")
|
||||
msg.liveParameters.steerRatio = (random.random() + 0.5) * CP.steerRatio
|
||||
msg.liveParameters.stiffnessFactor = random.random()
|
||||
msg.liveParameters.angleOffsetAverageDeg = random.random()
|
||||
msg.liveParameters.debugFilterState.std = [random.random() for _ in range(CarKalman.P_initial.shape[0])]
|
||||
return msg
|
||||
|
||||
|
||||
class TestParamsd:
|
||||
def test_read_saved_params(self):
|
||||
params = Params()
|
||||
|
||||
lr = migrate(LogReader(TEST_ROUTE), [migrate_carParams])
|
||||
CP = next(m for m in lr if m.which() == "carParams").carParams
|
||||
|
||||
msg = get_random_live_parameters(CP)
|
||||
params.put("LiveParameters", msg.to_bytes())
|
||||
params.put("CarParamsPrevRoute", CP.as_builder().to_bytes())
|
||||
|
||||
migrate_cached_vehicle_params_if_needed(params) # this is not tested here but should not mess anything up or throw an error
|
||||
sr, sf, offset, p_init = retrieve_initial_vehicle_params(params, CP, replay=True, debug=True)
|
||||
np.testing.assert_allclose(sr, msg.liveParameters.steerRatio)
|
||||
np.testing.assert_allclose(sf, msg.liveParameters.stiffnessFactor)
|
||||
np.testing.assert_allclose(offset, msg.liveParameters.angleOffsetAverageDeg)
|
||||
np.testing.assert_equal(p_init.shape, CarKalman.P_initial.shape)
|
||||
np.testing.assert_allclose(np.diagonal(p_init), msg.liveParameters.debugFilterState.std)
|
||||
|
||||
# TODO Remove this test after the support for old format is removed
|
||||
def test_read_saved_params_old_format(self):
|
||||
params = Params()
|
||||
|
||||
lr = migrate(LogReader(TEST_ROUTE), [migrate_carParams])
|
||||
CP = next(m for m in lr if m.which() == "carParams").carParams
|
||||
|
||||
msg = get_random_live_parameters(CP)
|
||||
params.put("LiveParameters", json.dumps(msg.liveParameters.to_dict()))
|
||||
params.put("CarParamsPrevRoute", CP.as_builder().to_bytes())
|
||||
|
||||
migrate_cached_vehicle_params_if_needed(params)
|
||||
sr, sf, offset, _ = retrieve_initial_vehicle_params(params, CP, replay=True, debug=True)
|
||||
np.testing.assert_allclose(sr, msg.liveParameters.steerRatio)
|
||||
np.testing.assert_allclose(sf, msg.liveParameters.stiffnessFactor)
|
||||
np.testing.assert_allclose(offset, msg.liveParameters.angleOffsetAverageDeg)
|
||||
@@ -32,7 +32,7 @@ MIN_BUCKET_POINTS = np.array([100, 300, 500, 500, 500, 500, 300, 100])
|
||||
MIN_ENGAGE_BUFFER = 2 # secs
|
||||
|
||||
VERSION = 1 # bump this to invalidate old parameter caches
|
||||
ALLOWED_CARS = ['toyota', 'hyundai']
|
||||
ALLOWED_CARS = ['toyota', 'hyundai', 'rivian']
|
||||
|
||||
|
||||
def slope2rot(slope):
|
||||
|
||||
@@ -134,7 +134,7 @@ def get_driverstate_packet(model_output: np.ndarray, frame_id: int, location_ts:
|
||||
|
||||
def main():
|
||||
setproctitle(PROCESS_NAME)
|
||||
config_realtime_process([0, 1, 2, 3], 5)
|
||||
config_realtime_process(7, 5)
|
||||
|
||||
sentry.set_tag("daemon", PROCESS_NAME)
|
||||
cloudlog.bind(daemon=PROCESS_NAME)
|
||||
@@ -173,6 +173,9 @@ def main():
|
||||
model_output, gpu_execution_time = model.run(buf, calib, model_transform)
|
||||
t2 = time.perf_counter()
|
||||
|
||||
# run one more time, just for the load
|
||||
model.run(buf, calib, model_transform)
|
||||
|
||||
pm.send("driverStateV2", get_driverstate_packet(model_output, vipc_client.frame_id, vipc_client.timestamp_sof, t2 - t1, gpu_execution_time))
|
||||
|
||||
|
||||
|
||||
@@ -90,10 +90,17 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
|
||||
# temporal pose
|
||||
temporal_pose = modelV2.temporalPose
|
||||
temporal_pose.trans = net_output_data['sim_pose'][0,:ModelConstants.POSE_WIDTH//2].tolist()
|
||||
temporal_pose.transStd = net_output_data['sim_pose_stds'][0,:ModelConstants.POSE_WIDTH//2].tolist()
|
||||
temporal_pose.rot = net_output_data['sim_pose'][0,ModelConstants.POSE_WIDTH//2:].tolist()
|
||||
temporal_pose.rotStd = net_output_data['sim_pose_stds'][0,ModelConstants.POSE_WIDTH//2:].tolist()
|
||||
if 'sim_pose' in net_output_data:
|
||||
temporal_pose.trans = net_output_data['sim_pose'][0,:ModelConstants.POSE_WIDTH//2].tolist()
|
||||
temporal_pose.transStd = net_output_data['sim_pose_stds'][0,:ModelConstants.POSE_WIDTH//2].tolist()
|
||||
temporal_pose.rot = net_output_data['sim_pose'][0,ModelConstants.POSE_WIDTH//2:].tolist()
|
||||
temporal_pose.rotStd = net_output_data['sim_pose_stds'][0,ModelConstants.POSE_WIDTH//2:].tolist()
|
||||
else:
|
||||
temporal_pose.trans = net_output_data['plan'][0,0,Plan.VELOCITY].tolist()
|
||||
temporal_pose.transStd = net_output_data['plan_stds'][0,0,Plan.VELOCITY].tolist()
|
||||
temporal_pose.rot = net_output_data['plan'][0,0,Plan.ORIENTATION_RATE].tolist()
|
||||
temporal_pose.rotStd = net_output_data['plan_stds'][0,0,Plan.ORIENTATION_RATE].tolist()
|
||||
|
||||
|
||||
# poly path
|
||||
fill_xyz_poly(driving_model_data.path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T)
|
||||
@@ -101,30 +108,14 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
# lateral planning
|
||||
modelV2.action.desiredCurvature = float(net_output_data['desired_curvature'][0,0])
|
||||
|
||||
# times at X_IDXS according to model plan
|
||||
PLAN_T_IDXS = [np.nan] * ModelConstants.IDX_N
|
||||
PLAN_T_IDXS[0] = 0.0
|
||||
plan_x = net_output_data['plan'][0,:,Plan.POSITION][:,0].tolist()
|
||||
for xidx in range(1, ModelConstants.IDX_N):
|
||||
tidx = 0
|
||||
# increment tidx until we find an element that's further away than the current xidx
|
||||
while tidx < ModelConstants.IDX_N - 1 and plan_x[tidx+1] < ModelConstants.X_IDXS[xidx]:
|
||||
tidx += 1
|
||||
if tidx == ModelConstants.IDX_N - 1:
|
||||
# if the Plan doesn't extend far enough, set plan_t to the max value (10s), then break
|
||||
PLAN_T_IDXS[xidx] = ModelConstants.T_IDXS[ModelConstants.IDX_N - 1]
|
||||
break
|
||||
# interpolate to find `t` for the current xidx
|
||||
current_x_val = plan_x[tidx]
|
||||
next_x_val = plan_x[tidx+1]
|
||||
p = (ModelConstants.X_IDXS[xidx] - current_x_val) / (next_x_val - current_x_val) if abs(next_x_val - current_x_val) > 1e-9 else float('nan')
|
||||
PLAN_T_IDXS[xidx] = p * ModelConstants.T_IDXS[tidx+1] + (1 - p) * ModelConstants.T_IDXS[tidx]
|
||||
# times at X_IDXS of edges and lines aren't used
|
||||
LINE_T_IDXS: list[float] = []
|
||||
|
||||
# lane lines
|
||||
modelV2.init('laneLines', 4)
|
||||
for i in range(4):
|
||||
lane_line = modelV2.laneLines[i]
|
||||
fill_xyzt(lane_line, PLAN_T_IDXS, np.array(ModelConstants.X_IDXS), net_output_data['lane_lines'][0,i,:,0], net_output_data['lane_lines'][0,i,:,1])
|
||||
fill_xyzt(lane_line, LINE_T_IDXS, np.array(ModelConstants.X_IDXS), net_output_data['lane_lines'][0,i,:,0], net_output_data['lane_lines'][0,i,:,1])
|
||||
modelV2.laneLineStds = net_output_data['lane_lines_stds'][0,:,0,0].tolist()
|
||||
modelV2.laneLineProbs = net_output_data['lane_lines_prob'][0,1::2].tolist()
|
||||
|
||||
@@ -134,7 +125,7 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
modelV2.init('roadEdges', 2)
|
||||
for i in range(2):
|
||||
road_edge = modelV2.roadEdges[i]
|
||||
fill_xyzt(road_edge, PLAN_T_IDXS, np.array(ModelConstants.X_IDXS), net_output_data['road_edges'][0,i,:,0], net_output_data['road_edges'][0,i,:,1])
|
||||
fill_xyzt(road_edge, LINE_T_IDXS, np.array(ModelConstants.X_IDXS), net_output_data['road_edges'][0,i,:,0], net_output_data['road_edges'][0,i,:,1])
|
||||
modelV2.roadEdgeStds = net_output_data['road_edges_stds'][0,:,0,0].tolist()
|
||||
|
||||
# leads
|
||||
|
||||
@@ -10,7 +10,8 @@ def dmonitoringd_thread():
|
||||
|
||||
params = Params()
|
||||
pm = messaging.PubMaster(['driverMonitoringState'])
|
||||
sm = messaging.SubMaster(['driverStateV2', 'liveCalibration', 'carState', 'selfdriveState', 'modelV2'], poll='driverStateV2')
|
||||
sm = messaging.SubMaster(['driverStateV2', 'liveCalibration', 'carState', 'selfdriveState', 'modelV2',
|
||||
'selfdriveStateSP'], poll='driverStateV2')
|
||||
|
||||
DM = DriverMonitoring(rhd_saved=params.get_bool("IsRhdDetected"), always_on=params.get_bool("AlwaysOnDM"))
|
||||
|
||||
|
||||
@@ -403,13 +403,13 @@ class DriverMonitoring:
|
||||
driver_state=sm['driverStateV2'],
|
||||
cal_rpy=sm['liveCalibration'].rpyCalib,
|
||||
car_speed=sm['carState'].vEgo,
|
||||
op_engaged=sm['selfdriveState'].enabled
|
||||
op_engaged=sm['selfdriveState'].enabled or sm['selfdriveStateSP'].mads.enabled
|
||||
)
|
||||
|
||||
# Update distraction events
|
||||
self._update_events(
|
||||
driver_engaged=sm['carState'].steeringPressed or sm['carState'].gasPressed,
|
||||
op_engaged=sm['selfdriveState'].enabled,
|
||||
op_engaged=sm['selfdriveState'].enabled or sm['selfdriveStateSP'].mads.enabled,
|
||||
standstill=sm['carState'].standstill,
|
||||
wrong_gear=sm['carState'].gearShifter in [car.CarState.GearShifter.reverse, car.CarState.GearShifter.park],
|
||||
car_speed=sm['carState'].vEgo
|
||||
|
||||
@@ -62,8 +62,8 @@ void Panda::set_safety_model(cereal::CarParams::SafetyModel safety_model, uint16
|
||||
handle->control_write(0xdc, (uint16_t)safety_model, safety_param);
|
||||
}
|
||||
|
||||
void Panda::set_alternative_experience(uint16_t alternative_experience) {
|
||||
handle->control_write(0xdf, alternative_experience, 0);
|
||||
void Panda::set_alternative_experience(uint16_t alternative_experience, uint16_t safety_param_sp) {
|
||||
handle->control_write(0xdf, alternative_experience, safety_param_sp);
|
||||
}
|
||||
|
||||
std::string Panda::serial_read(int port_number) {
|
||||
@@ -156,8 +156,8 @@ void Panda::enable_deepsleep() {
|
||||
handle->control_write(0xfb, 0, 0);
|
||||
}
|
||||
|
||||
void Panda::send_heartbeat(bool engaged) {
|
||||
handle->control_write(0xf3, engaged, 0);
|
||||
void Panda::send_heartbeat(bool engaged, bool engaged_mads) {
|
||||
handle->control_write(0xf3, engaged, engaged_mads);
|
||||
}
|
||||
|
||||
void Panda::set_can_speed_kbps(uint16_t bus, uint16_t speed) {
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
// Panda functionality
|
||||
cereal::PandaState::PandaType get_hw_type();
|
||||
void set_safety_model(cereal::CarParams::SafetyModel safety_model, uint16_t safety_param=0U);
|
||||
void set_alternative_experience(uint16_t alternative_experience);
|
||||
void set_alternative_experience(uint16_t alternative_experience, uint16_t safety_param_sp=0U);
|
||||
std::string serial_read(int port_number = 0);
|
||||
void set_uart_baud(int uart, int rate);
|
||||
void set_fan_speed(uint16_t fan_speed);
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
std::optional<std::string> get_serial();
|
||||
void set_power_saving(bool power_saving);
|
||||
void enable_deepsleep();
|
||||
void send_heartbeat(bool engaged);
|
||||
void send_heartbeat(bool engaged, bool engaged_mads);
|
||||
void set_can_speed_kbps(uint16_t bus, uint16_t speed);
|
||||
void set_can_fd_auto(uint16_t bus, bool enabled);
|
||||
void set_data_speed_kbps(uint16_t bus, uint16_t speed);
|
||||
|
||||
@@ -10,7 +10,8 @@ void PandaSafety::configureSafetyMode() {
|
||||
|
||||
auto car_params = fetchCarParams();
|
||||
if (!car_params.empty()) {
|
||||
LOGW("got %lu bytes CarParams", car_params.size());
|
||||
LOGW("got %lu bytes CarParams", car_params[0].size());
|
||||
LOGW("got %lu bytes CarParamsSP", car_params[1].size());
|
||||
setSafetyMode(car_params);
|
||||
safety_configured_ = true;
|
||||
}
|
||||
@@ -43,7 +44,8 @@ void PandaSafety::updateMultiplexingMode() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string PandaSafety::fetchCarParams() {
|
||||
// TODO-SP: Use structs instead of vector
|
||||
std::vector<std::string> PandaSafety::fetchCarParams() {
|
||||
if (!params_.getBool("FirmwareQueryDone")) {
|
||||
return {};
|
||||
}
|
||||
@@ -56,16 +58,23 @@ std::string PandaSafety::fetchCarParams() {
|
||||
if (!params_.getBool("ControlsReady")) {
|
||||
return {};
|
||||
}
|
||||
return params_.get("CarParams");
|
||||
return {params_.get("CarParams"), params_.get("CarParamsSP")};
|
||||
}
|
||||
|
||||
void PandaSafety::setSafetyMode(const std::string ¶ms_string) {
|
||||
// TODO-SP: Use structs instead of vector
|
||||
void PandaSafety::setSafetyMode(const std::vector<std::string> ¶ms_string) {
|
||||
AlignedBuffer aligned_buf;
|
||||
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(params_string.data(), params_string.size()));
|
||||
AlignedBuffer aligned_buf_sp;
|
||||
|
||||
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(params_string[0].data(), params_string[0].size()));
|
||||
cereal::CarParams::Reader car_params = cmsg.getRoot<cereal::CarParams>();
|
||||
|
||||
capnp::FlatArrayMessageReader cmsg_sp(aligned_buf_sp.align(params_string[1].data(), params_string[1].size()));
|
||||
cereal::CarParamsSP::Reader car_params_sp = cmsg_sp.getRoot<cereal::CarParamsSP>();
|
||||
|
||||
auto safety_configs = car_params.getSafetyConfigs();
|
||||
uint16_t alternative_experience = car_params.getAlternativeExperience();
|
||||
uint16_t safety_param_sp = car_params_sp.getSafetyParam();
|
||||
|
||||
for (int i = 0; i < pandas_.size(); ++i) {
|
||||
// Default to SILENT safety model if not specified
|
||||
@@ -76,8 +85,13 @@ void PandaSafety::setSafetyMode(const std::string ¶ms_string) {
|
||||
safety_param = safety_configs[i].getSafetyParam();
|
||||
}
|
||||
|
||||
LOGW("Panda %d: setting safety model: %d, param: %d, alternative experience: %d", i, (int)safety_model, safety_param, alternative_experience);
|
||||
pandas_[i]->set_alternative_experience(alternative_experience);
|
||||
LOGW("Panda %d: setting safety model: %d, param: %d, alternative experience: %d, param_sp: %d", i, (int)safety_model, safety_param, alternative_experience, safety_param_sp);
|
||||
pandas_[i]->set_alternative_experience(alternative_experience, safety_param_sp);
|
||||
pandas_[i]->set_safety_model(safety_model, safety_param);
|
||||
}
|
||||
}
|
||||
|
||||
bool PandaSafety::getOffroadMode() {
|
||||
auto offroad_mode = params_.getBool("OffroadMode");
|
||||
return offroad_mode;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#define CUTOFF_IL 400
|
||||
#define SATURATE_IL 1000
|
||||
|
||||
#define ALT_EXP_DISENGAGE_LATERAL_ON_BRAKE 2048
|
||||
|
||||
ExitHandler do_exit;
|
||||
|
||||
bool check_all_connected(const std::vector<Panda *> &pandas) {
|
||||
@@ -53,6 +55,18 @@ bool check_all_connected(const std::vector<Panda *> &pandas) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool process_mads_heartbeat(SubMaster *sm) {
|
||||
const int &alt_exp = (*sm)["carParams"].getCarParams().getAlternativeExperience();
|
||||
const bool disengage_lateral_on_brake = (alt_exp & ALT_EXP_DISENGAGE_LATERAL_ON_BRAKE) != 0;
|
||||
|
||||
const auto &mads = (*sm)["selfdriveStateSP"].getSelfdriveStateSP().getMads();
|
||||
const bool heartbeat_type = disengage_lateral_on_brake ? mads.getActive() : mads.getEnabled();
|
||||
|
||||
const bool engaged = sm->allAliveAndValid({"selfdriveStateSP"}) && heartbeat_type;
|
||||
|
||||
return engaged;
|
||||
}
|
||||
|
||||
Panda *connect(std::string serial="", uint32_t index=0) {
|
||||
std::unique_ptr<Panda> panda;
|
||||
try {
|
||||
@@ -188,7 +202,7 @@ void fill_panda_can_state(cereal::PandaState::PandaCanState::Builder &cs, const
|
||||
cs.setCanCoreResetCnt(can_health.can_core_reset_cnt);
|
||||
}
|
||||
|
||||
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool spoofing_started) {
|
||||
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool spoofing_started, bool always_offroad) {
|
||||
bool ignition_local = false;
|
||||
const uint32_t pandas_cnt = pandas.size();
|
||||
|
||||
@@ -236,7 +250,7 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
|
||||
health.ignition_line_pkt = 0;
|
||||
}
|
||||
|
||||
ignition_local |= ((health.ignition_line_pkt != 0) || (health.ignition_can_pkt != 0));
|
||||
ignition_local |= ((health.ignition_line_pkt != 0) || (health.ignition_can_pkt != 0)) && !always_offroad;
|
||||
|
||||
pandaStates.push_back(health);
|
||||
}
|
||||
@@ -323,14 +337,14 @@ void send_peripheral_state(Panda *panda, PubMaster *pm) {
|
||||
pm->send("peripheralState", msg);
|
||||
}
|
||||
|
||||
void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool engaged, bool spoofing_started) {
|
||||
void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool engaged, bool engaged_mads, bool spoofing_started, bool always_offroad) {
|
||||
std::vector<std::string> connected_serials;
|
||||
for (Panda *p : pandas) {
|
||||
connected_serials.push_back(p->hw_serial());
|
||||
}
|
||||
|
||||
{
|
||||
auto ignition_opt = send_panda_states(pm, pandas, spoofing_started);
|
||||
auto ignition_opt = send_panda_states(pm, pandas, spoofing_started, always_offroad);
|
||||
if (!ignition_opt) {
|
||||
LOGE("Failed to get ignition_opt");
|
||||
return;
|
||||
@@ -360,7 +374,7 @@ void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool engag
|
||||
}
|
||||
|
||||
for (const auto &panda : pandas) {
|
||||
panda->send_heartbeat(engaged);
|
||||
panda->send_heartbeat(engaged, engaged_mads);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -424,11 +438,13 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
||||
std::thread send_thread(can_send_thread, pandas, fake_send);
|
||||
|
||||
RateKeeper rk("pandad", 100);
|
||||
SubMaster sm({"selfdriveState"});
|
||||
SubMaster sm({"selfdriveState", "selfdriveStateSP", "carParams"});
|
||||
PubMaster pm({"can", "pandaStates", "peripheralState"});
|
||||
PandaSafety panda_safety(pandas);
|
||||
Panda *peripheral_panda = pandas[0];
|
||||
bool engaged = false;
|
||||
bool engaged_mads = false;
|
||||
bool always_offroad = false;
|
||||
|
||||
// Main loop: receive CAN data and process states
|
||||
while (!do_exit && check_all_connected(pandas)) {
|
||||
@@ -443,7 +459,9 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
||||
if (rk.frame() % 10 == 0) {
|
||||
sm.update(0);
|
||||
engaged = sm.allAliveAndValid({"selfdriveState"}) && sm["selfdriveState"].getSelfdriveState().getEnabled();
|
||||
process_panda_state(pandas, &pm, engaged, spoofing_started);
|
||||
engaged_mads = process_mads_heartbeat(&sm);
|
||||
always_offroad = panda_safety.getOffroadMode();
|
||||
process_panda_state(pandas, &pm, engaged, engaged_mads, spoofing_started, always_offroad);
|
||||
panda_safety.configureSafetyMode();
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user