mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-06-19 16:52:06 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e99599d51 |
@@ -2,4 +2,3 @@ Wen
|
|||||||
REGIST
|
REGIST
|
||||||
PullRequest
|
PullRequest
|
||||||
cancelled
|
cancelled
|
||||||
FOF
|
|
||||||
|
|||||||
@@ -18,6 +18,19 @@
|
|||||||
|
|
||||||
venv/
|
venv/
|
||||||
.venv/
|
.venv/
|
||||||
|
**/.idea
|
||||||
|
**/.hypothesis
|
||||||
|
**/.mypy_cache
|
||||||
|
|
||||||
|
**/.venv
|
||||||
|
**/.venv/
|
||||||
|
|
||||||
|
**/.ci_cache
|
||||||
|
**/*.rlog
|
||||||
|
|
||||||
|
**/Dockerfile*
|
||||||
|
**/dockerfile*
|
||||||
|
**/build_output
|
||||||
|
|
||||||
notebooks
|
notebooks
|
||||||
phone
|
phone
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: "PR review"
|
name: "PR review"
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [ opened, reopened, synchronize, edited ]
|
types: [opened, reopened, synchronize, edited]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
labeler:
|
labeler:
|
||||||
@@ -29,17 +29,17 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
target: /^(?!master$).*/
|
target: /^(?!master-new$).*/
|
||||||
exclude: /sunnypilot:.*/
|
exclude: /sunnypilot:.*/
|
||||||
change-to: ${{ github.base_ref }}
|
change-to: ${{ github.base_ref }}
|
||||||
already-exists-action: close_this
|
already-exists-action: close_this
|
||||||
already-exists-comment: "Your PR should be made against the `master` branch"
|
already-exists-comment: "Your PR should be made against the `master-new` branch"
|
||||||
|
|
||||||
update-pr-labels:
|
update-pr-labels:
|
||||||
name: Update fork's PR Labels
|
name: Update fork's PR Labels
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: (github.event.pull_request.head.repo.fork && (contains(github.event_name, 'pull_request') && github.event.action == 'synchronize'))
|
if: (github.event.pull_request.head.repo.fork && (contains(github.event_name, 'pull_request') && github.event.action == 'synchronize'))
|
||||||
env:
|
env:
|
||||||
PR_LABEL: 'dev-c3'
|
PR_LABEL: 'dev-c3'
|
||||||
TRUST_FORK_PR_LABEL: 'trust-fork-pr'
|
TRUST_FORK_PR_LABEL: 'trust-fork-pr'
|
||||||
steps:
|
steps:
|
||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
|
|
||||||
core.setOutput('has-dev-c3', hasDevC3Label ? 'true' : 'false');
|
core.setOutput('has-dev-c3', hasDevC3Label ? 'true' : 'false');
|
||||||
core.setOutput('has-trust', hasTrustLabel ? 'true' : 'false');
|
core.setOutput('has-trust', hasTrustLabel ? 'true' : 'false');
|
||||||
|
|
||||||
- name: Remove trust-fork-pr label if present
|
- name: Remove trust-fork-pr label if present
|
||||||
if: steps.check-labels.outputs.has-dev-c3 == 'true' && steps.check-labels.outputs.has-trust == 'true'
|
if: steps.check-labels.outputs.has-dev-c3 == 'true' && steps.check-labels.outputs.has-trust == 'true'
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
@@ -72,14 +72,14 @@ jobs:
|
|||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
script: |
|
script: |
|
||||||
const prNumber = context.payload.pull_request.number;
|
const prNumber = context.payload.pull_request.number;
|
||||||
|
|
||||||
await github.rest.issues.removeLabel({
|
await github.rest.issues.removeLabel({
|
||||||
owner: context.repo.owner,
|
owner: context.repo.owner,
|
||||||
repo: context.repo.repo,
|
repo: context.repo.repo,
|
||||||
issue_number: prNumber,
|
issue_number: prNumber,
|
||||||
name: process.env.TRUST_FORK_PR_LABEL
|
name: process.env.TRUST_FORK_PR_LABEL
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Removed '${process.env.TRUST_FORK_PR_LABEL}' label from PR #${prNumber} as it received new commits`);
|
console.log(`Removed '${process.env.TRUST_FORK_PR_LABEL}' label from PR #${prNumber} as it received new commits`);
|
||||||
|
|
||||||
// Add a comment to the PR
|
// Add a comment to the PR
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BASE_IMAGE: sunnypilot-base
|
BASE_IMAGE: openpilot-base
|
||||||
DOCKER_REGISTRY: ghcr.io/sunnypilot
|
DOCKER_REGISTRY: ghcr.io/commaai
|
||||||
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $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 $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/bash -c
|
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $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 $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/bash -c
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@@ -1,285 +0,0 @@
|
|||||||
name: Build and push all tinygrad models
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
set_min_version:
|
|
||||||
description: 'Minimum selector version required for the models (see helpers.py or readme.md)'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
setup:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
json_version: ${{ steps.get-json.outputs.json_version }}
|
|
||||||
recompiled_dir: ${{ steps.create-recompiled-dir.outputs.recompiled_dir }}
|
|
||||||
json_file: ${{ steps.get-json.outputs.json_file }}
|
|
||||||
model_matrix: ${{ steps.set-matrix.outputs.model_matrix }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout docs repo (sunnypilot-docs, gh-pages)
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: sunnypilot/sunnypilot-docs
|
|
||||||
ref: gh-pages
|
|
||||||
path: docs
|
|
||||||
ssh-key: ${{ secrets.CI_SUNNYPILOT_DOCS_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Get next JSON version to use (from GitHub docs repo)
|
|
||||||
id: get-json
|
|
||||||
run: |
|
|
||||||
cd docs/docs
|
|
||||||
latest=$(ls driving_models_v*.json | sed -E 's/.*_v([0-9]+)\.json/\1/' | sort -n | tail -1)
|
|
||||||
next=$((latest+1))
|
|
||||||
json_file="driving_models_v${next}.json"
|
|
||||||
cp "driving_models_v${latest}.json" "$json_file"
|
|
||||||
echo "json_file=docs/docs/$json_file" >> $GITHUB_OUTPUT
|
|
||||||
echo "json_version=$((next+0))" >> $GITHUB_OUTPUT
|
|
||||||
echo "SRC_JSON_FILE=docs/docs/driving_models_v${latest}.json" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Extract tinygrad models
|
|
||||||
id: set-matrix
|
|
||||||
working-directory: docs/docs
|
|
||||||
run: |
|
|
||||||
jq -c '[.bundles[] | select(.runner=="tinygrad") | {ref, display_name: (.display_name | gsub(" \\([^)]*\\)"; "")), is_20hz}]' "$(basename "${SRC_JSON_FILE}")" > matrix.json
|
|
||||||
echo "model_matrix=$(cat matrix.json)" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Set up SSH
|
|
||||||
uses: webfactory/ssh-agent@v0.9.0
|
|
||||||
with:
|
|
||||||
ssh-private-key: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
|
||||||
- run: |
|
|
||||||
mkdir -p ~/.ssh
|
|
||||||
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
|
||||||
|
|
||||||
- name: Clone GitLab docs repo and create new recompiled dir
|
|
||||||
id: create-recompiled-dir
|
|
||||||
env:
|
|
||||||
GIT_SSH_COMMAND: 'ssh -o UserKnownHostsFile=~/.ssh/known_hosts'
|
|
||||||
run: |
|
|
||||||
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/docs.sunnypilot.ai2.git gitlab_docs
|
|
||||||
cd gitlab_docs
|
|
||||||
git checkout main
|
|
||||||
git sparse-checkout set --no-cone models/
|
|
||||||
cd models
|
|
||||||
latest_dir=$(ls -d recompiled* 2>/dev/null | sed -E 's/recompiled([0-9]+)/\1/' | sort -n | tail -1)
|
|
||||||
if [[ -z "$latest_dir" ]]; then
|
|
||||||
next_dir=1
|
|
||||||
else
|
|
||||||
next_dir=$((latest_dir+1))
|
|
||||||
fi
|
|
||||||
recompiled_dir="${next_dir}"
|
|
||||||
mkdir -p "recompiled${recompiled_dir}"
|
|
||||||
touch "recompiled${recompiled_dir}/.gitkeep"
|
|
||||||
cd ../..
|
|
||||||
echo "recompiled_dir=$recompiled_dir" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Push empty recompiled dir to GitLab
|
|
||||||
run: |
|
|
||||||
cd gitlab_docs
|
|
||||||
git add models/recompiled${{ steps.create-recompiled-dir.outputs.recompiled_dir }}
|
|
||||||
git config --global user.name "GitHub Action"
|
|
||||||
git config --global user.email "action@github.com"
|
|
||||||
git commit -m "Add recompiled${{ steps.create-recompiled-dir.outputs.recompiled_dir }} for build-all" || echo "No changes to commit"
|
|
||||||
git push origin main
|
|
||||||
|
|
||||||
- name: Push new JSON to GitHub docs repo
|
|
||||||
run: |
|
|
||||||
cd docs
|
|
||||||
git pull origin gh-pages
|
|
||||||
git add docs/"$(basename ${{ steps.get-json.outputs.json_file }})"
|
|
||||||
git config --global user.name "GitHub Action"
|
|
||||||
git config --global user.email "action@github.com"
|
|
||||||
git commit -m "Add new ${{ steps.get-json.outputs.json_file }} for build-all" || echo "No changes to commit"
|
|
||||||
git push origin gh-pages
|
|
||||||
|
|
||||||
get_and_build:
|
|
||||||
needs: [setup]
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
model: ${{ fromJson(needs.setup.outputs.model_matrix) }}
|
|
||||||
fail-fast: false
|
|
||||||
uses: ./.github/workflows/build-single-tinygrad-model.yaml
|
|
||||||
with:
|
|
||||||
upstream_branch: ${{ matrix.model.ref }}
|
|
||||||
custom_name: ${{ matrix.model.display_name }}
|
|
||||||
recompiled_dir: ${{ needs.setup.outputs.recompiled_dir }}
|
|
||||||
json_version: ${{ needs.setup.outputs.json_version }}
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
retry_failed_models:
|
|
||||||
needs: [setup, get_and_build]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ needs.setup.result != 'failure' && (failure() && !cancelled()) }}
|
|
||||||
outputs:
|
|
||||||
retry_matrix: ${{ steps.set-retry-matrix.outputs.retry_matrix }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
pattern: model-*
|
|
||||||
path: output
|
|
||||||
|
|
||||||
- id: set-retry-matrix
|
|
||||||
run: |
|
|
||||||
echo '${{ needs.setup.outputs.model_matrix }}' > matrix.json
|
|
||||||
built=(); while IFS= read -r line; do built+=("$line"); done < <(
|
|
||||||
ls output | sed -E 's/^model-//' | sed -E 's/-[0-9]+$//' | sed -E 's/ \([^)]*\)//' | awk '{gsub(/^ +| +$/, ""); print}'
|
|
||||||
)
|
|
||||||
jq -c --argjson built "$(printf '%s\n' "${built[@]}" | jq -R . | jq -s .)" \
|
|
||||||
'map(select(.display_name as $n | ($built | index($n | gsub("^ +| +$"; "")) | not)))' matrix.json > retry_matrix.json
|
|
||||||
echo "retry_matrix=$(cat retry_matrix.json)" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
retry_get_and_build:
|
|
||||||
needs: [setup, get_and_build, retry_failed_models]
|
|
||||||
if: ${{ needs.get_and_build.result == 'failure' || (needs.retry_failed_models.outputs.retry_matrix != '[]' && needs.retry_failed_models.outputs.retry_matrix != '') }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
model: ${{ fromJson(needs.retry_failed_models.outputs.retry_matrix) }}
|
|
||||||
fail-fast: false
|
|
||||||
uses: ./.github/workflows/build-single-tinygrad-model.yaml
|
|
||||||
with:
|
|
||||||
upstream_branch: ${{ matrix.model.ref }}
|
|
||||||
custom_name: ${{ matrix.model.display_name }}
|
|
||||||
recompiled_dir: ${{ needs.setup.outputs.recompiled_dir }}
|
|
||||||
json_version: ${{ needs.setup.outputs.json_version }}
|
|
||||||
artifact_suffix: -retry
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
publish_models:
|
|
||||||
name: Publish models sequentially
|
|
||||||
needs: [setup, get_and_build, retry_failed_models, retry_get_and_build]
|
|
||||||
if: ${{ !cancelled() && (needs.get_and_build.result != 'failure' || needs.retry_get_and_build.result == 'success' || (needs.retry_failed_models.outputs.retry_matrix != '[]' && needs.retry_failed_models.outputs.retry_matrix != '')) }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
max-parallel: 1
|
|
||||||
matrix:
|
|
||||||
model: ${{ fromJson(needs.setup.outputs.model_matrix) }}
|
|
||||||
env:
|
|
||||||
RECOMPILED_DIR: recompiled${{ needs.setup.outputs.recompiled_dir }}
|
|
||||||
JSON_FILE: ${{ needs.setup.outputs.json_file }}
|
|
||||||
ARTIFACT_NAME_INPUT: ${{ matrix.model.display_name }}
|
|
||||||
steps:
|
|
||||||
- name: Set up SSH
|
|
||||||
uses: webfactory/ssh-agent@v0.9.0
|
|
||||||
with:
|
|
||||||
ssh-private-key: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Add GitLab.com SSH key to known_hosts
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.ssh
|
|
||||||
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
|
||||||
|
|
||||||
- name: Clone GitLab docs repo
|
|
||||||
env:
|
|
||||||
GIT_SSH_COMMAND: 'ssh -o UserKnownHostsFile=~/.ssh/known_hosts'
|
|
||||||
run: |
|
|
||||||
echo "Cloning GitLab"
|
|
||||||
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/docs.sunnypilot.ai2.git gitlab_docs
|
|
||||||
cd gitlab_docs
|
|
||||||
echo "checkout models/${RECOMPILED_DIR}"
|
|
||||||
git sparse-checkout set --no-cone models/${RECOMPILED_DIR}
|
|
||||||
git checkout main
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
- name: Checkout docs repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: sunnypilot/sunnypilot-docs
|
|
||||||
ref: gh-pages
|
|
||||||
path: docs
|
|
||||||
ssh-key: ${{ secrets.CI_SUNNYPILOT_DOCS_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Validate recompiled dir and JSON version
|
|
||||||
run: |
|
|
||||||
if [ ! -d "gitlab_docs/models/$RECOMPILED_DIR" ]; then
|
|
||||||
echo "Recompiled dir $RECOMPILED_DIR does not exist in GitLab repo"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ ! -f "$JSON_FILE" ]; then
|
|
||||||
echo "JSON file $JSON_FILE does not exist!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Download artifact name file
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: artifact-name-${{ env.ARTIFACT_NAME_INPUT }}
|
|
||||||
path: artifact_name
|
|
||||||
|
|
||||||
- name: Read artifact name
|
|
||||||
id: read-artifact-name
|
|
||||||
run: |
|
|
||||||
ARTIFACT_NAME=$(cat artifact_name/artifact_name.txt)
|
|
||||||
echo "artifact_name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Download model artifact
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
|
||||||
path: output
|
|
||||||
|
|
||||||
- name: Remove onnx files bc not needed for recompiled dir since they already exist from single build
|
|
||||||
run: |
|
|
||||||
find output -type f -name '*.onnx' -delete
|
|
||||||
find output -type f -name 'big_*.pkl' -delete
|
|
||||||
find output -type f -name 'dmonitoring_model_tinygrad.pkl' -delete
|
|
||||||
|
|
||||||
- name: Copy model artifacts to gitlab
|
|
||||||
env:
|
|
||||||
ARTIFACT_NAME: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
|
||||||
run: |
|
|
||||||
ARTIFACT_DIR="gitlab_docs/models/${RECOMPILED_DIR}/${ARTIFACT_NAME}"
|
|
||||||
mkdir -p "$ARTIFACT_DIR"
|
|
||||||
for path in output/*; do
|
|
||||||
if [ "$(basename "$path")" = "artifact_name.txt" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
name="$(basename "$path")"
|
|
||||||
if [ -d "$path" ]; then
|
|
||||||
mkdir -p "$ARTIFACT_DIR/$name"
|
|
||||||
cp -r "$path"/* "$ARTIFACT_DIR/$name/"
|
|
||||||
echo "Copied dir $name -> $ARTIFACT_DIR/$name"
|
|
||||||
else
|
|
||||||
cp "$path" "$ARTIFACT_DIR/"
|
|
||||||
echo "Copied file $name -> $ARTIFACT_DIR/"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Push recompiled dir to GitLab
|
|
||||||
env:
|
|
||||||
GITLAB_SSH_PRIVATE_KEY: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
|
||||||
run: |
|
|
||||||
cd gitlab_docs
|
|
||||||
git checkout main
|
|
||||||
git pull origin main
|
|
||||||
for d in models/"$RECOMPILED_DIR"/*/; do
|
|
||||||
git sparse-checkout add "$d"
|
|
||||||
done
|
|
||||||
git add models/"$RECOMPILED_DIR"
|
|
||||||
git config --global user.name "GitHub Action"
|
|
||||||
git config --global user.email "action@github.com"
|
|
||||||
git commit -m "Update $RECOMPILED_DIR with model from build-all-tinygrad-models" || echo "No changes to commit"
|
|
||||||
git push origin main
|
|
||||||
- run: |
|
|
||||||
cd docs
|
|
||||||
git pull origin gh-pages
|
|
||||||
|
|
||||||
- name: update json
|
|
||||||
run: |
|
|
||||||
ARGS=""
|
|
||||||
[ -n "${{ inputs.set_min_version }}" ] && ARGS="$ARGS --set-min-version \"${{ inputs.set_min_version }}\""
|
|
||||||
ARGS="$ARGS --sort-by-date"
|
|
||||||
eval python3 docs/json_parser.py \
|
|
||||||
--json-path "$JSON_FILE" \
|
|
||||||
--recompiled-dir "gitlab_docs/models/$RECOMPILED_DIR" \
|
|
||||||
$ARGS
|
|
||||||
|
|
||||||
- name: Push updated json to GitHub
|
|
||||||
run: |
|
|
||||||
cd docs
|
|
||||||
git config --global user.name "GitHub Action"
|
|
||||||
git config --global user.email "action@github.com"
|
|
||||||
git checkout gh-pages
|
|
||||||
git add docs/"$(basename $JSON_FILE)"
|
|
||||||
git commit -m "Update $(basename $JSON_FILE) after recompiling model" || echo "No changes to commit"
|
|
||||||
git push origin gh-pages
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
name: Build Single Tinygrad Model and Push
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
upstream_branch:
|
|
||||||
description: 'Upstream commit to build from'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
custom_name:
|
|
||||||
description: 'Custom name for the model (no date, only name)'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
recompiled_dir:
|
|
||||||
description: 'Existing recompiled directory number (e.g. 3 for recompiled3)'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
json_version:
|
|
||||||
description: 'driving_models version number to update (e.g. 5 for driving_models_v5.json)'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
artifact_suffix:
|
|
||||||
description: 'Suffix for artifact name'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: ''
|
|
||||||
bypass_push:
|
|
||||||
description: 'Bypass pushing to GitLab for build-all'
|
|
||||||
required: false
|
|
||||||
default: true
|
|
||||||
type: boolean
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
upstream_branch:
|
|
||||||
description: 'Upstream commit to build from'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
custom_name:
|
|
||||||
description: 'Custom name for the model (no date, only name)'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
recompiled_dir:
|
|
||||||
description: 'Existing recompiled directory number (e.g. 3 for recompiled3)'
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
json_version:
|
|
||||||
description: 'driving_models version number to update (e.g. 5 for driving_models_v5.json)'
|
|
||||||
required: true
|
|
||||||
type: number
|
|
||||||
model_folder:
|
|
||||||
description: 'Model folder'
|
|
||||||
type: choice
|
|
||||||
default: 'None'
|
|
||||||
options:
|
|
||||||
- None
|
|
||||||
- Simple Plan Models
|
|
||||||
- Space Lab Models
|
|
||||||
- TR Models
|
|
||||||
- DTR Models
|
|
||||||
- Custom Merge Models
|
|
||||||
- FOF series models
|
|
||||||
- Other
|
|
||||||
custom_model_folder:
|
|
||||||
description: 'Custom model folder name (if "Other" selected)'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
generation:
|
|
||||||
description: 'Model generation'
|
|
||||||
required: false
|
|
||||||
type: number
|
|
||||||
version:
|
|
||||||
description: 'Minimum selector version'
|
|
||||||
required: false
|
|
||||||
type: number
|
|
||||||
env:
|
|
||||||
RECOMPILED_DIR: recompiled${{ inputs.recompiled_dir }}
|
|
||||||
JSON_FILE: docs/docs/driving_models_v${{ inputs.json_version }}.json
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_model:
|
|
||||||
uses: ./.github/workflows/sunnypilot-build-model.yaml
|
|
||||||
with:
|
|
||||||
upstream_branch: ${{ inputs.upstream_branch }}
|
|
||||||
custom_name: ${{ inputs.custom_name || inputs.upstream_branch }}
|
|
||||||
is_20hz: true
|
|
||||||
artifact_suffix: ${{ inputs.artifact_suffix }}
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
publish_model:
|
|
||||||
if: ${{ !inputs.bypass_push && !cancelled() }}
|
|
||||||
concurrency:
|
|
||||||
group: gitlab-push-${{ inputs.recompiled_dir }}
|
|
||||||
cancel-in-progress: false
|
|
||||||
needs: build_model
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up SSH
|
|
||||||
uses: webfactory/ssh-agent@v0.9.0
|
|
||||||
with:
|
|
||||||
ssh-private-key: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Add GitLab.com SSH key to known_hosts
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.ssh
|
|
||||||
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
|
||||||
|
|
||||||
- name: Clone GitLab docs repo
|
|
||||||
env:
|
|
||||||
GIT_SSH_COMMAND: 'ssh -o UserKnownHostsFile=~/.ssh/known_hosts'
|
|
||||||
run: |
|
|
||||||
echo "Cloning GitLab"
|
|
||||||
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/docs.sunnypilot.ai2.git gitlab_docs
|
|
||||||
cd gitlab_docs
|
|
||||||
echo "checkout models/${RECOMPILED_DIR}"
|
|
||||||
git sparse-checkout set --no-cone models/${RECOMPILED_DIR}
|
|
||||||
git checkout main
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
- name: Checkout docs repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: sunnypilot/sunnypilot-docs
|
|
||||||
ref: gh-pages
|
|
||||||
path: docs
|
|
||||||
ssh-key: ${{ secrets.CI_SUNNYPILOT_DOCS_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Validate recompiled dir and JSON version
|
|
||||||
run: |
|
|
||||||
if [ ! -d "gitlab_docs/models/$RECOMPILED_DIR" ]; then
|
|
||||||
echo "Recompiled dir $RECOMPILED_DIR does not exist in GitLab repo"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ ! -f "$JSON_FILE" ]; then
|
|
||||||
echo "JSON file $JSON_FILE does not exist!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Download artifact name file
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: artifact-name-${{ inputs.custom_name || inputs.upstream_branch }}
|
|
||||||
path: artifact_name
|
|
||||||
|
|
||||||
- name: Read artifact name
|
|
||||||
id: read-artifact-name
|
|
||||||
run: |
|
|
||||||
ARTIFACT_NAME=$(cat artifact_name/artifact_name.txt)
|
|
||||||
echo "artifact_name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Download and extract model artifact
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
|
||||||
path: output
|
|
||||||
|
|
||||||
- name: Remove unwanted files
|
|
||||||
run: |
|
|
||||||
find output -type f -name 'dmonitoring_model_tinygrad.pkl' -delete
|
|
||||||
find output -type f -name 'dmonitoring_model.onnx' -delete
|
|
||||||
|
|
||||||
- name: Copy model artifact(s) to GitLab recompiled dir
|
|
||||||
env:
|
|
||||||
ARTIFACT_NAME: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
|
||||||
run: |
|
|
||||||
ARTIFACT_DIR="gitlab_docs/models/${RECOMPILED_DIR}/${ARTIFACT_NAME}"
|
|
||||||
mkdir -p "$ARTIFACT_DIR"
|
|
||||||
for path in output/*; do
|
|
||||||
if [ "$(basename "$path")" = "artifact_name.txt" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
name="$(basename "$path")"
|
|
||||||
if [ -d "$path" ]; then
|
|
||||||
mkdir -p "$ARTIFACT_DIR/$name"
|
|
||||||
cp -r "$path"/* "$ARTIFACT_DIR/$name/"
|
|
||||||
echo "Copied dir $name -> $ARTIFACT_DIR/$name"
|
|
||||||
else
|
|
||||||
cp "$path" "$ARTIFACT_DIR/"
|
|
||||||
echo "Copied file $name -> $ARTIFACT_DIR/"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Push recompiled dir to GitLab
|
|
||||||
env:
|
|
||||||
GITLAB_SSH_PRIVATE_KEY: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
|
||||||
run: |
|
|
||||||
cd gitlab_docs
|
|
||||||
git checkout main
|
|
||||||
git pull origin main
|
|
||||||
for d in models/"$RECOMPILED_DIR"/*/; do
|
|
||||||
git sparse-checkout add "$d"
|
|
||||||
done
|
|
||||||
git add models/"$RECOMPILED_DIR"
|
|
||||||
git config --global user.name "GitHub Action"
|
|
||||||
git config --global user.email "action@github.com"
|
|
||||||
git commit -m "Create/Update $RECOMPILED_DIR with new/updated model from build-single-tinygrad-model" || echo "No changes to commit"
|
|
||||||
git push origin main
|
|
||||||
|
|
||||||
- run: |
|
|
||||||
cd docs
|
|
||||||
git pull origin gh-pages
|
|
||||||
|
|
||||||
- name: Run json_parser.py to update JSON
|
|
||||||
run: |
|
|
||||||
FOLDER="${{ inputs.model_folder }}"
|
|
||||||
if [ "$FOLDER" = "Other" ]; then
|
|
||||||
FOLDER="${{ inputs.custom_model_folder }}"
|
|
||||||
fi
|
|
||||||
ARGS=""
|
|
||||||
if [ "$FOLDER" != "None" ] && [ -n "$FOLDER" ]; then
|
|
||||||
ARGS="$ARGS --model-folder \"$FOLDER\""
|
|
||||||
fi
|
|
||||||
[ -n "${{ inputs.generation }}" ] && ARGS="$ARGS --generation \"${{ inputs.generation }}\""
|
|
||||||
[ -n "${{ inputs.version }}" ] && ARGS="$ARGS --version \"${{ inputs.version }}\""
|
|
||||||
eval python3 docs/json_parser.py \
|
|
||||||
--json-path "$JSON_FILE" \
|
|
||||||
--recompiled-dir "gitlab_docs/models/$RECOMPILED_DIR" \
|
|
||||||
--sort-by-date \
|
|
||||||
$ARGS
|
|
||||||
|
|
||||||
- name: Push updated JSON to GitHub docs repo
|
|
||||||
run: |
|
|
||||||
cd docs
|
|
||||||
git config --global user.name "GitHub Action"
|
|
||||||
git config --global user.email "action@github.com"
|
|
||||||
git checkout gh-pages
|
|
||||||
git add docs/"$(basename $JSON_FILE)"
|
|
||||||
git commit -m "Update $(basename $JSON_FILE) after recompiling model" || echo "No changes to commit"
|
|
||||||
git push origin gh-pages
|
|
||||||
@@ -4,6 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
- master-new
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'cereal/**'
|
- 'cereal/**'
|
||||||
@@ -16,13 +17,13 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: cereal-validation-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: 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
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHONWARNINGS: error
|
PYTHONWARNINGS: error
|
||||||
BASE_IMAGE: sunnypilot-base
|
BASE_IMAGE: openpilot-base
|
||||||
BUILD: release/ci/docker_build_sp.sh 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
|
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:
|
jobs:
|
||||||
@@ -59,7 +60,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: 'sunnypilot/sunnypilot'
|
repository: 'commaai/openpilot'
|
||||||
submodules: true
|
submodules: true
|
||||||
ref: "refs/heads/master"
|
ref: "refs/heads/master"
|
||||||
- uses: ./.github/workflows/setup-with-retry
|
- uses: ./.github/workflows/setup-with-retry
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ runs:
|
|||||||
scons -j$(nproc) --cache-populate"
|
scons -j$(nproc) --cache-populate"
|
||||||
- name: Save scons cache
|
- name: Save scons cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v4
|
||||||
if: github.ref == 'refs/heads/master'
|
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new')
|
||||||
with:
|
with:
|
||||||
path: .ci_cache/scons_cache
|
path: .ci_cache/scons_cache
|
||||||
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ on:
|
|||||||
- cron: '0 0 * * *' # Runs at 00:00 UTC every day
|
- cron: '0 0 * * *' # Runs at 00:00 UTC every day
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master-new'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master-new'
|
||||||
workflow_dispatch: # enables manual triggering
|
workflow_dispatch: # enables manual triggering
|
||||||
inputs:
|
inputs:
|
||||||
upstream_branch:
|
upstream_branch:
|
||||||
default: 'master'
|
default: 'master'
|
||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repository: 'commaai/openpilot'
|
repository: 'commaai/openpilot'
|
||||||
ref: ${{ inputs.upstream_branch }}
|
ref: ${{ inputs.upstream_branch }}
|
||||||
|
|
||||||
- name: LFS Fetch
|
- name: LFS Fetch
|
||||||
run: |
|
run: |
|
||||||
git lfs fetch
|
git lfs fetch
|
||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
- name: Add GitLab public keys
|
- name: Add GitLab public keys
|
||||||
run: |
|
run: |
|
||||||
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
- name: Ensure branch
|
- name: Ensure branch
|
||||||
run: |
|
run: |
|
||||||
if git symbolic-ref -q HEAD >/dev/null; then
|
if git symbolic-ref -q HEAD >/dev/null; then
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
||||||
BUILD: release/ci/docker_build_sp.sh prebuilt
|
BUILD: selfdrive/test/docker_build.sh prebuilt
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_prebuilt:
|
build_prebuilt:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ name: Release Drafter
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
- master-new
|
||||||
- master
|
- master
|
||||||
tags:
|
tags:
|
||||||
- 'v*'
|
- 'v*'
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build___nightly:
|
build_masterci:
|
||||||
name: build __nightly
|
name: build master-ci
|
||||||
env:
|
env:
|
||||||
ImageOS: ubuntu24
|
ImageOS: ubuntu24
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/sunnypilot/sunnypilot-base:latest
|
image: ghcr.io/commaai/openpilot-base:latest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
permissions:
|
permissions:
|
||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
wait-interval: 30
|
wait-interval: 30
|
||||||
running-workflow-name: 'build __nightly'
|
running-workflow-name: 'build master-ci'
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
check-regexp: ^((?!.*(build prebuilt).*).)*$
|
check-regexp: ^((?!.*(build prebuilt).*).)*$
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -38,5 +38,5 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
git config --global --add safe.directory '*'
|
git config --global --add safe.directory '*'
|
||||||
git lfs pull
|
git lfs pull
|
||||||
- name: Push __nightly
|
- name: Push master-ci
|
||||||
run: BRANCH=__nightly release/build_devel.sh
|
run: BRANCH=__nightly release/build_devel.sh
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BASE_IMAGE: sunnypilot-base
|
BASE_IMAGE: openpilot-base
|
||||||
BUILD: release/ci/docker_build_sp.sh 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
|
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:
|
jobs:
|
||||||
update_translations:
|
update_translations:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'commaai/openpilot'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: ./.github/workflows/setup-with-retry
|
- uses: ./.github/workflows/setup-with-retry
|
||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
|
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
|
||||||
with:
|
with:
|
||||||
author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
|
author: Vehicle Researcher <user@comma.ai>
|
||||||
commit-message: "Update translations"
|
commit-message: "Update translations"
|
||||||
title: "[bot] Update translations"
|
title: "[bot] Update translations"
|
||||||
body: "Automatic PR from repo-maintenance -> update_translations"
|
body: "Automatic PR from repo-maintenance -> update_translations"
|
||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
name: package_updates
|
name: package_updates
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/sunnypilot/sunnypilot-base:latest
|
image: ghcr.io/commaai/openpilot-base:latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -61,8 +61,8 @@ jobs:
|
|||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
|
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
|
||||||
with:
|
with:
|
||||||
author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
|
author: Vehicle Researcher <user@comma.ai>
|
||||||
token: ${{ github.repository == 'commaai/openpilot' && secrets.ACTIONS_CREATE_PR_PAT || secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.ACTIONS_CREATE_PR_PAT }}
|
||||||
commit-message: Update Python packages
|
commit-message: Update Python packages
|
||||||
title: '[bot] Update Python packages'
|
title: '[bot] Update Python packages'
|
||||||
branch: auto-package-updates
|
branch: auto-package-updates
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
- master-new
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
@@ -14,30 +15,28 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
concurrency:
|
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
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
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
|
PYTHONWARNINGS: error
|
||||||
BASE_IMAGE: sunnypilot-base
|
BASE_IMAGE: openpilot-base
|
||||||
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
||||||
|
|
||||||
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
||||||
BUILD: release/ci/docker_build_sp.sh 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
|
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
|
||||||
|
|
||||||
PYTEST: pytest --continue-on-collection-errors --durations=0 --durations-min=5 -n logical
|
PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 -n logical
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_release:
|
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
|
name: build release
|
||||||
runs-on: ${{
|
runs-on:
|
||||||
(github.repository == 'commaai/openpilot') &&
|
- 'ubuntu-24.04'
|
||||||
((github.event_name != 'pull_request') ||
|
|
||||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
|
||||||
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|
||||||
env:
|
env:
|
||||||
STRIPPED_DIR: /tmp/releasepilot
|
STRIPPED_DIR: /tmp/releasepilot
|
||||||
steps:
|
steps:
|
||||||
@@ -67,37 +66,17 @@ jobs:
|
|||||||
- name: Check submodules
|
- name: Check submodules
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
timeout-minutes: 3
|
timeout-minutes: 3
|
||||||
run: |
|
run: release/check-submodules.sh
|
||||||
if [ "${{ github.ref }}" != "refs/heads/master" ]; then
|
|
||||||
git fetch origin master:refs/remotes/origin/master
|
|
||||||
|
|
||||||
SUBMODULE_PATHS=$(git diff origin/master HEAD --name-only | grep -E '^[^/]+$' | while read path; do
|
|
||||||
if git ls-files --stage "$path" | grep -q "^160000"; then
|
|
||||||
echo "$path"
|
|
||||||
fi
|
|
||||||
done | tr '\n' ' ')
|
|
||||||
|
|
||||||
if [ -n "$SUBMODULE_PATHS" ]; then
|
|
||||||
echo "Changed submodule paths: $SUBMODULE_PATHS"
|
|
||||||
export SUBMODULE_PATHS="$SUBMODULE_PATHS"
|
|
||||||
export CHECK_PR_REFS=true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
release/check-submodules.sh
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ${{
|
runs-on:
|
||||||
(github.repository == 'commaai/openpilot') &&
|
- 'ubuntu-24.04'
|
||||||
((github.event_name != 'pull_request') ||
|
|
||||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
|
||||||
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup docker push
|
- name: Setup docker push
|
||||||
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'sunnypilot/sunnypilot'
|
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
|
||||||
run: |
|
run: |
|
||||||
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
|
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
|
||||||
$DOCKER_LOGIN
|
$DOCKER_LOGIN
|
||||||
@@ -107,7 +86,6 @@ jobs:
|
|||||||
|
|
||||||
build_mac:
|
build_mac:
|
||||||
name: build macOS
|
name: build macOS
|
||||||
if: false # temp disable since homebrew install is getting stuck
|
|
||||||
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' }}
|
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:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -129,7 +107,7 @@ jobs:
|
|||||||
PYTHONWARNINGS: default
|
PYTHONWARNINGS: default
|
||||||
- name: Save Homebrew cache
|
- name: Save Homebrew cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v4
|
||||||
if: github.ref == 'refs/heads/master'
|
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new')
|
||||||
with:
|
with:
|
||||||
path: ~/Library/Caches/Homebrew
|
path: ~/Library/Caches/Homebrew
|
||||||
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
@@ -146,19 +124,15 @@ jobs:
|
|||||||
run: . .venv/bin/activate && scons -j$(nproc)
|
run: . .venv/bin/activate && scons -j$(nproc)
|
||||||
- name: Save scons cache
|
- name: Save scons cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v4
|
||||||
if: github.ref == 'refs/heads/master'
|
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new')
|
||||||
with:
|
with:
|
||||||
path: /tmp/scons_cache
|
path: /tmp/scons_cache
|
||||||
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
|
|
||||||
static_analysis:
|
static_analysis:
|
||||||
name: static analysis
|
name: static analysis
|
||||||
runs-on: ${{
|
runs-on:
|
||||||
(github.repository == 'commaai/openpilot') &&
|
- 'ubuntu-latest'
|
||||||
((github.event_name != 'pull_request') ||
|
|
||||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
|
||||||
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|
||||||
env:
|
env:
|
||||||
PYTHONWARNINGS: default
|
PYTHONWARNINGS: default
|
||||||
steps:
|
steps:
|
||||||
@@ -172,44 +146,40 @@ jobs:
|
|||||||
|
|
||||||
unit_tests:
|
unit_tests:
|
||||||
name: unit tests
|
name: unit tests
|
||||||
runs-on: ${{
|
runs-on:
|
||||||
(github.repository == 'commaai/openpilot') &&
|
- 'ubuntu-24.04'
|
||||||
((github.event_name != 'pull_request') ||
|
|
||||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
|
||||||
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: ./.github/workflows/setup-with-retry
|
- uses: ./.github/workflows/setup-with-retry
|
||||||
id: setup-step
|
|
||||||
- name: Build openpilot
|
- name: Build openpilot
|
||||||
run: ${{ env.RUN }} "scons -j$(nproc)"
|
run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
timeout-minutes: ${{ contains(runner.name, 'nsc') && ((steps.setup-step.outputs.duration < 18) && 1 || 2) || 999 }}
|
timeout-minutes: ${{ contains(runner.name, 'nsc') && 1 || 20 }}
|
||||||
run: |
|
run: |
|
||||||
${{ env.RUN }} "$PYTEST --collect-only -m 'not slow' &> /dev/null && \
|
${{ env.RUN }} "$PYTEST --collect-only -m 'not slow' &> /dev/null && \
|
||||||
MAX_EXAMPLES=1 $PYTEST -m 'not slow' && \
|
MAX_EXAMPLES=1 $PYTEST -m 'not slow' && \
|
||||||
./selfdrive/ui/tests/create_test_translations.sh && \
|
./selfdrive/ui/tests/create_test_translations.sh && \
|
||||||
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \
|
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \
|
||||||
chmod -R 777 /tmp/comma_download_cache"
|
chmod -R 777 /tmp/comma_download_cache"
|
||||||
|
- name: "Upload coverage to Codecov"
|
||||||
|
uses: codecov/codecov-action@v4
|
||||||
|
with:
|
||||||
|
name: ${{ github.job }}
|
||||||
|
env:
|
||||||
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
process_replay:
|
process_replay:
|
||||||
name: process replay
|
name: process replay
|
||||||
if: false # disable process_replay for forks
|
if: github.repository == 'commaai/openpilot' # disable process_replay for forks
|
||||||
runs-on: ${{
|
runs-on:
|
||||||
(github.repository == 'commaai/openpilot') &&
|
- 'ubuntu-24.04'
|
||||||
((github.event_name != 'pull_request') ||
|
|
||||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
|
||||||
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: ./.github/workflows/setup-with-retry
|
- uses: ./.github/workflows/setup-with-retry
|
||||||
id: setup-step
|
|
||||||
- name: Cache test routes
|
- name: Cache test routes
|
||||||
id: dependency-cache
|
id: dependency-cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@@ -220,10 +190,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
${{ env.RUN }} "scons -j$(nproc)"
|
${{ env.RUN }} "scons -j$(nproc)"
|
||||||
- name: Run replay
|
- name: Run replay
|
||||||
timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.dependency-cache.outputs.cache-hit == 'true') && ((steps.setup-step.outputs.duration < 18) && 1 || 2) || 20 }}
|
timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.dependency-cache.outputs.cache-hit == 'true') && 1 || 20 }}
|
||||||
run: |
|
run: |
|
||||||
${{ env.RUN }} "selfdrive/test/process_replay/test_processes.py -j$(nproc) && \
|
${{ env.RUN }} "coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \
|
||||||
chmod -R 777 /tmp/comma_download_cache"
|
chmod -R 777 /tmp/comma_download_cache && \
|
||||||
|
coverage combine && \
|
||||||
|
coverage xml"
|
||||||
- name: Print diff
|
- name: Print diff
|
||||||
id: print-diff
|
id: print-diff
|
||||||
if: always()
|
if: always()
|
||||||
@@ -235,7 +207,7 @@ jobs:
|
|||||||
name: process_replay_diff.txt
|
name: process_replay_diff.txt
|
||||||
path: selfdrive/test/process_replay/diff.txt
|
path: selfdrive/test/process_replay/diff.txt
|
||||||
- name: Upload reference logs
|
- name: Upload reference logs
|
||||||
if: false # TODO: move this to github instead of azure
|
if: ${{ failure() && steps.print-diff.outcome == 'success' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }}
|
||||||
run: |
|
run: |
|
||||||
${{ env.RUN }} "unset PYTHONWARNINGS && AZURE_TOKEN='$AZURE_TOKEN' python3 selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only"
|
${{ env.RUN }} "unset PYTHONWARNINGS && AZURE_TOKEN='$AZURE_TOKEN' python3 selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only"
|
||||||
- name: Run regen
|
- name: Run regen
|
||||||
@@ -244,27 +216,119 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
${{ env.RUN }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \
|
${{ env.RUN }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \
|
||||||
chmod -R 777 /tmp/comma_download_cache"
|
chmod -R 777 /tmp/comma_download_cache"
|
||||||
|
- name: "Upload coverage to Codecov"
|
||||||
|
uses: codecov/codecov-action@v4
|
||||||
|
with:
|
||||||
|
name: ${{ github.job }}
|
||||||
|
env:
|
||||||
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
|
test_cars:
|
||||||
|
name: cars
|
||||||
|
runs-on:
|
||||||
|
- 'ubuntu-24.04'
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
job: [0, 1, 2, 3]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: ./.github/workflows/setup-with-retry
|
||||||
|
- name: Cache test routes
|
||||||
|
id: routes-cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: .ci_cache/comma_download_cache
|
||||||
|
key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'opendbc/car/tests/routes.py') }}-${{ matrix.job }}
|
||||||
|
- name: Build openpilot
|
||||||
|
run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||||
|
- name: Test car models
|
||||||
|
timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.routes-cache.outputs.cache-hit == 'true') && 1 || 6 }}
|
||||||
|
run: |
|
||||||
|
${{ env.RUN }} "MAX_EXAMPLES=1 $PYTEST selfdrive/car/tests/test_models.py && \
|
||||||
|
chmod -R 777 /tmp/comma_download_cache"
|
||||||
|
env:
|
||||||
|
NUM_JOBS: 4
|
||||||
|
JOB_ID: ${{ matrix.job }}
|
||||||
|
- name: "Upload coverage to Codecov"
|
||||||
|
uses: codecov/codecov-action@v4
|
||||||
|
with:
|
||||||
|
name: ${{ github.job }}-${{ matrix.job }}
|
||||||
|
env:
|
||||||
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
|
car_docs_diff:
|
||||||
|
name: PR comments
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
#if: github.event_name == 'pull_request'
|
||||||
|
if: false # TODO: run this in opendbc?
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
ref: ${{ github.event.pull_request.base.ref }}
|
||||||
|
- run: git lfs pull
|
||||||
|
- uses: ./.github/workflows/setup-with-retry
|
||||||
|
- name: Get base car info
|
||||||
|
run: |
|
||||||
|
${{ env.RUN }} "scons -j$(nproc) && python3 selfdrive/debug/dump_car_docs.py --path /tmp/openpilot_cache/base_car_docs"
|
||||||
|
sudo chown -R $USER:$USER ${{ github.workspace }}
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
path: current
|
||||||
|
- run: cd current && git lfs pull
|
||||||
|
- name: Save car docs diff
|
||||||
|
id: save_diff
|
||||||
|
run: |
|
||||||
|
cd current
|
||||||
|
${{ env.RUN }} "scons -j$(nproc)"
|
||||||
|
output=$(${{ env.RUN }} "python3 selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_docs")
|
||||||
|
output="${output//$'\n'/'%0A'}"
|
||||||
|
echo "::set-output name=diff::$output"
|
||||||
|
- name: Find comment
|
||||||
|
if: ${{ env.AZURE_TOKEN != '' }}
|
||||||
|
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e
|
||||||
|
id: fc
|
||||||
|
with:
|
||||||
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
body-includes: This PR makes changes to
|
||||||
|
- name: Update comment
|
||||||
|
if: ${{ steps.save_diff.outputs.diff != '' && env.AZURE_TOKEN != '' }}
|
||||||
|
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043
|
||||||
|
with:
|
||||||
|
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||||
|
issue-number: ${{ github.event.pull_request.number }}
|
||||||
|
body: "${{ steps.save_diff.outputs.diff }}"
|
||||||
|
edit-mode: replace
|
||||||
|
- name: Delete comment
|
||||||
|
if: ${{ steps.fc.outputs.comment-id != '' && steps.save_diff.outputs.diff == '' && env.AZURE_TOKEN != '' }}
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
github.rest.issues.deleteComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
comment_id: ${{ steps.fc.outputs.comment-id }}
|
||||||
|
})
|
||||||
|
|
||||||
simulator_driving:
|
simulator_driving:
|
||||||
name: simulator driving
|
name: simulator driving
|
||||||
runs-on: ${{
|
runs-on:
|
||||||
(github.repository == 'commaai/openpilot') &&
|
- 'ubuntu-24.04'
|
||||||
((github.event_name != 'pull_request') ||
|
|
||||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
|
||||||
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|
||||||
if: (github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
if: (github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: ./.github/workflows/setup-with-retry
|
- uses: ./.github/workflows/setup-with-retry
|
||||||
id: setup-step
|
|
||||||
- name: Build openpilot
|
- name: Build openpilot
|
||||||
run: |
|
run: |
|
||||||
${{ env.RUN }} "scons -j$(nproc)"
|
${{ env.RUN }} "scons -j$(nproc)"
|
||||||
- name: Driving test
|
- name: Driving test
|
||||||
timeout-minutes: ${{ (steps.setup-step.outputs.duration < 18) && 1 || 2 }}
|
timeout-minutes: 1
|
||||||
run: |
|
run: |
|
||||||
${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
|
${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
|
||||||
source selfdrive/test/setup_vsound.sh && \
|
source selfdrive/test/setup_vsound.sh && \
|
||||||
@@ -273,13 +337,8 @@ jobs:
|
|||||||
create_ui_report:
|
create_ui_report:
|
||||||
# This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml
|
# This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml
|
||||||
name: Create UI Report
|
name: Create UI Report
|
||||||
runs-on: ${{
|
runs-on:
|
||||||
(github.repository == 'commaai/openpilot') &&
|
- 'ubuntu-24.04'
|
||||||
((github.event_name != 'pull_request') ||
|
|
||||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
|
||||||
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|
||||||
if: false # FIXME: FrameReader is broken on CI runners
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -303,5 +362,5 @@ jobs:
|
|||||||
- name: Upload Test Report
|
- name: Upload Test Report
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
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
|
path: selfdrive/ui/tests/test_ui/report_1/screenshots
|
||||||
|
|||||||
@@ -10,17 +10,9 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
default: 30
|
default: 30
|
||||||
|
|
||||||
outputs:
|
|
||||||
duration:
|
|
||||||
description: 'Duration of the setup process in seconds'
|
|
||||||
value: ${{ steps.get_duration.outputs.duration }}
|
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- id: start_time
|
|
||||||
shell: bash
|
|
||||||
run: echo "START_TIME=$(date +%s)" >> $GITHUB_ENV
|
|
||||||
- id: setup1
|
- id: setup1
|
||||||
uses: ./.github/workflows/setup
|
uses: ./.github/workflows/setup
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@@ -43,10 +35,3 @@ runs:
|
|||||||
uses: ./.github/workflows/setup
|
uses: ./.github/workflows/setup
|
||||||
with:
|
with:
|
||||||
is_retried: true
|
is_retried: true
|
||||||
- id: get_duration
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
END_TIME=$(date +%s)
|
|
||||||
DURATION=$((END_TIME - START_TIME))
|
|
||||||
echo "Total duration: $DURATION seconds"
|
|
||||||
echo "duration=$DURATION" >> $GITHUB_OUTPUT
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ on:
|
|||||||
env:
|
env:
|
||||||
DAYS_BEFORE_PR_CLOSE: 2
|
DAYS_BEFORE_PR_CLOSE: 2
|
||||||
DAYS_BEFORE_PR_STALE: 9
|
DAYS_BEFORE_PR_STALE: 9
|
||||||
DAYS_BEFORE_PR_STALE_DRAFT: 30
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
@@ -25,28 +24,6 @@ jobs:
|
|||||||
exempt-pr-labels: "ignore stale,needs testing" # if wip or it needs testing from the community, don't mark as stale
|
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-stale: ${{ env.DAYS_BEFORE_PR_STALE }}
|
||||||
days-before-pr-close: ${{ env.DAYS_BEFORE_PR_CLOSE }}
|
days-before-pr-close: ${{ env.DAYS_BEFORE_PR_CLOSE }}
|
||||||
exempt-draft-pr: false
|
|
||||||
|
|
||||||
# issue config
|
|
||||||
days-before-issue-stale: -1 # ignore issues for now
|
|
||||||
|
|
||||||
# same as above, but give draft PRs more time
|
|
||||||
stale_drafts:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@v9
|
|
||||||
with:
|
|
||||||
exempt-all-milestones: true
|
|
||||||
|
|
||||||
# pull request config
|
|
||||||
stale-pr-message: 'This PR has had no activity for ${{ env.DAYS_BEFORE_PR_STALE_DRAFT }} 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
|
|
||||||
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_DRAFT }}
|
|
||||||
days-before-pr-close: ${{ env.DAYS_BEFORE_PR_CLOSE }}
|
|
||||||
exempt-draft-pr: true
|
|
||||||
|
|
||||||
# issue config
|
# issue config
|
||||||
days-before-issue-stale: -1 # ignore issues for now
|
days-before-issue-stale: -1 # ignore issues for now
|
||||||
|
|||||||
@@ -9,27 +9,6 @@ env:
|
|||||||
MODELS_DIR: ${{ github.workspace }}/selfdrive/modeld/models
|
MODELS_DIR: ${{ github.workspace }}/selfdrive/modeld/models
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
upstream_branch:
|
|
||||||
description: 'Upstream branch to build from'
|
|
||||||
required: true
|
|
||||||
default: 'master'
|
|
||||||
type: string
|
|
||||||
custom_name:
|
|
||||||
description: 'Custom name for the model (no date, only name)'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
is_20hz:
|
|
||||||
description: 'Is this a 20Hz model'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
artifact_suffix:
|
|
||||||
description: 'Suffix for artifact name'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: ''
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
upstream_branch:
|
upstream_branch:
|
||||||
@@ -53,53 +32,34 @@ run-name: Build model [${{ inputs.custom_name || inputs.upstream_branch }}] from
|
|||||||
jobs:
|
jobs:
|
||||||
get_model:
|
get_model:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
|
||||||
REF: ${{ inputs.upstream_branch }}
|
|
||||||
outputs:
|
outputs:
|
||||||
model_date: ${{ steps.commit-date.outputs.model_date }}
|
model_date: ${{ steps.commit-date.outputs.model_date }}
|
||||||
steps:
|
steps:
|
||||||
# Note: To allow dynamic models from both openpilot and sunnypilot (merges/mashups), we try commaai as default,
|
- uses: actions/checkout@v4
|
||||||
# and fallback to sunnypilot if the ref checkout fails.
|
|
||||||
- name: Checkout commaai/openpilot
|
|
||||||
id: checkout_upstream
|
|
||||||
continue-on-error: true
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
with:
|
||||||
repository: commaai/openpilot
|
repository: ${{ env.UPSTREAM_REPO }}
|
||||||
ref: ${{ inputs.upstream_branch }}
|
ref: ${{ github.event.inputs.upstream_branch }}
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
path: openpilot
|
|
||||||
|
|
||||||
- name: Fallback to sunnypilot/sunnypilot
|
|
||||||
if: steps.checkout_upstream.outcome == 'failure'
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: sunnypilot/sunnypilot
|
|
||||||
ref: ${{ inputs.upstream_branch }}
|
|
||||||
submodules: recursive
|
|
||||||
path: openpilot
|
|
||||||
- name: Get commit date
|
- name: Get commit date
|
||||||
id: commit-date
|
id: commit-date
|
||||||
run: |
|
run: |
|
||||||
cd ${{ github.workspace }}/openpilot
|
# Get the commit date in YYYY-MM-DD format
|
||||||
commit_date=$(git log -1 --format=%cd --date=format:'%B %d, %Y')
|
commit_date=$(git log -1 --format=%cd --date=format:'%B %d, %Y')
|
||||||
echo "model_date=${commit_date}" >> $GITHUB_OUTPUT
|
echo "model_date=${commit_date}" >> $GITHUB_OUTPUT
|
||||||
cat $GITHUB_OUTPUT
|
cat $GITHUB_OUTPUT
|
||||||
- run: |
|
- run: git lfs pull
|
||||||
cd ${{ github.workspace }}/openpilot
|
|
||||||
git lfs pull
|
|
||||||
- name: 'Upload Artifact'
|
- name: 'Upload Artifact'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: models-${{ env.REF }}${{ inputs.artifact_suffix }}
|
name: models
|
||||||
path: ${{ github.workspace }}/openpilot/selfdrive/modeld/models/*.onnx
|
path: ${{ github.workspace }}/selfdrive/modeld/models/*.onnx
|
||||||
|
|
||||||
build_model:
|
build_model:
|
||||||
runs-on: [self-hosted, tici]
|
runs-on: self-hosted
|
||||||
needs: get_model
|
needs: get_model
|
||||||
env:
|
env:
|
||||||
MODEL_NAME: ${{ inputs.custom_name || inputs.upstream_branch }} (${{ needs.get_model.outputs.model_date }})
|
MODEL_NAME: ${{ inputs.custom_name || inputs.upstream_branch }} (${{ needs.get_model.outputs.model_date }})
|
||||||
REF: ${{ inputs.upstream_branch }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -111,7 +71,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: ${{env.SCONS_CACHE_DIR}}
|
path: ${{env.SCONS_CACHE_DIR}}
|
||||||
key: scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}-model-${{ github.sha }}
|
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.)
|
# 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.
|
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
|
||||||
restore-keys: |
|
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 }}-model
|
||||||
@@ -154,7 +114,7 @@ jobs:
|
|||||||
- name: Download model artifacts
|
- name: Download model artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: models-${{ env.REF }}${{ inputs.artifact_suffix }}
|
name: models
|
||||||
path: ${{ github.workspace }}/selfdrive/modeld/models
|
path: ${{ github.workspace }}/selfdrive/modeld/models
|
||||||
|
|
||||||
- name: Build Model
|
- name: Build Model
|
||||||
@@ -197,22 +157,12 @@ jobs:
|
|||||||
--upstream-branch "${{ inputs.upstream_branch }}" \
|
--upstream-branch "${{ inputs.upstream_branch }}" \
|
||||||
${{ inputs.is_20hz && '--is-20hz' || '' }}
|
${{ inputs.is_20hz && '--is-20hz' || '' }}
|
||||||
|
|
||||||
- name: Write artifact name to file
|
|
||||||
run: echo "model-${{ env.MODEL_NAME }}${{ inputs.artifact_suffix }}-${{ github.run_number }}" > ${{ env.OUTPUT_DIR }}/artifact_name.txt
|
|
||||||
|
|
||||||
- name: Upload Build Artifacts
|
- name: Upload Build Artifacts
|
||||||
id: upload-artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: model-${{ env.MODEL_NAME }}${{ inputs.artifact_suffix }}-${{ github.run_number }}
|
name: model-${{ env.MODEL_NAME }}-${{ github.run_number }}
|
||||||
path: ${{ env.OUTPUT_DIR }}
|
path: ${{ env.OUTPUT_DIR }}
|
||||||
|
|
||||||
- name: Upload artifact name file
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: artifact-name-${{ inputs.custom_name || inputs.upstream_branch }}
|
|
||||||
path: ${{ env.OUTPUT_DIR }}/artifact_name.txt
|
|
||||||
|
|
||||||
- name: Re-enable powersave
|
- name: Re-enable powersave
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ env:
|
|||||||
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
||||||
|
|
||||||
# Branch configurations
|
# Branch configurations
|
||||||
STAGING_C3_SOURCE_BRANCH: ${{ vars.STAGING_C3_SOURCE_BRANCH || 'master' }} # vars are set on repo settings.
|
STAGING_C3_SOURCE_BRANCH: ${{ vars.STAGING_C3_SOURCE_BRANCH || 'master-new' }} # vars are set on repo settings.
|
||||||
DEV_C3_SOURCE_BRANCH: ${{ vars.DEV_C3_SOURCE_BRANCH || 'master-dev-c3-new' }} # vars are set on repo settings.
|
DEV_C3_SOURCE_BRANCH: ${{ vars.DEV_C3_SOURCE_BRANCH || 'master-dev-c3-new' }} # vars are set on repo settings.
|
||||||
|
|
||||||
# Target branch configurations
|
# Target branch configurations
|
||||||
@@ -21,7 +21,7 @@ env:
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, master-dev-c3-new ]
|
branches: [ master, master-new, master-dev-c3-new ]
|
||||||
tags: [ '*' ]
|
tags: [ '*' ]
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [ labeled ]
|
types: [ labeled ]
|
||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
concurrency:
|
concurrency:
|
||||||
group: build-${{ github.head_ref || github.ref_name }}
|
group: build-${{ github.head_ref || github.ref_name }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
runs-on: [self-hosted, tici]
|
runs-on: self-hosted
|
||||||
outputs:
|
outputs:
|
||||||
new_branch: ${{ steps.set-env.outputs.new_branch }}
|
new_branch: ${{ steps.set-env.outputs.new_branch }}
|
||||||
version: ${{ steps.set-env.outputs.version }}
|
version: ${{ steps.set-env.outputs.version }}
|
||||||
@@ -80,10 +80,10 @@ jobs:
|
|||||||
- name: Set Feature Branch Prebuilt Configuration
|
- name: Set Feature Branch Prebuilt Configuration
|
||||||
id: set_feature_configuration
|
id: set_feature_configuration
|
||||||
if: (
|
if: (
|
||||||
!(env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH) &&
|
!(env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH) &&
|
||||||
!(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH) &&
|
!(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH) &&
|
||||||
!(startsWith(github.ref, 'refs/tags/'))
|
!(startsWith(github.ref, 'refs/tags/'))
|
||||||
)
|
)
|
||||||
run: |
|
run: |
|
||||||
echo "NEW_BRANCH=${{ env.SOURCE_BRANCH }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-prebuilt" >> $GITHUB_ENV
|
echo "NEW_BRANCH=${{ env.SOURCE_BRANCH }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-prebuilt" >> $GITHUB_ENV
|
||||||
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
||||||
@@ -91,9 +91,9 @@ jobs:
|
|||||||
- name: Set dev-c3-new prebuilt Configuration
|
- name: Set dev-c3-new prebuilt Configuration
|
||||||
id: set_dev_configuration
|
id: set_dev_configuration
|
||||||
if: (
|
if: (
|
||||||
steps.set_feature_configuration.outcome == 'skipped' &&
|
steps.set_feature_configuration.outcome == 'skipped' &&
|
||||||
env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH
|
env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH
|
||||||
)
|
)
|
||||||
run: |
|
run: |
|
||||||
echo "NEW_BRANCH=${{ env.DEV_TARGET_BRANCH }}" >> $GITHUB_ENV
|
echo "NEW_BRANCH=${{ env.DEV_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||||||
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
||||||
@@ -102,11 +102,11 @@ jobs:
|
|||||||
- name: Set staging-c3-new prebuilt Configuration
|
- name: Set staging-c3-new prebuilt Configuration
|
||||||
id: set_staging_configuration
|
id: set_staging_configuration
|
||||||
if: (
|
if: (
|
||||||
steps.set_feature_configuration.outcome == 'skipped' &&
|
steps.set_feature_configuration.outcome == 'skipped' &&
|
||||||
!contains(github.event_name, 'pull_request') &&
|
!contains(github.event_name, 'pull_request') &&
|
||||||
steps.set_dev_configuration.outcome == 'skipped' &&
|
steps.set_dev_configuration.outcome == 'skipped' &&
|
||||||
(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH)
|
(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH)
|
||||||
)
|
)
|
||||||
run: |
|
run: |
|
||||||
echo "NEW_BRANCH=${{ env.STAGING_TARGET_BRANCH }}" >> $GITHUB_ENV
|
echo "NEW_BRANCH=${{ env.STAGING_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||||||
echo "EXTRA_VERSION_IDENTIFIER=staging" >> $GITHUB_ENV
|
echo "EXTRA_VERSION_IDENTIFIER=staging" >> $GITHUB_ENV
|
||||||
@@ -115,11 +115,11 @@ jobs:
|
|||||||
- name: Set release-c3-new prebuilt Configuration
|
- name: Set release-c3-new prebuilt Configuration
|
||||||
id: set_tag_configuration
|
id: set_tag_configuration
|
||||||
if: (
|
if: (
|
||||||
steps.set_feature_configuration.outcome == 'skipped' &&
|
steps.set_feature_configuration.outcome == 'skipped' &&
|
||||||
!contains(github.event_name, 'pull_request') &&
|
!contains(github.event_name, 'pull_request') &&
|
||||||
steps.set_staging_configuration.outcome == 'skipped' &&
|
steps.set_staging_configuration.outcome == 'skipped' &&
|
||||||
startsWith(github.ref, 'refs/tags/')
|
startsWith(github.ref, 'refs/tags/')
|
||||||
)
|
)
|
||||||
run: |
|
run: |
|
||||||
echo "NEW_BRANCH=${{ env.RELEASE_TARGET_BRANCH }}" >> $GITHUB_ENV
|
echo "NEW_BRANCH=${{ env.RELEASE_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||||||
echo "EXTRA_VERSION_IDENTIFIER=release" >> $GITHUB_ENV
|
echo "EXTRA_VERSION_IDENTIFIER=release" >> $GITHUB_ENV
|
||||||
@@ -227,6 +227,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
|
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
|
||||||
|
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
concurrency:
|
concurrency:
|
||||||
group: publish-${{ github.head_ref || github.ref_name }}
|
group: publish-${{ github.head_ref || github.ref_name }}
|
||||||
@@ -267,7 +268,7 @@ jobs:
|
|||||||
"${{ needs.build.outputs.version }}" \
|
"${{ needs.build.outputs.version }}" \
|
||||||
"https://x-access-token:${{github.token}}@github.com/sunnypilot/sunnypilot.git" \
|
"https://x-access-token:${{github.token}}@github.com/sunnypilot/sunnypilot.git" \
|
||||||
"-${{ needs.build.outputs.extra_version_identifier }}"
|
"-${{ needs.build.outputs.extra_version_identifier }}"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "---- ℹ️ To update the list of branches that auto deploy prebuilts -----"
|
echo "---- ℹ️ To update the list of branches that auto deploy prebuilts -----"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -298,7 +299,7 @@ jobs:
|
|||||||
export extra_version_identifier=${{ needs.build.outputs.extra_version_identifier || github.run_number}}
|
export extra_version_identifier=${{ needs.build.outputs.extra_version_identifier || github.run_number}}
|
||||||
echo ${TEMPLATE} | envsubst | jq -c '.' | tee payload.json
|
echo ${TEMPLATE} | envsubst | jq -c '.' | tee payload.json
|
||||||
curl -X POST -H "Content-Type: application/json" -d @payload.json $DISCORD_WEBHOOK
|
curl -X POST -H "Content-Type: application/json" -d @payload.json $DISCORD_WEBHOOK
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "---- ℹ️ To update the list of branches that notify to dev-feedback -----"
|
echo "---- ℹ️ To update the list of branches that notify to dev-feedback -----"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -306,7 +307,7 @@ jobs:
|
|||||||
echo "2. Current value: ${{ vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES }}"
|
echo "2. Current value: ${{ vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES }}"
|
||||||
echo "3. Update as needed (JSON array with no spaces)"
|
echo "3. Update as needed (JSON array with no spaces)"
|
||||||
shell: alpine.sh {0}
|
shell: alpine.sh {0}
|
||||||
|
|
||||||
manage-pr-labels:
|
manage-pr-labels:
|
||||||
name: Remove prebuilt label
|
name: Remove prebuilt label
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: Build dev-c3-new
|
name: Build dev-c3-new
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DEFAULT_SOURCE_BRANCH: "master"
|
DEFAULT_SOURCE_BRANCH: "master-new"
|
||||||
DEFAULT_TARGET_BRANCH: "master-dev-c3-new"
|
DEFAULT_TARGET_BRANCH: "master-dev-c3-new"
|
||||||
PR_LABEL: "dev-c3"
|
PR_LABEL: "dev-c3"
|
||||||
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
|
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
|
||||||
@@ -11,16 +11,18 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
- master-new
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [ labeled ]
|
types: [ labeled ]
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
|
- 'master-new'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
source_branch:
|
source_branch:
|
||||||
description: 'Source branch to reset from'
|
description: 'Source branch to reset from'
|
||||||
required: true
|
required: true
|
||||||
default: 'master'
|
default: 'master-new'
|
||||||
type: string
|
type: string
|
||||||
target_branch:
|
target_branch:
|
||||||
description: 'Target branch to reset and squash into'
|
description: 'Target branch to reset and squash into'
|
||||||
@@ -41,10 +43,10 @@ jobs:
|
|||||||
reset-and-squash:
|
reset-and-squash:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: (
|
if: (
|
||||||
(github.event_name == 'workflow_dispatch')
|
(github.event_name == 'workflow_dispatch')
|
||||||
|| (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
|| (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
||||||
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3'))))
|
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3'))))
|
||||||
)
|
)
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -54,9 +56,9 @@ jobs:
|
|||||||
- name: Wait for Tests
|
- name: Wait for Tests
|
||||||
uses: ./.github/workflows/wait-for-action # Path to where you place the action
|
uses: ./.github/workflows/wait-for-action # Path to where you place the action
|
||||||
if: (
|
if: (
|
||||||
(github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
(github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
||||||
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3'))))
|
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3'))))
|
||||||
)
|
)
|
||||||
with:
|
with:
|
||||||
workflow: selfdrive_tests.yaml # The workflow file to monitor
|
workflow: selfdrive_tests.yaml # The workflow file to monitor
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -151,7 +153,6 @@ jobs:
|
|||||||
}
|
}
|
||||||
}' -F label="is:pr is:open label:${PR_LABEL} draft:false sort:created-asc")
|
}' -F label="is:pr is:open label:${PR_LABEL} draft:false sort:created-asc")
|
||||||
|
|
||||||
PR_LIST=${PR_LIST//\'/}
|
|
||||||
echo "PR_LIST=${PR_LIST}" >> $GITHUB_OUTPUT
|
echo "PR_LIST=${PR_LIST}" >> $GITHUB_OUTPUT
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -3,18 +3,20 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
- master-new
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [assigned, opened, synchronize, reopened, edited]
|
types: [assigned, opened, synchronize, reopened, edited]
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
|
- 'master-new'
|
||||||
paths:
|
paths:
|
||||||
- 'selfdrive/ui/**'
|
- 'selfdrive/ui/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
UI_JOB_NAME: "Create UI Report"
|
UI_JOB_NAME: "Create UI Report"
|
||||||
REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
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.sha || github.event.pull_request.head.sha }}
|
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 }}"
|
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -64,7 +66,7 @@ jobs:
|
|||||||
ref: openpilot_master_ui
|
ref: openpilot_master_ui
|
||||||
|
|
||||||
- name: Saving new 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
|
working-directory: ${{ github.workspace }}/master_ui
|
||||||
run: |
|
run: |
|
||||||
git checkout --orphan=new_master_ui
|
git checkout --orphan=new_master_ui
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ flycheck_*
|
|||||||
cppcheck_report.txt
|
cppcheck_report.txt
|
||||||
comma*.sh
|
comma*.sh
|
||||||
|
|
||||||
|
selfdrive/modeld/thneed/compile
|
||||||
|
selfdrive/modeld/models/*.thneed
|
||||||
selfdrive/modeld/models/*.pkl
|
selfdrive/modeld/models/*.pkl
|
||||||
sunnypilot/modeld*/thneed/compile
|
sunnypilot/modeld*/thneed/compile
|
||||||
sunnypilot/modeld*/models/*.thneed
|
sunnypilot/modeld*/models/*.thneed
|
||||||
|
|||||||
Generated
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
<tool name="uv Scons Build Debug" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
<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>
|
<exec>
|
||||||
<option name="COMMAND" value="bash" />
|
<option name="COMMAND" value="bash" />
|
||||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) --ccflags=\"-fno-inline\""" />
|
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) --compile_db --ccflags=\"-fno-inline\""" />
|
||||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||||
</exec>
|
</exec>
|
||||||
</tool>
|
</tool>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<tool name="uv Scons Build Release" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
<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>
|
<exec>
|
||||||
<option name="COMMAND" value="bash" />
|
<option name="COMMAND" value="bash" />
|
||||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc)" " />
|
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) --compile_db" " />
|
||||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||||
</exec>
|
</exec>
|
||||||
</tool>
|
</tool>
|
||||||
|
|||||||
+60
-6
@@ -1,12 +1,66 @@
|
|||||||
FROM ghcr.io/sunnypilot/sunnypilot-base:latest
|
FROM sunnypilot-base
|
||||||
|
|
||||||
|
ARG RUNNER_DEBUG=0
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
ENV OPENPILOT_SRC_PATH=/tmp/openpilot
|
||||||
|
ENV BUILD_DIR=/data/openpilot
|
||||||
|
ENV OUTPUT_DIR=/output
|
||||||
|
|
||||||
ENV OPENPILOT_PATH=/home/batman/openpilot
|
RUN sudo apt update && sudo apt install -y rsync
|
||||||
|
|
||||||
RUN mkdir -p ${OPENPILOT_PATH}
|
RUN mkdir -p ${OPENPILOT_SRC_PATH}
|
||||||
WORKDIR ${OPENPILOT_PATH}
|
RUN mkdir -p ${BUILD_DIR}
|
||||||
|
COPY . ${OPENPILOT_SRC_PATH}
|
||||||
|
ENV PYTHONPATH=${BUILD_DIR}
|
||||||
|
|
||||||
COPY . ${OPENPILOT_PATH}/
|
WORKDIR ${OPENPILOT_SRC_PATH}
|
||||||
|
RUN ./tools/ubuntu_setup.sh
|
||||||
|
|
||||||
RUN scons --cache-readonly -j$(nproc)
|
RUN ./release/release_files.py | sort | uniq | rsync -rRl${RUNNER_DEBUG:+v} --files-from=- . $BUILD_DIR/
|
||||||
|
WORKDIR ${BUILD_DIR}
|
||||||
|
RUN sed -i '/from .board.jungle import PandaJungle, PandaJungleDFU/s/^/#/' panda/__init__.py
|
||||||
|
RUN scons --cache-readonly -j$(nproc) --minimal
|
||||||
|
RUN touch ${BUILD_DIR}/prebuilt
|
||||||
|
RUN sudo rm -rf ${OUTPUT_DIR}
|
||||||
|
RUN mkdir -p ${OUTPUT_DIR}
|
||||||
|
|
||||||
|
ENTRYPOINT [\
|
||||||
|
"rsync", \
|
||||||
|
"-am", \
|
||||||
|
"--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=${SCONS_CACHE_DIR:-}", \
|
||||||
|
"--exclude=**/.git/", \
|
||||||
|
"--exclude=**/SConstruct", \
|
||||||
|
"--exclude=**/SConscript", \
|
||||||
|
"--exclude=**/.venv/", \
|
||||||
|
"--delete-excluded", \
|
||||||
|
"--chown=1000:1000", \
|
||||||
|
"/data/openpilot/", \
|
||||||
|
"/output/" \
|
||||||
|
]
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
FROM ubuntu:24.04
|
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install -y --no-install-recommends sudo tzdata locales ssh pulseaudio xvfb x11-xserver-utils gnome-screenshot python3-tk python3-dev && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
|
|
||||||
ENV LANG=en_US.UTF-8
|
|
||||||
ENV LANGUAGE=en_US:en
|
|
||||||
ENV LC_ALL=en_US.UTF-8
|
|
||||||
|
|
||||||
COPY tools/install_ubuntu_dependencies.sh /tmp/tools/
|
|
||||||
RUN /tmp/tools/install_ubuntu_dependencies.sh && \
|
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* && \
|
|
||||||
cd /usr/lib/gcc/arm-none-eabi/* && \
|
|
||||||
rm -rf arm/ thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp
|
|
||||||
|
|
||||||
# Add OpenCL
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
apt-utils \
|
|
||||||
alien \
|
|
||||||
unzip \
|
|
||||||
tar \
|
|
||||||
curl \
|
|
||||||
xz-utils \
|
|
||||||
dbus \
|
|
||||||
gcc-arm-none-eabi \
|
|
||||||
tmux \
|
|
||||||
vim \
|
|
||||||
libx11-6 \
|
|
||||||
wget \
|
|
||||||
rsync \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN mkdir -p /tmp/opencl-driver-intel && \
|
|
||||||
cd /tmp/opencl-driver-intel && \
|
|
||||||
wget https://github.com/intel/llvm/releases/download/2024-WW14/oclcpuexp-2024.17.3.0.09_rel.tar.gz && \
|
|
||||||
wget https://github.com/oneapi-src/oneTBB/releases/download/v2021.12.0/oneapi-tbb-2021.12.0-lin.tgz && \
|
|
||||||
mkdir -p /opt/intel/oclcpuexp_2024.17.3.0.09_rel && \
|
|
||||||
cd /opt/intel/oclcpuexp_2024.17.3.0.09_rel && \
|
|
||||||
tar -zxvf /tmp/opencl-driver-intel/oclcpuexp-2024.17.3.0.09_rel.tar.gz && \
|
|
||||||
mkdir -p /etc/OpenCL/vendors && \
|
|
||||||
echo /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64/libintelocl.so > /etc/OpenCL/vendors/intel_expcpu.icd && \
|
|
||||||
cd /opt/intel && \
|
|
||||||
tar -zxvf /tmp/opencl-driver-intel/oneapi-tbb-2021.12.0-lin.tgz && \
|
|
||||||
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbb.so /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
|
|
||||||
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbbmalloc.so /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
|
|
||||||
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbb.so.12 /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
|
|
||||||
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbbmalloc.so.2 /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
|
|
||||||
mkdir -p /etc/ld.so.conf.d && \
|
|
||||||
echo /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 > /etc/ld.so.conf.d/libintelopenclexp.conf && \
|
|
||||||
ldconfig -f /etc/ld.so.conf.d/libintelopenclexp.conf && \
|
|
||||||
cd / && \
|
|
||||||
rm -rf /tmp/opencl-driver-intel
|
|
||||||
|
|
||||||
ENV NVIDIA_VISIBLE_DEVICES=all
|
|
||||||
ENV NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute
|
|
||||||
ENV QTWEBENGINE_DISABLE_SANDBOX=1
|
|
||||||
|
|
||||||
RUN dbus-uuidgen > /etc/machine-id
|
|
||||||
RUN apt-get update && apt-get install -y fonts-noto-cjk fonts-noto-color-emoji
|
|
||||||
|
|
||||||
ARG USER=batman
|
|
||||||
ARG USER_UID=1001
|
|
||||||
RUN useradd -m -s /bin/bash -u $USER_UID $USER
|
|
||||||
RUN usermod -aG sudo $USER
|
|
||||||
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
|
||||||
USER $USER
|
|
||||||
|
|
||||||
COPY --chown=$USER pyproject.toml uv.lock /home/$USER
|
|
||||||
COPY --chown=$USER tools/install_python_dependencies.sh /home/$USER/tools/
|
|
||||||
|
|
||||||
ENV VIRTUAL_ENV=/home/$USER/.venv
|
|
||||||
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
|
||||||
RUN cd /home/$USER && \
|
|
||||||
tools/install_python_dependencies.sh && \
|
|
||||||
rm -rf tools/ pyproject.toml uv.lock .cache
|
|
||||||
|
|
||||||
USER root
|
|
||||||
RUN sudo git config --global --add safe.directory /tmp/openpilot
|
|
||||||
@@ -64,7 +64,7 @@ Please refer to [Recommended Branches](#-recommended-branches) to find your pref
|
|||||||
## 🎆 Pull Requests
|
## 🎆 Pull Requests
|
||||||
We welcome both pull requests and issues on GitHub. Bug fixes are encouraged.
|
We welcome both pull requests and issues on GitHub. Bug fixes are encouraged.
|
||||||
|
|
||||||
Pull requests should be against the most current `master` branch.
|
Pull requests should be against the most current `master-new` branch.
|
||||||
|
|
||||||
## 📊 User Data
|
## 📊 User Data
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ By default, sunnypilot uploads the driving data to comma servers. You can also a
|
|||||||
sunnypilot is open source software. The user is free to disable data collection if they wish to do so.
|
sunnypilot is open source software. The user is free to disable data collection if they wish to do so.
|
||||||
|
|
||||||
sunnypilot logs the road-facing camera, 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 and microphone are only logged if you explicitly opt-in in settings.
|
The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
|||||||
+1
-7
@@ -1,11 +1,5 @@
|
|||||||
Version 0.10.0 (2025-07-07)
|
Version 0.9.10 (2025-06-30)
|
||||||
========================
|
========================
|
||||||
* New driving model
|
|
||||||
* Lead car ground-truth fixes
|
|
||||||
* Ported over VAE from the MLSIM stack
|
|
||||||
* New training architecture described in CVPR paper
|
|
||||||
* Enable live-learned steering actuation delay
|
|
||||||
* Opt-in audio recording for dashcam video
|
|
||||||
|
|
||||||
Version 0.9.9 (2025-05-23)
|
Version 0.9.9 (2025-05-23)
|
||||||
========================
|
========================
|
||||||
|
|||||||
+9
-2
@@ -39,6 +39,10 @@ AddOption('--clazy',
|
|||||||
action='store_true',
|
action='store_true',
|
||||||
help='build with clazy')
|
help='build with clazy')
|
||||||
|
|
||||||
|
AddOption('--compile_db',
|
||||||
|
action='store_true',
|
||||||
|
help='build clang compilation database')
|
||||||
|
|
||||||
AddOption('--ccflags',
|
AddOption('--ccflags',
|
||||||
action='store',
|
action='store',
|
||||||
type='string',
|
type='string',
|
||||||
@@ -82,6 +86,7 @@ assert arch in ["larch64", "aarch64", "x86_64", "Darwin"]
|
|||||||
|
|
||||||
lenv = {
|
lenv = {
|
||||||
"PATH": os.environ['PATH'],
|
"PATH": os.environ['PATH'],
|
||||||
|
"LD_LIBRARY_PATH": [Dir(f"#third_party/acados/{arch}/lib").abspath],
|
||||||
"PYTHONPATH": Dir("#").abspath + ':' + Dir(f"#third_party/acados").abspath,
|
"PYTHONPATH": Dir("#").abspath + ':' + Dir(f"#third_party/acados").abspath,
|
||||||
|
|
||||||
"ACADOS_SOURCE_DIR": Dir("#third_party/acados").abspath,
|
"ACADOS_SOURCE_DIR": Dir("#third_party/acados").abspath,
|
||||||
@@ -89,7 +94,7 @@ lenv = {
|
|||||||
"TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer"
|
"TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer"
|
||||||
}
|
}
|
||||||
|
|
||||||
rpath = []
|
rpath = lenv["LD_LIBRARY_PATH"].copy()
|
||||||
|
|
||||||
if arch == "larch64":
|
if arch == "larch64":
|
||||||
cpppath = [
|
cpppath = [
|
||||||
@@ -132,6 +137,7 @@ else:
|
|||||||
f"{brew_prefix}/include",
|
f"{brew_prefix}/include",
|
||||||
f"{brew_prefix}/opt/openssl@3.0/include",
|
f"{brew_prefix}/opt/openssl@3.0/include",
|
||||||
]
|
]
|
||||||
|
lenv["DYLD_LIBRARY_PATH"] = lenv["LD_LIBRARY_PATH"]
|
||||||
# Linux
|
# Linux
|
||||||
else:
|
else:
|
||||||
libpath = [
|
libpath = [
|
||||||
@@ -228,7 +234,8 @@ if arch == "Darwin":
|
|||||||
darwin_rpath_link_flags = [f"-Wl,-rpath,{path}" for path in env["RPATH"]]
|
darwin_rpath_link_flags = [f"-Wl,-rpath,{path}" for path in env["RPATH"]]
|
||||||
env["LINKFLAGS"] += darwin_rpath_link_flags
|
env["LINKFLAGS"] += darwin_rpath_link_flags
|
||||||
|
|
||||||
env.CompilationDatabase('compile_commands.json')
|
if GetOption('compile_db'):
|
||||||
|
env.CompilationDatabase('compile_commands.json')
|
||||||
|
|
||||||
# Setup cache dir
|
# Setup cache dir
|
||||||
default_cache_dir = '/data/scons_cache' if AGNOS else '/tmp/scons_cache'
|
default_cache_dir = '/data/scons_cache' if AGNOS else '/tmp/scons_cache'
|
||||||
|
|||||||
@@ -25,27 +25,6 @@ struct ModularAssistiveDrivingSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Same struct as Log.RadarState.LeadData
|
|
||||||
struct LeadData {
|
|
||||||
dRel @0 :Float32;
|
|
||||||
yRel @1 :Float32;
|
|
||||||
vRel @2 :Float32;
|
|
||||||
aRel @3 :Float32;
|
|
||||||
vLead @4 :Float32;
|
|
||||||
dPath @6 :Float32;
|
|
||||||
vLat @7 :Float32;
|
|
||||||
vLeadK @8 :Float32;
|
|
||||||
aLeadK @9 :Float32;
|
|
||||||
fcw @10 :Bool;
|
|
||||||
status @11 :Bool;
|
|
||||||
aLeadTau @12 :Float32;
|
|
||||||
modelProb @13 :Float32;
|
|
||||||
radar @14 :Bool;
|
|
||||||
radarTrackId @15 :Int32 = -1;
|
|
||||||
|
|
||||||
aLeadDEPRECATED @5 :Float32;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SelfdriveStateSP @0x81c2f05a394cf4af {
|
struct SelfdriveStateSP @0x81c2f05a394cf4af {
|
||||||
mads @0 :ModularAssistiveDrivingSystem;
|
mads @0 :ModularAssistiveDrivingSystem;
|
||||||
}
|
}
|
||||||
@@ -195,8 +174,6 @@ struct CarParamsSP @0x80ae746ee2596b11 {
|
|||||||
struct CarControlSP @0xa5cd762cd951a455 {
|
struct CarControlSP @0xa5cd762cd951a455 {
|
||||||
mads @0 :ModularAssistiveDrivingSystem;
|
mads @0 :ModularAssistiveDrivingSystem;
|
||||||
params @1 :List(Param);
|
params @1 :List(Param);
|
||||||
leadOne @2 :LeadData;
|
|
||||||
leadTwo @3 :LeadData;
|
|
||||||
|
|
||||||
struct Param {
|
struct Param {
|
||||||
key @0 :Text;
|
key @0 :Text;
|
||||||
|
|||||||
+6
-14
@@ -128,7 +128,6 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
|||||||
personalityChanged @91;
|
personalityChanged @91;
|
||||||
aeb @92;
|
aeb @92;
|
||||||
userFlag @95;
|
userFlag @95;
|
||||||
excessiveActuation @96;
|
|
||||||
|
|
||||||
soundsUnavailableDEPRECATED @47;
|
soundsUnavailableDEPRECATED @47;
|
||||||
}
|
}
|
||||||
@@ -493,6 +492,7 @@ struct DeviceState @0xa4d8b5af2aa492eb {
|
|||||||
gpuTempC @27 :List(Float32);
|
gpuTempC @27 :List(Float32);
|
||||||
dspTempC @49 :Float32;
|
dspTempC @49 :Float32;
|
||||||
memoryTempC @28 :Float32;
|
memoryTempC @28 :Float32;
|
||||||
|
nvmeTempC @35 :List(Float32);
|
||||||
modemTempC @36 :List(Float32);
|
modemTempC @36 :List(Float32);
|
||||||
pmicTempC @39 :List(Float32);
|
pmicTempC @39 :List(Float32);
|
||||||
intakeTempC @46 :Float32;
|
intakeTempC @46 :Float32;
|
||||||
@@ -568,7 +568,6 @@ struct DeviceState @0xa4d8b5af2aa492eb {
|
|||||||
chargingDisabledDEPRECATED @18 :Bool;
|
chargingDisabledDEPRECATED @18 :Bool;
|
||||||
usbOnlineDEPRECATED @12 :Bool;
|
usbOnlineDEPRECATED @12 :Bool;
|
||||||
ambientTempCDEPRECATED @30 :Float32;
|
ambientTempCDEPRECATED @30 :Float32;
|
||||||
nvmeTempCDEPRECATED @35 :List(Float32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PandaState @0xa7649e2575e4591e {
|
struct PandaState @0xa7649e2575e4591e {
|
||||||
@@ -586,7 +585,7 @@ struct PandaState @0xa7649e2575e4591e {
|
|||||||
fanPower @28 :UInt8;
|
fanPower @28 :UInt8;
|
||||||
fanStallCount @34 :UInt8;
|
fanStallCount @34 :UInt8;
|
||||||
|
|
||||||
spiErrorCount @33 :UInt16;
|
spiChecksumErrorCount @33 :UInt16;
|
||||||
|
|
||||||
harnessStatus @21 :HarnessStatus;
|
harnessStatus @21 :HarnessStatus;
|
||||||
sbu1Voltage @35 :Float32;
|
sbu1Voltage @35 :Float32;
|
||||||
@@ -1084,7 +1083,7 @@ struct ModelDataV2 {
|
|||||||
confidence @23: ConfidenceClass;
|
confidence @23: ConfidenceClass;
|
||||||
|
|
||||||
# Model perceived motion
|
# Model perceived motion
|
||||||
temporalPoseDEPRECATED @21 :Pose;
|
temporalPose @21 :Pose;
|
||||||
|
|
||||||
# e2e lateral planner
|
# e2e lateral planner
|
||||||
action @26: Action;
|
action @26: Action;
|
||||||
@@ -2471,19 +2470,13 @@ struct DebugAlert {
|
|||||||
struct UserFlag {
|
struct UserFlag {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundPressure @0xdc24138990726023 {
|
struct Microphone {
|
||||||
soundPressure @0 :Float32;
|
soundPressure @0 :Float32;
|
||||||
|
|
||||||
# uncalibrated, A-weighted
|
# uncalibrated, A-weighted
|
||||||
soundPressureWeighted @3 :Float32;
|
soundPressureWeighted @3 :Float32;
|
||||||
soundPressureWeightedDb @1 :Float32;
|
soundPressureWeightedDb @1 :Float32;
|
||||||
|
filteredSoundPressureWeightedDb @2 :Float32;
|
||||||
filteredSoundPressureWeightedDbDEPRECATED @2 :Float32;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AudioData {
|
|
||||||
data @0 :Data;
|
|
||||||
sampleRate @1 :UInt32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Touch {
|
struct Touch {
|
||||||
@@ -2563,8 +2556,7 @@ struct Event {
|
|||||||
livestreamDriverEncodeIdx @119 :EncodeIndex;
|
livestreamDriverEncodeIdx @119 :EncodeIndex;
|
||||||
|
|
||||||
# microphone data
|
# microphone data
|
||||||
soundPressure @103 :SoundPressure;
|
microphone @103 :Microphone;
|
||||||
rawAudioData @147 :AudioData;
|
|
||||||
|
|
||||||
# systems stuff
|
# systems stuff
|
||||||
androidLog @20 :AndroidLogEntry;
|
androidLog @20 :AndroidLogEntry;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ def zmq_sleep(t=1):
|
|||||||
|
|
||||||
# TODO: this should take any capnp struct and returrn a msg with random populated data
|
# TODO: this should take any capnp struct and returrn a msg with random populated data
|
||||||
def random_carstate():
|
def random_carstate():
|
||||||
fields = ["vEgo", "aEgo", "brake", "steeringAngleDeg"]
|
fields = ["vEgo", "aEgo", "gas", "steeringAngleDeg"]
|
||||||
msg = messaging.new_message("carState")
|
msg = messaging.new_message("carState")
|
||||||
cs = msg.carState
|
cs = msg.carState
|
||||||
for f in fields:
|
for f in fields:
|
||||||
|
|||||||
+1
-2
@@ -73,8 +73,7 @@ _services: dict[str, tuple] = {
|
|||||||
"navThumbnail": (True, 0.),
|
"navThumbnail": (True, 0.),
|
||||||
"qRoadEncodeIdx": (False, 20.),
|
"qRoadEncodeIdx": (False, 20.),
|
||||||
"userFlag": (True, 0., 1),
|
"userFlag": (True, 0., 1),
|
||||||
"soundPressure": (True, 10., 10),
|
"microphone": (True, 10., 10),
|
||||||
"rawAudioData": (False, 20.),
|
|
||||||
|
|
||||||
# sunnypilot
|
# sunnypilot
|
||||||
"modelManagerSP": (False, 1., 1),
|
"modelManagerSP": (False, 1., 1),
|
||||||
|
|||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
comment: false
|
||||||
|
coverage:
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
informational: true
|
||||||
|
patch: off
|
||||||
|
|
||||||
|
ignore:
|
||||||
|
- "**/test_*.py"
|
||||||
|
- "selfdrive/test/**"
|
||||||
|
- "system/version.py" # codecov changes depending on if we are in a branch or not
|
||||||
|
- "tools"
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
#define DEFAULT_MODEL "Space Lab 2 (Default)"
|
#define DEFAULT_MODEL "Vegetarian Filet o Fish (Default)"
|
||||||
|
|||||||
+6
-14
@@ -103,10 +103,10 @@ Params::~Params() {
|
|||||||
assert(queue.empty());
|
assert(queue.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> Params::allKeys(ParamKeyFlag flag) const {
|
std::vector<std::string> Params::allKeys(ParamKeyType type) const {
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
for (auto &p : keys) {
|
for (auto &p : keys) {
|
||||||
if (flag == ALL || (p.second.flags & flag)) {
|
if (type == ALL || (p.second & type)) {
|
||||||
ret.push_back(p.first);
|
ret.push_back(p.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,16 +117,8 @@ bool Params::checkKey(const std::string &key) {
|
|||||||
return keys.find(key) != keys.end();
|
return keys.find(key) != keys.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
ParamKeyFlag Params::getKeyFlag(const std::string &key) {
|
|
||||||
return static_cast<ParamKeyFlag>(keys[key].flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
ParamKeyType Params::getKeyType(const std::string &key) {
|
ParamKeyType Params::getKeyType(const std::string &key) {
|
||||||
return keys[key].type;
|
return static_cast<ParamKeyType>(keys[key]);
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::string> Params::getKeyDefaultValue(const std::string &key) {
|
|
||||||
return keys[key].default_value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Params::put(const char* key, const char* value, size_t value_size) {
|
int Params::put(const char* key, const char* value, size_t value_size) {
|
||||||
@@ -205,17 +197,17 @@ std::map<std::string, std::string> Params::readAll() {
|
|||||||
return util::read_files_in_dir(getParamPath());
|
return util::read_files_in_dir(getParamPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Params::clearAll(ParamKeyFlag key_flag) {
|
void Params::clearAll(ParamKeyType key_type) {
|
||||||
FileLock file_lock(params_path + "/.lock");
|
FileLock file_lock(params_path + "/.lock");
|
||||||
|
|
||||||
// 1) delete params of key_flag
|
// 1) delete params of key_type
|
||||||
// 2) delete files that are not defined in the keys.
|
// 2) delete files that are not defined in the keys.
|
||||||
if (DIR *d = opendir(getParamPath().c_str())) {
|
if (DIR *d = opendir(getParamPath().c_str())) {
|
||||||
struct dirent *de = NULL;
|
struct dirent *de = NULL;
|
||||||
while ((de = readdir(d))) {
|
while ((de = readdir(d))) {
|
||||||
if (de->d_type != DT_DIR) {
|
if (de->d_type != DT_DIR) {
|
||||||
auto it = keys.find(de->d_name);
|
auto it = keys.find(de->d_name);
|
||||||
if (it == keys.end() || (it->second.flags & key_flag)) {
|
if (it == keys.end() || (it->second & key_type)) {
|
||||||
unlink(getParamPath(de->d_name).c_str());
|
unlink(getParamPath(de->d_name).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-24
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -10,34 +9,17 @@
|
|||||||
|
|
||||||
#include "common/queue.h"
|
#include "common/queue.h"
|
||||||
|
|
||||||
enum ParamKeyFlag {
|
enum ParamKeyType {
|
||||||
PERSISTENT = 0x02,
|
PERSISTENT = 0x02,
|
||||||
CLEAR_ON_MANAGER_START = 0x04,
|
CLEAR_ON_MANAGER_START = 0x04,
|
||||||
CLEAR_ON_ONROAD_TRANSITION = 0x08,
|
CLEAR_ON_ONROAD_TRANSITION = 0x08,
|
||||||
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
|
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
|
||||||
DONT_LOG = 0x20,
|
DONT_LOG = 0x20,
|
||||||
DEVELOPMENT_ONLY = 0x40,
|
DEVELOPMENT_ONLY = 0x40,
|
||||||
CLEAR_ON_IGNITION_ON = 0x80,
|
BACKUP = 0x80,
|
||||||
BACKUP = 0x100,
|
|
||||||
ALL = 0xFFFFFFFF
|
ALL = 0xFFFFFFFF
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ParamKeyType {
|
|
||||||
STRING = 0, // must be utf-8 decodable
|
|
||||||
BOOL = 1,
|
|
||||||
INT = 2,
|
|
||||||
FLOAT = 3,
|
|
||||||
TIME = 4, // ISO 8601
|
|
||||||
JSON = 5,
|
|
||||||
BYTES = 6
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ParamKeyAttributes {
|
|
||||||
uint32_t flags;
|
|
||||||
ParamKeyType type;
|
|
||||||
std::optional<std::string> default_value = std::nullopt;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Params {
|
class Params {
|
||||||
public:
|
public:
|
||||||
explicit Params(const std::string &path = {});
|
explicit Params(const std::string &path = {});
|
||||||
@@ -46,18 +28,16 @@ public:
|
|||||||
Params(const Params&) = delete;
|
Params(const Params&) = delete;
|
||||||
Params& operator=(const Params&) = delete;
|
Params& operator=(const Params&) = delete;
|
||||||
|
|
||||||
std::vector<std::string> allKeys(ParamKeyFlag flag = ALL) const;
|
std::vector<std::string> allKeys(ParamKeyType type = ALL) const;
|
||||||
bool checkKey(const std::string &key);
|
bool checkKey(const std::string &key);
|
||||||
ParamKeyFlag getKeyFlag(const std::string &key);
|
|
||||||
ParamKeyType getKeyType(const std::string &key);
|
ParamKeyType getKeyType(const std::string &key);
|
||||||
std::optional<std::string> getKeyDefaultValue(const std::string &key);
|
|
||||||
inline std::string getParamPath(const std::string &key = {}) {
|
inline std::string getParamPath(const std::string &key = {}) {
|
||||||
return params_path + params_prefix + (key.empty() ? "" : "/" + key);
|
return params_path + params_prefix + (key.empty() ? "" : "/" + key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete a value
|
// Delete a value
|
||||||
int remove(const std::string &key);
|
int remove(const std::string &key);
|
||||||
void clearAll(ParamKeyFlag flag);
|
void clearAll(ParamKeyType type);
|
||||||
|
|
||||||
// helpers for reading values
|
// helpers for reading values
|
||||||
std::string get(const std::string &key, bool block = false);
|
std::string get(const std::string &key, bool block = false);
|
||||||
|
|||||||
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
from openpilot.common.params_pyx import Params, ParamKeyFlag, ParamKeyType, UnknownKeyName
|
from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName
|
||||||
assert Params
|
assert Params
|
||||||
assert ParamKeyFlag
|
|
||||||
assert ParamKeyType
|
assert ParamKeyType
|
||||||
assert UnknownKeyName
|
assert UnknownKeyName
|
||||||
|
|
||||||
|
|||||||
+179
-192
@@ -3,215 +3,202 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "cereal/gen/cpp/log.capnp.h"
|
inline static std::unordered_map<std::string, uint32_t> keys = {
|
||||||
|
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
|
||||||
inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
{"AdbEnabled", PERSISTENT},
|
||||||
{"AccessToken", {CLEAR_ON_MANAGER_START | DONT_LOG, STRING}},
|
{"AlwaysOnDM", PERSISTENT},
|
||||||
{"AdbEnabled", {PERSISTENT | BACKUP, BOOL}},
|
{"ApiCache_Device", PERSISTENT},
|
||||||
{"AlwaysOnDM", {PERSISTENT | BACKUP, BOOL}},
|
{"ApiCache_FirehoseStats", PERSISTENT},
|
||||||
{"ApiCache_Device", {PERSISTENT, STRING}},
|
{"AssistNowToken", PERSISTENT},
|
||||||
{"ApiCache_FirehoseStats", {PERSISTENT, JSON}},
|
{"AthenadPid", PERSISTENT},
|
||||||
{"AssistNowToken", {PERSISTENT, STRING}},
|
{"AthenadUploadQueue", PERSISTENT},
|
||||||
{"AthenadPid", {PERSISTENT, STRING}},
|
{"AthenadRecentlyViewedRoutes", PERSISTENT},
|
||||||
{"AthenadUploadQueue", {PERSISTENT, JSON}},
|
{"BootCount", PERSISTENT},
|
||||||
{"AthenadRecentlyViewedRoutes", {PERSISTENT, STRING}},
|
{"CalibrationParams", PERSISTENT},
|
||||||
{"BootCount", {PERSISTENT, INT}},
|
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
|
||||||
{"CalibrationParams", {PERSISTENT, BYTES}},
|
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
|
||||||
{"CameraDebugExpGain", {CLEAR_ON_MANAGER_START, STRING}},
|
{"CarBatteryCapacity", PERSISTENT},
|
||||||
{"CameraDebugExpTime", {CLEAR_ON_MANAGER_START, STRING}},
|
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"CarBatteryCapacity", {PERSISTENT, INT}},
|
{"CarParamsCache", CLEAR_ON_MANAGER_START},
|
||||||
{"CarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}},
|
{"CarParamsPersistent", PERSISTENT},
|
||||||
{"CarParamsCache", {CLEAR_ON_MANAGER_START, BYTES}},
|
{"CarParamsPrevRoute", PERSISTENT},
|
||||||
{"CarParamsPersistent", {PERSISTENT, BYTES}},
|
{"CompletedTrainingVersion", PERSISTENT},
|
||||||
{"CarParamsPrevRoute", {PERSISTENT, BYTES}},
|
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"CompletedTrainingVersion", {PERSISTENT, STRING, "0"}},
|
{"CurrentBootlog", PERSISTENT},
|
||||||
{"ControlsReady", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"CurrentBootlog", {PERSISTENT, STRING}},
|
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"CurrentRoute", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, STRING}},
|
{"DisablePowerDown", PERSISTENT | BACKUP},
|
||||||
{"DisableLogging", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
{"DisableUpdates", PERSISTENT | BACKUP},
|
||||||
{"DisablePowerDown", {PERSISTENT | BACKUP, BOOL}},
|
{"DisengageOnAccelerator", PERSISTENT | BACKUP},
|
||||||
{"DisableUpdates", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"DongleId", PERSISTENT},
|
||||||
{"DisengageOnAccelerator", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"DoReboot", CLEAR_ON_MANAGER_START},
|
||||||
{"DongleId", {PERSISTENT, STRING}},
|
{"DoShutdown", CLEAR_ON_MANAGER_START},
|
||||||
{"DoReboot", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"DoUninstall", CLEAR_ON_MANAGER_START},
|
||||||
{"DoShutdown", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"AlphaLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY | BACKUP},
|
||||||
{"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"ExperimentalMode", PERSISTENT | BACKUP},
|
||||||
{"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}},
|
{"ExperimentalModeConfirmed", PERSISTENT | BACKUP},
|
||||||
{"AlphaLongitudinalEnabled", {PERSISTENT | DEVELOPMENT_ONLY | BACKUP, BOOL}},
|
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"ExperimentalMode", {PERSISTENT | BACKUP, BOOL}},
|
{"ForcePowerDown", PERSISTENT},
|
||||||
{"ExperimentalModeConfirmed", {PERSISTENT | BACKUP, BOOL}},
|
{"GitBranch", PERSISTENT},
|
||||||
{"FirmwareQueryDone", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
{"GitCommit", PERSISTENT},
|
||||||
{"ForcePowerDown", {PERSISTENT, BOOL}},
|
{"GitCommitDate", PERSISTENT},
|
||||||
{"GitBranch", {PERSISTENT, STRING}},
|
{"GitDiff", PERSISTENT},
|
||||||
{"GitCommit", {PERSISTENT, STRING}},
|
{"GithubSshKeys", PERSISTENT | BACKUP},
|
||||||
{"GitCommitDate", {PERSISTENT, STRING}},
|
{"GithubUsername", PERSISTENT | BACKUP},
|
||||||
{"GitDiff", {PERSISTENT, STRING}},
|
{"GitRemote", PERSISTENT},
|
||||||
{"GithubSshKeys", {PERSISTENT | BACKUP, STRING}},
|
{"GsmApn", PERSISTENT | BACKUP},
|
||||||
{"GithubUsername", {PERSISTENT | BACKUP, STRING}},
|
{"GsmMetered", PERSISTENT | BACKUP},
|
||||||
{"GitRemote", {PERSISTENT, STRING}},
|
{"GsmRoaming", PERSISTENT | BACKUP},
|
||||||
{"GsmApn", {PERSISTENT | BACKUP, STRING}},
|
{"HardwareSerial", PERSISTENT},
|
||||||
{"GsmMetered", {PERSISTENT | BACKUP, BOOL, "1"}},
|
{"HasAcceptedTerms", PERSISTENT},
|
||||||
{"GsmRoaming", {PERSISTENT | BACKUP, BOOL}},
|
{"InstallDate", PERSISTENT},
|
||||||
{"HardwareSerial", {PERSISTENT, STRING}},
|
{"IsDriverViewEnabled", CLEAR_ON_MANAGER_START},
|
||||||
{"HasAcceptedTerms", {PERSISTENT, STRING, "0"}},
|
{"IsEngaged", PERSISTENT},
|
||||||
{"InstallDate", {PERSISTENT, TIME}},
|
{"IsLdwEnabled", PERSISTENT | BACKUP},
|
||||||
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsMetric", PERSISTENT | BACKUP},
|
||||||
{"IsEngaged", {PERSISTENT, BOOL}},
|
{"IsOffroad", CLEAR_ON_MANAGER_START},
|
||||||
{"IsLdwEnabled", {PERSISTENT | BACKUP, BOOL}},
|
{"IsOnroad", PERSISTENT},
|
||||||
{"IsMetric", {PERSISTENT | BACKUP, BOOL}},
|
{"IsRhdDetected", PERSISTENT},
|
||||||
{"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsReleaseBranch", CLEAR_ON_MANAGER_START},
|
||||||
{"IsOnroad", {PERSISTENT, BOOL}},
|
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
||||||
{"IsRhdDetected", {PERSISTENT, BOOL}},
|
{"IsTestedBranch", CLEAR_ON_MANAGER_START},
|
||||||
{"IsReleaseBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"LanguageSetting", PERSISTENT | BACKUP},
|
||||||
{"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
|
||||||
{"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"LastGPSPosition", PERSISTENT},
|
||||||
{"LanguageSetting", {PERSISTENT | BACKUP, STRING, "main_en"}},
|
{"LastManagerExitReason", CLEAR_ON_MANAGER_START},
|
||||||
{"LastAthenaPingTime", {CLEAR_ON_MANAGER_START, INT}},
|
{"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"LastGPSPosition", {PERSISTENT, STRING}},
|
{"LastPowerDropDetected", CLEAR_ON_MANAGER_START},
|
||||||
{"LastManagerExitReason", {CLEAR_ON_MANAGER_START, STRING}},
|
{"LastUpdateException", CLEAR_ON_MANAGER_START},
|
||||||
{"LastOffroadStatusPacket", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON}},
|
{"LastUpdateTime", PERSISTENT},
|
||||||
{"LastPowerDropDetected", {CLEAR_ON_MANAGER_START, STRING}},
|
{"LiveDelay", PERSISTENT | BACKUP},
|
||||||
{"LastUpdateException", {CLEAR_ON_MANAGER_START, STRING}},
|
{"LiveParameters", PERSISTENT},
|
||||||
{"LastUpdateRouteCount", {PERSISTENT, INT}},
|
{"LiveParametersV2", PERSISTENT},
|
||||||
{"LastUpdateTime", {PERSISTENT, TIME}},
|
{"LiveTorqueParameters", PERSISTENT | DONT_LOG},
|
||||||
{"LastUpdateUptimeOnroad", {PERSISTENT, FLOAT}},
|
{"LocationFilterInitialState", PERSISTENT},
|
||||||
{"LiveDelay", {PERSISTENT | BACKUP, BYTES}},
|
{"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"LiveParameters", {PERSISTENT, JSON}},
|
{"LongitudinalPersonality", PERSISTENT | BACKUP},
|
||||||
{"LiveParametersV2", {PERSISTENT, BYTES}},
|
{"NetworkMetered", PERSISTENT},
|
||||||
{"LiveTorqueParameters", {PERSISTENT | DONT_LOG, BYTES}},
|
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"LocationFilterInitialState", {PERSISTENT, BYTES}},
|
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"LongitudinalManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
|
||||||
{"LongitudinalPersonality", {PERSISTENT | BACKUP, INT, std::to_string(static_cast<int>(cereal::LongitudinalPersonality::STANDARD))}},
|
{"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"NetworkMetered", {PERSISTENT | BACKUP, BOOL}},
|
{"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
|
||||||
{"ObdMultiplexingChanged", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
{"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
|
||||||
{"ObdMultiplexingEnabled", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
{"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
||||||
{"Offroad_CarUnrecognized", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
{"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START},
|
||||||
{"Offroad_ConnectivityNeeded", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"Offroad_ConnectivityNeededPrompt", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_Recalibration", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"Offroad_ExcessiveActuation", {PERSISTENT, JSON}},
|
{"Offroad_StorageMissing", CLEAR_ON_MANAGER_START},
|
||||||
{"Offroad_IsTakingSnapshot", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
|
||||||
{"Offroad_NeosUpdate", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
|
||||||
{"Offroad_NoFirmware", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
{"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
|
||||||
{"Offroad_Recalibration", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
{"OnroadCycleRequested", CLEAR_ON_MANAGER_START},
|
||||||
{"Offroad_StorageMissing", {CLEAR_ON_MANAGER_START, JSON}},
|
{"OpenpilotEnabledToggle", PERSISTENT | BACKUP},
|
||||||
{"Offroad_TemperatureTooHigh", {CLEAR_ON_MANAGER_START, JSON}},
|
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"Offroad_UnregisteredHardware", {CLEAR_ON_MANAGER_START, JSON}},
|
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"Offroad_UpdateFailed", {CLEAR_ON_MANAGER_START, JSON}},
|
{"PandaSignatures", CLEAR_ON_MANAGER_START},
|
||||||
{"OnroadCycleRequested", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"PrimeType", PERSISTENT},
|
||||||
{"OpenpilotEnabledToggle", {PERSISTENT | BACKUP, BOOL, "1"}},
|
{"RecordFront", PERSISTENT | BACKUP},
|
||||||
{"PandaHeartbeatLost", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
|
||||||
{"PandaSomResetTriggered", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"SecOCKey", PERSISTENT | DONT_LOG}, // Candidate for | BACKUP
|
||||||
{"PandaSignatures", {CLEAR_ON_MANAGER_START, BYTES}},
|
{"RouteCount", PERSISTENT},
|
||||||
{"PrimeType", {PERSISTENT, INT}},
|
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"RecordAudio", {PERSISTENT | BACKUP, BOOL}},
|
{"SshEnabled", PERSISTENT | BACKUP},
|
||||||
{"RecordFront", {PERSISTENT | BACKUP, BOOL}},
|
{"TermsVersion", PERSISTENT},
|
||||||
{"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet
|
{"TrainingVersion", PERSISTENT},
|
||||||
{"SecOCKey", {PERSISTENT | DONT_LOG | BACKUP, STRING}},
|
{"UbloxAvailable", PERSISTENT},
|
||||||
{"RouteCount", {PERSISTENT, INT, "0"}},
|
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"UpdateFailedCount", CLEAR_ON_MANAGER_START},
|
||||||
{"SshEnabled", {PERSISTENT | BACKUP, BOOL}},
|
{"UpdaterAvailableBranches", PERSISTENT},
|
||||||
{"TermsVersion", {PERSISTENT, STRING}},
|
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
|
||||||
{"TrainingVersion", {PERSISTENT, STRING}},
|
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||||
{"UbloxAvailable", {PERSISTENT, BOOL}},
|
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdateAvailable", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
{"UpdaterNewDescription", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdateFailedCount", {CLEAR_ON_MANAGER_START, INT}},
|
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdaterAvailableBranches", {PERSISTENT, STRING}},
|
{"UpdaterState", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdaterCurrentDescription", {CLEAR_ON_MANAGER_START, STRING}},
|
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdaterCurrentReleaseNotes", {CLEAR_ON_MANAGER_START, BYTES}},
|
{"UpdaterLastFetchTime", PERSISTENT},
|
||||||
{"UpdaterFetchAvailable", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"Version", PERSISTENT},
|
||||||
{"UpdaterNewDescription", {CLEAR_ON_MANAGER_START, STRING}},
|
|
||||||
{"UpdaterNewReleaseNotes", {CLEAR_ON_MANAGER_START, BYTES}},
|
|
||||||
{"UpdaterState", {CLEAR_ON_MANAGER_START, STRING}},
|
|
||||||
{"UpdaterTargetBranch", {CLEAR_ON_MANAGER_START, STRING}},
|
|
||||||
{"UpdaterLastFetchTime", {PERSISTENT, TIME}},
|
|
||||||
{"UptimeOffroad", {PERSISTENT, FLOAT, "0.0"}},
|
|
||||||
{"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
|
|
||||||
{"Version", {PERSISTENT, STRING}},
|
|
||||||
|
|
||||||
// --- sunnypilot params --- //
|
// --- sunnypilot params --- //
|
||||||
{"ApiCache_DriveStats", {PERSISTENT, JSON}},
|
{"ApiCache_DriveStats", PERSISTENT},
|
||||||
{"AutoLaneChangeBsmDelay", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"AutoLaneChangeBsmDelay", PERSISTENT},
|
||||||
{"AutoLaneChangeTimer", {PERSISTENT | BACKUP, INT, "0"}},
|
{"AutoLaneChangeTimer", PERSISTENT},
|
||||||
{"BlinkerMinLateralControlSpeed", {PERSISTENT | BACKUP, INT, "20"}}, // MPH or km/h
|
{"BlinkerMinLateralControlSpeed", PERSISTENT | BACKUP},
|
||||||
{"BlinkerPauseLateralControl", {PERSISTENT | BACKUP, INT, "0"}},
|
{"BlinkerPauseLateralControl", PERSISTENT | BACKUP},
|
||||||
{"Brightness", {PERSISTENT | BACKUP, INT, "0"}},
|
{"CarParamsSP", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"CarParamsSP", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}},
|
{"CarParamsSPCache", CLEAR_ON_MANAGER_START},
|
||||||
{"CarParamsSPCache", {CLEAR_ON_MANAGER_START, BYTES}},
|
{"CarParamsSPPersistent", PERSISTENT},
|
||||||
{"CarParamsSPPersistent", {PERSISTENT, BYTES}},
|
{"CarPlatformBundle", PERSISTENT},
|
||||||
{"CarPlatformBundle", {PERSISTENT | BACKUP, STRING}},
|
{"CustomAccIncrementsEnabled", PERSISTENT | BACKUP},
|
||||||
{"ChevronInfo", {PERSISTENT | BACKUP, INT, "4"}},
|
{"CustomAccLongPressIncrement", PERSISTENT | BACKUP},
|
||||||
{"CustomAccIncrementsEnabled", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"CustomAccShortPressIncrement", PERSISTENT | BACKUP},
|
||||||
{"CustomAccLongPressIncrement", {PERSISTENT | BACKUP, INT, "5"}},
|
{"DeviceBootMode", PERSISTENT | BACKUP},
|
||||||
{"CustomAccShortPressIncrement", {PERSISTENT | BACKUP, INT, "1"}},
|
{"EnableGithubRunner", PERSISTENT | BACKUP},
|
||||||
{"DeviceBootMode", {PERSISTENT | BACKUP, INT, "0"}},
|
{"InteractivityTimeout", PERSISTENT | BACKUP},
|
||||||
{"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}},
|
{"MaxTimeOffroad", PERSISTENT | BACKUP},
|
||||||
{"InteractivityTimeout", {PERSISTENT | BACKUP, INT, "0"}},
|
{"Brightness", PERSISTENT | BACKUP},
|
||||||
{"IsDevelopmentBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"MaxTimeOffroad", {PERSISTENT | BACKUP, INT, "1800"}},
|
{"OffroadMode", CLEAR_ON_MANAGER_START},
|
||||||
{"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}},
|
{"QuietMode", PERSISTENT | BACKUP},
|
||||||
{"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}},
|
|
||||||
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
|
|
||||||
// MADS params
|
// MADS params
|
||||||
{"Mads", {PERSISTENT | BACKUP, BOOL, "1"}},
|
{"Mads", PERSISTENT | BACKUP},
|
||||||
{"MadsMainCruiseAllowed", {PERSISTENT | BACKUP, BOOL, "1"}},
|
{"MadsMainCruiseAllowed", PERSISTENT | BACKUP},
|
||||||
{"MadsSteeringMode", {PERSISTENT | BACKUP, INT, "0"}},
|
{"MadsSteeringMode", PERSISTENT | BACKUP},
|
||||||
{"MadsUnifiedEngagementMode", {PERSISTENT | BACKUP, BOOL, "1"}},
|
{"MadsUnifiedEngagementMode", PERSISTENT | BACKUP},
|
||||||
|
|
||||||
// Model Manager params
|
// Model Manager params
|
||||||
{"ModelManager_ActiveBundle", {PERSISTENT, STRING}},
|
{"ModelManager_ActiveBundle", PERSISTENT},
|
||||||
{"ModelManager_ClearCache", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"ModelManager_DownloadIndex", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"ModelManager_DownloadIndex", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, INT, "0"}},
|
{"ModelManager_LastSyncTime", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"ModelManager_LastSyncTime", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, INT, "0"}},
|
{"ModelManager_ModelsCache", PERSISTENT | BACKUP},
|
||||||
{"ModelManager_ModelsCache", {PERSISTENT | BACKUP, STRING}},
|
|
||||||
|
|
||||||
// Neural Network Lateral Control
|
// Neural Network Lateral Control
|
||||||
{"NeuralNetworkLateralControl", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"NeuralNetworkLateralControl", PERSISTENT | BACKUP},
|
||||||
|
|
||||||
// sunnylink params
|
// sunnylink params
|
||||||
{"EnableSunnylinkUploader", {PERSISTENT | BACKUP, BOOL}},
|
{"EnableSunnylinkUploader", PERSISTENT | BACKUP},
|
||||||
{"LastSunnylinkPingTime", {CLEAR_ON_MANAGER_START, INT}},
|
{"LastSunnylinkPingTime", CLEAR_ON_MANAGER_START},
|
||||||
{"SunnylinkCache_Roles", {PERSISTENT, STRING}},
|
{"SunnylinkCache_Roles", PERSISTENT},
|
||||||
{"SunnylinkCache_Users", {PERSISTENT, STRING}},
|
{"SunnylinkCache_Users", PERSISTENT},
|
||||||
{"SunnylinkDongleId", {PERSISTENT, STRING}},
|
{"SunnylinkDongleId", PERSISTENT},
|
||||||
{"SunnylinkdPid", {PERSISTENT, STRING}},
|
{"SunnylinkdPid", PERSISTENT},
|
||||||
{"SunnylinkEnabled", {PERSISTENT, BOOL}},
|
{"SunnylinkEnabled", PERSISTENT},
|
||||||
|
|
||||||
// Backup Manager params
|
// Backup Manager params
|
||||||
{"BackupManager_CreateBackup", {PERSISTENT, BOOL}},
|
{"BackupManager_CreateBackup", PERSISTENT},
|
||||||
{"BackupManager_RestoreVersion", {PERSISTENT, STRING}},
|
{"BackupManager_RestoreVersion", PERSISTENT},
|
||||||
|
|
||||||
// sunnypilot car specific params
|
// sunnypilot car specific params
|
||||||
{"HyundaiLongitudinalTuning", {PERSISTENT | BACKUP, INT, "0"}},
|
{"HyundaiLongitudinalTuning", PERSISTENT},
|
||||||
|
|
||||||
{"DynamicExperimentalControl", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"DynamicExperimentalControl", PERSISTENT},
|
||||||
{"BlindSpot", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"BlindSpot", PERSISTENT | BACKUP},
|
||||||
|
|
||||||
// model panel params
|
// model panel params
|
||||||
{"LagdToggle", {PERSISTENT | BACKUP, BOOL, "1"}},
|
{"LagdToggle", PERSISTENT | BACKUP},
|
||||||
{"LagdToggleDesc", {PERSISTENT, STRING}},
|
{"LagdToggleDesc", PERSISTENT},
|
||||||
{"LagdToggleDelay", {PERSISTENT | BACKUP, FLOAT, "0.2"}},
|
{"LagdToggledelay", PERSISTENT | BACKUP},
|
||||||
|
|
||||||
// mapd
|
// mapd
|
||||||
{"MapAdvisorySpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, FLOAT}},
|
{"MapAdvisorySpeedLimit", CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"MapdVersion", {PERSISTENT, STRING, ""}},
|
{"MapdVersion", PERSISTENT},
|
||||||
{"MapSpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, FLOAT, "0.0"}},
|
{"MapSpeedLimit", CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"NextMapSpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, STRING}},
|
{"NextMapSpeedLimit", CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"Offroad_OSMUpdateRequired", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_OSMUpdateRequired", CLEAR_ON_MANAGER_START},
|
||||||
{"OsmDbUpdatesCheck", {CLEAR_ON_MANAGER_START, BOOL}}, // mapd database update happens with device ON, reset on boot
|
{"OsmDbUpdatesCheck", CLEAR_ON_MANAGER_START}, // mapd database update happens with device ON, reset on boot
|
||||||
{"OSMDownloadBounds", {PERSISTENT, STRING}},
|
{"OSMDownloadBounds", PERSISTENT},
|
||||||
{"OsmDownloadedDate", {PERSISTENT, STRING, "0.0"}},
|
{"OsmDownloadedDate", PERSISTENT},
|
||||||
{"OSMDownloadLocations", {PERSISTENT, STRING}},
|
{"OSMDownloadLocations", PERSISTENT},
|
||||||
{"OSMDownloadProgress", {CLEAR_ON_MANAGER_START, JSON}},
|
{"OSMDownloadProgress", CLEAR_ON_MANAGER_START},
|
||||||
{"OsmLocal", {PERSISTENT, BOOL}},
|
{"OsmLocal", PERSISTENT},
|
||||||
{"OsmLocationName", {PERSISTENT, STRING}},
|
{"OsmLocationName", PERSISTENT},
|
||||||
{"OsmLocationTitle", {PERSISTENT, STRING}},
|
{"OsmLocationTitle", PERSISTENT},
|
||||||
{"OsmLocationUrl", {PERSISTENT, STRING}},
|
{"OsmLocationUrl", PERSISTENT},
|
||||||
{"OsmStateName", {PERSISTENT, STRING, "All"}},
|
{"OsmStateName", PERSISTENT},
|
||||||
{"OsmStateTitle", {PERSISTENT, STRING}},
|
{"OsmStateTitle", PERSISTENT},
|
||||||
{"OsmWayTest", {PERSISTENT, STRING}},
|
{"OsmWayTest", PERSISTENT},
|
||||||
{"RoadName", {CLEAR_ON_ONROAD_TRANSITION, STRING, ""}},
|
{"RoadName", CLEAR_ON_ONROAD_TRANSITION},
|
||||||
};
|
};
|
||||||
|
|||||||
+13
-81
@@ -1,35 +1,19 @@
|
|||||||
# distutils: language = c++
|
# distutils: language = c++
|
||||||
# cython: language_level = 3
|
# cython: language_level = 3
|
||||||
import builtins
|
|
||||||
import datetime
|
|
||||||
import json
|
|
||||||
from libcpp cimport bool
|
from libcpp cimport bool
|
||||||
from libcpp.string cimport string
|
from libcpp.string cimport string
|
||||||
from libcpp.vector cimport vector
|
from libcpp.vector cimport vector
|
||||||
from libcpp.optional cimport optional
|
|
||||||
|
|
||||||
from openpilot.common.swaglog import cloudlog
|
|
||||||
|
|
||||||
cdef extern from "common/params.h":
|
cdef extern from "common/params.h":
|
||||||
cpdef enum ParamKeyFlag:
|
cpdef enum ParamKeyType:
|
||||||
PERSISTENT
|
PERSISTENT
|
||||||
CLEAR_ON_MANAGER_START
|
CLEAR_ON_MANAGER_START
|
||||||
CLEAR_ON_ONROAD_TRANSITION
|
CLEAR_ON_ONROAD_TRANSITION
|
||||||
CLEAR_ON_OFFROAD_TRANSITION
|
CLEAR_ON_OFFROAD_TRANSITION
|
||||||
DEVELOPMENT_ONLY
|
DEVELOPMENT_ONLY
|
||||||
CLEAR_ON_IGNITION_ON
|
|
||||||
BACKUP
|
BACKUP
|
||||||
ALL
|
ALL
|
||||||
|
|
||||||
cpdef enum ParamKeyType:
|
|
||||||
STRING
|
|
||||||
BOOL
|
|
||||||
INT
|
|
||||||
FLOAT
|
|
||||||
TIME
|
|
||||||
JSON
|
|
||||||
BYTES
|
|
||||||
|
|
||||||
cdef cppclass c_Params "Params":
|
cdef cppclass c_Params "Params":
|
||||||
c_Params(string) except + nogil
|
c_Params(string) except + nogil
|
||||||
string get(string, bool) nogil
|
string get(string, bool) nogil
|
||||||
@@ -40,31 +24,10 @@ cdef extern from "common/params.h":
|
|||||||
void putBoolNonBlocking(string, bool) nogil
|
void putBoolNonBlocking(string, bool) nogil
|
||||||
int putBool(string, bool) nogil
|
int putBool(string, bool) nogil
|
||||||
bool checkKey(string) nogil
|
bool checkKey(string) nogil
|
||||||
ParamKeyType getKeyType(string) nogil
|
|
||||||
optional[string] getKeyDefaultValue(string) nogil
|
|
||||||
string getParamPath(string) nogil
|
string getParamPath(string) nogil
|
||||||
void clearAll(ParamKeyFlag)
|
void clearAll(ParamKeyType)
|
||||||
vector[string] allKeys(ParamKeyFlag)
|
vector[string] allKeys(ParamKeyType)
|
||||||
|
|
||||||
PYTHON_2_CPP = {
|
|
||||||
(str, STRING): lambda v: v,
|
|
||||||
(builtins.bool, BOOL): lambda v: "1" if v else "0",
|
|
||||||
(int, INT): str,
|
|
||||||
(float, FLOAT): str,
|
|
||||||
(datetime.datetime, TIME): lambda v: v.isoformat(),
|
|
||||||
(dict, JSON): json.dumps,
|
|
||||||
(list, JSON): json.dumps,
|
|
||||||
(bytes, BYTES): lambda v: v,
|
|
||||||
}
|
|
||||||
CPP_2_PYTHON = {
|
|
||||||
STRING: lambda v: v.decode("utf-8"),
|
|
||||||
BOOL: lambda v: v == b"1",
|
|
||||||
INT: int,
|
|
||||||
FLOAT: float,
|
|
||||||
TIME: lambda v: datetime.datetime.fromisoformat(v.decode("utf-8")),
|
|
||||||
JSON: json.loads,
|
|
||||||
BYTES: lambda v: v,
|
|
||||||
}
|
|
||||||
|
|
||||||
def ensure_bytes(v):
|
def ensure_bytes(v):
|
||||||
return v.encode() if isinstance(v, str) else v
|
return v.encode() if isinstance(v, str) else v
|
||||||
@@ -88,8 +51,8 @@ cdef class Params:
|
|||||||
def __dealloc__(self):
|
def __dealloc__(self):
|
||||||
del self.p
|
del self.p
|
||||||
|
|
||||||
def clear_all(self, tx_flag=ParamKeyFlag.ALL):
|
def clear_all(self, tx_type=ParamKeyType.ALL):
|
||||||
self.p.clearAll(tx_flag)
|
self.p.clearAll(tx_type)
|
||||||
|
|
||||||
def check_key(self, key):
|
def check_key(self, key):
|
||||||
key = ensure_bytes(key)
|
key = ensure_bytes(key)
|
||||||
@@ -97,38 +60,21 @@ cdef class Params:
|
|||||||
raise UnknownKeyName(key)
|
raise UnknownKeyName(key)
|
||||||
return key
|
return key
|
||||||
|
|
||||||
def python2cpp(self, proposed_type, expected_type, value, key):
|
def get(self, key, bool block=False, encoding=None):
|
||||||
cast = PYTHON_2_CPP.get((proposed_type, expected_type))
|
|
||||||
if cast:
|
|
||||||
return cast(value)
|
|
||||||
raise TypeError(f"Type mismatch while writing param {key}: {proposed_type=} {expected_type=} {value=}")
|
|
||||||
|
|
||||||
def cpp2python(self, t, value, default, key):
|
|
||||||
if value is None:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
return CPP_2_PYTHON[t](value)
|
|
||||||
except (KeyError, TypeError, ValueError):
|
|
||||||
cloudlog.warning(f"Failed to cast param {key} with {value=} from type {t=}")
|
|
||||||
return self.cpp2python(t, default, None, key)
|
|
||||||
|
|
||||||
def get(self, key, bool block=False, bool return_default=False):
|
|
||||||
cdef string k = self.check_key(key)
|
cdef string k = self.check_key(key)
|
||||||
cdef ParamKeyType t = self.p.getKeyType(k)
|
|
||||||
cdef optional[string] default = self.p.getKeyDefaultValue(k)
|
|
||||||
cdef string val
|
cdef string val
|
||||||
with nogil:
|
with nogil:
|
||||||
val = self.p.get(k, block)
|
val = self.p.get(k, block)
|
||||||
|
|
||||||
default_val = (default.value() if default.has_value() else None) if return_default else None
|
|
||||||
if val == b"":
|
if val == b"":
|
||||||
if block:
|
if block:
|
||||||
# If we got no value while running in blocked mode
|
# If we got no value while running in blocked mode
|
||||||
# it means we got an interrupt while waiting
|
# it means we got an interrupt while waiting
|
||||||
raise KeyboardInterrupt
|
raise KeyboardInterrupt
|
||||||
else:
|
else:
|
||||||
return self.cpp2python(t, default_val, None, key)
|
return None
|
||||||
return self.cpp2python(t, val, default_val, key)
|
|
||||||
|
return val if encoding is None else val.decode(encoding)
|
||||||
|
|
||||||
def get_bool(self, key, bool block=False):
|
def get_bool(self, key, bool block=False):
|
||||||
cdef string k = self.check_key(key)
|
cdef string k = self.check_key(key)
|
||||||
@@ -137,11 +83,6 @@ cdef class Params:
|
|||||||
r = self.p.getBool(k, block)
|
r = self.p.getBool(k, block)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def _put_cast(self, key, dat):
|
|
||||||
cdef string k = self.check_key(key)
|
|
||||||
cdef ParamKeyType t = self.p.getKeyType(k)
|
|
||||||
return ensure_bytes(self.python2cpp(type(dat), t, dat, key))
|
|
||||||
|
|
||||||
def put(self, key, dat):
|
def put(self, key, dat):
|
||||||
"""
|
"""
|
||||||
Warning: This function blocks until the param is written to disk!
|
Warning: This function blocks until the param is written to disk!
|
||||||
@@ -150,7 +91,7 @@ cdef class Params:
|
|||||||
in general try to avoid writing params as much as possible.
|
in general try to avoid writing params as much as possible.
|
||||||
"""
|
"""
|
||||||
cdef string k = self.check_key(key)
|
cdef string k = self.check_key(key)
|
||||||
cdef string dat_bytes = self._put_cast(key, dat)
|
cdef string dat_bytes = ensure_bytes(dat)
|
||||||
with nogil:
|
with nogil:
|
||||||
self.p.put(k, dat_bytes)
|
self.p.put(k, dat_bytes)
|
||||||
|
|
||||||
@@ -161,7 +102,7 @@ cdef class Params:
|
|||||||
|
|
||||||
def put_nonblocking(self, key, dat):
|
def put_nonblocking(self, key, dat):
|
||||||
cdef string k = self.check_key(key)
|
cdef string k = self.check_key(key)
|
||||||
cdef string dat_bytes = self._put_cast(key, dat)
|
cdef string dat_bytes = ensure_bytes(dat)
|
||||||
with nogil:
|
with nogil:
|
||||||
self.p.putNonBlocking(k, dat_bytes)
|
self.p.putNonBlocking(k, dat_bytes)
|
||||||
|
|
||||||
@@ -179,14 +120,5 @@ cdef class Params:
|
|||||||
cdef string key_bytes = ensure_bytes(key)
|
cdef string key_bytes = ensure_bytes(key)
|
||||||
return self.p.getParamPath(key_bytes).decode("utf-8")
|
return self.p.getParamPath(key_bytes).decode("utf-8")
|
||||||
|
|
||||||
def get_type(self, key):
|
def all_keys(self, type=ParamKeyType.ALL):
|
||||||
return self.p.getKeyType(self.check_key(key))
|
return self.p.allKeys(type)
|
||||||
|
|
||||||
def all_keys(self, flag=ParamKeyFlag.ALL):
|
|
||||||
return self.p.allKeys(flag)
|
|
||||||
|
|
||||||
def get_default_value(self, key):
|
|
||||||
cdef string k = self.check_key(key)
|
|
||||||
cdef ParamKeyType t = self.p.getKeyType(k)
|
|
||||||
cdef optional[string] default = self.p.getKeyDefaultValue(k)
|
|
||||||
return self.cpp2python(t, default.value(), None, key) if default.has_value() else None
|
|
||||||
|
|||||||
+11
-43
@@ -1,11 +1,10 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import datetime
|
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from openpilot.common.params import Params, ParamKeyFlag, UnknownKeyName
|
from openpilot.common.params import Params, ParamKeyType, UnknownKeyName
|
||||||
|
|
||||||
class TestParams:
|
class TestParams:
|
||||||
def setup_method(self):
|
def setup_method(self):
|
||||||
@@ -13,7 +12,7 @@ class TestParams:
|
|||||||
|
|
||||||
def test_params_put_and_get(self):
|
def test_params_put_and_get(self):
|
||||||
self.params.put("DongleId", "cb38263377b873ee")
|
self.params.put("DongleId", "cb38263377b873ee")
|
||||||
assert self.params.get("DongleId") == "cb38263377b873ee"
|
assert self.params.get("DongleId") == b"cb38263377b873ee"
|
||||||
|
|
||||||
def test_params_non_ascii(self):
|
def test_params_non_ascii(self):
|
||||||
st = b"\xe1\x90\xff"
|
st = b"\xe1\x90\xff"
|
||||||
@@ -21,7 +20,7 @@ class TestParams:
|
|||||||
assert self.params.get("CarParams") == st
|
assert self.params.get("CarParams") == st
|
||||||
|
|
||||||
def test_params_get_cleared_manager_start(self):
|
def test_params_get_cleared_manager_start(self):
|
||||||
self.params.put("CarParams", b"test")
|
self.params.put("CarParams", "test")
|
||||||
self.params.put("DongleId", "cb38263377b873ee")
|
self.params.put("DongleId", "cb38263377b873ee")
|
||||||
assert self.params.get("CarParams") == b"test"
|
assert self.params.get("CarParams") == b"test"
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ class TestParams:
|
|||||||
f.write("test")
|
f.write("test")
|
||||||
assert os.path.isfile(undefined_param)
|
assert os.path.isfile(undefined_param)
|
||||||
|
|
||||||
self.params.clear_all(ParamKeyFlag.CLEAR_ON_MANAGER_START)
|
self.params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START)
|
||||||
assert self.params.get("CarParams") is None
|
assert self.params.get("CarParams") is None
|
||||||
assert self.params.get("DongleId") is not None
|
assert self.params.get("DongleId") is not None
|
||||||
assert not os.path.isfile(undefined_param)
|
assert not os.path.isfile(undefined_param)
|
||||||
@@ -38,16 +37,16 @@ class TestParams:
|
|||||||
def test_params_two_things(self):
|
def test_params_two_things(self):
|
||||||
self.params.put("DongleId", "bob")
|
self.params.put("DongleId", "bob")
|
||||||
self.params.put("AthenadPid", "123")
|
self.params.put("AthenadPid", "123")
|
||||||
assert self.params.get("DongleId") == "bob"
|
assert self.params.get("DongleId") == b"bob"
|
||||||
assert self.params.get("AthenadPid") == "123"
|
assert self.params.get("AthenadPid") == b"123"
|
||||||
|
|
||||||
def test_params_get_block(self):
|
def test_params_get_block(self):
|
||||||
def _delayed_writer():
|
def _delayed_writer():
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
self.params.put("CarParams", b"test")
|
self.params.put("CarParams", "test")
|
||||||
threading.Thread(target=_delayed_writer).start()
|
threading.Thread(target=_delayed_writer).start()
|
||||||
assert self.params.get("CarParams") is None
|
assert self.params.get("CarParams") is None
|
||||||
assert self.params.get("CarParams", block=True) == b"test"
|
assert self.params.get("CarParams", True) == b"test"
|
||||||
|
|
||||||
def test_params_unknown_key_fails(self):
|
def test_params_unknown_key_fails(self):
|
||||||
with pytest.raises(UnknownKeyName):
|
with pytest.raises(UnknownKeyName):
|
||||||
@@ -77,17 +76,17 @@ class TestParams:
|
|||||||
self.params.put_bool("IsMetric", False)
|
self.params.put_bool("IsMetric", False)
|
||||||
assert not self.params.get_bool("IsMetric")
|
assert not self.params.get_bool("IsMetric")
|
||||||
|
|
||||||
self.params.put("IsMetric", True)
|
self.params.put("IsMetric", "1")
|
||||||
assert self.params.get_bool("IsMetric")
|
assert self.params.get_bool("IsMetric")
|
||||||
|
|
||||||
self.params.put("IsMetric", False)
|
self.params.put("IsMetric", "0")
|
||||||
assert not self.params.get_bool("IsMetric")
|
assert not self.params.get_bool("IsMetric")
|
||||||
|
|
||||||
def test_put_non_blocking_with_get_block(self):
|
def test_put_non_blocking_with_get_block(self):
|
||||||
q = Params()
|
q = Params()
|
||||||
def _delayed_writer():
|
def _delayed_writer():
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
Params().put_nonblocking("CarParams", b"test")
|
Params().put_nonblocking("CarParams", "test")
|
||||||
threading.Thread(target=_delayed_writer).start()
|
threading.Thread(target=_delayed_writer).start()
|
||||||
assert q.get("CarParams") is None
|
assert q.get("CarParams") is None
|
||||||
assert q.get("CarParams", True) == b"test"
|
assert q.get("CarParams", True) == b"test"
|
||||||
@@ -108,34 +107,3 @@ class TestParams:
|
|||||||
assert len(keys) > 20
|
assert len(keys) > 20
|
||||||
assert len(keys) == len(set(keys))
|
assert len(keys) == len(set(keys))
|
||||||
assert b"CarParams" in keys
|
assert b"CarParams" in keys
|
||||||
|
|
||||||
def test_params_default_value(self):
|
|
||||||
self.params.remove("LanguageSetting")
|
|
||||||
self.params.remove("LongitudinalPersonality")
|
|
||||||
self.params.remove("LiveParameters")
|
|
||||||
|
|
||||||
assert self.params.get("LanguageSetting") is None
|
|
||||||
assert self.params.get("LanguageSetting", return_default=False) is None
|
|
||||||
assert isinstance(self.params.get("LanguageSetting", return_default=True), str)
|
|
||||||
assert isinstance(self.params.get("LongitudinalPersonality", return_default=True), int)
|
|
||||||
assert self.params.get("LiveParameters") is None
|
|
||||||
assert self.params.get("LiveParameters", return_default=True) is None
|
|
||||||
|
|
||||||
def test_params_get_type(self):
|
|
||||||
# json
|
|
||||||
self.params.put("ApiCache_FirehoseStats", {"a": 0})
|
|
||||||
assert self.params.get("ApiCache_FirehoseStats") == {"a": 0}
|
|
||||||
|
|
||||||
# int
|
|
||||||
self.params.put("BootCount", 1441)
|
|
||||||
assert self.params.get("BootCount") == 1441
|
|
||||||
|
|
||||||
# bool
|
|
||||||
self.params.put("AdbEnabled", True)
|
|
||||||
assert self.params.get("AdbEnabled")
|
|
||||||
assert isinstance(self.params.get("AdbEnabled"), bool)
|
|
||||||
|
|
||||||
# time
|
|
||||||
now = datetime.datetime.now(datetime.UTC)
|
|
||||||
self.params.put("InstallDate", now)
|
|
||||||
assert self.params.get("InstallDate") == now
|
|
||||||
|
|||||||
+2
-4
@@ -12,7 +12,6 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
@@ -79,9 +78,8 @@ std::string read_file(const std::string& fn) {
|
|||||||
std::ifstream f(fn, std::ios::binary | std::ios::in);
|
std::ifstream f(fn, std::ios::binary | std::ios::in);
|
||||||
if (f.is_open()) {
|
if (f.is_open()) {
|
||||||
f.seekg(0, std::ios::end);
|
f.seekg(0, std::ios::end);
|
||||||
std::streamsize size = f.tellg();
|
int size = f.tellg();
|
||||||
// seekg and tellg on a directory doesn't return pos_type(-1) but max(streamsize)
|
if (f.good() && size > 0) {
|
||||||
if (f.good() && size > 0 && size < std::numeric_limits<std::streamsize>::max()) {
|
|
||||||
std::string result(size, '\0');
|
std::string result(size, '\0');
|
||||||
f.seekg(0, std::ios::beg);
|
f.seekg(0, std::ios::beg);
|
||||||
f.read(result.data(), size);
|
f.read(result.data(), size);
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
#define COMMA_VERSION "0.10.0"
|
#define COMMA_VERSION "0.9.10"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import contextlib
|
|||||||
import gc
|
import gc
|
||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
|
import random
|
||||||
|
|
||||||
from openpilot.common.prefix import OpenpilotPrefix
|
from openpilot.common.prefix import OpenpilotPrefix
|
||||||
from openpilot.system.manager import manager
|
from openpilot.system.manager import manager
|
||||||
@@ -48,6 +49,8 @@ def clean_env():
|
|||||||
|
|
||||||
@pytest.fixture(scope="function", autouse=True)
|
@pytest.fixture(scope="function", autouse=True)
|
||||||
def openpilot_function_fixture(request):
|
def openpilot_function_fixture(request):
|
||||||
|
random.seed(0)
|
||||||
|
|
||||||
with clean_env():
|
with clean_env():
|
||||||
# setup a clean environment for each test
|
# setup a clean environment for each test
|
||||||
with OpenpilotPrefix(shared_download_cache=request.node.get_closest_marker("shared_download_cache") is not None) as prefix:
|
with OpenpilotPrefix(shared_download_cache=request.node.get_closest_marker("shared_download_cache") is not None) as prefix:
|
||||||
|
|||||||
+313
-314
@@ -4,323 +4,322 @@
|
|||||||
|
|
||||||
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||||
|
|
||||||
# 313 Supported Cars
|
# 312 Supported Cars
|
||||||
|
|
||||||
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br> |Video|Setup Video|
|
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br> |Video|Setup Video|
|
||||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||||
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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?harness=Acura ILX 2016-18">Buy Here</a></sub></details>|||
|
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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-18">Buy Here</a></sub></details>|||
|
||||||
|Acura|ILX 2019|All|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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?harness=Acura ILX 2019">Buy Here</a></sub></details>|||
|
|Acura|ILX 2019|All|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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 2019">Buy Here</a></sub></details>|||
|
||||||
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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?harness=Acura RDX 2016-18">Buy Here</a></sub></details>|||
|
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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?harness=Acura RDX 2019-21">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,16</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?harness=Audi A3 2014-19">Buy Here</a></sub></details>|||
|
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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,16</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?harness=Audi A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>|||
|
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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,16</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?harness=Audi Q2 2018">Buy Here</a></sub></details>|||
|
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Audi Q3 2019-24">Buy Here</a></sub></details>|||
|
|Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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-24">Buy Here</a></sub></details>|||
|
||||||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Audi RS3 2018">Buy Here</a></sub></details>|||
|
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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,16</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?harness=Audi S3 2015-17">Buy Here</a></sub></details>|||
|
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Chevrolet Bolt EUV 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|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?harness=Chevrolet Bolt EV 2022-23">Buy Here</a></sub></details>|||
|
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 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?harness=Chevrolet Equinox 2019-22">Buy Here</a></sub></details>|||
|
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 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?harness=Chevrolet Silverado 1500 2020-21">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?harness=Chevrolet Trailblazer 2021-22">Buy Here</a></sub></details>|||
|
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 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 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?harness=Chrysler Pacifica 2017-18">Buy Here</a></sub></details>|||
|
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 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?harness=Chrysler Pacifica 2019-20">Buy Here</a></sub></details>|||
|
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 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?harness=Chrysler Pacifica 2021-23">Buy Here</a></sub></details>|||
|
|Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 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?harness=Chrysler Pacifica Hybrid 2017-18">Buy Here</a></sub></details>|||
|
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 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-25|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?harness=Chrysler Pacifica Hybrid 2019-25">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|<a href="https://youtu.be/VT-i3yRsX2s?t=2736" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|comma|body|All|openpilot|0 mph|0 mph|[](##)|[](##)|None|||
|
||||||
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=CUPRA Ateca 2018-23">Buy Here</a></sub></details>|||
|
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Dodge Durango 2020-21">Buy Here</a></sub></details>|||
|
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 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?harness=Ford Bronco Sport 2021-24">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?harness=Ford Escape 2020-22">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 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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?harness=Ford Escape 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Escape 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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=Escape 2023-24">Buy Here</a></sub></details>||https://www.youtube.com/watch?v=uUGkH6C_EQU|
|
||||||
|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?harness=Ford Escape Hybrid 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 Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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?harness=Ford Escape Hybrid 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Escape Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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=Escape Hybrid 2023-24">Buy Here</a></sub></details>||https://www.youtube.com/watch?v=uUGkH6C_EQU|
|
||||||
|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?harness=Ford Escape Plug-in 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|Escape Plug-in Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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?harness=Ford Escape Plug-in Hybrid 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Escape Plug-in Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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=Escape Plug-in Hybrid 2023-24">Buy Here</a></sub></details>||https://www.youtube.com/watch?v=uUGkH6C_EQU|
|
||||||
|Ford|Expedition 2022-24|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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?harness=Ford Expedition 2022-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Expedition 2022-24|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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=Expedition 2022-24">Buy Here</a></sub></details>||https://www.youtube.com/watch?v=MewJc9LYp9M|
|
||||||
|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?harness=Ford Explorer 2020-24">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?harness=Ford Explorer Hybrid 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?harness=Ford F-150 2021-23">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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>||https://www.youtube.com/watch?v=MewJc9LYp9M|
|
||||||
|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?harness=Ford F-150 Hybrid 2021-23">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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>||https://www.youtube.com/watch?v=MewJc9LYp9M|
|
||||||
|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?harness=Ford Focus 2018">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?harness=Ford Focus Hybrid 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-23|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?harness=Ford Kuga 2020-23">Buy Here</a></sub></details>|||
|
|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 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-23">Buy Here</a></sub></details>|||
|
||||||
|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 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?harness=Ford Kuga Hybrid 2020-23">Buy Here</a></sub></details>|||
|
|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 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-23">Buy Here</a></sub></details>|||
|
||||||
|Ford|Kuga Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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?harness=Ford Kuga Hybrid 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Kuga Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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=Kuga Hybrid 2024">Buy Here</a></sub></details>||https://www.youtube.com/watch?v=uUGkH6C_EQU|
|
||||||
|Ford|Kuga Plug-in Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 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?harness=Ford Kuga Plug-in Hybrid 2020-23">Buy Here</a></sub></details>|||
|
|Ford|Kuga Plug-in Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|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-23">Buy Here</a></sub></details>|||
|
||||||
|Ford|Kuga Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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?harness=Ford Kuga Plug-in Hybrid 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Kuga Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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=Kuga Plug-in Hybrid 2024">Buy Here</a></sub></details>||https://www.youtube.com/watch?v=uUGkH6C_EQU|
|
||||||
|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?harness=Ford Maverick 2022">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?harness=Ford Maverick 2023-24">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?harness=Ford Maverick Hybrid 2022">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?harness=Ford Maverick Hybrid 2023-24">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-24|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?harness=Ford Mustang Mach-E 2021-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Mustang Mach-E 2021-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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-24">Buy Here</a></sub></details>||https://www.youtube.com/watch?v=uUGkH6C_EQU|
|
||||||
|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?harness=Ford Ranger 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 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>||https://www.youtube.com/watch?v=uUGkH6C_EQU|
|
||||||
|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?harness=Genesis G70 2018">Buy Here</a></sub></details>|||
|
|Genesis|G70 2018|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 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?harness=Genesis G70 2019-21">Buy Here</a></sub></details>|||
|
|Genesis|G70 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 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?harness=Genesis G70 2022-23">Buy Here</a></sub></details>|||
|
|Genesis|G70 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 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?harness=Genesis G80 2017">Buy Here</a></sub></details>|||
|
|Genesis|G80 2017|All|Stock|19 mph|37 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 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?harness=Genesis G80 2018-19">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>6</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?harness=Genesis G80 (2.5T Advanced Trim, with HDA II) 2024">Buy Here</a></sub></details>|||
|
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024[<sup>6</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?harness=Genesis G90 2017-20">Buy Here</a></sub></details>|||
|
|Genesis|G90 2017-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 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>6</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?harness=Genesis GV60 (Advanced Trim) 2023">Buy Here</a></sub></details>|||
|
|Genesis|GV60 (Advanced Trim) 2023[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<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>6</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?harness=Genesis GV60 (Performance Trim) 2022-23">Buy Here</a></sub></details>|||
|
|Genesis|GV60 (Performance Trim) 2022-23[<sup>6</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>6</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?harness=Genesis GV70 (2.5T Trim, without HDA II) 2022-24">Buy Here</a></sub></details>|||
|
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24[<sup>6</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>6</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?harness=Genesis GV70 (3.5T Trim, without HDA II) 2022-23">Buy Here</a></sub></details>|||
|
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23[<sup>6</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>6</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?harness=Genesis GV70 Electrified (Australia Only) 2022">Buy Here</a></sub></details>|||
|
|Genesis|GV70 Electrified (Australia Only) 2022[<sup>6</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>6</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?harness=Genesis GV70 Electrified (with HDA II) 2023-24">Buy Here</a></sub></details>|||
|
|Genesis|GV70 Electrified (with HDA II) 2023-24[<sup>6</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>6</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?harness=Genesis GV80 2023">Buy Here</a></sub></details>|||
|
|Genesis|GV80 2023[<sup>6</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?harness=GMC Sierra 1500 2020-21">Buy Here</a></sub></details>|<a href="https://youtu.be/5HbNoBLzRwE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|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 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?harness=Honda Accord 2018-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=mrUwlj3Mi58" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Honda|Accord 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?harness=Honda Accord Hybrid 2018-22">Buy Here</a></sub></details>|||
|
|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?harness=Honda Civic 2016-18">Buy Here</a></sub></details>|<a href="https://youtu.be/-IkImTe1NYE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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>5</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?harness=Honda Civic 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=4Iz1Mz5LGF8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Honda|Civic 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|2 mph[<sup>5</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?harness=Honda Civic 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Honda|Civic 2022-24|All|openpilot available[<sup>1</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?harness=Honda Civic Hatchback 2017-21">Buy Here</a></sub></details>|||
|
|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?harness=Honda Civic Hatchback 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Honda|Civic Hatchback 2022-24|All|openpilot available[<sup>1</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|Civic Hatchback Hybrid 2025|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?harness=Honda Civic Hatchback Hybrid 2025">Buy Here</a></sub></details>|||
|
|Honda|Civic Hatchback Hybrid 2025|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 Hybrid 2025">Buy Here</a></sub></details>|||
|
||||||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 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?harness=Honda Civic Hatchback Hybrid (Europe only) 2023">Buy Here</a></sub></details>|||
|
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[<sup>1</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 Hybrid (Europe only) 2023">Buy Here</a></sub></details>|||
|
||||||
|Honda|Civic Hybrid 2025|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?harness=Honda Civic Hybrid 2025">Buy Here</a></sub></details>|||
|
|Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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 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?harness=Honda CR-V 2015-16">Buy Here</a></sub></details>|||
|
|Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|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 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|15 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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?harness=Honda 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|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?harness=Honda 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|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?harness=Honda e 2020">Buy Here</a></sub></details>|||
|
|Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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|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?harness=Honda 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|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?harness=Honda Freed 2020">Buy Here</a></sub></details>|||
|
|Honda|HR-V 2019-22|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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 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?harness=Honda HR-V 2019-22">Buy Here</a></sub></details>|||
|
|Honda|HR-V 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 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-25">Buy Here</a></sub></details>|||
|
||||||
|Honda|HR-V 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 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?harness=Honda HR-V 2023-25">Buy Here</a></sub></details>|||
|
|Honda|Insight 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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|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?harness=Honda Insight 2019-22">Buy Here</a></sub></details>|||
|
|Honda|Inspire 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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|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?harness=Honda 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|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?harness=Honda 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|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?harness=Honda 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|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?harness=Honda 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>|||
|
||||||
|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?harness=Honda Ridgeline 2017-25">Buy Here</a></sub></details>|||
|
|Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 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 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?harness=Hyundai Azera 2022">Buy Here</a></sub></details>|||
|
|Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 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 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?harness=Hyundai 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|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?harness=Hyundai 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|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?harness=Hyundai 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 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?harness=Hyundai Elantra 2017-18">Buy Here</a></sub></details>|||
|
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 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 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?harness=Hyundai Elantra 2019">Buy Here</a></sub></details>|||
|
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 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 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?harness=Hyundai Elantra 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Hyundai|Elantra 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 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?harness=Hyundai Elantra GT 2017-20">Buy Here</a></sub></details>|||
|
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 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|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?harness=Hyundai Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Hyundai|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|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?harness=Hyundai Genesis 2015-16">Buy Here</a></sub></details>|||
|
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 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|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?harness=Hyundai i30 2017-19">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24[<sup>6</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 (Southeast Asia and Europe only) 2022-24[<sup>6</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?harness=Hyundai Ioniq 5 (Southeast Asia and Europe only) 2022-24">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq 5 (with HDA II) 2022-24[<sup>6</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 (with HDA II) 2022-24[<sup>6</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?harness=Hyundai Ioniq 5 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq 5 (without HDA II) 2022-24[<sup>6</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 5 (without HDA II) 2022-24[<sup>6</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?harness=Hyundai Ioniq 5 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq 6 (with HDA II) 2023-24[<sup>6</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 6 (with HDA II) 2023-24[<sup>6</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?harness=Hyundai 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 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?harness=Hyundai Ioniq Electric 2019">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 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 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?harness=Hyundai Ioniq Electric 2020">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 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 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?harness=Hyundai 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 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?harness=Hyundai 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 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?harness=Hyundai Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>|||
|
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 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|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?harness=Hyundai Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|||
|
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 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 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?harness=Hyundai Kona 2020">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 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?harness=Hyundai Kona Electric 2018-21">Buy Here</a></sub></details>|||
|
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 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 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?harness=Hyundai Kona Electric 2022-23">Buy Here</a></sub></details>|||
|
|Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<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 Electric (with HDA II, Korea only) 2023[<sup>6</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?harness=Hyundai Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Hyundai|Kona 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|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?harness=Hyundai 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|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?harness=Hyundai Nexo 2021">Buy Here</a></sub></details>|||
|
|Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 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|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?harness=Hyundai Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Hyundai|Santa Cruz 2022-24[<sup>6</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 Cruz 2022-24[<sup>6</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?harness=Hyundai 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 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?harness=Hyundai Santa Fe 2019-20">Buy Here</a></sub></details>|<a href="https://youtu.be/bjDR0YjM__s" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Hyundai|Santa Fe 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 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 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?harness=Hyundai Santa Fe 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 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 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?harness=Hyundai 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|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?harness=Hyundai Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>|||
|
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 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 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?harness=Hyundai Sonata 2018-19">Buy Here</a></sub></details>|||
|
|Hyundai|Sonata 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 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 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?harness=Hyundai Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Hyundai|Sonata 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|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?harness=Hyundai Sonata Hybrid 2020-23">Buy Here</a></sub></details>|||
|
|Hyundai|Staria 2023[<sup>6</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|Staria 2023[<sup>6</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?harness=Hyundai Staria 2023">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 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 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?harness=Hyundai Tucson 2021">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson 2022[<sup>6</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 2022[<sup>6</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?harness=Hyundai Tucson 2022">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson 2023-24[<sup>6</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 2023-24[<sup>6</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?harness=Hyundai 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 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?harness=Hyundai Tucson Diesel 2019">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson Hybrid 2022-24[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<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 Hybrid 2022-24[<sup>6</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?harness=Hyundai Tucson Hybrid 2022-24">Buy Here</a></sub></details>|||
|
|Hyundai|Tucson Plug-in Hybrid 2024[<sup>6</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|Tucson Plug-in Hybrid 2024[<sup>6</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?harness=Hyundai 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>|||
|
||||||
|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?harness=Hyundai Veloster 2019-20">Buy Here</a></sub></details>|||
|
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 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 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?harness=Jeep Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 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>||
|
||||||
|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?harness=Jeep Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Kia|Carnival 2022-24[<sup>6</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 2022-24[<sup>6</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?harness=Kia Carnival 2022-24">Buy Here</a></sub></details>|||
|
|Kia|Carnival (China only) 2023[<sup>6</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|Carnival (China only) 2023[<sup>6</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?harness=Kia 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|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?harness=Kia Ceed 2019-21">Buy Here</a></sub></details>|||
|
|Kia|EV6 (Southeast Asia only) 2022-24[<sup>6</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 (Southeast Asia only) 2022-24[<sup>6</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?harness=Kia EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>|||
|
|Kia|EV6 (with HDA II) 2022-24[<sup>6</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 (with HDA II) 2022-24[<sup>6</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?harness=Kia EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|
|Kia|EV6 (without HDA II) 2022-24[<sup>6</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|EV6 (without HDA II) 2022-24[<sup>6</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?harness=Kia 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 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?harness=Kia Forte 2019-21">Buy Here</a></sub></details>|||
|
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 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|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?harness=Kia 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 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?harness=Kia 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|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?harness=Kia K5 Hybrid 2020-22">Buy Here</a></sub></details>|||
|
|Kia|K8 Hybrid (with HDA II) 2023[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<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|K8 Hybrid (with HDA II) 2023[<sup>6</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?harness=Kia K8 Hybrid (with HDA II) 2023">Buy Here</a></sub></details>|||
|
|Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 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 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?harness=Kia Niro EV 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Kia|Niro EV 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 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?harness=Kia 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 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?harness=Kia 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 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?harness=Kia 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 (with HDA II) 2025[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 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 (with HDA II) 2025">Buy Here</a></sub></details>|||
|
||||||
|Kia|Niro EV (with HDA II) 2025[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 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?harness=Kia Niro EV (with HDA II) 2025">Buy Here</a></sub></details>|||
|
|Kia|Niro EV (without HDA II) 2023-25[<sup>6</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 (without HDA II) 2023-25">Buy Here</a></sub></details>|||
|
||||||
|Kia|Niro EV (without HDA II) 2023-25[<sup>6</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?harness=Kia Niro EV (without HDA II) 2023-25">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 2018|Smart Cruise Control (SCC)|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?harness=Kia 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 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?harness=Kia 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 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?harness=Kia Niro Hybrid 2022">Buy Here</a></sub></details>|||
|
|Kia|Niro Hybrid 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<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 Hybrid 2023[<sup>6</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?harness=Kia 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 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?harness=Kia 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 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?harness=Kia 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 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?harness=Kia 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|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?harness=Kia 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 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?harness=Kia 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 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?harness=Kia 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|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?harness=Kia 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|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?harness=Kia 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 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?harness=Kia Sorento 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 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 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?harness=Kia Sorento 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Kia|Sorento 2021-23[<sup>6</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 2021-23[<sup>6</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?harness=Kia Sorento 2021-23">Buy Here</a></sub></details>|||
|
|Kia|Sorento Hybrid 2021-23[<sup>6</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 Hybrid 2021-23[<sup>6</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?harness=Kia Sorento Hybrid 2021-23">Buy Here</a></sub></details>|||
|
|Kia|Sorento Plug-in Hybrid 2022-23[<sup>6</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|Sorento Plug-in Hybrid 2022-23[<sup>6</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?harness=Kia Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>|||
|
|Kia|Sportage 2023-24[<sup>6</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 2023-24[<sup>6</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?harness=Kia Sportage 2023-24">Buy Here</a></sub></details>|||
|
|Kia|Sportage Hybrid 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<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|Sportage Hybrid 2023[<sup>6</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?harness=Kia 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 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?harness=Kia Stinger 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Kia|Stinger 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 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|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?harness=Kia Stinger 2022-23">Buy Here</a></sub></details>|||
|
|Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 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>|||
|
||||||
|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?harness=Kia 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|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?harness=Lexus 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 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?harness=Lexus ES 2017-18">Buy Here</a></sub></details>|||
|
|Lexus|ES 2019-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 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-25">Buy Here</a></sub></details>|||
|
||||||
|Lexus|ES 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?harness=Lexus ES 2019-25">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 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?harness=Lexus 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|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?harness=Lexus 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|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?harness=Lexus 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 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?harness=Lexus IS 2017-19">Buy Here</a></sub></details>|||
|
|Lexus|IS 2022-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=IS 2022-24">Buy Here</a></sub></details>|||
|
||||||
|Lexus|IS 2022-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?harness=Lexus IS 2022-24">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|LC 2024-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?harness=Lexus LC 2024-25">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 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?harness=Lexus 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 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?harness=Lexus 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 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?harness=Lexus 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|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?harness=Lexus 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|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?harness=Lexus RC 2018-20">Buy Here</a></sub></details>|||
|
|Lexus|RC 2023|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=RC 2023">Buy Here</a></sub></details>|||
|
||||||
|Lexus|RC 2023|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?harness=Lexus RC 2023">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 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?harness=Lexus 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 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?harness=Lexus 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 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?harness=Lexus 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 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?harness=Lexus 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 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?harness=Lexus RX Hybrid 2017-19">Buy Here</a></sub></details>|||
|
|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 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|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?harness=Lexus RX Hybrid 2020-22">Buy Here</a></sub></details>|||
|
|Lexus|UX Hybrid 2019-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 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>|||
|
||||||
|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?harness=Lexus UX Hybrid 2019-24">Buy Here</a></sub></details>|||
|
|Lincoln|Aviator 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 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 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?harness=Lincoln Aviator 2020-24">Buy Here</a></sub></details>|||
|
|Lincoln|Aviator Plug-in Hybrid 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 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>|||
|
||||||
|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?harness=Lincoln Aviator Plug-in Hybrid 2020-24">Buy Here</a></sub></details>|||
|
|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=MAN eTGE 2020-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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>||
|
||||||
|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=MAN TGE 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Mazda|CX-5 2022-25|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 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-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?harness=Mazda CX-5 2022-25">Buy Here</a></sub></details>|||
|
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 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>||
|
||||||
|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?harness=Mazda CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Nissan[<sup>7</sup>](#footnotes)|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[<sup>7</sup>](#footnotes)|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?harness=Nissan Altima 2019-20">Buy Here</a></sub></details>|||
|
|Nissan[<sup>7</sup>](#footnotes)|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[<sup>7</sup>](#footnotes)|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?harness=Nissan Leaf 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Nissan[<sup>7</sup>](#footnotes)|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[<sup>7</sup>](#footnotes)|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?harness=Nissan Rogue 2018-20">Buy Here</a></sub></details>|||
|
|Nissan[<sup>7</sup>](#footnotes)|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>|||
|
||||||
|Nissan[<sup>7</sup>](#footnotes)|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?harness=Nissan 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>|||
|
||||||
|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?harness=Ram 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>||https://youtu.be/uaISd1j7Z4U|
|
||||||
|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?harness=Rivian R1S 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|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>||https://youtu.be/uaISd1j7Z4U|
|
||||||
|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?harness=Rivian R1T 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=SEAT Ateca 2016-23">Buy Here</a></sub></details>|||
|
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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>|||
|
||||||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=SEAT Leon 2014-20">Buy Here</a></sub></details>|||
|
|Subaru|Ascent 2019-21|All[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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|Ascent 2019-21|All[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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?harness=Subaru Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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?harness=Subaru Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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?harness=Subaru Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Subaru|Forester 2019-21|All[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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|Forester 2019-21|All[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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?harness=Subaru Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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 2017-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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?harness=Subaru Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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|Impreza 2020-22|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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?harness=Subaru Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Subaru|Legacy 2020-22|All[<sup>8</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|Legacy 2020-22|All[<sup>8</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?harness=Subaru Legacy 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Subaru|Outback 2020-22|All[<sup>8</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|Outback 2020-22|All[<sup>8</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?harness=Subaru Outback 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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?harness=Subaru XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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>|||
|
||||||
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</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?harness=Subaru XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Škoda|Fabia 2022-23[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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>17</sup>](#footnotes)|||
|
||||||
|Škoda|Fabia 2022-23[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Škoda Fabia 2022-23">Buy Here</a></sub></details>[<sup>17</sup>](#footnotes)|||
|
|Škoda|Kamiq 2021-23[<sup>13,15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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>17</sup>](#footnotes)|||
|
||||||
|Škoda|Kamiq 2021-23[<sup>13,15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Škoda Kamiq 2021-23">Buy Here</a></sub></details>[<sup>17</sup>](#footnotes)|||
|
|Škoda|Karoq 2019-23[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Karoq 2019-23[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Škoda Karoq 2019-23">Buy Here</a></sub></details>|||
|
|Škoda|Kodiaq 2017-23[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Kodiaq 2017-23[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Škoda Kodiaq 2017-23">Buy Here</a></sub></details>|||
|
|Škoda|Octavia 2015-19[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 2015-19[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Škoda Octavia 2015-19">Buy Here</a></sub></details>|||
|
|Škoda|Octavia RS 2016[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 RS 2016[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Škoda Octavia RS 2016">Buy Here</a></sub></details>|||
|
|Škoda|Octavia Scout 2017-19[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Octavia Scout 2017-19[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Škoda Octavia Scout 2017-19">Buy Here</a></sub></details>|||
|
|Škoda|Scala 2020-23[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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>17</sup>](#footnotes)|||
|
||||||
|Škoda|Scala 2020-23[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Škoda Scala 2020-23">Buy Here</a></sub></details>[<sup>17</sup>](#footnotes)|||
|
|Škoda|Superb 2015-22[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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>|||
|
||||||
|Škoda|Superb 2015-22[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Škoda Superb 2015-22">Buy Here</a></sub></details>|||
|
|Tesla[<sup>11</sup>](#footnotes)|Model 3 (with HW3) 2019-23[<sup>10</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[<sup>11</sup>](#footnotes)|Model 3 (with HW3) 2019-23[<sup>10</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?harness=Tesla Model 3 (with HW3) 2019-23">Buy Here</a></sub></details>|||
|
|Tesla[<sup>11</sup>](#footnotes)|Model 3 (with HW4) 2024-25[<sup>10</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[<sup>11</sup>](#footnotes)|Model 3 (with HW4) 2024-25[<sup>10</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?harness=Tesla Model 3 (with HW4) 2024-25">Buy Here</a></sub></details>|||
|
|Tesla[<sup>11</sup>](#footnotes)|Model Y (with HW3) 2020-23[<sup>10</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[<sup>11</sup>](#footnotes)|Model Y (with HW3) 2020-23[<sup>10</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?harness=Tesla Model Y (with HW3) 2020-23">Buy Here</a></sub></details>|||
|
|Tesla[<sup>11</sup>](#footnotes)|Model Y (with HW4) 2024[<sup>10</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>|||
|
||||||
|Tesla[<sup>11</sup>](#footnotes)|Model Y (with HW4) 2024[<sup>10</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?harness=Tesla 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 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?harness=Toyota Alphard 2019-20">Buy Here</a></sub></details>|||
|
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 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|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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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|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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota C-HR 2021">Buy Here</a></sub></details>|||
|
|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 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 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?harness=Toyota C-HR Hybrid 2017-20">Buy Here</a></sub></details>|||
|
|Toyota|C-HR Hybrid 2021-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 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|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?harness=Toyota C-HR Hybrid 2021-22">Buy Here</a></sub></details>|||
|
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>12</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 2018-20|All|Stock|0 mph[<sup>12</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?harness=Toyota Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>12</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 2021-24|All|openpilot|0 mph[<sup>12</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?harness=Toyota Camry 2021-24">Buy Here</a></sub></details>|||
|
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 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 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?harness=Toyota Camry Hybrid 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 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|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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 (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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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|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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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|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?harness=Toyota 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|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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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|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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota 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 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?harness=Toyota RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Toyota|RAV4 Hybrid 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 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|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?harness=Toyota RAV4 Hybrid 2023-25">Buy Here</a></sub></details>|<a href="https://youtu.be/4eIsEq4L4Ng" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Toyota|Sienna 2018-20|All|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>||
|
||||||
|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?harness=Toyota Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Arteon Shooting Brake 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Atlas 2018-23">Buy Here</a></sub></details>|||
|
|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Atlas Cross Sport 2020-22">Buy Here</a></sub></details>|||
|
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen California 2021-23">Buy Here</a></sub></details>|||
|
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Caravelle 2020">Buy Here</a></sub></details>|||
|
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Crafter 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|e-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen e-Crafter 2018-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen e-Golf 2014-20">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Golf 2015-20">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Golf Alltrack 2015-19">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Golf GTD 2015-20">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Golf GTE 2015-20">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Golf GTI 2015-21">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Golf R 2015-19">Buy Here</a></sub></details>|||
|
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Golf SportsVan 2015-20">Buy Here</a></sub></details>|||
|
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Grand California 2019-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
|Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Jetta 2018-23">Buy Here</a></sub></details>|||
|
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Jetta GLI 2021-23">Buy Here</a></sub></details>|||
|
|Volkswagen|Passat 2015-22[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 2015-22[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Passat 2015-22">Buy Here</a></sub></details>|||
|
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Passat Alltrack 2015-22">Buy Here</a></sub></details>|||
|
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Passat GTE 2015-22">Buy Here</a></sub></details>|||
|
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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>17</sup>](#footnotes)|||
|
||||||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Polo 2018-23">Buy Here</a></sub></details>[<sup>17</sup>](#footnotes)|||
|
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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>17</sup>](#footnotes)|||
|
||||||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>17</sup>](#footnotes)|||
|
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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>17</sup>](#footnotes)|||
|
||||||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen T-Cross 2021">Buy Here</a></sub></details>[<sup>17</sup>](#footnotes)|||
|
|Volkswagen|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen T-Roc 2018-23">Buy Here</a></sub></details>|||
|
|Volkswagen|Taos 2022-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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-24">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Taos 2022-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Taos 2022-24">Buy Here</a></sub></details>|||
|
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Teramont 2018-22">Buy Here</a></sub></details>|||
|
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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 Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Teramont Cross Sport 2021-22">Buy Here</a></sub></details>|||
|
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Teramont X 2021-22">Buy Here</a></sub></details>|||
|
|Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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-24">Buy Here</a></sub></details>|||
|
||||||
|Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Tiguan 2018-24">Buy Here</a></sub></details>|||
|
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Tiguan eHybrid 2021-23">Buy Here</a></sub></details>|||
|
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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>|||
|
||||||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</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?harness=Volkswagen Touran 2016-23">Buy Here</a></sub></details>|||
|
|
||||||
|
|
||||||
### Footnotes
|
### Footnotes
|
||||||
<sup>1</sup>openpilot Longitudinal Control (Alpha) is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `nightly-dev`. <br />
|
<sup>1</sup>openpilot Longitudinal Control (Alpha) is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `nightly-dev`. <br />
|
||||||
|
|||||||
+1
-1
Submodule opendbc_repo updated: 2975ddffbc...c87940a6b5
+1
-1
Submodule panda updated: e46680ff6f...c33cfa0803
+13
-5
@@ -26,7 +26,7 @@ dependencies = [
|
|||||||
"pycapnp",
|
"pycapnp",
|
||||||
"Cython",
|
"Cython",
|
||||||
"setuptools",
|
"setuptools",
|
||||||
"numpy >=2.0",
|
"numpy >=2.0, <2.2", # Linting issues with mypy in 2.2
|
||||||
|
|
||||||
# body / webrtcd
|
# body / webrtcd
|
||||||
"aiohttp",
|
"aiohttp",
|
||||||
@@ -42,6 +42,7 @@ dependencies = [
|
|||||||
|
|
||||||
# modeld
|
# modeld
|
||||||
"onnx >= 1.14.0",
|
"onnx >= 1.14.0",
|
||||||
|
"llvmlite",
|
||||||
|
|
||||||
# logging
|
# logging
|
||||||
"pyzmq",
|
"pyzmq",
|
||||||
@@ -80,13 +81,15 @@ docs = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
testing = [
|
testing = [
|
||||||
|
"coverage",
|
||||||
"hypothesis ==6.47.*",
|
"hypothesis ==6.47.*",
|
||||||
"mypy",
|
"mypy",
|
||||||
"pytest",
|
"pytest",
|
||||||
|
"pytest-cov",
|
||||||
"pytest-cpp",
|
"pytest-cpp",
|
||||||
"pytest-subtests",
|
"pytest-subtests",
|
||||||
# https://github.com/pytest-dev/pytest-xdist/pull/1229
|
# https://github.com/pytest-dev/pytest-xdist/issues/1215
|
||||||
"pytest-xdist @ git+https://github.com/sshane/pytest-xdist@2b4372bd62699fb412c4fe2f95bf9f01bd2018da",
|
"pytest-xdist @ git+https://github.com/sshane/pytest-xdist@909e97b49d12401c10608f9d777bfc9dab8a4413",
|
||||||
"pytest-timeout",
|
"pytest-timeout",
|
||||||
"pytest-randomly",
|
"pytest-randomly",
|
||||||
"pytest-asyncio",
|
"pytest-asyncio",
|
||||||
@@ -120,7 +123,7 @@ dev = [
|
|||||||
|
|
||||||
tools = [
|
tools = [
|
||||||
"metadrive-simulator @ https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl ; (platform_machine != 'aarch64')",
|
"metadrive-simulator @ https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl ; (platform_machine != 'aarch64')",
|
||||||
#"rerun-sdk >= 0.18", # this is pretty big, so only enable once we use it
|
"rerun-sdk >= 0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
@@ -177,6 +180,9 @@ skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, .
|
|||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
python_version = "3.11"
|
python_version = "3.11"
|
||||||
|
plugins = [
|
||||||
|
"numpy.typing.mypy_plugin",
|
||||||
|
]
|
||||||
exclude = [
|
exclude = [
|
||||||
"cereal/",
|
"cereal/",
|
||||||
"msgq/",
|
"msgq/",
|
||||||
@@ -259,7 +265,9 @@ lint.flake8-implicit-str-concat.allow-multiline = false
|
|||||||
"pytest.main".msg = "pytest.main requires special handling that is easy to mess up!"
|
"pytest.main".msg = "pytest.main requires special handling that is easy to mess up!"
|
||||||
"unittest".msg = "Use pytest"
|
"unittest".msg = "Use pytest"
|
||||||
"pyray.measure_text_ex".msg = "Use openpilot.system.ui.lib.text_measure"
|
"pyray.measure_text_ex".msg = "Use openpilot.system.ui.lib.text_measure"
|
||||||
"time.time".msg = "Use time.monotonic"
|
|
||||||
|
[tool.coverage.run]
|
||||||
|
concurrency = ["multiprocessing", "thread"]
|
||||||
|
|
||||||
[tool.ruff.format]
|
[tool.ruff.format]
|
||||||
quote-style = "preserve"
|
quote-style = "preserve"
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ git clean -xdff
|
|||||||
git lfs uninstall
|
git lfs uninstall
|
||||||
|
|
||||||
# remove everything except .git
|
# remove everything except .git
|
||||||
echo "[-] erasing old sunnypilot T=$SECONDS"
|
echo "[-] erasing old openpilot T=$SECONDS"
|
||||||
find . -maxdepth 1 -not -path './.git' -not -name '.' -not -name '..' -exec rm -rf '{}' \;
|
find . -maxdepth 1 -not -path './.git' -not -name '.' -not -name '..' -exec rm -rf '{}' \;
|
||||||
|
|
||||||
# reset source tree
|
# reset source tree
|
||||||
@@ -61,7 +61,7 @@ echo -n "$GIT_COMMIT_DATE" > git_src_commit_date
|
|||||||
echo "[-] committing version $VERSION T=$SECONDS"
|
echo "[-] committing version $VERSION T=$SECONDS"
|
||||||
git add -f .
|
git add -f .
|
||||||
git status
|
git status
|
||||||
git commit -a -m "sunnypilot v$VERSION release
|
git commit -a -m "openpilot v$VERSION release
|
||||||
|
|
||||||
date: $DATETIME
|
date: $DATETIME
|
||||||
master commit: $GIT_HASH
|
master commit: $GIT_HASH
|
||||||
|
|||||||
@@ -1,43 +1,17 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
has_submodule_changes() {
|
|
||||||
local submodule_path="$1"
|
|
||||||
if [ -n "$SUBMODULE_PATHS" ]; then
|
|
||||||
echo "$SUBMODULE_PATHS" | grep -q "$submodule_path"
|
|
||||||
return $?
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
while read hash submodule ref; do
|
while read hash submodule ref; do
|
||||||
if [ -z "$hash" ] || [ -z "$submodule" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
hash=$(echo "$hash" | sed 's/^[+-]//')
|
|
||||||
|
|
||||||
if [ "$submodule" = "tinygrad_repo" ]; then
|
if [ "$submodule" = "tinygrad_repo" ]; then
|
||||||
echo "Skipping $submodule"
|
echo "Skipping $submodule"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$CHECK_PR_REFS" = "true" ] && has_submodule_changes "$submodule"; then
|
git -C $submodule fetch --depth 100 origin master
|
||||||
echo "Checking $submodule (non-master): verifying hash $hash exists"
|
git -C $submodule branch -r --contains $hash | grep "origin/master"
|
||||||
git -C $submodule fetch --depth 100 origin
|
if [ "$?" -eq 0 ]; then
|
||||||
if git -C $submodule cat-file -e $hash 2>/dev/null; then
|
echo "$submodule ok"
|
||||||
echo "$submodule ok (hash exists)"
|
|
||||||
else
|
|
||||||
echo "$submodule: $hash does not exist in the repository"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
git -C $submodule fetch --depth 100 origin master
|
echo "$submodule: $hash is not on master"
|
||||||
git -C $submodule branch -r --contains $hash | grep "origin/master"
|
exit 1
|
||||||
if [ "$?" -eq 0 ]; then
|
|
||||||
echo "$submodule ok"
|
|
||||||
else
|
|
||||||
echo "$submodule: $hash is not on master"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done <<< $(git submodule status --recursive)
|
done <<< $(git submodule status --recursive)
|
||||||
|
|||||||
Executable → Regular
+46
-21
@@ -1,26 +1,51 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
set -e
|
# run_openpilot_docker.sh
|
||||||
|
# POSIX-compliant script to run openpilot in Docker for local testing
|
||||||
|
|
||||||
# To build sim and docs, you can run the following to mount the scons cache to the same place as in CI:
|
# === Configurable Variables ===
|
||||||
# mkdir -p .ci_cache/scons_cache
|
|
||||||
# sudo mount --bind /tmp/scons_cache/ .ci_cache/scons_cache
|
|
||||||
|
|
||||||
SCRIPT_DIR=$(dirname "$0")
|
# Base image to use (required)
|
||||||
OPENPILOT_DIR=$SCRIPT_DIR/../../
|
BASE_IMAGE="${BASE_IMAGE:-commaai/openpilot-base:latest}"
|
||||||
if [ -n "$TARGET_ARCHITECTURE" ]; then
|
|
||||||
PLATFORM="linux/$TARGET_ARCHITECTURE"
|
|
||||||
TAG_SUFFIX="-$TARGET_ARCHITECTURE"
|
|
||||||
else
|
|
||||||
PLATFORM="linux/$(uname -m)"
|
|
||||||
TAG_SUFFIX=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
source $SCRIPT_DIR/docker_common_sp.sh $1 "$TAG_SUFFIX"
|
# Working directory inside the container
|
||||||
|
WORKDIR="/tmp/openpilot"
|
||||||
|
|
||||||
DOCKER_BUILDKIT=1 docker buildx build --provenance false --pull --platform $PLATFORM --load --cache-to type=inline --cache-from type=registry,ref=$REMOTE_TAG -t $DOCKER_IMAGE:latest -t $REMOTE_TAG -t $LOCAL_TAG -f $OPENPILOT_DIR/$DOCKER_FILE $OPENPILOT_DIR
|
# Local project path
|
||||||
|
LOCAL_DIR="$PWD"
|
||||||
|
|
||||||
if [ -n "$PUSH_IMAGE" ]; then
|
# Shared memory size (adjust for large builds/tests)
|
||||||
docker push $REMOTE_TAG
|
SHM_SIZE="2G"
|
||||||
docker tag $REMOTE_TAG $REMOTE_SHA_TAG
|
|
||||||
docker push $REMOTE_SHA_TAG
|
# Environment configuration
|
||||||
fi
|
CI=1
|
||||||
|
PYTHONWARNINGS="error"
|
||||||
|
FILEREADER_CACHE=1
|
||||||
|
PYTHONPATH="$WORKDIR"
|
||||||
|
|
||||||
|
# Optional: GitHub Actions env vars — set them only if needed for local mirroring/debug
|
||||||
|
USE_GITHUB_ENV_VARS=false # set to true to enable GitHub-related mounts/envs
|
||||||
|
GITHUB_WORKSPACE="${GITHUB_WORKSPACE:-$HOME/openpilot_ci}" # fallback path
|
||||||
|
|
||||||
|
# === Docker Command ===
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
--shm-size "$SHM_SIZE" \
|
||||||
|
-v "$LOCAL_DIR":"$WORKDIR" \
|
||||||
|
-w "$WORKDIR" \
|
||||||
|
-e CI="$CI" \
|
||||||
|
-e PYTHONWARNINGS="$PYTHONWARNINGS" \
|
||||||
|
-e FILEREADER_CACHE="$FILEREADER_CACHE" \
|
||||||
|
-e PYTHONPATH="$PYTHONPATH" \
|
||||||
|
${USE_GITHUB_ENV_VARS:+\
|
||||||
|
-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 "${1:-/bin/bash}"
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
if [ "$1" = "base" ]; then
|
|
||||||
export DOCKER_IMAGE=sunnypilot-base
|
|
||||||
export DOCKER_FILE=Dockerfile.sunnypilot_base
|
|
||||||
elif [ "$1" = "prebuilt" ]; then
|
|
||||||
export DOCKER_IMAGE=sunnypilot-prebuilt
|
|
||||||
export DOCKER_FILE=Dockerfile.sunnypilot
|
|
||||||
else
|
|
||||||
echo "Invalid docker build image: '$1'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
export DOCKER_REGISTRY=ghcr.io/sunnypilot
|
|
||||||
export COMMIT_SHA=$(git rev-parse HEAD)
|
|
||||||
|
|
||||||
TAG_SUFFIX=$2
|
|
||||||
LOCAL_TAG=$DOCKER_IMAGE$TAG_SUFFIX
|
|
||||||
REMOTE_TAG=$DOCKER_REGISTRY/$LOCAL_TAG
|
|
||||||
REMOTE_SHA_TAG=$DOCKER_REGISTRY/$LOCAL_TAG:$COMMIT_SHA
|
|
||||||
@@ -13,32 +13,17 @@ def create_short_name(full_name):
|
|||||||
words = [re.sub(r'[^a-zA-Z0-9]', '', word) for word in clean_name.split() if re.sub(r'[^a-zA-Z0-9]', '', word)]
|
words = [re.sub(r'[^a-zA-Z0-9]', '', word) for word in clean_name.split() if re.sub(r'[^a-zA-Z0-9]', '', word)]
|
||||||
|
|
||||||
if len(words) == 1:
|
if len(words) == 1:
|
||||||
return words[0][:8].upper()
|
# If there's only one word, return it as is, lowercased, truncated to 8 characters
|
||||||
|
truncated = words[0][:8]
|
||||||
|
return truncated.lower() if truncated.isupper() else truncated
|
||||||
|
|
||||||
# Handle special case: Name + Version (e.g., "Word A1" -> "WordA1")
|
# Handle special case: Name + Version (e.g., "Word A1" -> "WordA1")
|
||||||
if len(words) == 2 and re.match(r'^[A-Za-z]\d+$', words[1]):
|
if len(words) == 2 and re.match(r'^[A-Za-z]\d+$', words[1]):
|
||||||
return (words[0] + words[1])[:8].upper()
|
first_word = words[0].lower() if words[0].isupper() else words[0]
|
||||||
|
return (first_word + words[1])[:8]
|
||||||
|
|
||||||
result = ""
|
# Normal case: first letter and trailing numbers from each word
|
||||||
for word in words:
|
result = ''.join(word if word.isdigit() else word[0] + (re.search(r'\d+$', word) or [''])[0] for word in words)
|
||||||
# Version or number patterns
|
|
||||||
if (re.match(r'^\d+[a-zA-Z]+$', word) or
|
|
||||||
re.match(r'^\d+[vVbB]\d+$', word) or
|
|
||||||
re.match(r'^[vVbB]\d+$', word) or
|
|
||||||
re.match(r'^\d{4}$', word)):
|
|
||||||
result += word.upper()
|
|
||||||
# All uppercase abbreviations (2-3 letters)
|
|
||||||
elif re.match(r'^[A-Z]{2,3}$', word):
|
|
||||||
result += word
|
|
||||||
# Letters+digits (for example tr15 rev2)
|
|
||||||
elif re.match(r'^[a-zA-Z]+[0-9]+$', word):
|
|
||||||
result += word[0].upper() + ''.join(re.findall(r'\d+', word))
|
|
||||||
elif word.isalpha():
|
|
||||||
result += word[0].upper()
|
|
||||||
elif word.isdigit():
|
|
||||||
result += word
|
|
||||||
else:
|
|
||||||
result += word[0].upper()
|
|
||||||
return result[:8]
|
return result[:8]
|
||||||
|
|
||||||
|
|
||||||
@@ -73,14 +58,14 @@ def generate_metadata(model_path: Path, output_dir: Path, short_name: str):
|
|||||||
"artifact": {
|
"artifact": {
|
||||||
"file_name": tinygrad_file.name,
|
"file_name": tinygrad_file.name,
|
||||||
"download_uri": {
|
"download_uri": {
|
||||||
"url": "https://gitlab.com/sunnypilot/public/docs.sunnypilot.ai/-/raw/main/",
|
"url": "https://gitlab.com/sunnypilot/public/docs.sunnypilot.ai/-/raw/main/<FILLME>",
|
||||||
"sha256": tinygrad_hash
|
"sha256": tinygrad_hash
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"file_name": metadata_file.name,
|
"file_name": metadata_file.name,
|
||||||
"download_uri": {
|
"download_uri": {
|
||||||
"url": "https://gitlab.com/sunnypilot/public/docs.sunnypilot.ai/-/raw/main/",
|
"url": "https://gitlab.com/sunnypilot/public/docs.sunnypilot.ai/-/raw/main/<FILLME>",
|
||||||
"sha256": metadata_hash
|
"sha256": metadata_hash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,12 +83,12 @@ def create_metadata_json(models: list, output_dir: Path, custom_name=None, short
|
|||||||
"ref": upstream_branch,
|
"ref": upstream_branch,
|
||||||
"environment": "development",
|
"environment": "development",
|
||||||
"runner": "tinygrad",
|
"runner": "tinygrad",
|
||||||
|
"build_time": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||||
|
"models": models,
|
||||||
|
"overrides": {},
|
||||||
"index": -1,
|
"index": -1,
|
||||||
"minimum_selector_version": "-1",
|
"minimum_selector_version": "-1",
|
||||||
"generation": "-1",
|
"generation": "-1",
|
||||||
"build_time": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
||||||
"overrides": {},
|
|
||||||
"models": models,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Write metadata to output_dir
|
# Write metadata to output_dir
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ TRUST_FORK_LABEL = "trust-fork-pr"
|
|||||||
def setup_argument_parser():
|
def setup_argument_parser():
|
||||||
parser = argparse.ArgumentParser(description='Process and squash GitHub PRs')
|
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('--pr-data', type=str, help='PR data in JSON format')
|
||||||
parser.add_argument('--source-branch', type=str, default='master',
|
parser.add_argument('--source-branch', type=str, default='master-new',
|
||||||
help='Source branch for merging')
|
help='Source branch for merging')
|
||||||
parser.add_argument('--target-branch', type=str, default='master-dev-c3-new-test',
|
parser.add_argument('--target-branch', type=str, default='master-dev-c3-new-test',
|
||||||
help='Target branch for merging')
|
help='Target branch for merging')
|
||||||
|
|||||||
+4
-4
@@ -1,4 +1,4 @@
|
|||||||
export GIT_COMMITTER_NAME="github-actions[bot]"
|
export GIT_COMMITTER_NAME="Vehicle Researcher"
|
||||||
export GIT_COMMITTER_EMAIL="github-actions[bot]@users.noreply.github.com"
|
export GIT_COMMITTER_EMAIL="user@comma.ai"
|
||||||
export GIT_AUTHOR_NAME="github-actions[bot]"
|
export GIT_AUTHOR_NAME="Vehicle Researcher"
|
||||||
export GIT_AUTHOR_EMAIL="github-actions[bot]@users.noreply.github.com"
|
export GIT_AUTHOR_EMAIL="user@comma.ai"
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ blacklist = [
|
|||||||
".gitattributes",
|
".gitattributes",
|
||||||
".git$",
|
".git$",
|
||||||
".gitmodules",
|
".gitmodules",
|
||||||
".run/",
|
|
||||||
".idea/",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# gets you through the blacklist
|
# gets you through the blacklist
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:9fc1f7f31d41f26ea7d6f52b3096f7a91844a3b897bc233a8489253c46f0403b
|
|
||||||
size 6324
|
|
||||||
@@ -78,8 +78,7 @@ class CarSpecificEvents:
|
|||||||
events.add(EventName.manualRestart)
|
events.add(EventName.manualRestart)
|
||||||
|
|
||||||
elif self.CP.brand == 'toyota':
|
elif self.CP.brand == 'toyota':
|
||||||
# TODO: when we check for unexpected disengagement, check gear not S1, S2, S3
|
events = self.create_common_events(CS, CS_prev)
|
||||||
events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.sport])
|
|
||||||
|
|
||||||
if self.CP.openpilotLongitudinalControl:
|
if self.CP.openpilotLongitudinalControl:
|
||||||
if CS.cruiseState.standstill and not CS.brakePressed:
|
if CS.cruiseState.standstill and not CS.brakePressed:
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ class Car:
|
|||||||
with car.CarParams.from_bytes(cached_params_raw) as _cached_params:
|
with car.CarParams.from_bytes(cached_params_raw) as _cached_params:
|
||||||
cached_params = _cached_params
|
cached_params = _cached_params
|
||||||
|
|
||||||
fixed_fingerprint = json.loads(self.params.get("CarPlatformBundle") or "{}").get("platform", None)
|
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), alpha_long_allowed, is_release, num_pandas, cached_params, fixed_fingerprint)
|
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), alpha_long_allowed, is_release, num_pandas, cached_params, fixed_fingerprint)
|
||||||
sunnypilot_interfaces.setup_interfaces(self.CI, self.params)
|
sunnypilot_interfaces.setup_interfaces(self.CI, self.params)
|
||||||
@@ -147,7 +147,7 @@ class Car:
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
secoc_key = self.params.get("SecOCKey")
|
secoc_key = self.params.get("SecOCKey", encoding='utf8')
|
||||||
if secoc_key is not None:
|
if secoc_key is not None:
|
||||||
saved_secoc_key = bytes.fromhex(secoc_key.strip())
|
saved_secoc_key = bytes.fromhex(secoc_key.strip())
|
||||||
if len(saved_secoc_key) == 16:
|
if len(saved_secoc_key) == 16:
|
||||||
|
|||||||
@@ -58,7 +58,5 @@ def convert_carControlSP(struct: capnp.lib.capnp._DynamicStructReader) -> struct
|
|||||||
|
|
||||||
struct_dataclass.mads = structs.ModularAssistiveDrivingSystem(**remove_deprecated(struct_dict.get('mads', {})))
|
struct_dataclass.mads = structs.ModularAssistiveDrivingSystem(**remove_deprecated(struct_dict.get('mads', {})))
|
||||||
struct_dataclass.params = [structs.CarControlSP.Param(**remove_deprecated(p)) for p in struct_dict.get('params', [])]
|
struct_dataclass.params = [structs.CarControlSP.Param(**remove_deprecated(p)) for p in struct_dict.get('params', [])]
|
||||||
struct_dataclass.leadOne = structs.LeadData(**remove_deprecated(struct_dict.get('leadOne', {})))
|
|
||||||
struct_dataclass.leadTwo = structs.LeadData(**remove_deprecated(struct_dict.get('leadTwo', {})))
|
|
||||||
|
|
||||||
return struct_dataclass
|
return struct_dataclass
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import pytest
|
|||||||
import random
|
import random
|
||||||
import unittest # noqa: TID251
|
import unittest # noqa: TID251
|
||||||
from collections import defaultdict, Counter
|
from collections import defaultdict, Counter
|
||||||
|
from functools import partial
|
||||||
import hypothesis.strategies as st
|
import hypothesis.strategies as st
|
||||||
from hypothesis import Phase, given, settings
|
from hypothesis import Phase, given, settings
|
||||||
from parameterized import parameterized_class
|
from parameterized import parameterized_class
|
||||||
@@ -22,7 +23,8 @@ from openpilot.common.basedir import BASEDIR
|
|||||||
from openpilot.selfdrive.pandad import can_capnp_to_list
|
from openpilot.selfdrive.pandad import can_capnp_to_list
|
||||||
from openpilot.selfdrive.test.helpers import read_segment_list
|
from openpilot.selfdrive.test.helpers import read_segment_list
|
||||||
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||||
from openpilot.tools.lib.logreader import LogReader, LogsUnavailable, openpilotci_source, internal_source, comma_api_source
|
from openpilot.tools.lib.logreader import LogReader, LogsUnavailable, openpilotci_source_zst, openpilotci_source, internal_source, \
|
||||||
|
internal_source_zst, comma_api_source, auto_source
|
||||||
from openpilot.tools.lib.route import SegmentName
|
from openpilot.tools.lib.route import SegmentName
|
||||||
|
|
||||||
SafetyModel = car.CarParams.SafetyModel
|
SafetyModel = car.CarParams.SafetyModel
|
||||||
@@ -124,8 +126,9 @@ class TestCarModelBase(unittest.TestCase):
|
|||||||
segment_range = f"{cls.test_route.route}/{seg}"
|
segment_range = f"{cls.test_route.route}/{seg}"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sources = [internal_source] if len(INTERNAL_SEG_LIST) else [openpilotci_source, comma_api_source]
|
source = partial(auto_source, sources=[internal_source, internal_source_zst] if len(INTERNAL_SEG_LIST) else \
|
||||||
lr = LogReader(segment_range, sources=sources, sort_by_time=True)
|
[openpilotci_source_zst, openpilotci_source, comma_api_source])
|
||||||
|
lr = LogReader(segment_range, source=source, sort_by_time=True)
|
||||||
return cls.get_testing_data_from_logreader(lr)
|
return cls.get_testing_data_from_logreader(lr)
|
||||||
except (LogsUnavailable, AssertionError):
|
except (LogsUnavailable, AssertionError):
|
||||||
pass
|
pass
|
||||||
@@ -196,6 +199,7 @@ class TestCarModelBase(unittest.TestCase):
|
|||||||
def test_car_interface(self):
|
def test_car_interface(self):
|
||||||
# TODO: also check for checksum violations from can parser
|
# TODO: also check for checksum violations from can parser
|
||||||
can_invalid_cnt = 0
|
can_invalid_cnt = 0
|
||||||
|
can_valid = False
|
||||||
CC = structs.CarControl().as_reader()
|
CC = structs.CarControl().as_reader()
|
||||||
CC_SP = structs.CarControlSP()
|
CC_SP = structs.CarControlSP()
|
||||||
|
|
||||||
@@ -203,8 +207,11 @@ class TestCarModelBase(unittest.TestCase):
|
|||||||
CS, _ = self.CI.update(msg)
|
CS, _ = self.CI.update(msg)
|
||||||
self.CI.apply(CC, CC_SP, msg[0])
|
self.CI.apply(CC, CC_SP, msg[0])
|
||||||
|
|
||||||
|
if CS.canValid:
|
||||||
|
can_valid = True
|
||||||
|
|
||||||
# wait max of 2s for low frequency msgs to be seen
|
# wait max of 2s for low frequency msgs to be seen
|
||||||
if i > 250:
|
if i > 200 or can_valid:
|
||||||
can_invalid_cnt += not CS.canValid
|
can_invalid_cnt += not CS.canValid
|
||||||
|
|
||||||
self.assertEqual(can_invalid_cnt, 0)
|
self.assertEqual(can_invalid_cnt, 0)
|
||||||
@@ -324,7 +331,7 @@ class TestCarModelBase(unittest.TestCase):
|
|||||||
|
|
||||||
vehicle_speed_seen = self.CP.steerControlType == SteerControlType.angle and not self.CP.notCar
|
vehicle_speed_seen = self.CP.steerControlType == SteerControlType.angle and not self.CP.notCar
|
||||||
|
|
||||||
for n, dat in enumerate(msgs):
|
for dat in msgs:
|
||||||
# due to panda updating state selectively, only edges are expected to match
|
# due to panda updating state selectively, only edges are expected to match
|
||||||
# TODO: warm up CarState with real CAN messages to check edge of both sources
|
# TODO: warm up CarState with real CAN messages to check edge of both sources
|
||||||
# (eg. toyota's gasPressed is the inverse of a signal being set)
|
# (eg. toyota's gasPressed is the inverse of a signal being set)
|
||||||
@@ -343,8 +350,6 @@ class TestCarModelBase(unittest.TestCase):
|
|||||||
|
|
||||||
can = [(int(time.monotonic() * 1e9), [CanData(address=address, dat=dat, src=bus)])]
|
can = [(int(time.monotonic() * 1e9), [CanData(address=address, dat=dat, src=bus)])]
|
||||||
CS, _ = self.CI.update(can)
|
CS, _ = self.CI.update(can)
|
||||||
if n < 5: # CANParser warmup time
|
|
||||||
continue
|
|
||||||
|
|
||||||
if self.safety.get_gas_pressed_prev() != prev_panda_gas:
|
if self.safety.get_gas_pressed_prev() != prev_panda_gas:
|
||||||
self.assertEqual(CS.gasPressed, self.safety.get_gas_pressed_prev())
|
self.assertEqual(CS.gasPressed, self.safety.get_gas_pressed_prev())
|
||||||
@@ -364,7 +369,7 @@ class TestCarModelBase(unittest.TestCase):
|
|||||||
if self.safety.get_steering_disengage_prev() != prev_panda_steering_disengage:
|
if self.safety.get_steering_disengage_prev() != prev_panda_steering_disengage:
|
||||||
self.assertEqual(CS.steeringDisengage, self.safety.get_steering_disengage_prev())
|
self.assertEqual(CS.steeringDisengage, self.safety.get_steering_disengage_prev())
|
||||||
|
|
||||||
if self.safety.get_vehicle_moving() != prev_panda_vehicle_moving and not self.CP.notCar:
|
if self.safety.get_vehicle_moving() != prev_panda_vehicle_moving:
|
||||||
self.assertEqual(not CS.standstill, self.safety.get_vehicle_moving())
|
self.assertEqual(not CS.standstill, self.safety.get_vehicle_moving())
|
||||||
|
|
||||||
# check vehicle speed if angle control car or available
|
# check vehicle speed if angle control car or available
|
||||||
@@ -422,7 +427,7 @@ class TestCarModelBase(unittest.TestCase):
|
|||||||
# TODO: check rest of panda's carstate (steering, ACC main on, etc.)
|
# TODO: check rest of panda's carstate (steering, ACC main on, etc.)
|
||||||
|
|
||||||
checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev()
|
checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev()
|
||||||
checks['standstill'] += (CS.standstill == self.safety.get_vehicle_moving()) and not self.CP.notCar
|
checks['standstill'] += CS.standstill == self.safety.get_vehicle_moving()
|
||||||
|
|
||||||
# check vehicle speed if angle control car or available
|
# check vehicle speed if angle control car or available
|
||||||
if self.safety.get_vehicle_speed_min() > 0 or self.safety.get_vehicle_speed_max() > 0:
|
if self.safety.get_vehicle_speed_min() > 0 or self.safety.get_vehicle_speed_max() > 0:
|
||||||
|
|||||||
@@ -164,7 +164,10 @@ class Controls(ControlsExt):
|
|||||||
|
|
||||||
CC.cruiseControl.override = CC.enabled and not CC.longActive and self.CP.openpilotLongitudinalControl
|
CC.cruiseControl.override = CC.enabled and not CC.longActive and self.CP.openpilotLongitudinalControl
|
||||||
CC.cruiseControl.cancel = CS.cruiseState.enabled and (not CC.enabled or not self.CP.pcmCruise)
|
CC.cruiseControl.cancel = CS.cruiseState.enabled and (not CC.enabled or not self.CP.pcmCruise)
|
||||||
CC.cruiseControl.resume = CC.enabled and CS.cruiseState.standstill and not self.sm['longitudinalPlan'].shouldStop
|
|
||||||
|
speeds = self.sm['longitudinalPlan'].speeds
|
||||||
|
if len(speeds):
|
||||||
|
CC.cruiseControl.resume = CC.enabled and CS.cruiseState.standstill and speeds[-1] > 0.1
|
||||||
|
|
||||||
hudControl = CC.hudControl
|
hudControl = CC.hudControl
|
||||||
hudControl.setSpeed = float(CS.vCruiseCluster * CV.KPH_TO_MS)
|
hudControl.setSpeed = float(CS.vCruiseCluster * CV.KPH_TO_MS)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
from cereal import log
|
||||||
from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
||||||
from openpilot.common.realtime import DT_CTRL, DT_MDL
|
from openpilot.common.realtime import DT_CTRL, DT_MDL
|
||||||
|
|
||||||
@@ -39,6 +40,14 @@ def clip_curvature(v_ego, prev_curvature, new_curvature, roll):
|
|||||||
return float(new_curvature), limited_accel or limited_max_curv
|
return float(new_curvature), limited_accel or limited_max_curv
|
||||||
|
|
||||||
|
|
||||||
|
def get_speed_error(modelV2: log.ModelDataV2, v_ego: float) -> float:
|
||||||
|
# ToDo: Try relative error, and absolute speed
|
||||||
|
if len(modelV2.temporalPose.trans):
|
||||||
|
vel_err = np.clip(modelV2.temporalPose.trans[0] - v_ego, -MAX_VEL_ERR, MAX_VEL_ERR)
|
||||||
|
return float(vel_err)
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
def get_accel_from_plan(speeds, accels, t_idxs, action_t=DT_MDL, vEgoStopping=0.05):
|
def get_accel_from_plan(speeds, accels, t_idxs, action_t=DT_MDL, vEgoStopping=0.05):
|
||||||
if len(speeds) == len(t_idxs):
|
if len(speeds) == len(t_idxs):
|
||||||
v_now = speeds[0]
|
v_now = speeds[0]
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import math
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
from opendbc.car import FRICTION_THRESHOLD, get_friction
|
|
||||||
from opendbc.car.interfaces import LatControlInputs
|
from opendbc.car.interfaces import LatControlInputs
|
||||||
from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
||||||
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
|
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
|
||||||
@@ -32,6 +31,7 @@ class LatControlTorque(LatControl):
|
|||||||
self.pid = PIDController(self.torque_params.kp, self.torque_params.ki,
|
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)
|
k_f=self.torque_params.kf, pos_limit=self.steer_max, neg_limit=-self.steer_max)
|
||||||
self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
|
self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
|
||||||
|
self.use_steering_angle = self.torque_params.useSteeringAngle
|
||||||
self.steering_angle_deadzone_deg = self.torque_params.steeringAngleDeadzoneDeg
|
self.steering_angle_deadzone_deg = self.torque_params.steeringAngleDeadzoneDeg
|
||||||
|
|
||||||
self.extension = LatControlTorqueExt(self, CP, CP_SP)
|
self.extension = LatControlTorqueExt(self, CP, CP_SP)
|
||||||
@@ -47,9 +47,16 @@ class LatControlTorque(LatControl):
|
|||||||
output_torque = 0.0
|
output_torque = 0.0
|
||||||
pid_log.active = False
|
pid_log.active = False
|
||||||
else:
|
else:
|
||||||
actual_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
|
actual_curvature_vm = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
|
||||||
roll_compensation = params.roll * ACCELERATION_DUE_TO_GRAVITY
|
roll_compensation = params.roll * ACCELERATION_DUE_TO_GRAVITY
|
||||||
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0))
|
if self.use_steering_angle:
|
||||||
|
actual_curvature = actual_curvature_vm
|
||||||
|
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0))
|
||||||
|
else:
|
||||||
|
assert calibrated_pose is not None
|
||||||
|
actual_curvature_pose = calibrated_pose.angular_velocity.yaw / CS.vEgo
|
||||||
|
actual_curvature = np.interp(CS.vEgo, [2.0, 5.0], [actual_curvature_vm, actual_curvature_pose])
|
||||||
|
curvature_deadzone = 0.0
|
||||||
desired_lateral_accel = desired_curvature * CS.vEgo ** 2
|
desired_lateral_accel = desired_curvature * CS.vEgo ** 2
|
||||||
|
|
||||||
# desired rate is the desired rate of change in the setpoint, not the absolute desired curvature
|
# desired rate is the desired rate of change in the setpoint, not the absolute desired curvature
|
||||||
@@ -62,13 +69,13 @@ class LatControlTorque(LatControl):
|
|||||||
measurement = actual_lateral_accel + low_speed_factor * actual_curvature
|
measurement = actual_lateral_accel + low_speed_factor * actual_curvature
|
||||||
gravity_adjusted_lateral_accel = desired_lateral_accel - roll_compensation
|
gravity_adjusted_lateral_accel = desired_lateral_accel - roll_compensation
|
||||||
torque_from_setpoint = self.torque_from_lateral_accel(LatControlInputs(setpoint, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params,
|
torque_from_setpoint = self.torque_from_lateral_accel(LatControlInputs(setpoint, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params,
|
||||||
gravity_adjusted=False)
|
setpoint, lateral_accel_deadzone, friction_compensation=False, gravity_adjusted=False)
|
||||||
torque_from_measurement = self.torque_from_lateral_accel(LatControlInputs(measurement, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params,
|
torque_from_measurement = self.torque_from_lateral_accel(LatControlInputs(measurement, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params,
|
||||||
gravity_adjusted=False)
|
measurement, lateral_accel_deadzone, friction_compensation=False, gravity_adjusted=False)
|
||||||
pid_log.error = float(torque_from_setpoint - torque_from_measurement)
|
pid_log.error = float(torque_from_setpoint - torque_from_measurement)
|
||||||
ff = self.torque_from_lateral_accel(LatControlInputs(gravity_adjusted_lateral_accel, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params,
|
ff = self.torque_from_lateral_accel(LatControlInputs(gravity_adjusted_lateral_accel, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params,
|
||||||
|
desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, friction_compensation=True,
|
||||||
gravity_adjusted=True)
|
gravity_adjusted=True)
|
||||||
ff += get_friction(desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, FRICTION_THRESHOLD, self.torque_params)
|
|
||||||
|
|
||||||
# Lateral acceleration torque controller extension updates
|
# Lateral acceleration torque controller extension updates
|
||||||
# Overrides stock ff and pid_log.error
|
# Overrides stock ff and pid_log.error
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'np_version')
|
Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'np_version')
|
||||||
|
|
||||||
gen = "c_generated_code"
|
gen = "c_generated_code"
|
||||||
|
|
||||||
@@ -55,23 +55,18 @@ source_list = ['lat_mpc.py',
|
|||||||
]
|
]
|
||||||
|
|
||||||
lenv = env.Clone()
|
lenv = env.Clone()
|
||||||
acados_rel_path = Dir(gen).rel_path(Dir(f"#third_party/acados/{arch}/lib"))
|
|
||||||
lenv["RPATH"] += [lenv.Literal(f'\\$$ORIGIN/{acados_rel_path}')]
|
|
||||||
lenv.Clean(generated_files, Dir(gen))
|
lenv.Clean(generated_files, Dir(gen))
|
||||||
|
|
||||||
generated_lat = lenv.Command(generated_files,
|
generated_lat = lenv.Command(generated_files,
|
||||||
source_list,
|
source_list,
|
||||||
f"cd {Dir('.').abspath} && python3 lat_mpc.py")
|
f"cd {Dir('.').abspath} && python3 lat_mpc.py")
|
||||||
lenv.Depends(generated_lat, [msgq_python, common_python])
|
lenv.Depends(generated_lat, [msgq_python, common_python, opendbc_python])
|
||||||
|
|
||||||
lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES")
|
lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES")
|
||||||
lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES")
|
lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES")
|
||||||
lenv["CCFLAGS"].append("-Wno-unused")
|
lenv["CCFLAGS"].append("-Wno-unused")
|
||||||
if arch != "Darwin":
|
if arch != "Darwin":
|
||||||
lenv["LINKFLAGS"].append("-Wl,--disable-new-dtags")
|
lenv["LINKFLAGS"].append("-Wl,--disable-new-dtags")
|
||||||
else:
|
|
||||||
lenv["LINKFLAGS"].append("-Wl,-install_name,@loader_path/libacados_ocp_solver_lat.dylib")
|
|
||||||
lenv["LINKFLAGS"].append(f"-Wl,-rpath,@loader_path/{acados_rel_path}")
|
|
||||||
lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_lat",
|
lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_lat",
|
||||||
build_files,
|
build_files,
|
||||||
LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e'])
|
LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e'])
|
||||||
@@ -83,8 +78,7 @@ libacados_ocp_solver_pxd = File(f'{gen}/acados_solver.pxd')
|
|||||||
libacados_ocp_solver_c = File(f'{gen}/acados_ocp_solver_pyx.c')
|
libacados_ocp_solver_c = File(f'{gen}/acados_ocp_solver_pyx.c')
|
||||||
|
|
||||||
lenv2 = envCython.Clone()
|
lenv2 = envCython.Clone()
|
||||||
lenv2["LIBPATH"] += [lib_solver[0].dir.abspath]
|
lenv2["LINKFLAGS"] += [lib_solver[0].get_labspath()]
|
||||||
lenv2["RPATH"] += [lenv2.Literal('\\$$ORIGIN')]
|
|
||||||
lenv2.Command(libacados_ocp_solver_c,
|
lenv2.Command(libacados_ocp_solver_c,
|
||||||
[acados_ocp_solver_pyx, acados_ocp_solver_common, libacados_ocp_solver_pxd],
|
[acados_ocp_solver_pyx, acados_ocp_solver_common, libacados_ocp_solver_pxd],
|
||||||
f'cython' + \
|
f'cython' + \
|
||||||
@@ -92,6 +86,6 @@ lenv2.Command(libacados_ocp_solver_c,
|
|||||||
f' -I {libacados_ocp_solver_pxd.get_dir().get_labspath()}' + \
|
f' -I {libacados_ocp_solver_pxd.get_dir().get_labspath()}' + \
|
||||||
f' -I {acados_ocp_solver_common.get_dir().get_labspath()}' + \
|
f' -I {acados_ocp_solver_common.get_dir().get_labspath()}' + \
|
||||||
f' {acados_ocp_solver_pyx.get_labspath()}')
|
f' {acados_ocp_solver_pyx.get_labspath()}')
|
||||||
lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c], LIBS=['acados_ocp_solver_lat'])
|
lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c])
|
||||||
lenv2.Depends(lib_cython, lib_solver)
|
lenv2.Depends(lib_cython, lib_solver)
|
||||||
lenv2.Depends(libacados_ocp_solver_c, np_version)
|
lenv2.Depends(libacados_ocp_solver_c, np_version)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'pandad_python', 'np_version')
|
Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'pandad_python', 'np_version')
|
||||||
|
|
||||||
gen = "c_generated_code"
|
gen = "c_generated_code"
|
||||||
|
|
||||||
@@ -61,13 +61,12 @@ source_list = ['long_mpc.py',
|
|||||||
]
|
]
|
||||||
|
|
||||||
lenv = env.Clone()
|
lenv = env.Clone()
|
||||||
acados_rel_path = Dir(gen).rel_path(Dir(f"#third_party/acados/{arch}/lib"))
|
|
||||||
lenv["RPATH"] += [lenv.Literal(f'\\$$ORIGIN/{acados_rel_path}')]
|
|
||||||
lenv.Clean(generated_files, Dir(gen))
|
lenv.Clean(generated_files, Dir(gen))
|
||||||
|
|
||||||
generated_long = lenv.Command(generated_files,
|
generated_long = lenv.Command(generated_files,
|
||||||
source_list,
|
source_list,
|
||||||
f"cd {Dir('.').abspath} && python3 long_mpc.py")
|
f"cd {Dir('.').abspath} && python3 long_mpc.py")
|
||||||
lenv.Depends(generated_long, [msgq_python, common_python, pandad_python])
|
lenv.Depends(generated_long, [msgq_python, common_python, opendbc_python, pandad_python])
|
||||||
|
|
||||||
lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES")
|
lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES")
|
||||||
lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES")
|
lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES")
|
||||||
@@ -76,7 +75,6 @@ if arch != "Darwin":
|
|||||||
lenv["LINKFLAGS"].append("-Wl,--disable-new-dtags")
|
lenv["LINKFLAGS"].append("-Wl,--disable-new-dtags")
|
||||||
else:
|
else:
|
||||||
lenv["LINKFLAGS"].append("-Wl,-install_name,@loader_path/libacados_ocp_solver_long.dylib")
|
lenv["LINKFLAGS"].append("-Wl,-install_name,@loader_path/libacados_ocp_solver_long.dylib")
|
||||||
lenv["LINKFLAGS"].append(f"-Wl,-rpath,@loader_path/{acados_rel_path}")
|
|
||||||
lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_long",
|
lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_long",
|
||||||
build_files,
|
build_files,
|
||||||
LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e'])
|
LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e'])
|
||||||
@@ -88,8 +86,7 @@ libacados_ocp_solver_pxd = File(f'{gen}/acados_solver.pxd')
|
|||||||
libacados_ocp_solver_c = File(f'{gen}/acados_ocp_solver_pyx.c')
|
libacados_ocp_solver_c = File(f'{gen}/acados_ocp_solver_pyx.c')
|
||||||
|
|
||||||
lenv2 = envCython.Clone()
|
lenv2 = envCython.Clone()
|
||||||
lenv2["LIBPATH"] += [lib_solver[0].dir.abspath]
|
lenv2["LINKFLAGS"] += [lib_solver[0].get_labspath()]
|
||||||
lenv2["RPATH"] += [lenv2.Literal('\\$$ORIGIN')]
|
|
||||||
lenv2.Command(libacados_ocp_solver_c,
|
lenv2.Command(libacados_ocp_solver_c,
|
||||||
[acados_ocp_solver_pyx, acados_ocp_solver_common, libacados_ocp_solver_pxd],
|
[acados_ocp_solver_pyx, acados_ocp_solver_common, libacados_ocp_solver_pxd],
|
||||||
f'cython' + \
|
f'cython' + \
|
||||||
@@ -97,6 +94,6 @@ lenv2.Command(libacados_ocp_solver_c,
|
|||||||
f' -I {libacados_ocp_solver_pxd.get_dir().get_labspath()}' + \
|
f' -I {libacados_ocp_solver_pxd.get_dir().get_labspath()}' + \
|
||||||
f' -I {acados_ocp_solver_common.get_dir().get_labspath()}' + \
|
f' -I {acados_ocp_solver_common.get_dir().get_labspath()}' + \
|
||||||
f' {acados_ocp_solver_pyx.get_labspath()}')
|
f' {acados_ocp_solver_pyx.get_labspath()}')
|
||||||
lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c], LIBS=['acados_ocp_solver_long'])
|
lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c])
|
||||||
lenv2.Depends(lib_cython, lib_solver)
|
lenv2.Depends(lib_cython, lib_solver)
|
||||||
lenv2.Depends(libacados_ocp_solver_c, np_version)
|
lenv2.Depends(libacados_ocp_solver_c, np_version)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from openpilot.selfdrive.modeld.constants import ModelConstants
|
|||||||
from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState
|
from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState
|
||||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc
|
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc
|
||||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC
|
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC
|
||||||
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, get_accel_from_plan
|
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, get_speed_error, get_accel_from_plan
|
||||||
from openpilot.selfdrive.car.cruise import V_CRUISE_MAX, V_CRUISE_UNSET
|
from openpilot.selfdrive.car.cruise import V_CRUISE_MAX, V_CRUISE_UNSET
|
||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
|
|
||||||
@@ -54,7 +54,6 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
|
|||||||
def __init__(self, CP, init_v=0.0, init_a=0.0, dt=DT_MDL):
|
def __init__(self, CP, init_v=0.0, init_a=0.0, dt=DT_MDL):
|
||||||
self.CP = CP
|
self.CP = CP
|
||||||
self.mpc = LongitudinalMpc(dt=dt)
|
self.mpc = LongitudinalMpc(dt=dt)
|
||||||
# TODO remove mpc modes when TR released
|
|
||||||
self.mpc.mode = 'acc'
|
self.mpc.mode = 'acc'
|
||||||
LongitudinalPlannerSP.__init__(self, self.CP, self.mpc)
|
LongitudinalPlannerSP.__init__(self, self.CP, self.mpc)
|
||||||
self.fcw = False
|
self.fcw = False
|
||||||
@@ -64,6 +63,7 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
|
|||||||
self.a_desired = init_a
|
self.a_desired = init_a
|
||||||
self.v_desired_filter = FirstOrderFilter(init_v, 2.0, self.dt)
|
self.v_desired_filter = FirstOrderFilter(init_v, 2.0, self.dt)
|
||||||
self.prev_accel_clip = [ACCEL_MIN, ACCEL_MAX]
|
self.prev_accel_clip = [ACCEL_MIN, ACCEL_MAX]
|
||||||
|
self.v_model_error = 0.0
|
||||||
self.output_a_target = 0.0
|
self.output_a_target = 0.0
|
||||||
self.output_should_stop = False
|
self.output_should_stop = False
|
||||||
|
|
||||||
@@ -73,12 +73,12 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
|
|||||||
self.solverExecutionTime = 0.0
|
self.solverExecutionTime = 0.0
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_model(model_msg):
|
def parse_model(model_msg, model_error):
|
||||||
if (len(model_msg.position.x) == ModelConstants.IDX_N and
|
if (len(model_msg.position.x) == ModelConstants.IDX_N and
|
||||||
len(model_msg.velocity.x) == ModelConstants.IDX_N and
|
len(model_msg.velocity.x) == ModelConstants.IDX_N and
|
||||||
len(model_msg.acceleration.x) == ModelConstants.IDX_N):
|
len(model_msg.acceleration.x) == ModelConstants.IDX_N):
|
||||||
x = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.position.x)
|
x = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.position.x) - model_error * T_IDXS_MPC
|
||||||
v = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.velocity.x)
|
v = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.velocity.x) - model_error
|
||||||
a = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.acceleration.x)
|
a = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.acceleration.x)
|
||||||
j = np.zeros(len(T_IDXS_MPC))
|
j = np.zeros(len(T_IDXS_MPC))
|
||||||
else:
|
else:
|
||||||
@@ -137,7 +137,9 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
|
|||||||
|
|
||||||
# Prevent divergence, smooth in current v_ego
|
# Prevent divergence, smooth in current v_ego
|
||||||
self.v_desired_filter.x = max(0.0, self.v_desired_filter.update(v_ego))
|
self.v_desired_filter.x = max(0.0, self.v_desired_filter.update(v_ego))
|
||||||
x, v, a, j, throttle_prob = self.parse_model(sm['modelV2'])
|
# Compute model v_ego error
|
||||||
|
self.v_model_error = get_speed_error(sm['modelV2'], v_ego)
|
||||||
|
x, v, a, j, throttle_prob = self.parse_model(sm['modelV2'], self.v_model_error)
|
||||||
# Don't clip at low speeds since throttle_prob doesn't account for creep
|
# Don't clip at low speeds since throttle_prob doesn't account for creep
|
||||||
self.allow_throttle = throttle_prob > ALLOW_THROTTLE_THRESHOLD or v_ego <= MIN_ALLOW_THROTTLE_SPEED
|
self.allow_throttle = throttle_prob > ALLOW_THROTTLE_THRESHOLD or v_ego <= MIN_ALLOW_THROTTLE_SPEED
|
||||||
|
|
||||||
|
|||||||
@@ -47,15 +47,15 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
num_pandas = len(messaging.recv_one_retry(pandaStates_sock).pandaStates)
|
num_pandas = len(messaging.recv_one_retry(pandaStates_sock).pandaStates)
|
||||||
|
|
||||||
t = time.monotonic()
|
t = time.time()
|
||||||
print("Getting vin...")
|
print("Getting vin...")
|
||||||
set_obd_multiplexing(True)
|
set_obd_multiplexing(True)
|
||||||
vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (0, 1))
|
vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (0, 1))
|
||||||
print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}')
|
print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}')
|
||||||
print(f"Getting VIN took {time.monotonic() - t:.3f} s")
|
print(f"Getting VIN took {time.time() - t:.3f} s")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
t = time.monotonic()
|
t = time.time()
|
||||||
fw_vers = get_fw_versions(*can_callbacks, set_obd_multiplexing, query_brand=args.brand, extra=extra, num_pandas=num_pandas, progress=True)
|
fw_vers = get_fw_versions(*can_callbacks, set_obd_multiplexing, query_brand=args.brand, extra=extra, num_pandas=num_pandas, progress=True)
|
||||||
_, candidates = match_fw_to_car(fw_vers, vin)
|
_, candidates = match_fw_to_car(fw_vers, vin)
|
||||||
|
|
||||||
@@ -71,4 +71,4 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
print()
|
print()
|
||||||
print("Possible matches:", candidates)
|
print("Possible matches:", candidates)
|
||||||
print(f"Getting fw took {time.monotonic() - t:.3f} s")
|
print(f"Getting fw took {time.time() - t:.3f} s")
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
panda = Panda()
|
panda = Panda()
|
||||||
panda.set_safety_mode(CarParams.SafetyModel.elm327)
|
panda.set_safety_mode(CarParams.SafetyModel.elm327)
|
||||||
uds_client = UdsClient(panda, MQB_EPS_CAN_ADDR, MQB_EPS_CAN_ADDR + RX_OFFSET, 1, timeout=0.2)
|
bus = 1 if panda.has_obd() else 0
|
||||||
|
uds_client = UdsClient(panda, MQB_EPS_CAN_ADDR, MQB_EPS_CAN_ADDR + RX_OFFSET, bus, timeout=0.2)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
uds_client.diagnostic_session_control(SESSION_TYPE.EXTENDED_DIAGNOSTIC)
|
uds_client.diagnostic_session_control(SESSION_TYPE.EXTENDED_DIAGNOSTIC)
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ monitored_proc_names = [
|
|||||||
|
|
||||||
cpu_time_names = ['user', 'system', 'children_user', 'children_system']
|
cpu_time_names = ['user', 'system', 'children_user', 'children_system']
|
||||||
|
|
||||||
|
timer = getattr(time, 'monotonic', time.time)
|
||||||
|
|
||||||
|
|
||||||
def get_arg_parser():
|
def get_arg_parser():
|
||||||
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
@@ -70,7 +72,7 @@ if __name__ == "__main__":
|
|||||||
print('Add monitored proc:', k)
|
print('Add monitored proc:', k)
|
||||||
stats[k] = {'cpu_samples': defaultdict(list), 'min': defaultdict(lambda: None), 'max': defaultdict(lambda: None),
|
stats[k] = {'cpu_samples': defaultdict(list), 'min': defaultdict(lambda: None), 'max': defaultdict(lambda: None),
|
||||||
'avg': defaultdict(float), 'last_cpu_times': None, 'last_sys_time': None}
|
'avg': defaultdict(float), 'last_cpu_times': None, 'last_sys_time': None}
|
||||||
stats[k]['last_sys_time'] = time.monotonic()
|
stats[k]['last_sys_time'] = timer()
|
||||||
stats[k]['last_cpu_times'] = p.cpu_times()
|
stats[k]['last_cpu_times'] = p.cpu_times()
|
||||||
monitored_procs.append(p)
|
monitored_procs.append(p)
|
||||||
i = 0
|
i = 0
|
||||||
@@ -78,7 +80,7 @@ if __name__ == "__main__":
|
|||||||
while True:
|
while True:
|
||||||
for p in monitored_procs:
|
for p in monitored_procs:
|
||||||
k = ' '.join(p.cmdline())
|
k = ' '.join(p.cmdline())
|
||||||
cur_sys_time = time.monotonic()
|
cur_sys_time = timer()
|
||||||
cur_cpu_times = p.cpu_times()
|
cur_cpu_times = p.cpu_times()
|
||||||
cpu_times = np.subtract(cur_cpu_times, stats[k]['last_cpu_times']) / (cur_sys_time - stats[k]['last_sys_time'])
|
cpu_times = np.subtract(cur_cpu_times, stats[k]['last_cpu_times']) / (cur_sys_time - stats[k]['last_sys_time'])
|
||||||
stats[k]['last_sys_time'] = cur_sys_time
|
stats[k]['last_sys_time'] = cur_sys_time
|
||||||
|
|||||||
@@ -157,7 +157,8 @@ class LateralLagEstimator:
|
|||||||
block_count: int = BLOCK_NUM, min_valid_block_count: int = BLOCK_NUM_NEEDED, block_size: int = BLOCK_SIZE,
|
block_count: int = BLOCK_NUM, min_valid_block_count: int = BLOCK_NUM_NEEDED, block_size: int = BLOCK_SIZE,
|
||||||
window_sec: float = MOVING_WINDOW_SEC, okay_window_sec: float = MIN_OKAY_WINDOW_SEC, min_recovery_buffer_sec: float = MIN_RECOVERY_BUFFER_SEC,
|
window_sec: float = MOVING_WINDOW_SEC, okay_window_sec: float = MIN_OKAY_WINDOW_SEC, min_recovery_buffer_sec: float = MIN_RECOVERY_BUFFER_SEC,
|
||||||
min_vego: float = MIN_VEGO, min_yr: float = MIN_ABS_YAW_RATE, min_ncc: float = MIN_NCC,
|
min_vego: float = MIN_VEGO, min_yr: float = MIN_ABS_YAW_RATE, min_ncc: float = MIN_NCC,
|
||||||
max_lat_accel: float = MAX_LAT_ACCEL, max_lat_accel_diff: float = MAX_LAT_ACCEL_DIFF, min_confidence: float = MIN_CONFIDENCE):
|
max_lat_accel: float = MAX_LAT_ACCEL, max_lat_accel_diff: float = MAX_LAT_ACCEL_DIFF, min_confidence: float = MIN_CONFIDENCE,
|
||||||
|
enabled: bool = True):
|
||||||
self.dt = dt
|
self.dt = dt
|
||||||
self.window_sec = window_sec
|
self.window_sec = window_sec
|
||||||
self.okay_window_sec = okay_window_sec
|
self.okay_window_sec = okay_window_sec
|
||||||
@@ -172,6 +173,7 @@ class LateralLagEstimator:
|
|||||||
self.min_confidence = min_confidence
|
self.min_confidence = min_confidence
|
||||||
self.max_lat_accel = max_lat_accel
|
self.max_lat_accel = max_lat_accel
|
||||||
self.max_lat_accel_diff = max_lat_accel_diff
|
self.max_lat_accel_diff = max_lat_accel_diff
|
||||||
|
self.enabled = enabled
|
||||||
|
|
||||||
self.t = 0.0
|
self.t = 0.0
|
||||||
self.lat_active = False
|
self.lat_active = False
|
||||||
@@ -206,7 +208,7 @@ class LateralLagEstimator:
|
|||||||
liveDelay = msg.liveDelay
|
liveDelay = msg.liveDelay
|
||||||
|
|
||||||
valid_mean_lag, valid_std, current_mean_lag, current_std = self.block_avg.get()
|
valid_mean_lag, valid_std, current_mean_lag, current_std = self.block_avg.get()
|
||||||
if self.block_avg.valid_blocks >= self.min_valid_block_count and not np.isnan(valid_mean_lag) and not np.isnan(valid_std):
|
if self.enabled and self.block_avg.valid_blocks >= self.min_valid_block_count and not np.isnan(valid_mean_lag) and not np.isnan(valid_std):
|
||||||
if valid_std > MAX_LAG_STD:
|
if valid_std > MAX_LAG_STD:
|
||||||
liveDelay.status = log.LiveDelayData.Status.invalid
|
liveDelay.status = log.LiveDelayData.Status.invalid
|
||||||
else:
|
else:
|
||||||
@@ -369,7 +371,10 @@ def main():
|
|||||||
params = Params()
|
params = Params()
|
||||||
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
|
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
|
||||||
|
|
||||||
lag_learner = LateralLagEstimator(CP, 1. / SERVICE_LIST['livePose'].frequency)
|
# TODO: remove me, lagd is in shadow mode on release
|
||||||
|
is_release = params.get_bool("IsReleaseBranch")
|
||||||
|
|
||||||
|
lag_learner = LateralLagEstimator(CP, 1. / SERVICE_LIST['livePose'].frequency, enabled=not is_release)
|
||||||
if (initial_lag_params := retrieve_initial_lag(params, CP)) is not None:
|
if (initial_lag_params := retrieve_initial_lag(params, CP)) is not None:
|
||||||
lag, valid_blocks = initial_lag_params
|
lag, valid_blocks = initial_lag_params
|
||||||
lag_learner.reset(lag, valid_blocks)
|
lag_learner.reset(lag, valid_blocks)
|
||||||
|
|||||||
@@ -93,9 +93,8 @@ class CarKalman(KalmanFilter):
|
|||||||
dim_state = CarKalman.initial_x.shape[0]
|
dim_state = CarKalman.initial_x.shape[0]
|
||||||
name = CarKalman.name
|
name = CarKalman.name
|
||||||
|
|
||||||
# Linearized single-track lateral dynamics, equations 7.211-7.213
|
# vehicle models comes from The Science of Vehicle Dynamics: Handling, Braking, and Ride of Road and Race Cars
|
||||||
# Massimo Guiggiani, The Science of Vehicle Dynamics: Handling, Braking, and Ride of Road and Race Cars
|
# Model used is in 6.15 with formula from 6.198
|
||||||
# Springer Cham, 2023. doi: https://doi.org/10.1007/978-3-031-06461-6
|
|
||||||
|
|
||||||
# globals
|
# globals
|
||||||
global_vars = [sp.Symbol(name) for name in CarKalman.global_vars]
|
global_vars = [sp.Symbol(name) for name in CarKalman.global_vars]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import capnp
|
import capnp
|
||||||
|
|
||||||
@@ -206,11 +207,12 @@ def migrate_cached_vehicle_params_if_needed(params: Params):
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
last_parameters_dict = json.loads(last_parameters_data_old)
|
||||||
last_parameters_msg = messaging.new_message('liveParameters')
|
last_parameters_msg = messaging.new_message('liveParameters')
|
||||||
last_parameters_msg.liveParameters.valid = True
|
last_parameters_msg.liveParameters.valid = True
|
||||||
last_parameters_msg.liveParameters.steerRatio = last_parameters_data_old['steerRatio']
|
last_parameters_msg.liveParameters.steerRatio = last_parameters_dict['steerRatio']
|
||||||
last_parameters_msg.liveParameters.stiffnessFactor = last_parameters_data_old['stiffnessFactor']
|
last_parameters_msg.liveParameters.stiffnessFactor = last_parameters_dict['stiffnessFactor']
|
||||||
last_parameters_msg.liveParameters.angleOffsetAverageDeg = last_parameters_data_old['angleOffsetAverageDeg']
|
last_parameters_msg.liveParameters.angleOffsetAverageDeg = last_parameters_dict['angleOffsetAverageDeg']
|
||||||
params.put("LiveParametersV2", last_parameters_msg.to_bytes())
|
params.put("LiveParametersV2", last_parameters_msg.to_bytes())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
cloudlog.error(f"Failed to perform parameter migration: {e}")
|
cloudlog.error(f"Failed to perform parameter migration: {e}")
|
||||||
|
|||||||
@@ -110,6 +110,19 @@ class TestLagd:
|
|||||||
assert msg.liveDelay.validBlocks == BLOCK_NUM_NEEDED
|
assert msg.liveDelay.validBlocks == BLOCK_NUM_NEEDED
|
||||||
assert msg.liveDelay.calPerc == 100
|
assert msg.liveDelay.calPerc == 100
|
||||||
|
|
||||||
|
def test_disabled_estimator(self):
|
||||||
|
mocked_CP = car.CarParams(steerActuatorDelay=0.8)
|
||||||
|
estimator = LateralLagEstimator(mocked_CP, DT, min_recovery_buffer_sec=0.0, min_yr=0.0, enabled=False)
|
||||||
|
lag_frames = 5
|
||||||
|
process_messages(estimator, lag_frames, int(MIN_OKAY_WINDOW_SEC / DT) + BLOCK_NUM_NEEDED * BLOCK_SIZE)
|
||||||
|
msg = estimator.get_msg(True)
|
||||||
|
assert msg.liveDelay.status == 'unestimated'
|
||||||
|
assert np.allclose(msg.liveDelay.lateralDelay, 1.0, atol=0.01)
|
||||||
|
assert np.allclose(msg.liveDelay.lateralDelayEstimate, lag_frames * DT, atol=0.01)
|
||||||
|
assert np.allclose(msg.liveDelay.lateralDelayEstimateStd, 0.0, atol=0.01)
|
||||||
|
assert msg.liveDelay.validBlocks == BLOCK_NUM_NEEDED
|
||||||
|
assert msg.liveDelay.calPerc == 100
|
||||||
|
|
||||||
def test_estimator_masking(self):
|
def test_estimator_masking(self):
|
||||||
mocked_CP, lag_frames = car.CarParams(steerActuatorDelay=0.8), random.randint(1, 19)
|
mocked_CP, lag_frames = car.CarParams(steerActuatorDelay=0.8), random.randint(1, 19)
|
||||||
estimator = LateralLagEstimator(mocked_CP, DT, min_recovery_buffer_sec=0.0, min_yr=0.0, min_valid_block_count=1)
|
estimator = LateralLagEstimator(mocked_CP, DT, min_recovery_buffer_sec=0.0, min_yr=0.0, min_valid_block_count=1)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import random
|
import random
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import json
|
||||||
|
|
||||||
from cereal import messaging
|
from cereal import messaging
|
||||||
from openpilot.selfdrive.locationd.paramsd import retrieve_initial_vehicle_params, migrate_cached_vehicle_params_if_needed
|
from openpilot.selfdrive.locationd.paramsd import retrieve_initial_vehicle_params, migrate_cached_vehicle_params_if_needed
|
||||||
@@ -46,7 +47,7 @@ class TestParamsd:
|
|||||||
CP = next(m for m in lr if m.which() == "carParams").carParams
|
CP = next(m for m in lr if m.which() == "carParams").carParams
|
||||||
|
|
||||||
msg = get_random_live_parameters(CP)
|
msg = get_random_live_parameters(CP)
|
||||||
params.put("LiveParameters", msg.liveParameters.to_dict())
|
params.put("LiveParameters", json.dumps(msg.liveParameters.to_dict()))
|
||||||
params.put("CarParamsPrevRoute", CP.as_builder().to_bytes())
|
params.put("CarParamsPrevRoute", CP.as_builder().to_bytes())
|
||||||
params.remove("LiveParametersV2")
|
params.remove("LiveParametersV2")
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ class TestParamsd:
|
|||||||
|
|
||||||
def test_read_saved_params_corrupted_old_format(self):
|
def test_read_saved_params_corrupted_old_format(self):
|
||||||
params = Params()
|
params = Params()
|
||||||
params.put("LiveParameters", {})
|
params.put("LiveParameters", b'\x00\x00\x02\x00\x01\x00:F\xde\xed\xae;')
|
||||||
params.remove("LiveParametersV2")
|
params.remove("LiveParametersV2")
|
||||||
|
|
||||||
migrate_cached_vehicle_params_if_needed(params)
|
migrate_cached_vehicle_params_if_needed(params)
|
||||||
|
|||||||
+17
-15
@@ -50,21 +50,23 @@ def tg_compile(flags, model_name):
|
|||||||
# Compile small models
|
# Compile small models
|
||||||
for model_name in ['driving_vision', 'driving_policy', 'dmonitoring_model']:
|
for model_name in ['driving_vision', 'driving_policy', 'dmonitoring_model']:
|
||||||
flags = {
|
flags = {
|
||||||
'larch64': 'DEV=QCOM',
|
'larch64': 'QCOM=1',
|
||||||
'Darwin': 'DEV=CPU IMAGE=0',
|
'Darwin': 'CPU=1 IMAGE=0 JIT=2',
|
||||||
}.get(arch, 'DEV=LLVM IMAGE=0')
|
}.get(arch, 'LLVM=1 LLVMOPT=1 BEAM=0 IMAGE=0 JIT=2')
|
||||||
tg_compile(flags, model_name)
|
tg_compile(flags, model_name)
|
||||||
|
|
||||||
# Compile BIG model if USB GPU is available
|
# Compile BIG model if USB GPU is available
|
||||||
if "USBGPU" in os.environ:
|
import subprocess
|
||||||
import subprocess
|
from tinygrad import Device
|
||||||
# because tg doesn't support multi-process
|
|
||||||
devs = subprocess.check_output('python3 -c "from tinygrad import Device; print(list(Device.get_available_devices()))"', shell=True, cwd=env.Dir('#').abspath)
|
# because tg doesn't support multi-process
|
||||||
if b"AMD" in devs:
|
devs = subprocess.check_output('python3 -c "from tinygrad import Device; print(list(Device.get_available_devices()))"', shell=True, cwd=env.Dir('#').abspath)
|
||||||
print("USB GPU detected... building")
|
if b"AMD" in devs:
|
||||||
flags = "DEV=AMD AMD_IFACE=USB AMD_LLVM=1 NOLOCALS=0 IMAGE=0"
|
del Device
|
||||||
bp = tg_compile(flags, "big_driving_policy")
|
print("USB GPU detected... building")
|
||||||
bv = tg_compile(flags, "big_driving_vision")
|
flags = "AMD=1 AMD_IFACE=USB AMD_LLVM=1 NOLOCALS=0 IMAGE=0"
|
||||||
lenv.SideEffect('lock', [bp, bv]) # tg doesn't support multi-process so build serially
|
bp = tg_compile(flags, "big_driving_policy")
|
||||||
else:
|
bv = tg_compile(flags, "big_driving_vision")
|
||||||
print("USB GPU not detected... skipping")
|
lenv.SideEffect('lock', [bp, bv]) # tg doesn't support multi-process so build serially
|
||||||
|
else:
|
||||||
|
print("USB GPU not detected... skipping")
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os
|
import os
|
||||||
from openpilot.system.hardware import TICI
|
from openpilot.system.hardware import TICI
|
||||||
os.environ['DEV'] = 'QCOM' if TICI else 'LLVM'
|
|
||||||
from tinygrad.tensor import Tensor
|
from tinygrad.tensor import Tensor
|
||||||
from tinygrad.dtype import dtypes
|
from tinygrad.dtype import dtypes
|
||||||
|
if TICI:
|
||||||
|
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
|
||||||
|
os.environ['QCOM'] = '1'
|
||||||
|
else:
|
||||||
|
os.environ['LLVM'] = '1'
|
||||||
import math
|
import math
|
||||||
import time
|
import time
|
||||||
import pickle
|
import pickle
|
||||||
import ctypes
|
import ctypes
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from setproctitle import setproctitle
|
||||||
|
|
||||||
from cereal import messaging
|
from cereal import messaging
|
||||||
from cereal.messaging import PubMaster, SubMaster
|
from cereal.messaging import PubMaster, SubMaster
|
||||||
@@ -20,7 +25,7 @@ from openpilot.common.transformations.model import dmonitoringmodel_intrinsics,
|
|||||||
from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye
|
from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye
|
||||||
from openpilot.selfdrive.modeld.models.commonmodel_pyx import CLContext, MonitoringModelFrame
|
from openpilot.selfdrive.modeld.models.commonmodel_pyx import CLContext, MonitoringModelFrame
|
||||||
from openpilot.selfdrive.modeld.parse_model_outputs import sigmoid
|
from openpilot.selfdrive.modeld.parse_model_outputs import sigmoid
|
||||||
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
|
from openpilot.system import sentry
|
||||||
|
|
||||||
MODEL_WIDTH, MODEL_HEIGHT = DM_INPUT_SIZE
|
MODEL_WIDTH, MODEL_HEIGHT = DM_INPUT_SIZE
|
||||||
CALIB_LEN = 3
|
CALIB_LEN = 3
|
||||||
@@ -90,7 +95,7 @@ class ModelState:
|
|||||||
self.tensor_inputs['input_img'] = Tensor(self.frame.buffer_from_cl(input_img_cl).reshape((1, MODEL_WIDTH*MODEL_HEIGHT)), dtype=dtypes.uint8).realize()
|
self.tensor_inputs['input_img'] = Tensor(self.frame.buffer_from_cl(input_img_cl).reshape((1, MODEL_WIDTH*MODEL_HEIGHT)), dtype=dtypes.uint8).realize()
|
||||||
|
|
||||||
|
|
||||||
output = self.model_run(**self.tensor_inputs).contiguous().realize().uop.base.buffer.numpy()
|
output = self.model_run(**self.tensor_inputs).numpy().flatten()
|
||||||
|
|
||||||
t2 = time.perf_counter()
|
t2 = time.perf_counter()
|
||||||
return output, t2 - t1
|
return output, t2 - t1
|
||||||
@@ -128,8 +133,12 @@ def get_driverstate_packet(model_output: np.ndarray, frame_id: int, location_ts:
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
setproctitle(PROCESS_NAME)
|
||||||
config_realtime_process(7, 5)
|
config_realtime_process(7, 5)
|
||||||
|
|
||||||
|
sentry.set_tag("daemon", PROCESS_NAME)
|
||||||
|
cloudlog.bind(daemon=PROCESS_NAME)
|
||||||
|
|
||||||
cl_context = CLContext()
|
cl_context = CLContext()
|
||||||
model = ModelState(cl_context)
|
model = ModelState(cl_context)
|
||||||
cloudlog.warning("models loaded, dmonitoringmodeld starting")
|
cloudlog.warning("models loaded, dmonitoringmodeld starting")
|
||||||
@@ -171,4 +180,7 @@ if __name__ == "__main__":
|
|||||||
try:
|
try:
|
||||||
main()
|
main()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
cloudlog.warning("got SIGINT")
|
cloudlog.warning(f"child {PROCESS_NAME} got SIGINT")
|
||||||
|
except Exception:
|
||||||
|
sentry.capture_exception()
|
||||||
|
raise
|
||||||
|
|||||||
@@ -89,6 +89,13 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
|||||||
fill_xyzt(modelV2.orientation, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.T_FROM_CURRENT_EULER].T)
|
fill_xyzt(modelV2.orientation, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.T_FROM_CURRENT_EULER].T)
|
||||||
fill_xyzt(modelV2.orientationRate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T)
|
fill_xyzt(modelV2.orientationRate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T)
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
# poly path
|
# poly path
|
||||||
fill_xyz_poly(driving_model_data.path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T)
|
fill_xyz_poly(driving_model_data.path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T)
|
||||||
|
|
||||||
|
|||||||
+24
-16
@@ -1,11 +1,16 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os
|
import os
|
||||||
from openpilot.system.hardware import TICI
|
from openpilot.system.hardware import TICI
|
||||||
os.environ['DEV'] = 'QCOM' if TICI else 'LLVM'
|
|
||||||
USBGPU = "USBGPU" in os.environ
|
USBGPU = "USBGPU" in os.environ
|
||||||
if USBGPU:
|
if USBGPU:
|
||||||
os.environ['DEV'] = 'AMD'
|
os.environ['AMD'] = '1'
|
||||||
os.environ['AMD_IFACE'] = 'USB'
|
os.environ['AMD_IFACE'] = 'USB'
|
||||||
|
elif TICI:
|
||||||
|
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
|
||||||
|
os.environ['QCOM'] = '1'
|
||||||
|
else:
|
||||||
|
os.environ['LLVM'] = '1'
|
||||||
|
os.environ['JIT'] = '2'
|
||||||
from tinygrad.tensor import Tensor
|
from tinygrad.tensor import Tensor
|
||||||
from tinygrad.dtype import dtypes
|
from tinygrad.dtype import dtypes
|
||||||
import time
|
import time
|
||||||
@@ -14,6 +19,7 @@ import numpy as np
|
|||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from cereal import car, log
|
from cereal import car, log
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from setproctitle import setproctitle
|
||||||
from cereal.messaging import PubMaster, SubMaster
|
from cereal.messaging import PubMaster, SubMaster
|
||||||
from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf
|
from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf
|
||||||
from opendbc.car.car_helpers import get_demo_car_params
|
from opendbc.car.car_helpers import get_demo_car_params
|
||||||
@@ -23,13 +29,13 @@ from openpilot.common.filter_simple import FirstOrderFilter
|
|||||||
from openpilot.common.realtime import config_realtime_process, DT_MDL
|
from openpilot.common.realtime import config_realtime_process, DT_MDL
|
||||||
from openpilot.common.transformations.camera import DEVICE_CAMERAS
|
from openpilot.common.transformations.camera import DEVICE_CAMERAS
|
||||||
from openpilot.common.transformations.model import get_warp_matrix
|
from openpilot.common.transformations.model import get_warp_matrix
|
||||||
|
from openpilot.system import sentry
|
||||||
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
|
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
|
||||||
from openpilot.selfdrive.controls.lib.drive_helpers import get_accel_from_plan, smooth_value, get_curvature_from_plan
|
from openpilot.selfdrive.controls.lib.drive_helpers import get_accel_from_plan, smooth_value
|
||||||
from openpilot.selfdrive.modeld.parse_model_outputs import Parser
|
from openpilot.selfdrive.modeld.parse_model_outputs import Parser
|
||||||
from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_msg, PublishState
|
from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_msg, PublishState
|
||||||
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan
|
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan
|
||||||
from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext
|
from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext
|
||||||
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
|
|
||||||
|
|
||||||
from openpilot.sunnypilot.livedelay.lagd_toggle import LagdToggle
|
from openpilot.sunnypilot.livedelay.lagd_toggle import LagdToggle
|
||||||
|
|
||||||
@@ -42,8 +48,8 @@ POLICY_PKL_PATH = Path(__file__).parent / 'models/driving_policy_tinygrad.pkl'
|
|||||||
VISION_METADATA_PATH = Path(__file__).parent / 'models/driving_vision_metadata.pkl'
|
VISION_METADATA_PATH = Path(__file__).parent / 'models/driving_vision_metadata.pkl'
|
||||||
POLICY_METADATA_PATH = Path(__file__).parent / 'models/driving_policy_metadata.pkl'
|
POLICY_METADATA_PATH = Path(__file__).parent / 'models/driving_policy_metadata.pkl'
|
||||||
|
|
||||||
LAT_SMOOTH_SECONDS = 0.1
|
LAT_SMOOTH_SECONDS = 0.0
|
||||||
LONG_SMOOTH_SECONDS = 0.3
|
LONG_SMOOTH_SECONDS = 0.0
|
||||||
MIN_LAT_CONTROL_SPEED = 0.3
|
MIN_LAT_CONTROL_SPEED = 0.3
|
||||||
|
|
||||||
|
|
||||||
@@ -56,11 +62,7 @@ def get_action_from_model(model_output: dict[str, np.ndarray], prev_action: log.
|
|||||||
action_t=long_action_t)
|
action_t=long_action_t)
|
||||||
desired_accel = smooth_value(desired_accel, prev_action.desiredAcceleration, LONG_SMOOTH_SECONDS)
|
desired_accel = smooth_value(desired_accel, prev_action.desiredAcceleration, LONG_SMOOTH_SECONDS)
|
||||||
|
|
||||||
desired_curvature = get_curvature_from_plan(plan[:,Plan.T_FROM_CURRENT_EULER][:,2],
|
desired_curvature = model_output['desired_curvature'][0, 0]
|
||||||
plan[:,Plan.ORIENTATION_RATE][:,2],
|
|
||||||
ModelConstants.T_IDXS,
|
|
||||||
v_ego,
|
|
||||||
lat_action_t)
|
|
||||||
if v_ego > MIN_LAT_CONTROL_SPEED:
|
if v_ego > MIN_LAT_CONTROL_SPEED:
|
||||||
desired_curvature = smooth_value(desired_curvature, prev_action.desiredCurvature, LAT_SMOOTH_SECONDS)
|
desired_curvature = smooth_value(desired_curvature, prev_action.desiredCurvature, LAT_SMOOTH_SECONDS)
|
||||||
else:
|
else:
|
||||||
@@ -86,7 +88,7 @@ class ModelState:
|
|||||||
prev_desire: np.ndarray # for tracking the rising edge of the pulse
|
prev_desire: np.ndarray # for tracking the rising edge of the pulse
|
||||||
|
|
||||||
def __init__(self, context: CLContext):
|
def __init__(self, context: CLContext):
|
||||||
self.LAT_SMOOTH_SECONDS = LAT_SMOOTH_SECONDS
|
self.LAT_SMOOTH_SECONDS = 0.0
|
||||||
with open(VISION_METADATA_PATH, 'rb') as f:
|
with open(VISION_METADATA_PATH, 'rb') as f:
|
||||||
vision_metadata = pickle.load(f)
|
vision_metadata = pickle.load(f)
|
||||||
self.vision_input_shapes = vision_metadata['input_shapes']
|
self.vision_input_shapes = vision_metadata['input_shapes']
|
||||||
@@ -162,20 +164,20 @@ class ModelState:
|
|||||||
if prepare_only:
|
if prepare_only:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
self.vision_output = self.vision_run(**self.vision_inputs).contiguous().realize().uop.base.buffer.numpy()
|
self.vision_output = self.vision_run(**self.vision_inputs).numpy().flatten()
|
||||||
vision_outputs_dict = self.parser.parse_vision_outputs(self.slice_outputs(self.vision_output, self.vision_output_slices))
|
vision_outputs_dict = self.parser.parse_vision_outputs(self.slice_outputs(self.vision_output, self.vision_output_slices))
|
||||||
|
|
||||||
self.full_features_buffer[0,:-1] = self.full_features_buffer[0,1:]
|
self.full_features_buffer[0,:-1] = self.full_features_buffer[0,1:]
|
||||||
self.full_features_buffer[0,-1] = vision_outputs_dict['hidden_state'][0, :]
|
self.full_features_buffer[0,-1] = vision_outputs_dict['hidden_state'][0, :]
|
||||||
self.numpy_inputs['features_buffer'][:] = self.full_features_buffer[0, self.temporal_idxs]
|
self.numpy_inputs['features_buffer'][:] = self.full_features_buffer[0, self.temporal_idxs]
|
||||||
|
|
||||||
self.policy_output = self.policy_run(**self.policy_inputs).contiguous().realize().uop.base.buffer.numpy()
|
self.policy_output = self.policy_run(**self.policy_inputs).numpy().flatten()
|
||||||
policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices))
|
policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices))
|
||||||
|
|
||||||
# TODO model only uses last value now
|
# TODO model only uses last value now
|
||||||
self.full_prev_desired_curv[0,:-1] = self.full_prev_desired_curv[0,1:]
|
self.full_prev_desired_curv[0,:-1] = self.full_prev_desired_curv[0,1:]
|
||||||
self.full_prev_desired_curv[0,-1,:] = policy_outputs_dict['desired_curvature'][0, :]
|
self.full_prev_desired_curv[0,-1,:] = policy_outputs_dict['desired_curvature'][0, :]
|
||||||
self.numpy_inputs['prev_desired_curv'][:] = 0*self.full_prev_desired_curv[0, self.temporal_idxs]
|
self.numpy_inputs['prev_desired_curv'][:] = self.full_prev_desired_curv[0, self.temporal_idxs]
|
||||||
|
|
||||||
combined_outputs_dict = {**vision_outputs_dict, **policy_outputs_dict}
|
combined_outputs_dict = {**vision_outputs_dict, **policy_outputs_dict}
|
||||||
if SEND_RAW_PRED:
|
if SEND_RAW_PRED:
|
||||||
@@ -187,6 +189,9 @@ class ModelState:
|
|||||||
def main(demo=False):
|
def main(demo=False):
|
||||||
cloudlog.warning("modeld init")
|
cloudlog.warning("modeld init")
|
||||||
|
|
||||||
|
sentry.set_tag("daemon", PROCESS_NAME)
|
||||||
|
cloudlog.bind(daemon=PROCESS_NAME)
|
||||||
|
setproctitle(PROCESS_NAME)
|
||||||
if not USBGPU:
|
if not USBGPU:
|
||||||
# USB GPU currently saturates a core so can't do this yet,
|
# USB GPU currently saturates a core so can't do this yet,
|
||||||
# also need to move the aux USB interrupts for good timings
|
# also need to move the aux USB interrupts for good timings
|
||||||
@@ -374,4 +379,7 @@ if __name__ == "__main__":
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
main(demo=args.demo)
|
main(demo=args.demo)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
cloudlog.warning("got SIGINT")
|
cloudlog.warning(f"child {PROCESS_NAME} got SIGINT")
|
||||||
|
except Exception:
|
||||||
|
sentry.capture_exception()
|
||||||
|
raise
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:22aec22a10ce09384d4a4af2a0bbff08d54af7e0c888503508f356fae4ff0e29
|
oid sha256:5f714fb38bcd44b5d9f44e3a8e1595e1dfdf7558f0eec3485cf3f2dbb6dc7d8d
|
||||||
size 15583374
|
size 15971805
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:c824f68646a3b94f117f01c70dc8316fb466e05fbd42ccdba440b8a8dc86914b
|
oid sha256:3ac4867fbc618037e8d03143edbfeeae960f2025644b5dcf36c6665271b4f874
|
||||||
size 46265993
|
size 34883375
|
||||||
|
|||||||
@@ -88,23 +88,24 @@ class Parser:
|
|||||||
self.parse_mdn('pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
self.parse_mdn('pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
||||||
self.parse_mdn('wide_from_device_euler', outs, in_N=0, out_N=0, out_shape=(ModelConstants.WIDE_FROM_DEVICE_WIDTH,))
|
self.parse_mdn('wide_from_device_euler', outs, in_N=0, out_N=0, out_shape=(ModelConstants.WIDE_FROM_DEVICE_WIDTH,))
|
||||||
self.parse_mdn('road_transform', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
self.parse_mdn('road_transform', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
||||||
self.parse_mdn('lane_lines', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_LANE_LINES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
|
|
||||||
self.parse_mdn('road_edges', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_ROAD_EDGES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
|
|
||||||
self.parse_binary_crossentropy('lane_lines_prob', outs)
|
|
||||||
self.parse_categorical_crossentropy('desire_pred', outs, out_shape=(ModelConstants.DESIRE_PRED_LEN,ModelConstants.DESIRE_PRED_WIDTH))
|
self.parse_categorical_crossentropy('desire_pred', outs, out_shape=(ModelConstants.DESIRE_PRED_LEN,ModelConstants.DESIRE_PRED_WIDTH))
|
||||||
self.parse_binary_crossentropy('meta', outs)
|
self.parse_binary_crossentropy('meta', outs)
|
||||||
self.parse_binary_crossentropy('lead_prob', outs)
|
|
||||||
self.parse_mdn('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION,
|
|
||||||
out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH))
|
|
||||||
return outs
|
return outs
|
||||||
|
|
||||||
def parse_policy_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]:
|
def parse_policy_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]:
|
||||||
self.parse_mdn('plan', outs, in_N=ModelConstants.PLAN_MHP_N, out_N=ModelConstants.PLAN_MHP_SELECTION,
|
self.parse_mdn('plan', outs, in_N=ModelConstants.PLAN_MHP_N, out_N=ModelConstants.PLAN_MHP_SELECTION,
|
||||||
out_shape=(ModelConstants.IDX_N,ModelConstants.PLAN_WIDTH))
|
out_shape=(ModelConstants.IDX_N,ModelConstants.PLAN_WIDTH))
|
||||||
|
self.parse_mdn('lane_lines', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_LANE_LINES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
|
||||||
|
self.parse_mdn('road_edges', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_ROAD_EDGES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
|
||||||
|
self.parse_mdn('sim_pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
||||||
|
self.parse_mdn('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION,
|
||||||
|
out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH))
|
||||||
if 'lat_planner_solution' in outs:
|
if 'lat_planner_solution' in outs:
|
||||||
self.parse_mdn('lat_planner_solution', outs, in_N=0, out_N=0, out_shape=(ModelConstants.IDX_N,ModelConstants.LAT_PLANNER_SOLUTION_WIDTH))
|
self.parse_mdn('lat_planner_solution', outs, in_N=0, out_N=0, out_shape=(ModelConstants.IDX_N,ModelConstants.LAT_PLANNER_SOLUTION_WIDTH))
|
||||||
if 'desired_curvature' in outs:
|
if 'desired_curvature' in outs:
|
||||||
self.parse_mdn('desired_curvature', outs, in_N=0, out_N=0, out_shape=(ModelConstants.DESIRED_CURV_WIDTH,))
|
self.parse_mdn('desired_curvature', outs, in_N=0, out_N=0, out_shape=(ModelConstants.DESIRED_CURV_WIDTH,))
|
||||||
|
for k in ['lead_prob', 'lane_lines_prob']:
|
||||||
|
self.parse_binary_crossentropy(k, outs)
|
||||||
self.parse_categorical_crossentropy('desire_state', outs, out_shape=(ModelConstants.DESIRE_PRED_WIDTH,))
|
self.parse_categorical_crossentropy('desire_state', outs, out_shape=(ModelConstants.DESIRE_PRED_WIDTH,))
|
||||||
return outs
|
return outs
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import cereal.messaging as messaging
|
|||||||
from openpilot.selfdrive.selfdrived.events import Events
|
from openpilot.selfdrive.selfdrived.events import Events
|
||||||
from openpilot.common.realtime import DT_DMON
|
from openpilot.common.realtime import DT_DMON
|
||||||
from openpilot.common.filter_simple import FirstOrderFilter
|
from openpilot.common.filter_simple import FirstOrderFilter
|
||||||
from openpilot.common.params import Params
|
|
||||||
from openpilot.common.stat_live import RunningStatFilter
|
from openpilot.common.stat_live import RunningStatFilter
|
||||||
from openpilot.common.transformations.camera import DEVICE_CAMERAS
|
from openpilot.common.transformations.camera import DEVICE_CAMERAS
|
||||||
|
|
||||||
@@ -160,9 +159,6 @@ class DriverMonitoring:
|
|||||||
self.threshold_pre = self.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL / self.settings._DISTRACTED_TIME
|
self.threshold_pre = self.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL / self.settings._DISTRACTED_TIME
|
||||||
self.threshold_prompt = self.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL / self.settings._DISTRACTED_TIME
|
self.threshold_prompt = self.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL / self.settings._DISTRACTED_TIME
|
||||||
|
|
||||||
self.params = Params()
|
|
||||||
self.too_distracted = self.params.get_bool("DriverTooDistracted")
|
|
||||||
|
|
||||||
self._reset_awareness()
|
self._reset_awareness()
|
||||||
self._set_timers(active_monitoring=True)
|
self._set_timers(active_monitoring=True)
|
||||||
self._reset_events()
|
self._reset_events()
|
||||||
@@ -309,15 +305,10 @@ class DriverMonitoring:
|
|||||||
|
|
||||||
def _update_events(self, driver_engaged, op_engaged, standstill, wrong_gear, car_speed):
|
def _update_events(self, driver_engaged, op_engaged, standstill, wrong_gear, car_speed):
|
||||||
self._reset_events()
|
self._reset_events()
|
||||||
# Block engaging until ignition cycle after max number or time of distractions
|
# Block engaging after max number of distrations or when alert active
|
||||||
if self.terminal_alert_cnt >= self.settings._MAX_TERMINAL_ALERTS or \
|
if self.terminal_alert_cnt >= self.settings._MAX_TERMINAL_ALERTS or \
|
||||||
self.terminal_time >= self.settings._MAX_TERMINAL_DURATION:
|
self.terminal_time >= self.settings._MAX_TERMINAL_DURATION or \
|
||||||
if not self.too_distracted:
|
self.always_on and self.awareness <= self.threshold_prompt:
|
||||||
self.params.put_bool_nonblocking("DriverTooDistracted", True)
|
|
||||||
self.too_distracted = True
|
|
||||||
|
|
||||||
# Always-on distraction lockout is temporary
|
|
||||||
if self.too_distracted or (self.always_on and self.awareness <= self.threshold_prompt):
|
|
||||||
self.current_events.add(EventName.tooDistracted)
|
self.current_events.add(EventName.tooDistracted)
|
||||||
|
|
||||||
always_on_valid = self.always_on and not wrong_gear
|
always_on_valid = self.always_on and not wrong_gear
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "cereal/messaging/messaging.h"
|
#include "cereal/messaging/messaging.h"
|
||||||
#include "selfdrive/pandad/can_types.h"
|
#include "opendbc/can/common.h"
|
||||||
|
|
||||||
void can_list_to_can_capnp_cpp(const std::vector<CanFrame> &can_list, std::string &out, bool sendcan, bool valid) {
|
void can_list_to_can_capnp_cpp(const std::vector<CanFrame> &can_list, std::string &out, bool sendcan, bool valid) {
|
||||||
MessageBuilder msg;
|
MessageBuilder msg;
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
struct CanFrame {
|
|
||||||
long src;
|
|
||||||
uint32_t address;
|
|
||||||
std::vector<uint8_t> dat;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CanData {
|
|
||||||
uint64_t nanos;
|
|
||||||
std::vector<CanFrame> frames;
|
|
||||||
};
|
|
||||||
@@ -2,7 +2,9 @@
|
|||||||
#include "cereal/messaging/messaging.h"
|
#include "cereal/messaging/messaging.h"
|
||||||
#include "common/swaglog.h"
|
#include "common/swaglog.h"
|
||||||
|
|
||||||
void PandaSafety::configureSafetyMode(bool is_onroad) {
|
void PandaSafety::configureSafetyMode() {
|
||||||
|
bool is_onroad = params_.getBool("IsOnroad");
|
||||||
|
|
||||||
if (is_onroad && !safety_configured_) {
|
if (is_onroad && !safety_configured_) {
|
||||||
updateMultiplexingMode();
|
updateMultiplexingMode();
|
||||||
|
|
||||||
|
|||||||
+18
-21
@@ -36,7 +36,8 @@
|
|||||||
// Ignition:
|
// Ignition:
|
||||||
// - If any of the ignition sources in any panda is high, ignition is high
|
// - If any of the ignition sources in any panda is high, ignition is high
|
||||||
|
|
||||||
#define MAX_IR_PANDA_VAL 50
|
#define MAX_IR_POWER 0.5f
|
||||||
|
#define MIN_IR_POWER 0.0f
|
||||||
#define CUTOFF_IL 400
|
#define CUTOFF_IL 400
|
||||||
#define SATURATE_IL 1000
|
#define SATURATE_IL 1000
|
||||||
|
|
||||||
@@ -168,7 +169,7 @@ void fill_panda_state(cereal::PandaState::Builder &ps, cereal::PandaState::Panda
|
|||||||
ps.setFanPower(health.fan_power);
|
ps.setFanPower(health.fan_power);
|
||||||
ps.setFanStallCount(health.fan_stall_count);
|
ps.setFanStallCount(health.fan_stall_count);
|
||||||
ps.setSafetyRxChecksInvalid((bool)(health.safety_rx_checks_invalid_pkt));
|
ps.setSafetyRxChecksInvalid((bool)(health.safety_rx_checks_invalid_pkt));
|
||||||
ps.setSpiErrorCount(health.spi_error_count_pkt);
|
ps.setSpiChecksumErrorCount(health.spi_checksum_error_count_pkt);
|
||||||
ps.setSbu1Voltage(health.sbu1_voltage_mV / 1000.0f);
|
ps.setSbu1Voltage(health.sbu1_voltage_mV / 1000.0f);
|
||||||
ps.setSbu2Voltage(health.sbu2_voltage_mV / 1000.0f);
|
ps.setSbu2Voltage(health.sbu2_voltage_mV / 1000.0f);
|
||||||
}
|
}
|
||||||
@@ -201,7 +202,7 @@ void fill_panda_can_state(cereal::PandaState::PandaCanState::Builder &cs, const
|
|||||||
cs.setCanCoreResetCnt(can_health.can_core_reset_cnt);
|
cs.setCanCoreResetCnt(can_health.can_core_reset_cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool is_onroad, bool spoofing_started, bool always_offroad) {
|
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool spoofing_started, bool always_offroad) {
|
||||||
bool ignition_local = false;
|
bool ignition_local = false;
|
||||||
const uint32_t pandas_cnt = pandas.size();
|
const uint32_t pandas_cnt = pandas.size();
|
||||||
|
|
||||||
@@ -268,9 +269,8 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
|
|||||||
panda->set_power_saving(power_save_desired);
|
panda->set_power_saving(power_save_desired);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set safety mode to NO_OUTPUT when car is off or we're not onroad. ELM327 is an alternative if we want to leverage athenad/connect
|
// set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect
|
||||||
bool should_close_relay = !ignition_local || !is_onroad;
|
if (!ignition_local && (health.safety_mode_pkt != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) {
|
||||||
if (should_close_relay && (health.safety_mode_pkt != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) {
|
|
||||||
panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
|
panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,14 +337,14 @@ void send_peripheral_state(Panda *panda, PubMaster *pm) {
|
|||||||
pm->send("peripheralState", msg);
|
pm->send("peripheralState", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool engaged, bool engaged_mads, bool is_onroad, bool spoofing_started, bool always_offroad) {
|
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;
|
std::vector<std::string> connected_serials;
|
||||||
for (Panda *p : pandas) {
|
for (Panda *p : pandas) {
|
||||||
connected_serials.push_back(p->hw_serial());
|
connected_serials.push_back(p->hw_serial());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto ignition_opt = send_panda_states(pm, pandas, is_onroad, spoofing_started, always_offroad);
|
auto ignition_opt = send_panda_states(pm, pandas, spoofing_started, always_offroad);
|
||||||
if (!ignition_opt) {
|
if (!ignition_opt) {
|
||||||
LOGE("Failed to get ignition_opt");
|
LOGE("Failed to get ignition_opt");
|
||||||
return;
|
return;
|
||||||
@@ -384,8 +384,8 @@ void process_peripheral_state(Panda *panda, PubMaster *pm, bool no_fan_control)
|
|||||||
|
|
||||||
static uint64_t last_driver_camera_t = 0;
|
static uint64_t last_driver_camera_t = 0;
|
||||||
static uint16_t prev_fan_speed = 999;
|
static uint16_t prev_fan_speed = 999;
|
||||||
static int ir_pwr = 0;
|
static uint16_t ir_pwr = 0;
|
||||||
static int prev_ir_pwr = 999;
|
static uint16_t prev_ir_pwr = 999;
|
||||||
|
|
||||||
static FirstOrderFilter integ_lines_filter(0, 30.0, 0.05);
|
static FirstOrderFilter integ_lines_filter(0, 30.0, 0.05);
|
||||||
|
|
||||||
@@ -408,11 +408,11 @@ void process_peripheral_state(Panda *panda, PubMaster *pm, bool no_fan_control)
|
|||||||
last_driver_camera_t = event.getLogMonoTime();
|
last_driver_camera_t = event.getLogMonoTime();
|
||||||
|
|
||||||
if (cur_integ_lines <= CUTOFF_IL) {
|
if (cur_integ_lines <= CUTOFF_IL) {
|
||||||
ir_pwr = 0;
|
ir_pwr = 100.0 * MIN_IR_POWER;
|
||||||
} else if (cur_integ_lines > SATURATE_IL) {
|
} else if (cur_integ_lines > SATURATE_IL) {
|
||||||
ir_pwr = 100;
|
ir_pwr = 100.0 * MAX_IR_POWER;
|
||||||
} else {
|
} else {
|
||||||
ir_pwr = 100 * (cur_integ_lines - CUTOFF_IL) / (SATURATE_IL - CUTOFF_IL);
|
ir_pwr = 100.0 * (MIN_IR_POWER + ((cur_integ_lines - CUTOFF_IL) * (MAX_IR_POWER - MIN_IR_POWER) / (SATURATE_IL - CUTOFF_IL)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,9 +421,8 @@ void process_peripheral_state(Panda *panda, PubMaster *pm, bool no_fan_control)
|
|||||||
ir_pwr = 0;
|
ir_pwr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ir_pwr != prev_ir_pwr || sm.frame % 100 == 0) {
|
if (ir_pwr != prev_ir_pwr || sm.frame % 100 == 0 || ir_pwr >= 50.0) {
|
||||||
int16_t ir_panda = util::map_val(ir_pwr, 0, 100, 0, MAX_IR_PANDA_VAL);
|
panda->set_ir_pwr(ir_pwr);
|
||||||
panda->set_ir_pwr(ir_panda);
|
|
||||||
Hardware::set_ir_power(ir_pwr);
|
Hardware::set_ir_power(ir_pwr);
|
||||||
prev_ir_pwr = ir_pwr;
|
prev_ir_pwr = ir_pwr;
|
||||||
}
|
}
|
||||||
@@ -438,7 +437,6 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
|||||||
// Start the CAN send thread
|
// Start the CAN send thread
|
||||||
std::thread send_thread(can_send_thread, pandas, fake_send);
|
std::thread send_thread(can_send_thread, pandas, fake_send);
|
||||||
|
|
||||||
Params params;
|
|
||||||
RateKeeper rk("pandad", 100);
|
RateKeeper rk("pandad", 100);
|
||||||
SubMaster sm({"selfdriveState", "selfdriveStateSP", "carParams"});
|
SubMaster sm({"selfdriveState", "selfdriveStateSP", "carParams"});
|
||||||
PubMaster pm({"can", "pandaStates", "peripheralState"});
|
PubMaster pm({"can", "pandaStates", "peripheralState"});
|
||||||
@@ -446,7 +444,6 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
|||||||
Panda *peripheral_panda = pandas[0];
|
Panda *peripheral_panda = pandas[0];
|
||||||
bool engaged = false;
|
bool engaged = false;
|
||||||
bool engaged_mads = false;
|
bool engaged_mads = false;
|
||||||
bool is_onroad = false;
|
|
||||||
bool always_offroad = false;
|
bool always_offroad = false;
|
||||||
|
|
||||||
// Main loop: receive CAN data and process states
|
// Main loop: receive CAN data and process states
|
||||||
@@ -463,10 +460,9 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
|||||||
sm.update(0);
|
sm.update(0);
|
||||||
engaged = sm.allAliveAndValid({"selfdriveState"}) && sm["selfdriveState"].getSelfdriveState().getEnabled();
|
engaged = sm.allAliveAndValid({"selfdriveState"}) && sm["selfdriveState"].getSelfdriveState().getEnabled();
|
||||||
engaged_mads = process_mads_heartbeat(&sm);
|
engaged_mads = process_mads_heartbeat(&sm);
|
||||||
is_onroad = params.getBool("IsOnroad");
|
|
||||||
always_offroad = panda_safety.getOffroadMode();
|
always_offroad = panda_safety.getOffroadMode();
|
||||||
process_panda_state(pandas, &pm, engaged, engaged_mads, is_onroad, spoofing_started, always_offroad);
|
process_panda_state(pandas, &pm, engaged, engaged_mads, spoofing_started, always_offroad);
|
||||||
panda_safety.configureSafetyMode(is_onroad);
|
panda_safety.configureSafetyMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send out peripheralState at 2Hz
|
// Send out peripheralState at 2Hz
|
||||||
@@ -491,6 +487,7 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close relay on exit to prevent a fault
|
// Close relay on exit to prevent a fault
|
||||||
|
const bool is_onroad = Params().getBool("IsOnroad");
|
||||||
if (is_onroad && !engaged) {
|
if (is_onroad && !engaged) {
|
||||||
for (auto &p : pandas) {
|
for (auto &p : pandas) {
|
||||||
if (p->connected()) {
|
if (p->connected()) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ void pandad_main_thread(std::vector<std::string> serials);
|
|||||||
class PandaSafety {
|
class PandaSafety {
|
||||||
public:
|
public:
|
||||||
PandaSafety(const std::vector<Panda *> &pandas) : pandas_(pandas) {}
|
PandaSafety(const std::vector<Panda *> &pandas) : pandas_(pandas) {}
|
||||||
void configureSafetyMode(bool is_onroad);
|
void configureSafetyMode();
|
||||||
bool getOffroadMode();
|
bool getOffroadMode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from libcpp.string cimport string
|
|||||||
from libcpp cimport bool
|
from libcpp cimport bool
|
||||||
from libc.stdint cimport uint8_t, uint32_t, uint64_t
|
from libc.stdint cimport uint8_t, uint32_t, uint64_t
|
||||||
|
|
||||||
cdef extern from "selfdrive/pandad/can_types.h":
|
cdef extern from "opendbc/can/common.h":
|
||||||
cdef struct CanFrame:
|
cdef struct CanFrame:
|
||||||
long src
|
long src
|
||||||
uint32_t address
|
uint32_t address
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ def set_offroad_alert(alert: str, show_alert: bool, extra_text: str = None) -> N
|
|||||||
if show_alert:
|
if show_alert:
|
||||||
a = copy.copy(OFFROAD_ALERTS[alert])
|
a = copy.copy(OFFROAD_ALERTS[alert])
|
||||||
a['extra'] = extra_text or ''
|
a['extra'] = extra_text or ''
|
||||||
Params().put(alert, a)
|
Params().put(alert, json.dumps(a))
|
||||||
else:
|
else:
|
||||||
Params().remove(alert)
|
Params().remove(alert)
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,18 @@
|
|||||||
"text": "An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install.",
|
"text": "An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install.",
|
||||||
"severity": 0
|
"severity": 0
|
||||||
},
|
},
|
||||||
"Offroad_UnregisteredHardware": {
|
"Offroad_UnofficialHardware": {
|
||||||
"text": "Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support.",
|
"text": "Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support.",
|
||||||
"severity": 1
|
"severity": 1
|
||||||
},
|
},
|
||||||
"Offroad_StorageMissing": {
|
"Offroad_StorageMissing": {
|
||||||
"text": "NVMe drive not mounted.",
|
"text": "NVMe drive not mounted.",
|
||||||
"severity": 1
|
"severity": 1
|
||||||
},
|
},
|
||||||
|
"Offroad_BadNvme": {
|
||||||
|
"text": "Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe.",
|
||||||
|
"severity": 1
|
||||||
|
},
|
||||||
"Offroad_CarUnrecognized": {
|
"Offroad_CarUnrecognized": {
|
||||||
"text": "sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai.",
|
"text": "sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai.",
|
||||||
"severity": 0
|
"severity": 0
|
||||||
@@ -44,10 +48,5 @@
|
|||||||
"Offroad_OSMUpdateRequired": {
|
"Offroad_OSMUpdateRequired": {
|
||||||
"text": "OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display.\n\n%1",
|
"text": "OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display.\n\n%1",
|
||||||
"severity": 0
|
"severity": 0
|
||||||
},
|
|
||||||
"Offroad_ExcessiveActuation": {
|
|
||||||
"text": "openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support.",
|
|
||||||
"severity": 1,
|
|
||||||
"_comment": "Set extra field to lateral or longitudinal."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -591,11 +591,6 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
|||||||
ET.NO_ENTRY: NoEntryAlert("Distraction Level Too High"),
|
ET.NO_ENTRY: NoEntryAlert("Distraction Level Too High"),
|
||||||
},
|
},
|
||||||
|
|
||||||
EventName.excessiveActuation: {
|
|
||||||
ET.SOFT_DISABLE: soft_disable_alert("Excessive Actuation"),
|
|
||||||
ET.NO_ENTRY: NoEntryAlert("Excessive Actuation"),
|
|
||||||
},
|
|
||||||
|
|
||||||
EventName.overheat: {
|
EventName.overheat: {
|
||||||
ET.PERMANENT: overheat_alert,
|
ET.PERMANENT: overheat_alert,
|
||||||
ET.SOFT_DISABLE: soft_disable_alert("System Overheated"),
|
ET.SOFT_DISABLE: soft_disable_alert("System Overheated"),
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import cereal.messaging as messaging
|
|||||||
|
|
||||||
from cereal import car, log, custom
|
from cereal import car, log, custom
|
||||||
from msgq.visionipc import VisionIpcClient, VisionStreamType
|
from msgq.visionipc import VisionIpcClient, VisionStreamType
|
||||||
from opendbc.car.interfaces import ACCEL_MIN, ACCEL_MAX
|
|
||||||
|
|
||||||
|
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
@@ -16,7 +15,6 @@ from openpilot.common.swaglog import cloudlog
|
|||||||
from openpilot.common.gps import get_gps_location_service
|
from openpilot.common.gps import get_gps_location_service
|
||||||
|
|
||||||
from openpilot.selfdrive.car.car_specific import CarSpecificEvents
|
from openpilot.selfdrive.car.car_specific import CarSpecificEvents
|
||||||
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
|
|
||||||
from openpilot.selfdrive.selfdrived.events import Events, ET
|
from openpilot.selfdrive.selfdrived.events import Events, ET
|
||||||
from openpilot.selfdrive.selfdrived.state import StateMachine
|
from openpilot.selfdrive.selfdrived.state import StateMachine
|
||||||
from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroad_alert
|
from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroad_alert
|
||||||
@@ -32,9 +30,7 @@ from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
|
|||||||
REPLAY = "REPLAY" in os.environ
|
REPLAY = "REPLAY" in os.environ
|
||||||
SIMULATION = "SIMULATION" in os.environ
|
SIMULATION = "SIMULATION" in os.environ
|
||||||
TESTING_CLOSET = "TESTING_CLOSET" in os.environ
|
TESTING_CLOSET = "TESTING_CLOSET" in os.environ
|
||||||
|
|
||||||
LONGITUDINAL_PERSONALITY_MAP = {v: k for k, v in log.LongitudinalPersonality.schema.enumerants.items()}
|
LONGITUDINAL_PERSONALITY_MAP = {v: k for k, v in log.LongitudinalPersonality.schema.enumerants.items()}
|
||||||
MIN_EXCESSIVE_ACTUATION_COUNT = int(0.25 / DT_CTRL)
|
|
||||||
|
|
||||||
ThermalStatus = log.DeviceState.ThermalStatus
|
ThermalStatus = log.DeviceState.ThermalStatus
|
||||||
State = log.SelfdriveState.OpenpilotState
|
State = log.SelfdriveState.OpenpilotState
|
||||||
@@ -48,21 +44,6 @@ SafetyModel = car.CarParams.SafetyModel
|
|||||||
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
|
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
|
||||||
|
|
||||||
|
|
||||||
def check_excessive_actuation(sm: messaging.SubMaster, CS: car.CarState, calibrator: PoseCalibrator, counter: int) -> tuple[int, bool]:
|
|
||||||
# CS.aEgo can be noisy to bumps in the road, transitioning from standstill, losing traction, etc.
|
|
||||||
device_pose = Pose.from_live_pose(sm['livePose'])
|
|
||||||
calibrated_pose = calibrator.build_calibrated_pose(device_pose)
|
|
||||||
accel_calibrated = calibrated_pose.acceleration.x
|
|
||||||
|
|
||||||
# livePose acceleration can be noisy due to bad mounting or aliased livePose measurements
|
|
||||||
accel_valid = abs(CS.aEgo - accel_calibrated) < 2
|
|
||||||
|
|
||||||
excessive_actuation = accel_calibrated > ACCEL_MAX * 2 or accel_calibrated < ACCEL_MIN * 2
|
|
||||||
counter = counter + 1 if sm['carControl'].longActive and excessive_actuation and accel_valid else 0
|
|
||||||
|
|
||||||
return counter, counter > MIN_EXCESSIVE_ACTUATION_COUNT
|
|
||||||
|
|
||||||
|
|
||||||
class SelfdriveD(CruiseHelper):
|
class SelfdriveD(CruiseHelper):
|
||||||
def __init__(self, CP=None, CP_SP=None):
|
def __init__(self, CP=None, CP_SP=None):
|
||||||
self.params = Params()
|
self.params = Params()
|
||||||
@@ -85,7 +66,6 @@ class SelfdriveD(CruiseHelper):
|
|||||||
self.CP_SP = CP_SP
|
self.CP_SP = CP_SP
|
||||||
|
|
||||||
self.car_events = CarSpecificEvents(self.CP)
|
self.car_events = CarSpecificEvents(self.CP)
|
||||||
self.calibrator = PoseCalibrator()
|
|
||||||
|
|
||||||
# Setup sockets
|
# Setup sockets
|
||||||
self.pm = messaging.PubMaster(['selfdriveState', 'onroadEvents'] + ['selfdriveStateSP', 'onroadEventsSP'])
|
self.pm = messaging.PubMaster(['selfdriveState', 'onroadEvents'] + ['selfdriveStateSP', 'onroadEventsSP'])
|
||||||
@@ -141,10 +121,8 @@ class SelfdriveD(CruiseHelper):
|
|||||||
self.logged_comm_issue = None
|
self.logged_comm_issue = None
|
||||||
self.not_running_prev = None
|
self.not_running_prev = None
|
||||||
self.experimental_mode = False
|
self.experimental_mode = False
|
||||||
self.personality = self.params.get("LongitudinalPersonality", return_default=True)
|
self.personality = self.read_personality_param()
|
||||||
self.recalibrating_seen = False
|
self.recalibrating_seen = False
|
||||||
self.excessive_actuation = self.params.get("Offroad_ExcessiveActuation") is not None
|
|
||||||
self.excessive_actuation_counter = 0
|
|
||||||
self.state_machine = StateMachine()
|
self.state_machine = StateMachine()
|
||||||
self.rk = Ratekeeper(100, print_delay_threshold=None)
|
self.rk = Ratekeeper(100, print_delay_threshold=None)
|
||||||
|
|
||||||
@@ -157,8 +135,7 @@ class SelfdriveD(CruiseHelper):
|
|||||||
self.ignored_processes.update({'mapd'})
|
self.ignored_processes.update({'mapd'})
|
||||||
|
|
||||||
# Determine startup event
|
# Determine startup event
|
||||||
is_remote = build_metadata.openpilot.comma_remote or build_metadata.openpilot.sunnypilot_remote
|
self.startup_event = EventName.startup if build_metadata.openpilot.comma_remote and build_metadata.tested_channel else EventName.startupMaster
|
||||||
self.startup_event = EventName.startup if is_remote and build_metadata.tested_channel else EventName.startupMaster
|
|
||||||
if not car_recognized:
|
if not car_recognized:
|
||||||
self.startup_event = EventName.startupNoCar
|
self.startup_event = EventName.startupNoCar
|
||||||
elif car_recognized and self.CP.passive:
|
elif car_recognized and self.CP.passive:
|
||||||
@@ -276,18 +253,6 @@ class SelfdriveD(CruiseHelper):
|
|||||||
if self.sm['driverAssistance'].leftLaneDeparture or self.sm['driverAssistance'].rightLaneDeparture:
|
if self.sm['driverAssistance'].leftLaneDeparture or self.sm['driverAssistance'].rightLaneDeparture:
|
||||||
self.events.add(EventName.ldw)
|
self.events.add(EventName.ldw)
|
||||||
|
|
||||||
# Check for excessive (longitudinal) actuation
|
|
||||||
if self.sm.updated['liveCalibration']:
|
|
||||||
self.calibrator.feed_live_calib(self.sm['liveCalibration'])
|
|
||||||
|
|
||||||
self.excessive_actuation_counter, excessive_actuation = check_excessive_actuation(self.sm, CS, self.calibrator, self.excessive_actuation_counter)
|
|
||||||
if not self.excessive_actuation and excessive_actuation:
|
|
||||||
set_offroad_alert("Offroad_ExcessiveActuation", True, extra_text="longitudinal")
|
|
||||||
self.excessive_actuation = True
|
|
||||||
|
|
||||||
if self.excessive_actuation:
|
|
||||||
self.events.add(EventName.excessiveActuation)
|
|
||||||
|
|
||||||
# Handle lane change
|
# Handle lane change
|
||||||
if self.sm['modelV2'].meta.laneChangeState == LaneChangeState.preLaneChange:
|
if self.sm['modelV2'].meta.laneChangeState == LaneChangeState.preLaneChange:
|
||||||
direction = self.sm['modelV2'].meta.laneChangeDirection
|
direction = self.sm['modelV2'].meta.laneChangeDirection
|
||||||
@@ -441,13 +406,13 @@ class SelfdriveD(CruiseHelper):
|
|||||||
if any(not be.pressed and be.type == ButtonType.gapAdjustCruise for be in CS.buttonEvents):
|
if any(not be.pressed and be.type == ButtonType.gapAdjustCruise for be in CS.buttonEvents):
|
||||||
if not self.experimental_mode_switched:
|
if not self.experimental_mode_switched:
|
||||||
self.personality = (self.personality - 1) % 3
|
self.personality = (self.personality - 1) % 3
|
||||||
self.params.put_nonblocking('LongitudinalPersonality', self.personality)
|
self.params.put_nonblocking('LongitudinalPersonality', str(self.personality))
|
||||||
self.events.add(EventName.personalityChanged)
|
self.events.add(EventName.personalityChanged)
|
||||||
self.experimental_mode_switched = False
|
self.experimental_mode_switched = False
|
||||||
|
|
||||||
def data_sample(self):
|
def data_sample(self):
|
||||||
_car_state = messaging.recv_one(self.car_state_sock)
|
car_state = messaging.recv_one(self.car_state_sock)
|
||||||
CS = _car_state.carState if _car_state else self.CS_prev
|
CS = car_state.carState if car_state else self.CS_prev
|
||||||
|
|
||||||
self.sm.update(0)
|
self.sm.update(0)
|
||||||
|
|
||||||
@@ -572,13 +537,19 @@ class SelfdriveD(CruiseHelper):
|
|||||||
|
|
||||||
self.CS_prev = CS
|
self.CS_prev = CS
|
||||||
|
|
||||||
|
def read_personality_param(self):
|
||||||
|
try:
|
||||||
|
return int(self.params.get('LongitudinalPersonality'))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return log.LongitudinalPersonality.standard
|
||||||
|
|
||||||
def params_thread(self, evt):
|
def params_thread(self, evt):
|
||||||
while not evt.is_set():
|
while not evt.is_set():
|
||||||
self.is_metric = self.params.get_bool("IsMetric")
|
self.is_metric = self.params.get_bool("IsMetric")
|
||||||
self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
|
self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
|
||||||
self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
|
self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
|
||||||
self.experimental_mode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl
|
self.experimental_mode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl
|
||||||
self.personality = self.params.get("LongitudinalPersonality", return_default=True)
|
self.personality = self.read_personality_param()
|
||||||
|
|
||||||
self.mads.read_params()
|
self.mads.read_params()
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class TestAlerts:
|
|||||||
alert = copy.copy(self.offroad_alerts[a])
|
alert = copy.copy(self.offroad_alerts[a])
|
||||||
set_offroad_alert(a, True)
|
set_offroad_alert(a, True)
|
||||||
alert['extra'] = ''
|
alert['extra'] = ''
|
||||||
assert alert == params.get(a)
|
assert json.dumps(alert) == params.get(a, encoding='utf8')
|
||||||
|
|
||||||
# then delete it
|
# then delete it
|
||||||
set_offroad_alert(a, False)
|
set_offroad_alert(a, False)
|
||||||
@@ -125,6 +125,6 @@ class TestAlerts:
|
|||||||
alert = self.offroad_alerts[a]
|
alert = self.offroad_alerts[a]
|
||||||
set_offroad_alert(a, True, extra_text="a"*i)
|
set_offroad_alert(a, True, extra_text="a"*i)
|
||||||
|
|
||||||
written_alert = params.get(a)
|
written_alert = json.loads(params.get(a, encoding='utf8'))
|
||||||
assert "a"*i == written_alert['extra']
|
assert "a"*i == written_alert['extra']
|
||||||
assert alert["text"] == written_alert['text']
|
assert alert["text"] == written_alert['text']
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
c289a0359d1b1f26cf4d9e73a2c04b2bbfec840f
|
f440c9e0469d32d350aa99ddaa8f44591a2ce690
|
||||||
@@ -147,7 +147,7 @@ class TestOnroad:
|
|||||||
while not sm.seen['carState']:
|
while not sm.seen['carState']:
|
||||||
sm.update(1000)
|
sm.update(1000)
|
||||||
|
|
||||||
route = params.get("CurrentRoute")
|
route = params.get("CurrentRoute", encoding="utf-8")
|
||||||
assert route is not None
|
assert route is not None
|
||||||
|
|
||||||
segs = list(Path(Paths.log_root()).glob(f"{route}--*"))
|
segs = list(Path(Paths.log_root()).glob(f"{route}--*"))
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class TestUpdated:
|
|||||||
ret = None
|
ret = None
|
||||||
start_time = time.monotonic()
|
start_time = time.monotonic()
|
||||||
while ret is None:
|
while ret is None:
|
||||||
ret = self.params.get(key)
|
ret = self.params.get(key, encoding='utf8')
|
||||||
if time.monotonic() - start_time > timeout:
|
if time.monotonic() - start_time > timeout:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
@@ -162,7 +162,8 @@ class TestUpdated:
|
|||||||
|
|
||||||
def _check_update_state(self, update_available):
|
def _check_update_state(self, update_available):
|
||||||
# make sure LastUpdateTime is recent
|
# make sure LastUpdateTime is recent
|
||||||
last_update_time = self._read_param("LastUpdateTime")
|
t = self._read_param("LastUpdateTime")
|
||||||
|
last_update_time = datetime.datetime.fromisoformat(t)
|
||||||
td = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - last_update_time
|
td = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - last_update_time
|
||||||
assert td.total_seconds() < 10
|
assert td.total_seconds() < 10
|
||||||
self.params.remove("LastUpdateTime")
|
self.params.remove("LastUpdateTime")
|
||||||
@@ -173,7 +174,7 @@ class TestUpdated:
|
|||||||
# check params
|
# check params
|
||||||
update = self._read_param("UpdateAvailable")
|
update = self._read_param("UpdateAvailable")
|
||||||
assert update == "1" == update_available, f"UpdateAvailable: {repr(update)}"
|
assert update == "1" == update_available, f"UpdateAvailable: {repr(update)}"
|
||||||
assert self._read_param("UpdateFailedCount") == 0
|
assert self._read_param("UpdateFailedCount") == "0"
|
||||||
|
|
||||||
# TODO: check that the finalized update actually matches remote
|
# TODO: check that the finalized update actually matches remote
|
||||||
# check the .overlay_init and .overlay_consistent flags
|
# check the .overlay_init and .overlay_consistent flags
|
||||||
|
|||||||
@@ -72,10 +72,14 @@ if GetOption('extras'):
|
|||||||
|
|
||||||
qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs)
|
qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs)
|
||||||
|
|
||||||
# setup
|
# setup and factory resetter
|
||||||
|
qt_env.Program("qt/setup/reset", ["qt/setup/reset.cc"], LIBS=qt_libs)
|
||||||
qt_env.Program("qt/setup/setup", ["qt/setup/setup.cc", asset_obj],
|
qt_env.Program("qt/setup/setup", ["qt/setup/setup.cc", asset_obj],
|
||||||
LIBS=qt_libs + ['curl', 'common'])
|
LIBS=qt_libs + ['curl', 'common'])
|
||||||
|
|
||||||
|
# build updater UI
|
||||||
|
qt_env.Program("qt/setup/updater", ["qt/setup/updater.cc", asset_obj], LIBS=qt_libs)
|
||||||
|
|
||||||
if arch != "Darwin":
|
if arch != "Darwin":
|
||||||
# build installers
|
# build installers
|
||||||
raylib_env = env.Clone()
|
raylib_env = env.Clone()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from openpilot.selfdrive.ui.widgets.prime import PrimeWidget
|
|||||||
from openpilot.selfdrive.ui.widgets.setup import SetupWidget
|
from openpilot.selfdrive.ui.widgets.setup import SetupWidget
|
||||||
from openpilot.system.ui.lib.text_measure import measure_text_cached
|
from openpilot.system.ui.lib.text_measure import measure_text_cached
|
||||||
from openpilot.system.ui.lib.application import gui_app, FontWeight, DEFAULT_TEXT_COLOR
|
from openpilot.system.ui.lib.application import gui_app, FontWeight, DEFAULT_TEXT_COLOR
|
||||||
from openpilot.system.ui.widgets import Widget
|
from openpilot.system.ui.lib.widget import Widget
|
||||||
|
|
||||||
HEADER_HEIGHT = 80
|
HEADER_HEIGHT = 80
|
||||||
HEAD_BUTTON_FONT_SIZE = 40
|
HEAD_BUTTON_FONT_SIZE = 40
|
||||||
@@ -67,7 +67,7 @@ class HomeLayout(Widget):
|
|||||||
self.current_state = state
|
self.current_state = state
|
||||||
|
|
||||||
def _render(self, rect: rl.Rectangle):
|
def _render(self, rect: rl.Rectangle):
|
||||||
current_time = time.monotonic()
|
current_time = time.time()
|
||||||
if current_time - self.last_refresh >= REFRESH_INTERVAL:
|
if current_time - self.last_refresh >= REFRESH_INTERVAL:
|
||||||
self._refresh()
|
self._refresh()
|
||||||
self.last_refresh = current_time
|
self.last_refresh = current_time
|
||||||
@@ -210,5 +210,5 @@ class HomeLayout(Widget):
|
|||||||
|
|
||||||
def _get_version_text(self) -> str:
|
def _get_version_text(self) -> str:
|
||||||
brand = "openpilot"
|
brand = "openpilot"
|
||||||
description = self.params.get("UpdaterCurrentDescription")
|
description = self.params.get("UpdaterCurrentDescription", encoding='utf-8')
|
||||||
return f"{brand} {description}" if description else brand
|
return f"{brand} {description}" if description else brand
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import cereal.messaging as messaging
|
|||||||
from openpilot.selfdrive.ui.layouts.sidebar import Sidebar, SIDEBAR_WIDTH
|
from openpilot.selfdrive.ui.layouts.sidebar import Sidebar, SIDEBAR_WIDTH
|
||||||
from openpilot.selfdrive.ui.layouts.home import HomeLayout
|
from openpilot.selfdrive.ui.layouts.home import HomeLayout
|
||||||
from openpilot.selfdrive.ui.layouts.settings.settings import SettingsLayout, PanelType
|
from openpilot.selfdrive.ui.layouts.settings.settings import SettingsLayout, PanelType
|
||||||
from openpilot.selfdrive.ui.onroad.augmented_road_view import AugmentedRoadView
|
|
||||||
from openpilot.selfdrive.ui.ui_state import device, ui_state
|
from openpilot.selfdrive.ui.ui_state import device, ui_state
|
||||||
from openpilot.system.ui.widgets import Widget
|
from openpilot.selfdrive.ui.onroad.augmented_road_view import AugmentedRoadView
|
||||||
|
from openpilot.system.ui.lib.widget import Widget
|
||||||
|
|
||||||
|
|
||||||
class MainState(IntEnum):
|
class MainState(IntEnum):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import pyray as rl
|
import pyray as rl
|
||||||
|
from openpilot.system.ui.lib.widget import Widget
|
||||||
from openpilot.system.ui.lib.wifi_manager import WifiManagerWrapper
|
from openpilot.system.ui.lib.wifi_manager import WifiManagerWrapper
|
||||||
from openpilot.system.ui.widgets import Widget
|
|
||||||
from openpilot.system.ui.widgets.network import WifiManagerUI
|
from openpilot.system.ui.widgets.network import WifiManagerUI
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
from openpilot.system.ui.lib.list_view import toggle_item
|
||||||
|
from openpilot.system.ui.lib.scroller import Scroller
|
||||||
|
from openpilot.system.ui.lib.widget import Widget
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.selfdrive.ui.widgets.ssh_key import ssh_key_item
|
from openpilot.selfdrive.ui.widgets.ssh_key import ssh_key_item
|
||||||
from openpilot.system.ui.widgets import Widget
|
|
||||||
from openpilot.system.ui.widgets.list_view import toggle_item
|
|
||||||
from openpilot.system.ui.widgets.scroller import Scroller
|
|
||||||
|
|
||||||
# Description constants
|
# Description constants
|
||||||
DESCRIPTIONS = {
|
DESCRIPTIONS = {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user