mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-06-22 01:32:07 +08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 924eb1aa57 | |||
| 4faeedec57 | |||
| 638a92bffb | |||
| ad2fab062e | |||
| d5b59d2b19 | |||
| 079ce94cb4 | |||
| f7efd7c641 | |||
| 30907c3cf9 | |||
| a39bc65883 | |||
| 2cc3755760 | |||
| abf836a2b8 | |||
| 3c100e3d92 | |||
| cda3c90468 | |||
| 2c66b6bb75 | |||
| ee12e4b7b4 | |||
| a7751702b7 | |||
| eaa0b44f71 | |||
| 445b101a8b | |||
| 64cc311161 |
@@ -3,4 +3,3 @@ REGIST
|
|||||||
PullRequest
|
PullRequest
|
||||||
cancelled
|
cancelled
|
||||||
FOF
|
FOF
|
||||||
NoO
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
ci:
|
ci:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: "{.github/**,**/test_*,**/test/**,Jenkinsfile}"
|
- any-glob-to-all-files: "{.github/**,**/test_*,Jenkinsfile}"
|
||||||
|
|
||||||
chore:
|
chore:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
|
|||||||
@@ -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,21 +29,21 @@ 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'
|
PR_LABEL: 'dev-c3'
|
||||||
TRUST_FORK_PR_LABEL: 'trust-fork-pr'
|
TRUST_FORK_PR_LABEL: 'trust-fork-pr'
|
||||||
steps:
|
steps:
|
||||||
- name: Check if PR has dev label
|
- name: Check if PR has dev-c3 label
|
||||||
id: check-labels
|
id: check-labels
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
@@ -62,24 +62,24 @@ jobs:
|
|||||||
console.log(`PR #${prNumber} has ${process.env.PR_LABEL} label: ${hasDevC3Label}`);
|
console.log(`PR #${prNumber} has ${process.env.PR_LABEL} label: ${hasDevC3Label}`);
|
||||||
console.log(`PR #${prNumber} has ${process.env.TRUST_FORK_PR_LABEL} label: ${hasTrustLabel}`);
|
console.log(`PR #${prNumber} has ${process.env.TRUST_FORK_PR_LABEL} label: ${hasTrustLabel}`);
|
||||||
|
|
||||||
core.setOutput('has-dev', 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 == '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
|
||||||
with:
|
with:
|
||||||
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,40 +1,21 @@
|
|||||||
name: Build and push all tinygrad models
|
name: Build All Tinygrad Models and Push to GitLab
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
set_min_version:
|
branch:
|
||||||
description: 'Minimum selector version required for the models (see helpers.py or readme.md)'
|
description: 'Branch to run workflow from'
|
||||||
required: true
|
required: false
|
||||||
|
default: 'master-new'
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
setup:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
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 }}
|
json_file: ${{ steps.get-json.outputs.json_file }}
|
||||||
model_matrix: ${{ steps.set-matrix.outputs.model_matrix }}
|
|
||||||
tinygrad_ref: ${{ steps.get-tinygrad-ref.outputs.tinygrad_ref }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sunnypilot repo
|
- name: Checkout docs repo
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: sunnypilot/sunnypilot
|
|
||||||
path: sunnypilot
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- name: Get tinygrad_repo ref
|
|
||||||
id: get-tinygrad-ref
|
|
||||||
run: |
|
|
||||||
cd sunnypilot
|
|
||||||
export PYTHONPATH=$(pwd)
|
|
||||||
ref=$(python3 sunnypilot/models/tinygrad_ref.py)
|
|
||||||
echo "tinygrad_ref=$ref" >> $GITHUB_OUTPUT
|
|
||||||
echo "tinygrad_ref is $ref"
|
|
||||||
|
|
||||||
- name: Checkout docs repo (sunnypilot-docs, gh-pages)
|
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: sunnypilot/sunnypilot-docs
|
repository: sunnypilot/sunnypilot-docs
|
||||||
@@ -42,7 +23,7 @@ jobs:
|
|||||||
path: docs
|
path: docs
|
||||||
ssh-key: ${{ secrets.CI_SUNNYPILOT_DOCS_PRIVATE_KEY }}
|
ssh-key: ${{ secrets.CI_SUNNYPILOT_DOCS_PRIVATE_KEY }}
|
||||||
|
|
||||||
- name: Get next JSON version to use (from GitHub docs repo)
|
- name: Get next JSON version to use
|
||||||
id: get-json
|
id: get-json
|
||||||
run: |
|
run: |
|
||||||
cd docs/docs
|
cd docs/docs
|
||||||
@@ -50,131 +31,19 @@ jobs:
|
|||||||
next=$((latest+1))
|
next=$((latest+1))
|
||||||
json_file="driving_models_v${next}.json"
|
json_file="driving_models_v${next}.json"
|
||||||
cp "driving_models_v${latest}.json" "$json_file"
|
cp "driving_models_v${latest}.json" "$json_file"
|
||||||
echo "json_file=docs/docs/$json_file" >> $GITHUB_OUTPUT
|
echo "json_file=$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
|
- name: Upload context for next jobs
|
||||||
id: set-matrix
|
uses: actions/upload-artifact@v4
|
||||||
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:
|
with:
|
||||||
ssh-private-key: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
name: context
|
||||||
- run: |
|
path: docs
|
||||||
mkdir -p ~/.ssh
|
|
||||||
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
|
||||||
|
|
||||||
- name: Clone GitLab docs repo and create new recompiled dir
|
build-all:
|
||||||
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
|
runs-on: ubuntu-latest
|
||||||
if: ${{ needs.setup.result != 'failure' && !cancelled() }}
|
needs: setup
|
||||||
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:
|
env:
|
||||||
RECOMPILED_DIR: recompiled${{ needs.setup.outputs.recompiled_dir }}
|
JSON_FILE: docs/docs/${{ needs.setup.outputs.json_file }}
|
||||||
JSON_FILE: ${{ needs.setup.outputs.json_file }}
|
|
||||||
ARTIFACT_NAME_INPUT: ${{ matrix.model.display_name }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up SSH
|
- name: Set up SSH
|
||||||
uses: webfactory/ssh-agent@v0.9.0
|
uses: webfactory/ssh-agent@v0.9.0
|
||||||
@@ -193,73 +62,138 @@ jobs:
|
|||||||
echo "Cloning GitLab"
|
echo "Cloning GitLab"
|
||||||
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/docs.sunnypilot.ai2.git gitlab_docs
|
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/docs.sunnypilot.ai2.git gitlab_docs
|
||||||
cd gitlab_docs
|
cd gitlab_docs
|
||||||
echo "checkout models/${RECOMPILED_DIR}"
|
|
||||||
git sparse-checkout set --no-cone models/${RECOMPILED_DIR}
|
|
||||||
git checkout main
|
git checkout main
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
- name: Checkout docs repo
|
- name: Set next recompiled dir
|
||||||
uses: actions/checkout@v4
|
id: set-recompiled
|
||||||
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: |
|
run: |
|
||||||
if [ ! -d "gitlab_docs/models/$RECOMPILED_DIR" ]; then
|
cd gitlab_docs/models
|
||||||
echo "Recompiled dir $RECOMPILED_DIR does not exist in GitLab repo"
|
latest_dir=$(ls -d recompiled* 2>/dev/null | sed -E 's/recompiled([0-9]+)/\1/' | sort -n | tail -1)
|
||||||
exit 1
|
if [[ -z "$latest_dir" ]]; then
|
||||||
fi
|
next_dir=1
|
||||||
if [ ! -f "$JSON_FILE" ]; then
|
else
|
||||||
echo "JSON file $JSON_FILE does not exist!"
|
next_dir=$((latest_dir+1))
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
recompiled_dir="recompiled${next_dir}"
|
||||||
|
mkdir -p "$recompiled_dir"
|
||||||
|
echo "RECOMPILED_DIR=$recompiled_dir" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Download artifact name file
|
- name: Download context
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifact-name-${{ env.ARTIFACT_NAME_INPUT }}
|
name: context
|
||||||
path: artifact_name
|
path: .
|
||||||
|
|
||||||
- name: Read artifact name
|
- name: Install dependencies
|
||||||
id: read-artifact-name
|
|
||||||
run: |
|
run: |
|
||||||
ARTIFACT_NAME=$(cat artifact_name/artifact_name.txt)
|
sudo apt-get update
|
||||||
echo "artifact_name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
|
sudo apt-get install -y jq gh
|
||||||
|
|
||||||
- name: Download model artifact
|
- name: Build all tinygrad models
|
||||||
uses: actions/download-artifact@v4
|
id: trigger-builds
|
||||||
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:
|
env:
|
||||||
ARTIFACT_NAME: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
ARTIFACT_DIR="gitlab_docs/models/${RECOMPILED_DIR}/${ARTIFACT_NAME}"
|
set -e
|
||||||
mkdir -p "$ARTIFACT_DIR"
|
> triggered_run_ids.txt
|
||||||
for path in output/*; do
|
BRANCH="${{ github.event.inputs.branch }}"
|
||||||
if [ "$(basename "$path")" = "artifact_name.txt" ]; then
|
jq -c '.bundles[] | select(.runner=="tinygrad")' "$JSON_FILE" | while read -r bundle; do
|
||||||
continue
|
ref=$(echo "$bundle" | jq -r '.ref')
|
||||||
|
display_name=$(echo "$bundle" | jq -r '.display_name' | sed 's/ ([^)]*)//g')
|
||||||
|
is_20hz=$(echo "$bundle" | jq -r '.is_20hz')
|
||||||
|
echo "Triggering build for: $display_name ($ref) [20Hz: $is_20hz]"
|
||||||
|
START_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
gh workflow run sunnypilot-build-model.yaml \
|
||||||
|
--repo sunnypilot/sunnypilot \
|
||||||
|
--ref "$BRANCH" \
|
||||||
|
-f upstream_branch="$ref" \
|
||||||
|
-f custom_name="$display_name" \
|
||||||
|
-f is_20hz="$is_20hz"
|
||||||
|
for i in {1..24}; do
|
||||||
|
RUN_ID=$(gh run list --repo sunnypilot/sunnypilot --workflow=sunnypilot-build-model.yaml --branch="$BRANCH" --created ">$START_TIME" --limit=1 --json databaseId --jq '.[0].databaseId')
|
||||||
|
if [ -n "$RUN_ID" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
if [ -z "$RUN_ID" ]; then
|
||||||
|
echo "ould not find the triggered workflow run for $display_name ($ref)"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
name="$(basename "$path")"
|
echo "$RUN_ID" >> triggered_run_ids.txt
|
||||||
if [ -d "$path" ]; then
|
done
|
||||||
mkdir -p "$ARTIFACT_DIR/$name"
|
|
||||||
cp -r "$path"/* "$ARTIFACT_DIR/$name/"
|
- name: Wait for all model builds to finish
|
||||||
echo "Copied dir $name -> $ARTIFACT_DIR/$name"
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
SUCCESS_RUNS=()
|
||||||
|
FAILED_RUNS=()
|
||||||
|
declare -A RUN_ID_TO_NAME
|
||||||
|
|
||||||
|
while read -r RUN_ID; do
|
||||||
|
ARTIFACT_NAME=$(gh api repos/sunnypilot/sunnypilot/actions/runs/$RUN_ID/artifacts --jq '.artifacts[] | select(.name | startswith("model-")) | .name' || echo "unknown")
|
||||||
|
RUN_ID_TO_NAME["$RUN_ID"]="$ARTIFACT_NAME"
|
||||||
|
done < triggered_run_ids.txt
|
||||||
|
|
||||||
|
while read -r RUN_ID; do
|
||||||
|
echo "Watching run ID: $RUN_ID"
|
||||||
|
gh run watch "$RUN_ID" --repo sunnypilot/sunnypilot
|
||||||
|
CONCLUSION=$(gh run view "$RUN_ID" --repo sunnypilot/sunnypilot --json conclusion --jq '.conclusion')
|
||||||
|
ARTIFACT_NAME="${RUN_ID_TO_NAME[$RUN_ID]}"
|
||||||
|
echo "Run $RUN_ID ($ARTIFACT_NAME) concluded with: $CONCLUSION"
|
||||||
|
if [[ "$CONCLUSION" == "success" ]]; then
|
||||||
|
SUCCESS_RUNS+=("$RUN_ID")
|
||||||
else
|
else
|
||||||
cp "$path" "$ARTIFACT_DIR/"
|
FAILED_RUNS+=("$RUN_ID")
|
||||||
echo "Copied file $name -> $ARTIFACT_DIR/"
|
|
||||||
fi
|
fi
|
||||||
|
done < triggered_run_ids.txt
|
||||||
|
|
||||||
|
if [[ ${#SUCCESS_RUNS[@]} -eq 0 ]]; then
|
||||||
|
echo "All model builds failed. Aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#FAILED_RUNS[@]} -gt 0 ]]; then
|
||||||
|
echo "WARNING: The following model builds failed:"
|
||||||
|
for RUN_ID in "${FAILED_RUNS[@]}"; do
|
||||||
|
echo "- $RUN_ID (${RUN_ID_TO_NAME[$RUN_ID]})"
|
||||||
|
done
|
||||||
|
echo "You may want to rerun these models manually."
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Download and extract all model artifacts
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
ARTIFACT_DIR="gitlab_docs/models/$RECOMPILED_DIR"
|
||||||
|
SUCCESS_RUNS=()
|
||||||
|
while read -r RUN_ID; do
|
||||||
|
CONCLUSION=$(gh run view "$RUN_ID" --repo sunnypilot/sunnypilot --json conclusion --jq '.conclusion')
|
||||||
|
if [[ "$CONCLUSION" == "success" ]]; then
|
||||||
|
SUCCESS_RUNS+=("$RUN_ID")
|
||||||
|
fi
|
||||||
|
done < triggered_run_ids.txt
|
||||||
|
|
||||||
|
for RUN_ID in "${SUCCESS_RUNS[@]}"; do
|
||||||
|
ARTIFACT_NAME=$(gh api repos/sunnypilot/sunnypilot/actions/runs/$RUN_ID/artifacts --jq '.artifacts[] | select(.name | startswith("model-")) | .name')
|
||||||
|
echo "Downloading artifact: $ARTIFACT_NAME from run: $RUN_ID"
|
||||||
|
mkdir -p "$ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
|
echo "Created directory: $ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
|
gh run download "$RUN_ID" --repo sunnypilot/sunnypilot -n "$ARTIFACT_NAME" --dir "$ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
|
echo "Downloaded artifact zip(s) to: $ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
|
ZIP_PATH=$(find "$ARTIFACT_DIR/$ARTIFACT_NAME" -type f -name '*.zip' | head -n1)
|
||||||
|
if [ -n "$ZIP_PATH" ]; then
|
||||||
|
echo "Unzipping $ZIP_PATH to $ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
|
unzip -o "$ZIP_PATH" -d "$ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
|
rm -f "$ZIP_PATH"
|
||||||
|
echo "Unzipped and removed $ZIP_PATH"
|
||||||
|
else
|
||||||
|
echo "No zip file found in $ARTIFACT_DIR/$ARTIFACT_NAME (This is NOT an error)."
|
||||||
|
fi
|
||||||
|
echo "Done processing $ARTIFACT_NAME"
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Push recompiled dir to GitLab
|
- name: Push recompiled dir to GitLab
|
||||||
@@ -268,36 +202,25 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd gitlab_docs
|
cd gitlab_docs
|
||||||
git checkout main
|
git checkout main
|
||||||
git pull origin main
|
mkdir -p models/"$(basename $RECOMPILED_DIR)"
|
||||||
for d in models/"$RECOMPILED_DIR"/*/; do
|
git add models/"$(basename $RECOMPILED_DIR)"
|
||||||
git sparse-checkout add "$d"
|
|
||||||
done
|
|
||||||
git add models/"$RECOMPILED_DIR"
|
|
||||||
git config --global user.name "GitHub Action"
|
git config --global user.name "GitHub Action"
|
||||||
git config --global user.email "action@github.com"
|
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 commit -m "Add $(basename $RECOMPILED_DIR) from build-all-tinygrad-models"
|
||||||
git push origin main
|
git push origin main
|
||||||
- run: |
|
|
||||||
cd docs
|
|
||||||
git pull origin gh-pages
|
|
||||||
|
|
||||||
- name: update json
|
- name: Run json_parser.py to update JSON
|
||||||
run: |
|
run: |
|
||||||
ARGS=""
|
python3 docs/json_parser.py \
|
||||||
[ -n "${{ inputs.set_min_version }}" ] && ARGS="$ARGS --set-min-version \"${{ inputs.set_min_version }}\""
|
|
||||||
ARGS="$ARGS --sort-by-date"
|
|
||||||
ARGS="$ARGS --tinygrad-ref \"${{ needs.setup.outputs.tinygrad_ref }}\""
|
|
||||||
eval python3 docs/json_parser.py \
|
|
||||||
--json-path "$JSON_FILE" \
|
--json-path "$JSON_FILE" \
|
||||||
--recompiled-dir "gitlab_docs/models/$RECOMPILED_DIR" \
|
--recompiled-dir "gitlab_docs/models/$RECOMPILED_DIR"
|
||||||
$ARGS
|
|
||||||
|
|
||||||
- name: Push updated json to GitHub
|
- name: Push updated JSON to GitHub docs repo
|
||||||
run: |
|
run: |
|
||||||
cd docs
|
cd docs
|
||||||
git config --global user.name "GitHub Action"
|
git config --global user.name "GitHub Action"
|
||||||
git config --global user.email "action@github.com"
|
git config --global user.email "action@github.com"
|
||||||
git checkout gh-pages
|
git checkout gh-pages
|
||||||
git add docs/"$(basename $JSON_FILE)"
|
git add docs/"$(basename $JSON_FILE)"
|
||||||
git commit -m "Update $(basename $JSON_FILE) after recompiling model" || echo "No changes to commit"
|
git commit -m "Update $(basename $JSON_FILE) after recompiling models" || echo "No changes to commit"
|
||||||
git push origin gh-pages
|
git push origin gh-pages
|
||||||
|
|||||||
@@ -1,36 +1,13 @@
|
|||||||
name: Build Single Tinygrad Model and Push
|
name: Build Single Tinygrad Model and Push
|
||||||
|
|
||||||
on:
|
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:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
|
build_model_ref:
|
||||||
|
description: 'Branch to use for build-model workflow'
|
||||||
|
required: false
|
||||||
|
default: 'master-new'
|
||||||
|
type: string
|
||||||
upstream_branch:
|
upstream_branch:
|
||||||
description: 'Upstream commit to build from'
|
description: 'Upstream commit to build from'
|
||||||
required: true
|
required: true
|
||||||
@@ -42,19 +19,17 @@ on:
|
|||||||
recompiled_dir:
|
recompiled_dir:
|
||||||
description: 'Existing recompiled directory number (e.g. 3 for recompiled3)'
|
description: 'Existing recompiled directory number (e.g. 3 for recompiled3)'
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: number
|
||||||
json_version:
|
json_version:
|
||||||
description: 'driving_models version number to update (e.g. 5 for driving_models_v5.json)'
|
description: 'driving_models version number to update (e.g. 5 for driving_models_v5.json)'
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: number
|
||||||
model_folder:
|
model_folder:
|
||||||
description: 'Model folder'
|
description: 'Model folder'
|
||||||
|
required: true
|
||||||
type: choice
|
type: choice
|
||||||
default: 'None'
|
|
||||||
options:
|
options:
|
||||||
- None
|
|
||||||
- Simple Plan Models
|
- Simple Plan Models
|
||||||
- Space Lab Models
|
|
||||||
- TR Models
|
- TR Models
|
||||||
- DTR Models
|
- DTR Models
|
||||||
- Custom Merge Models
|
- Custom Merge Models
|
||||||
@@ -67,32 +42,18 @@ on:
|
|||||||
generation:
|
generation:
|
||||||
description: 'Model generation'
|
description: 'Model generation'
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: number
|
||||||
version:
|
version:
|
||||||
description: 'Minimum selector version'
|
description: 'Minimum selector version'
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: number
|
||||||
env:
|
|
||||||
RECOMPILED_DIR: recompiled${{ inputs.recompiled_dir }}
|
|
||||||
JSON_FILE: docs/docs/driving_models_v${{ inputs.json_version }}.json
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_model:
|
build-single:
|
||||||
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
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
RECOMPILED_DIR: recompiled${{ github.event.inputs.recompiled_dir }}
|
||||||
|
JSON_FILE: docs/docs/driving_models_v${{ github.event.inputs.json_version }}.json
|
||||||
steps:
|
steps:
|
||||||
- name: Set up SSH
|
- name: Set up SSH
|
||||||
uses: webfactory/ssh-agent@v0.9.0
|
uses: webfactory/ssh-agent@v0.9.0
|
||||||
@@ -135,49 +96,66 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Download artifact name file
|
- name: Install dependencies
|
||||||
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: |
|
run: |
|
||||||
ARTIFACT_NAME=$(cat artifact_name/artifact_name.txt)
|
sudo apt-get update
|
||||||
echo "artifact_name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
|
sudo apt-get install -y jq gh
|
||||||
|
|
||||||
|
- name: Build model
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
START_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
gh workflow run sunnypilot-build-model.yaml \
|
||||||
|
--repo sunnypilot/sunnypilot \
|
||||||
|
--ref "${{ github.event.inputs.build_model_ref }}" \
|
||||||
|
-f upstream_branch="${{ github.event.inputs.upstream_branch }}" \
|
||||||
|
-f custom_name="${{ github.event.inputs.custom_name }}"
|
||||||
|
|
||||||
|
for i in {1..24}; do
|
||||||
|
RUN_ID=$(gh run list --repo sunnypilot/sunnypilot --workflow=sunnypilot-build-model.yaml --branch="${{ github.event.inputs.build_model_ref }}" --created ">$START_TIME" --limit=1 --json databaseId --jq '.[0].databaseId')
|
||||||
|
if [ -n "$RUN_ID" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$RUN_ID" ]; then
|
||||||
|
echo "Could not find the triggered workflow run."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Watching run ID: $RUN_ID"
|
||||||
|
gh run watch "$RUN_ID" --repo sunnypilot/sunnypilot
|
||||||
|
CONCLUSION=$(gh run view "$RUN_ID" --repo sunnypilot/sunnypilot --json conclusion --jq '.conclusion')
|
||||||
|
echo "Run concluded with: $CONCLUSION"
|
||||||
|
if [[ "$CONCLUSION" != "success" ]]; then
|
||||||
|
echo "Workflow run failed with conclusion: $CONCLUSION"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Download and extract model artifact
|
- 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:
|
env:
|
||||||
ARTIFACT_NAME: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
ARTIFACT_DIR="gitlab_docs/models/${RECOMPILED_DIR}/${ARTIFACT_NAME}"
|
ARTIFACT_DIR="gitlab_docs/models/$RECOMPILED_DIR"
|
||||||
mkdir -p "$ARTIFACT_DIR"
|
RUN_ID=$(gh run list --repo sunnypilot/sunnypilot --workflow=sunnypilot-build-model.yaml --branch="${{ github.event.inputs.build_model_ref }}" --limit=1 --json databaseId --jq '.[0].databaseId')
|
||||||
for path in output/*; do
|
ARTIFACT_NAME=$(gh api repos/sunnypilot/sunnypilot/actions/runs/$RUN_ID/artifacts --jq '.artifacts[] | select(.name | startswith("model-")) | .name')
|
||||||
if [ "$(basename "$path")" = "artifact_name.txt" ]; then
|
echo "Downloading artifact: $ARTIFACT_NAME from run: $RUN_ID"
|
||||||
continue
|
mkdir -p "$ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
fi
|
echo "Created directory: $ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
name="$(basename "$path")"
|
gh run download "$RUN_ID" --repo sunnypilot/sunnypilot -n "$ARTIFACT_NAME" --dir "$ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
if [ -d "$path" ]; then
|
echo "Downloaded artifact zip(s) to: $ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
mkdir -p "$ARTIFACT_DIR/$name"
|
ZIP_PATH=$(find "$ARTIFACT_DIR/$ARTIFACT_NAME" -type f -name '*.zip' | head -n1)
|
||||||
cp -r "$path"/* "$ARTIFACT_DIR/$name/"
|
if [ -n "$ZIP_PATH" ]; then
|
||||||
echo "Copied dir $name -> $ARTIFACT_DIR/$name"
|
echo "Unzipping $ZIP_PATH to $ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
else
|
unzip -o "$ZIP_PATH" -d "$ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
cp "$path" "$ARTIFACT_DIR/"
|
rm -f "$ZIP_PATH"
|
||||||
echo "Copied file $name -> $ARTIFACT_DIR/"
|
echo "Unzipped and removed $ZIP_PATH"
|
||||||
fi
|
else
|
||||||
done
|
echo "No zip file found in $ARTIFACT_DIR/$ARTIFACT_NAME"
|
||||||
|
fi
|
||||||
|
echo "Done processing $ARTIFACT_NAME"
|
||||||
|
|
||||||
- name: Push recompiled dir to GitLab
|
- name: Push recompiled dir to GitLab
|
||||||
env:
|
env:
|
||||||
@@ -185,36 +163,28 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd gitlab_docs
|
cd gitlab_docs
|
||||||
git checkout main
|
git checkout main
|
||||||
git pull origin main
|
|
||||||
for d in models/"$RECOMPILED_DIR"/*/; do
|
for d in models/"$RECOMPILED_DIR"/*/; do
|
||||||
git sparse-checkout add "$d"
|
git sparse-checkout add "$d"
|
||||||
done
|
done
|
||||||
git add models/"$RECOMPILED_DIR"
|
git add models/"$RECOMPILED_DIR"
|
||||||
git config --global user.name "GitHub Action"
|
git config --global user.name "GitHub Action"
|
||||||
git config --global user.email "action@github.com"
|
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 commit -m "Update $RECOMPILED_DIR with new/updated model from build-single-tinygrad-model" || echo "No changes to commit"
|
||||||
git push origin main
|
git push origin main
|
||||||
|
|
||||||
- run: |
|
|
||||||
cd docs
|
|
||||||
git pull origin gh-pages
|
|
||||||
|
|
||||||
- name: Run json_parser.py to update JSON
|
- name: Run json_parser.py to update JSON
|
||||||
run: |
|
run: |
|
||||||
FOLDER="${{ inputs.model_folder }}"
|
FOLDER="${{ github.event.inputs.model_folder }}"
|
||||||
if [ "$FOLDER" = "Other" ]; then
|
if [ "$FOLDER" = "Other" ]; then
|
||||||
FOLDER="${{ inputs.custom_model_folder }}"
|
FOLDER="${{ github.event.inputs.custom_model_folder }}"
|
||||||
fi
|
fi
|
||||||
ARGS=""
|
ARGS=""
|
||||||
if [ "$FOLDER" != "None" ] && [ -n "$FOLDER" ]; then
|
[ -n "$FOLDER" ] && ARGS="$ARGS --model-folder \"$FOLDER\""
|
||||||
ARGS="$ARGS --model-folder \"$FOLDER\""
|
[ -n "${{ github.event.inputs.generation }}" ] && ARGS="$ARGS --generation \"${{ github.event.inputs.generation }}\""
|
||||||
fi
|
[ -n "${{ github.event.inputs.version }}" ] && ARGS="$ARGS --version \"${{ github.event.inputs.version }}\""
|
||||||
[ -n "${{ inputs.generation }}" ] && ARGS="$ARGS --generation \"${{ inputs.generation }}\""
|
|
||||||
[ -n "${{ inputs.version }}" ] && ARGS="$ARGS --version \"${{ inputs.version }}\""
|
|
||||||
eval python3 docs/json_parser.py \
|
eval python3 docs/json_parser.py \
|
||||||
--json-path "$JSON_FILE" \
|
--json-path "$JSON_FILE" \
|
||||||
--recompiled-dir "gitlab_docs/models/$RECOMPILED_DIR" \
|
--recompiled-dir "gitlab_docs/models/$RECOMPILED_DIR" \
|
||||||
--sort-by-date \
|
|
||||||
$ARGS
|
$ARGS
|
||||||
|
|
||||||
- name: Push updated JSON to GitHub docs repo
|
- name: Push updated JSON to GitHub docs repo
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
- master-new
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'cereal/**'
|
- 'cereal/**'
|
||||||
@@ -16,7 +17,7 @@ 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:
|
||||||
|
|||||||
@@ -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,9 +9,6 @@ jobs:
|
|||||||
scan-comments:
|
scan-comments:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.event.issue.pull_request }}
|
if: ${{ github.event.issue.pull_request }}
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
issues: write
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check for trigger phrase
|
- name: Check for trigger phrase
|
||||||
id: check_comment
|
id: check_comment
|
||||||
@@ -46,14 +43,3 @@ jobs:
|
|||||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
git checkout -b tmp-jenkins-${{ github.event.issue.number }}
|
git checkout -b tmp-jenkins-${{ github.event.issue.number }}
|
||||||
GIT_LFS_SKIP_PUSH=1 git push -f origin tmp-jenkins-${{ github.event.issue.number }}
|
GIT_LFS_SKIP_PUSH=1 git push -f origin tmp-jenkins-${{ github.event.issue.number }}
|
||||||
|
|
||||||
- name: Delete trigger comment
|
|
||||||
if: steps.check_comment.outputs.result == 'true' && always()
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
await github.rest.issues.deleteComment({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
comment_id: context.payload.comment.id,
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
name: 'Post to Discourse'
|
|
||||||
description: 'Posts a message to a Discourse topic (existing or new)'
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
discourse-url:
|
|
||||||
description: 'Discourse instance URL (e.g., https://discourse.example.com)'
|
|
||||||
required: true
|
|
||||||
api-key:
|
|
||||||
description: 'Discourse API key'
|
|
||||||
required: true
|
|
||||||
api-username:
|
|
||||||
description: 'Discourse API username'
|
|
||||||
required: true
|
|
||||||
topic-id:
|
|
||||||
description: 'Discourse topic ID to post to (use this OR category-id + title)'
|
|
||||||
required: false
|
|
||||||
category-id:
|
|
||||||
description: 'Category ID for new topic (required if topic-id not provided)'
|
|
||||||
required: false
|
|
||||||
title:
|
|
||||||
description: 'Title for new topic (required if topic-id not provided)'
|
|
||||||
required: false
|
|
||||||
message:
|
|
||||||
description: 'Message content (markdown supported)'
|
|
||||||
required: true
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
post-number:
|
|
||||||
description: 'The post number in the topic'
|
|
||||||
value: ${{ steps.post.outputs.post_number }}
|
|
||||||
post-url:
|
|
||||||
description: 'Direct URL to the post'
|
|
||||||
value: ${{ steps.post.outputs.post_url }}
|
|
||||||
topic-id:
|
|
||||||
description: 'The topic ID (useful when creating a new topic)'
|
|
||||||
value: ${{ steps.post.outputs.topic_id }}
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- name: Post to Discourse
|
|
||||||
id: post
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
# Validate inputs
|
|
||||||
if [ -z "${{ inputs.topic-id }}" ] && ([ -z "${{ inputs.category-id }}" ] || [ -z "${{ inputs.title }}" ]); then
|
|
||||||
echo "❌ Error: Must provide either topic-id OR both category-id and title"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "${{ inputs.topic-id }}" ] && ([ -n "${{ inputs.category-id }}" ] || [ -n "${{ inputs.title }}" ]); then
|
|
||||||
echo "⚠️ Warning: Both topic-id and category-id/title provided. Will post to existing topic."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Determine if creating new topic or posting to existing
|
|
||||||
if [ -n "${{ inputs.topic-id }}" ]; then
|
|
||||||
echo "📝 Posting to existing topic ID: ${{ inputs.topic-id }}"
|
|
||||||
|
|
||||||
# Create JSON payload for posting to existing topic
|
|
||||||
PAYLOAD=$(jq -n \
|
|
||||||
--arg content '${{ inputs.message }}' \
|
|
||||||
--arg topic_id "${{ inputs.topic-id }}" \
|
|
||||||
'{topic_id: $topic_id, raw: $content}')
|
|
||||||
else
|
|
||||||
echo "✨ Creating new topic: ${{ inputs.title }}"
|
|
||||||
|
|
||||||
# Create JSON payload for new topic
|
|
||||||
PAYLOAD=$(jq -n \
|
|
||||||
--arg content '${{ inputs.message }}' \
|
|
||||||
--arg title "${{ inputs.title }}" \
|
|
||||||
--arg category "${{ inputs.category-id }}" \
|
|
||||||
'{title: $title, category: ($category | tonumber), raw: $content}')
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Post to Discourse
|
|
||||||
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
|
||||||
-X POST "${{ inputs.discourse-url }}/posts.json" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "Api-Key: ${{ inputs.api-key }}" \
|
|
||||||
-H "Api-Username: ${{ inputs.api-username }}" \
|
|
||||||
-d "$PAYLOAD")
|
|
||||||
|
|
||||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
|
||||||
BODY=$(echo "$RESPONSE" | sed '$d')
|
|
||||||
|
|
||||||
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
|
|
||||||
echo "✅ Successfully posted to Discourse!"
|
|
||||||
|
|
||||||
POST_NUMBER=$(echo "$BODY" | jq -r '.post_number // "unknown"')
|
|
||||||
TOPIC_ID=$(echo "$BODY" | jq -r '.topic_id // "${{ inputs.topic-id }}"')
|
|
||||||
POST_URL="${{ inputs.discourse-url }}/t/${TOPIC_ID}/${POST_NUMBER}"
|
|
||||||
|
|
||||||
echo "post_number=${POST_NUMBER}" >> $GITHUB_OUTPUT
|
|
||||||
echo "post_url=${POST_URL}" >> $GITHUB_OUTPUT
|
|
||||||
echo "topic_id=${TOPIC_ID}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
echo "Topic ID: ${TOPIC_ID}"
|
|
||||||
echo "Post number: ${POST_NUMBER}"
|
|
||||||
echo "URL: ${POST_URL}"
|
|
||||||
else
|
|
||||||
echo "❌ Failed to post to Discourse"
|
|
||||||
echo "HTTP Code: ${HTTP_CODE}"
|
|
||||||
echo "Response: ${BODY}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -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_stripped.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,14 +36,13 @@ 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
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: uv lock
|
- name: uv lock
|
||||||
if: github.repository == 'commaai/openpilot'
|
|
||||||
run: |
|
run: |
|
||||||
python3 -m ensurepip --upgrade
|
python3 -m ensurepip --upgrade
|
||||||
pip3 install uv
|
pip3 install uv
|
||||||
@@ -51,7 +50,6 @@ jobs:
|
|||||||
- name: bump submodules
|
- name: bump submodules
|
||||||
run: |
|
run: |
|
||||||
git config --global --add safe.directory '*'
|
git config --global --add safe.directory '*'
|
||||||
git config submodule.tinygrad.update none
|
|
||||||
git submodule update --remote
|
git submodule update --remote
|
||||||
git add .
|
git add .
|
||||||
- name: update car docs
|
- name: update car docs
|
||||||
@@ -63,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 -n logical
|
PYTEST: pytest --continue-on-collection-errors --durations=0 --durations-min=5 -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:
|
||||||
@@ -52,7 +51,7 @@ jobs:
|
|||||||
command: git lfs pull
|
command: git lfs pull
|
||||||
- name: Build devel
|
- name: Build devel
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
run: TARGET_DIR=$STRIPPED_DIR release/build_stripped.sh
|
run: TARGET_DIR=$STRIPPED_DIR release/build_devel.sh
|
||||||
- uses: ./.github/workflows/setup-with-retry
|
- uses: ./.github/workflows/setup-with-retry
|
||||||
- name: Build openpilot and run checks
|
- name: Build openpilot and run checks
|
||||||
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
|
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
|
||||||
@@ -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
|
||||||
@@ -115,9 +94,7 @@ jobs:
|
|||||||
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
|
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
|
||||||
- name: Homebrew cache
|
- name: Homebrew cache
|
||||||
uses: ./.github/workflows/auto-cache
|
uses: ./.github/workflows/auto-cache
|
||||||
if: false # disabling the cache for now because it is breaking macos builds...
|
|
||||||
with:
|
with:
|
||||||
save: false # No need save here if we manually save it later conditionally
|
|
||||||
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 }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
@@ -126,11 +103,11 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: ./tools/mac_setup.sh
|
run: ./tools/mac_setup.sh
|
||||||
env:
|
env:
|
||||||
PYTHONWARNINGS: default # package install has DeprecationWarnings
|
# package install has DeprecationWarnings
|
||||||
HOMEBREW_DISPLAY_INSTALL_TIMES: 1
|
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 }}
|
||||||
@@ -138,7 +115,6 @@ jobs:
|
|||||||
- name: Getting scons cache
|
- name: Getting scons cache
|
||||||
uses: ./.github/workflows/auto-cache
|
uses: ./.github/workflows/auto-cache
|
||||||
with:
|
with:
|
||||||
save: false # No need save here if we manually save it later conditionally
|
|
||||||
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 }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
@@ -148,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:
|
||||||
@@ -174,26 +146,19 @@ 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 }} "source selfdrive/test/setup_xvfb.sh && \
|
${{ env.RUN }} "$PYTEST --collect-only -m 'not slow' &> /dev/null && \
|
||||||
# Pre-compile Python bytecode so each pytest worker doesn't need to
|
|
||||||
$PYTEST --collect-only -m 'not slow' -qq && \
|
|
||||||
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 && \
|
||||||
@@ -201,19 +166,14 @@ jobs:
|
|||||||
|
|
||||||
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
|
||||||
@@ -224,7 +184,7 @@ 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 }} "selfdrive/test/process_replay/test_processes.py -j$(nproc) && \
|
||||||
chmod -R 777 /tmp/comma_download_cache"
|
chmod -R 777 /tmp/comma_download_cache"
|
||||||
@@ -249,26 +209,106 @@ jobs:
|
|||||||
${{ 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"
|
||||||
|
|
||||||
|
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 }}
|
||||||
|
|
||||||
|
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 && \
|
||||||
@@ -277,13 +317,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:
|
||||||
@@ -307,5 +342,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
|
|
||||||
|
|||||||
@@ -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,15 +8,21 @@ env:
|
|||||||
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
||||||
|
|
||||||
# Branch configurations
|
# Branch configurations
|
||||||
STAGING_SOURCE_BRANCH: 'master'
|
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.
|
||||||
|
|
||||||
|
# Target branch configurations
|
||||||
|
STAGING_TARGET_BRANCH: ${{ vars.STAGING_TARGET_BRANCH || 'staging-c3-new' }} # vars are set on repo settings.
|
||||||
|
DEV_TARGET_BRANCH: ${{ vars.DEV_TARGET_BRANCH || 'dev-c3-new' }} # vars are set on repo settings.
|
||||||
|
RELEASE_TARGET_BRANCH: ${{ vars.RELEASE_TARGET_BRANCH || 'release-c3-new' }} # vars are set on repo settings.
|
||||||
|
|
||||||
# Runtime configuration
|
# Runtime configuration
|
||||||
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
|
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, master-dev ]
|
branches: [ master, master-new, master-dev-c3-new ]
|
||||||
tags: [ 'release/*' ]
|
tags: [ '*' ]
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [ labeled ]
|
types: [ labeled ]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -28,72 +34,9 @@ on:
|
|||||||
default: false
|
default: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
prepare_strategy:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
if: (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
|
|
||||||
outputs:
|
|
||||||
environment: ${{ steps.strategy.outputs.environment }}
|
|
||||||
new_branch: ${{ steps.strategy.outputs.new_branch }}
|
|
||||||
extra_version_identifier: ${{ steps.strategy.outputs.extra_version_identifier }}
|
|
||||||
version: ${{ steps.strategy.outputs.version }}
|
|
||||||
cancel_publish_in_progress: ${{ steps.strategy.outputs.cancel_publish_in_progress }}
|
|
||||||
publish_concurrency_group: ${{ steps.strategy.outputs.publish_concurrency_group }}
|
|
||||||
is_stable_branch: ${{ steps.strategy.outputs.is_stable_branch }}
|
|
||||||
build: ${{ steps.strategy.outputs.build }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Extract deploy strategy
|
|
||||||
id: strategy
|
|
||||||
run: |
|
|
||||||
echo '::group::Strategy Extraction'
|
|
||||||
BRANCH="${{ github.head_ref || github.ref_name }}"
|
|
||||||
echo "Current branch: $BRANCH"
|
|
||||||
|
|
||||||
STRATEGY_JSON='${{ vars.DEPLOY_STRATEGY }}'
|
|
||||||
CONFIG=$(echo "$STRATEGY_JSON" | jq -r --arg branch "$BRANCH" '
|
|
||||||
.configs[] | select(.branch == $branch)
|
|
||||||
')
|
|
||||||
|
|
||||||
BUILD="$(date '+%Y.%m.%d')-${{ github.run_number }}"
|
|
||||||
if [[ -z "$CONFIG" || "$CONFIG" == "null" ]]; then
|
|
||||||
echo "No exact strategy match found. Falling back to feature/fork logic."
|
|
||||||
IS_FORK="${{ github.event.pull_request.head.repo.fork && 'true' || 'false' }}"
|
|
||||||
FORK_SUFFIX=$( [[ "$IS_FORK" == "true" ]] && echo "-fork" || echo "" )
|
|
||||||
NEW_BRANCH="${BRANCH}${FORK_SUFFIX}-prebuilt"
|
|
||||||
|
|
||||||
echo "new_branch=$NEW_BRANCH" >> $GITHUB_OUTPUT
|
|
||||||
echo "version=$BUILD" >> $GITHUB_OUTPUT
|
|
||||||
echo "cancel_publish_in_progress=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "publish_concurrency_group=publish-${BRANCH}" >> $GITHUB_OUTPUT
|
|
||||||
echo "environment=feature-branch" >> $GITHUB_OUTPUT
|
|
||||||
echo "extra_version_identifier=feature-branch" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "Matched config: $CONFIG"
|
|
||||||
environment=$(echo "$CONFIG" | jq -r '.environment')
|
|
||||||
echo "environment=$environment" >> $GITHUB_OUTPUT
|
|
||||||
echo "new_branch=$(echo "$CONFIG" | jq -r '.target_branch')" >> $GITHUB_OUTPUT
|
|
||||||
cancel="$(echo "$CONFIG" | jq -r '.cancel_publish_in_progress')";
|
|
||||||
echo "cancel_publish_in_progress=$( [ "$cancel" = "null" ] && echo "true" || echo $cancel)" >> $GITHUB_OUTPUT
|
|
||||||
echo "publish_concurrency_group=publish-${BRANCH}$( [ "$cancel" = "null" ] || [ "$cancel" = "true" ] || echo "${{ github.sha }}" )" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
is_stable_branch="$(echo "$CONFIG" | jq -r '.stable_branch // false')";
|
|
||||||
echo "is_stable_branch=$is_stable_branch" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
stable_version=$(cat sunnypilot/common/version.h | grep SUNNYPILOT_VERSION | sed -e 's/[^0-9|.]//g');
|
|
||||||
echo "version=$([ "$is_stable_branch" = "true" ] && echo "$stable_version" || echo "$BUILD")" >> $GITHUB_OUTPUT
|
|
||||||
echo "extra_version_identifier=${environment}" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
echo "build=$BUILD" >> $GITHUB_OUTPUT
|
|
||||||
cat $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
validate_tests:
|
validate_tests:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
needs: [ prepare_strategy ]
|
if: ((github.event_name == 'workflow_dispatch' && inputs.wait_for_tests) || contains(github.event_name, 'pull_request') && (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
|
||||||
if: ${{
|
|
||||||
((github.event_name == 'workflow_dispatch' && inputs.wait_for_tests) ||
|
|
||||||
(github.event_name == 'push' && needs.prepare_strategy.outputs.is_stable_branch == 'true') ||
|
|
||||||
contains(github.event_name, 'pull_request') && (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
|
|
||||||
}}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Wait for Tests
|
- name: Wait for Tests
|
||||||
@@ -101,26 +44,19 @@ jobs:
|
|||||||
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 }}
|
||||||
should-wait-for-start: ${{ github.event_name == 'push' && 'true' || 'false' }}
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: [ validate_tests, prepare_strategy ]
|
needs: [ validate_tests ]
|
||||||
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: ${{ needs.prepare_strategy.outputs.new_branch }}
|
new_branch: ${{ steps.set-env.outputs.new_branch }}
|
||||||
version: ${{ needs.prepare_strategy.outputs.version }}
|
version: ${{ steps.set-env.outputs.version }}
|
||||||
extra_version_identifier: ${{ needs.prepare_strategy.outputs.extra_version_identifier }}
|
extra_version_identifier: ${{ steps.set-env.outputs.extra_version_identifier }}
|
||||||
commit_sha: ${{ github.sha }}
|
commit_sha: ${{ steps.set-env.outputs.commit_sha }}
|
||||||
if: ${{
|
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
|
||||||
(always() && !cancelled() && !failure()) &&
|
|
||||||
needs.prepare_strategy.result == 'success' &&
|
|
||||||
(needs.validate_tests.result == 'success' || needs.validate_tests.result == 'skipped') &&
|
|
||||||
(!contains(github.event_name, 'pull_request') ||
|
|
||||||
(github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
|
|
||||||
}}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -138,15 +74,64 @@ jobs:
|
|||||||
# 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 }}-${{ env.SOURCE_BRANCH }}
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.SOURCE_BRANCH }}
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.STAGING_SOURCE_BRANCH }}
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.STAGING_C3_SOURCE_BRANCH }}
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}
|
scons-${{ runner.os }}-${{ runner.arch }}
|
||||||
|
|
||||||
|
- name: Set Feature Branch Prebuilt Configuration
|
||||||
|
id: set_feature_configuration
|
||||||
|
if: (
|
||||||
|
!(env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH) &&
|
||||||
|
!(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH) &&
|
||||||
|
!(startsWith(github.ref, 'refs/tags/'))
|
||||||
|
)
|
||||||
|
run: |
|
||||||
|
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
|
||||||
|
|
||||||
|
- name: Set dev-c3-new prebuilt Configuration
|
||||||
|
id: set_dev_configuration
|
||||||
|
if: (
|
||||||
|
steps.set_feature_configuration.outcome == 'skipped' &&
|
||||||
|
env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH
|
||||||
|
)
|
||||||
|
run: |
|
||||||
|
echo "NEW_BRANCH=${{ env.DEV_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||||||
|
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
||||||
|
echo "EXTRA_VERSION_IDENTIFIER=${{ github.run_number }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Set staging-c3-new prebuilt Configuration
|
||||||
|
id: set_staging_configuration
|
||||||
|
if: (
|
||||||
|
steps.set_feature_configuration.outcome == 'skipped' &&
|
||||||
|
!contains(github.event_name, 'pull_request') &&
|
||||||
|
steps.set_dev_configuration.outcome == 'skipped' &&
|
||||||
|
(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH)
|
||||||
|
)
|
||||||
|
run: |
|
||||||
|
echo "NEW_BRANCH=${{ env.STAGING_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||||||
|
echo "EXTRA_VERSION_IDENTIFIER=staging" >> $GITHUB_ENV
|
||||||
|
echo "VERSION=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g')-staging" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Set release-c3-new prebuilt Configuration
|
||||||
|
id: set_tag_configuration
|
||||||
|
if: (
|
||||||
|
steps.set_feature_configuration.outcome == 'skipped' &&
|
||||||
|
!contains(github.event_name, 'pull_request') &&
|
||||||
|
steps.set_staging_configuration.outcome == 'skipped' &&
|
||||||
|
startsWith(github.ref, 'refs/tags/')
|
||||||
|
)
|
||||||
|
run: |
|
||||||
|
echo "NEW_BRANCH=${{ env.RELEASE_TARGET_BRANCH }}" >> $GITHUB_ENV
|
||||||
|
echo "EXTRA_VERSION_IDENTIFIER=release" >> $GITHUB_ENV
|
||||||
|
echo "VERSION=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g')-release" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set environment variables
|
- name: Set environment variables
|
||||||
id: set-env
|
id: set-env
|
||||||
run: |
|
run: |
|
||||||
echo "new_branch=${{ needs.prepare_strategy.outputs.new_branch }}" >> $GITHUB_OUTPUT
|
# Write to GITHUB_OUTPUT from environment variables
|
||||||
echo "version=${{ needs.prepare_strategy.outputs.version }}" >> $GITHUB_OUTPUT
|
echo "new_branch=$NEW_BRANCH" >> $GITHUB_OUTPUT
|
||||||
echo "extra_version_identifier=${{ needs.prepare_strategy.outputs.extra_version_identifier }}" >> $GITHUB_OUTPUT
|
[[ ! -z "$EXTRA_VERSION_IDENTIFIER" ]] && echo "extra_version_identifier=$EXTRA_VERSION_IDENTIFIER" >> $GITHUB_OUTPUT
|
||||||
|
[[ ! -z "$VERSION" ]] && echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
echo "commit_sha=${{ github.sha }}" >> $GITHUB_OUTPUT
|
echo "commit_sha=${{ github.sha }}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
# Set up common environment
|
# Set up common environment
|
||||||
@@ -241,19 +226,16 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
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:
|
||||||
# We do a bit of a hack here to avoid canceling the publishing job if a new commit comes in while we're publishing by adding the sha to the group name.
|
group: publish-${{ github.head_ref || github.ref_name }}
|
||||||
# This means that if multiple commits come in while we're publishing, they will be queued up and publish one after the other.
|
cancel-in-progress: true
|
||||||
# Otherwise, if a job is waiting to be published due to environment wait time, it would be canceled by a new commit and restart the wait time.
|
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
|
||||||
group: ${{ needs.prepare_strategy.outputs.publish_concurrency_group }}
|
needs: [ build ]
|
||||||
cancel-in-progress: ${{ needs.prepare_strategy.outputs.cancel_publish_in_progress == 'true' }}
|
|
||||||
if: ${{ (always() && !cancelled() && !failure()) && needs.build.result == 'success' && needs.prepare_strategy.result == 'success' && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
|
|
||||||
needs: [ build, prepare_strategy ]
|
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
environment: ${{ needs.prepare_strategy.outputs.environment }}
|
environment: ${{ (contains(fromJSON(vars.AUTO_DEPLOY_PREBUILT_BRANCHES), github.head_ref || github.ref_name) || contains(github.event.pull_request.labels.*.name, 'prebuilt')) && 'auto-deploy' || 'feature-branch' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
@@ -285,69 +267,47 @@ jobs:
|
|||||||
"${{ needs.build.outputs.new_branch }}" \
|
"${{ needs.build.outputs.new_branch }}" \
|
||||||
"${{ 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 ""
|
||||||
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/AUTO_DEPLOY_PREBUILT_BRANCHES"
|
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/AUTO_DEPLOY_PREBUILT_BRANCHES"
|
||||||
echo "2. Current value: ${{ vars.AUTO_DEPLOY_PREBUILT_BRANCHES }}"
|
echo "2. Current value: ${{ vars.AUTO_DEPLOY_PREBUILT_BRANCHES }}"
|
||||||
echo "3. Update as needed (JSON array with no spaces)"
|
echo "3. Update as needed (JSON array with no spaces)"
|
||||||
|
|
||||||
- name: Tag ${{ needs.prepare_strategy.outputs.environment }}
|
|
||||||
if: ${{ needs.prepare_strategy.outputs.is_stable_branch == 'true' && (github.event_name != 'push' || !startsWith(github.ref, 'refs/tags/')) }}
|
|
||||||
run: |
|
|
||||||
TAG="${{ needs.prepare_strategy.outputs.environment }}/${{ needs.prepare_strategy.outputs.version }}/${{ needs.prepare_strategy.outputs.build }}"
|
|
||||||
git tag -f -a ${TAG} -m "${{ needs.prepare_strategy.outputs.environment }} @ ${{ needs.prepare_strategy.outputs.version }} of build ${{ needs.build.outputs.build }}."
|
|
||||||
git push -f origin ${TAG}
|
|
||||||
|
|
||||||
notify:
|
notify:
|
||||||
needs:
|
needs: [ build, publish ]
|
||||||
- prepare_strategy
|
|
||||||
- build
|
|
||||||
- publish
|
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
if: ${{ (always() && !cancelled() && !failure())
|
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
|
||||||
&& needs.publish.result == 'success'
|
|
||||||
&& (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
|
|
||||||
&& (fromJSON(vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES_V2)[github.head_ref || github.ref_name] != null) }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Setup Alpine Linux environment
|
||||||
- name: Prepare notification message
|
uses: jirutka/setup-alpine@v1.2.0
|
||||||
id: message
|
|
||||||
run: |
|
|
||||||
TEMPLATE='${{ vars.DISCOURSE_GENERAL_UPDATE_NOTICE }}'
|
|
||||||
export VERSION="${{ needs.prepare_strategy.outputs.version }}"
|
|
||||||
export branch_name="${{ env.SOURCE_BRANCH }}"
|
|
||||||
export new_branch="${{ needs.prepare_strategy.outputs.new_branch }}"
|
|
||||||
export commit_sha="${{ github.sha }}"
|
|
||||||
export commit_short_sha="${{ github.sha }}"
|
|
||||||
export commit_short_sha="${commit_short_sha:0:7}"
|
|
||||||
export extra_version_identifier="${{ needs.prepare_strategy.outputs.extra_version_identifier || github.run_number }}"
|
|
||||||
export PUBLIC_REPO_URL="${{ env.PUBLIC_REPO_URL }}"
|
|
||||||
|
|
||||||
MESSAGE=$(cat << 'EOF' | envsubst
|
|
||||||
${{ vars.DISCOURSE_GENERAL_UPDATE_NOTICE }}
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
{
|
|
||||||
echo 'content<<EOFMARKER'
|
|
||||||
echo "$MESSAGE"
|
|
||||||
echo 'EOFMARKER'
|
|
||||||
} >> $GITHUB_OUTPUT
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Post to Discourse
|
|
||||||
uses: ./.github/workflows/post-to-discourse
|
|
||||||
with:
|
with:
|
||||||
discourse-url: ${{ vars.DISCOURSE_URL }}
|
packages: 'jq gettext curl'
|
||||||
api-key: ${{ secrets.DISCOURSE_API_KEY }}
|
|
||||||
api-username: "system"
|
|
||||||
topic-id: ${{ fromJSON(vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES_V2)[github.head_ref || github.ref_name].topic_id }}
|
|
||||||
message: ${{ steps.message.outputs.content }}
|
|
||||||
|
|
||||||
|
- name: Send Discord Notification
|
||||||
|
env:
|
||||||
|
DISCORD_WEBHOOK: ${{ contains(fromJSON(vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES), env.SOURCE_BRANCH) && secrets.DISCORD_DEV_FEEDBACK_CHANNEL_WEBHOOK || secrets.DISCORD_DEV_PRIVATE_CHANNEL_WEBHOOK }}
|
||||||
|
run: |
|
||||||
|
TEMPLATE='${{ vars.DISCORD_GENERAL_UPDATE_NOTICE }}'
|
||||||
|
export EXTRA_VERSION_IDENTIFIER="${{ needs.build.outputs.extra_version_identifier }}"
|
||||||
|
export VERSION="${{ needs.build.outputs.version }}"
|
||||||
|
export branch_name=${{ env.SOURCE_BRANCH }}
|
||||||
|
export new_branch=${{ needs.build.outputs.new_branch }}
|
||||||
|
export extra_version_identifier=${{ needs.build.outputs.extra_version_identifier || github.run_number}}
|
||||||
|
echo ${TEMPLATE} | envsubst | jq -c '.' | tee payload.json
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d @payload.json $DISCORD_WEBHOOK
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "---- ℹ️ To update the list of branches that notify to dev-feedback -----"
|
||||||
|
echo ""
|
||||||
|
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/DEV_FEEDBACK_NOTIFICATION_BRANCHES"
|
||||||
|
echo "2. Current value: ${{ vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES }}"
|
||||||
|
echo "3. Update as needed (JSON array with no spaces)"
|
||||||
|
shell: alpine.sh {0}
|
||||||
|
|
||||||
manage-pr-labels:
|
manage-pr-labels:
|
||||||
name: Remove prebuilt label
|
name: Remove prebuilt label
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
+21
-19
@@ -1,8 +1,9 @@
|
|||||||
name: Build dev
|
name: Build dev-c3-new
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DEFAULT_SOURCE_BRANCH: "master"
|
DEFAULT_SOURCE_BRANCH: "master-new"
|
||||||
DEFAULT_TARGET_BRANCH: "master-dev"
|
DEFAULT_TARGET_BRANCH: "master-dev-c3-new"
|
||||||
|
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'
|
||||||
LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git'
|
LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git'
|
||||||
|
|
||||||
@@ -10,21 +11,23 @@ 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'
|
||||||
required: true
|
required: true
|
||||||
default: 'master-dev'
|
default: 'master-dev-c3-new'
|
||||||
type: string
|
type: string
|
||||||
cancel_in_progress:
|
cancel_in_progress:
|
||||||
description: 'Cancel any in-progress runs of this workflow'
|
description: 'Cancel any in-progress runs of this workflow'
|
||||||
@@ -40,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 == vars.PREBUILT_PR_LABEL || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, vars.PREBUILT_PR_LABEL))))
|
|| (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:
|
||||||
@@ -53,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 == vars.PREBUILT_PR_LABEL || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, vars.PREBUILT_PR_LABEL))))
|
|| (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 }}
|
||||||
@@ -117,8 +120,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
# Use GitHub API to get PRs with specific label, ordered by creation date
|
# Use GitHub API to get PRs with specific label, ordered by creation date
|
||||||
PR_LIST=$(gh api graphql -f query='
|
PR_LIST=$(gh api graphql -f query='
|
||||||
query($search_query:String!) {
|
query($label:String!) {
|
||||||
search(query: $search_query, type:ISSUE, first:40) {
|
search(query: $label, type:ISSUE, first:100) {
|
||||||
nodes {
|
nodes {
|
||||||
... on PullRequest {
|
... on PullRequest {
|
||||||
number
|
number
|
||||||
@@ -148,9 +151,8 @@ jobs:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}' -F search_query="repo:${{ github.repository }} is:pr is:open label:${{ vars.PREBUILT_PR_LABEL }},${{ vars.PREBUILT_PR_LABEL }}-c3 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 }}
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
name: Debug Discourse Posting
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-discourse-post:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Post test message to Discourse
|
|
||||||
uses: ./.github/workflows/post-to-discourse
|
|
||||||
with:
|
|
||||||
discourse-url: ${{ vars.DISCOURSE_URL }}
|
|
||||||
api-key: ${{ secrets.DISCOURSE_API_KEY }}
|
|
||||||
api-username: ${{ secrets.DISCOURSE_API_USERNAME }}
|
|
||||||
topic-id: ${{ vars.DISCOURSE_UPDATES_TOPIC_ID }}
|
|
||||||
message: |
|
|
||||||
## 🧪 Test Post from GitHub Actions
|
|
||||||
|
|
||||||
**This is a test post to verify Discourse integration**
|
|
||||||
|
|
||||||
- **Workflow**: ${{ github.workflow }}
|
|
||||||
- **Run Number**: #${{ github.run_number }}
|
|
||||||
- **Branch**: `${{ github.ref_name }}`
|
|
||||||
- **Commit**: ${{ github.sha }}
|
|
||||||
- **Actor**: @${{ github.actor }}
|
|
||||||
- **Timestamp**: ${{ github.event.head_commit.timestamp }}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Fake Build Info (for testing)
|
|
||||||
- **Version**: 0.9.8-test
|
|
||||||
- **Build**: #42
|
|
||||||
- **Branch**: release-test
|
|
||||||
|
|
||||||
[View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
||||||
|
|
||||||
*This is an automated test message. Drive safe! 🚗💨*
|
|
||||||
|
|
||||||
|
|
||||||
- name: Create topic on Discourse
|
|
||||||
uses: ./.github/workflows/post-to-discourse
|
|
||||||
with:
|
|
||||||
discourse-url: ${{ vars.DISCOURSE_URL }}
|
|
||||||
api-key: ${{ secrets.DISCOURSE_API_KEY }}
|
|
||||||
api-username: ${{ secrets.DISCOURSE_API_USERNAME }}
|
|
||||||
#topic-id: ${{ vars.DISCOURSE_UPDATES_TOPIC_ID }}
|
|
||||||
category-id: 4
|
|
||||||
title: "This is a test of a new topic instead of a reply"
|
|
||||||
message: |
|
|
||||||
## 🧪 Test Post from GitHub Actions
|
|
||||||
|
|
||||||
**This is a test post to verify Discourse integration**
|
|
||||||
|
|
||||||
- **Workflow**: ${{ github.workflow }}
|
|
||||||
- **Run Number**: #${{ github.run_number }}
|
|
||||||
- **Branch**: `${{ github.ref_name }}`
|
|
||||||
- **Commit**: ${{ github.sha }}
|
|
||||||
- **Actor**: @${{ github.actor }}
|
|
||||||
- **Timestamp**: ${{ github.event.head_commit.timestamp }}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Fake Build Info (for testing)
|
|
||||||
- **Version**: 0.9.8-test
|
|
||||||
- **Build**: #42
|
|
||||||
- **Branch**: release-test
|
|
||||||
|
|
||||||
[View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
||||||
|
|
||||||
*This is an automated test message. Drive safe! 🚗💨*
|
|
||||||
- name: Display results
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
echo "::notice::Discourse post test completed"
|
|
||||||
echo "Check your Discourse topic to verify the post appeared correctly"
|
|
||||||
@@ -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
|
||||||
|
|||||||
+1
-2
@@ -13,11 +13,9 @@ venv/
|
|||||||
model2.png
|
model2.png
|
||||||
a.out
|
a.out
|
||||||
.hypothesis
|
.hypothesis
|
||||||
.cache/
|
|
||||||
|
|
||||||
/docs_site/
|
/docs_site/
|
||||||
|
|
||||||
*.mp4
|
|
||||||
*.dylib
|
*.dylib
|
||||||
*.DSYM
|
*.DSYM
|
||||||
*.d
|
*.d
|
||||||
@@ -50,6 +48,7 @@ cereal/services.h
|
|||||||
cereal/gen
|
cereal/gen
|
||||||
cereal/messaging/bridge
|
cereal/messaging/bridge
|
||||||
selfdrive/mapd/default_speeds_by_region.json
|
selfdrive/mapd/default_speeds_by_region.json
|
||||||
|
system/proclogd/proclogd
|
||||||
selfdrive/ui/translations/tmp
|
selfdrive/ui/translations/tmp
|
||||||
selfdrive/test/longitudinal_maneuvers/out
|
selfdrive/test/longitudinal_maneuvers/out
|
||||||
selfdrive/car/tests/cars_dump
|
selfdrive/car/tests/cars_dump
|
||||||
|
|||||||
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>
|
||||||
|
|||||||
Vendored
+1
-40
@@ -23,11 +23,6 @@
|
|||||||
"id": "args",
|
"id": "args",
|
||||||
"description": "Arguments to pass to the process",
|
"description": "Arguments to pass to the process",
|
||||||
"type": "promptString"
|
"type": "promptString"
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "replayArg",
|
|
||||||
"type": "promptString",
|
|
||||||
"description": "Enter route or segment to replay."
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"configurations": [
|
"configurations": [
|
||||||
@@ -45,41 +40,7 @@
|
|||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/${input:cpp_process}",
|
"program": "${workspaceFolder}/${input:cpp_process}",
|
||||||
"cwd": "${workspaceFolder}"
|
"cwd": "${workspaceFolder}",
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Attach LLDB to Replay drive",
|
|
||||||
"type": "lldb",
|
|
||||||
"request": "attach",
|
|
||||||
"pid": "${command:pickMyProcess}",
|
|
||||||
"initCommands": [
|
|
||||||
"script import time; time.sleep(3)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Replay drive",
|
|
||||||
"type": "debugpy",
|
|
||||||
"request": "launch",
|
|
||||||
"program": "${workspaceFolder}/opendbc/safety/tests/safety_replay/replay_drive.py",
|
|
||||||
"args": [
|
|
||||||
"${input:replayArg}"
|
|
||||||
],
|
|
||||||
"console": "integratedTerminal",
|
|
||||||
"justMyCode": false,
|
|
||||||
"env": {
|
|
||||||
"PYTHONPATH": "${workspaceFolder}"
|
|
||||||
},
|
|
||||||
"subProcess": true,
|
|
||||||
"stopOnEntry": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"compounds": [
|
|
||||||
{
|
|
||||||
"name": "Replay drive + Safety LLDB",
|
|
||||||
"configurations": [
|
|
||||||
"Replay drive",
|
|
||||||
"Attach LLDB to Replay drive"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
-1080
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
|||||||
FROM ghcr.io/sunnypilot/sunnypilot-base:latest
|
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
|
||||||
|
|
||||||
ENV OPENPILOT_PATH=/home/batman/openpilot
|
|
||||||
|
|
||||||
RUN mkdir -p ${OPENPILOT_PATH}
|
|
||||||
WORKDIR ${OPENPILOT_PATH}
|
|
||||||
|
|
||||||
COPY . ${OPENPILOT_PATH}/
|
|
||||||
|
|
||||||
RUN scons --cache-readonly -j$(nproc)
|
|
||||||
@@ -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
|
|
||||||
Vendored
+24
-10
@@ -167,7 +167,7 @@ node {
|
|||||||
env.GIT_COMMIT = checkout(scm).GIT_COMMIT
|
env.GIT_COMMIT = checkout(scm).GIT_COMMIT
|
||||||
|
|
||||||
def excludeBranches = ['__nightly', 'devel', 'devel-staging', 'release3', 'release3-staging',
|
def excludeBranches = ['__nightly', 'devel', 'devel-staging', 'release3', 'release3-staging',
|
||||||
'release-tici', 'testing-closet*', 'hotfix-*']
|
'testing-closet*', 'hotfix-*']
|
||||||
def excludeRegex = excludeBranches.join('|').replaceAll('\\*', '.*')
|
def excludeRegex = excludeBranches.join('|').replaceAll('\\*', '.*')
|
||||||
|
|
||||||
if (env.BRANCH_NAME != 'master' && !env.BRANCH_NAME.contains('__jenkins_loop_')) {
|
if (env.BRANCH_NAME != 'master' && !env.BRANCH_NAME.contains('__jenkins_loop_')) {
|
||||||
@@ -178,7 +178,7 @@ node {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (env.BRANCH_NAME == 'devel-staging') {
|
if (env.BRANCH_NAME == 'devel-staging') {
|
||||||
deviceStage("build release3-staging", "tizi-needs-can", [], [
|
deviceStage("build release3-staging", "tici-needs-can", [], [
|
||||||
step("build release3-staging", "RELEASE_BRANCH=release3-staging $SOURCE_DIR/release/build_release.sh"),
|
step("build release3-staging", "RELEASE_BRANCH=release3-staging $SOURCE_DIR/release/build_release.sh"),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
@@ -186,12 +186,12 @@ node {
|
|||||||
if (env.BRANCH_NAME == '__nightly') {
|
if (env.BRANCH_NAME == '__nightly') {
|
||||||
parallel (
|
parallel (
|
||||||
'nightly': {
|
'nightly': {
|
||||||
deviceStage("build nightly", "tizi-needs-can", [], [
|
deviceStage("build nightly", "tici-needs-can", [], [
|
||||||
step("build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/release/build_release.sh"),
|
step("build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/release/build_release.sh"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'nightly-dev': {
|
'nightly-dev': {
|
||||||
deviceStage("build nightly-dev", "tizi-needs-can", [], [
|
deviceStage("build nightly-dev", "tici-needs-can", [], [
|
||||||
step("build nightly-dev", "PANDA_DEBUG_BUILD=1 RELEASE_BRANCH=nightly-dev $SOURCE_DIR/release/build_release.sh"),
|
step("build nightly-dev", "PANDA_DEBUG_BUILD=1 RELEASE_BRANCH=nightly-dev $SOURCE_DIR/release/build_release.sh"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
@@ -200,30 +200,39 @@ node {
|
|||||||
|
|
||||||
if (!env.BRANCH_NAME.matches(excludeRegex)) {
|
if (!env.BRANCH_NAME.matches(excludeRegex)) {
|
||||||
parallel (
|
parallel (
|
||||||
|
// tici tests
|
||||||
'onroad tests': {
|
'onroad tests': {
|
||||||
deviceStage("onroad", "tizi-needs-can", ["UNSAFE=1"], [
|
deviceStage("onroad", "tici-needs-can", ["UNSAFE=1"], [
|
||||||
step("build openpilot", "cd system/manager && ./build.py"),
|
step("build openpilot", "cd system/manager && ./build.py"),
|
||||||
step("check dirty", "release/check-dirty.sh"),
|
step("check dirty", "release/check-dirty.sh"),
|
||||||
step("onroad tests", "pytest selfdrive/test/test_onroad.py -s", [timeout: 60]),
|
step("onroad tests", "pytest selfdrive/test/test_onroad.py -s", [timeout: 60]),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'HW + Unit Tests': {
|
'HW + Unit Tests': {
|
||||||
deviceStage("tizi-hardware", "tizi-common", ["UNSAFE=1"], [
|
deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
|
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
|
||||||
step("test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"),
|
step("test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"),
|
||||||
step("test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py", [diffPaths: ["system/loggerd/"]]),
|
step("test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py", [diffPaths: ["system/loggerd/"]]),
|
||||||
|
step("test pigeond", "pytest system/ubloxd/tests/test_pigeond.py", [diffPaths: ["system/ubloxd/"]]),
|
||||||
step("test manager", "pytest system/manager/test/test_manager.py"),
|
step("test manager", "pytest system/manager/test/test_manager.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'loopback': {
|
'loopback': {
|
||||||
deviceStage("loopback", "tizi-loopback", ["UNSAFE=1"], [
|
deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [
|
||||||
step("build openpilot", "cd system/manager && ./build.py"),
|
step("build openpilot", "cd system/manager && ./build.py"),
|
||||||
step("test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
step("test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
'camerad AR0231': {
|
||||||
|
deviceStage("AR0231", "tici-ar0231", ["UNSAFE=1"], [
|
||||||
|
step("build", "cd system/manager && ./build.py"),
|
||||||
|
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
||||||
|
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
||||||
|
])
|
||||||
|
},
|
||||||
'camerad OX03C10': {
|
'camerad OX03C10': {
|
||||||
deviceStage("OX03C10", "tizi-ox03c10", ["UNSAFE=1"], [
|
deviceStage("OX03C10", "tici-ox03c10", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
||||||
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
||||||
@@ -237,13 +246,17 @@ node {
|
|||||||
])
|
])
|
||||||
},
|
},
|
||||||
'sensord': {
|
'sensord': {
|
||||||
deviceStage("LSM + MMC", "tizi-lsmc", ["UNSAFE=1"], [
|
deviceStage("LSM + MMC", "tici-lsmc", ["UNSAFE=1"], [
|
||||||
|
step("build", "cd system/manager && ./build.py"),
|
||||||
|
step("test sensord", "pytest system/sensord/tests/test_sensord.py"),
|
||||||
|
])
|
||||||
|
deviceStage("BMX + LSM", "tici-bmx-lsm", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test sensord", "pytest system/sensord/tests/test_sensord.py"),
|
step("test sensord", "pytest system/sensord/tests/test_sensord.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'replay': {
|
'replay': {
|
||||||
deviceStage("model-replay", "tizi-replay", ["UNSAFE=1"], [
|
deviceStage("model-replay", "tici-replay", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
step("build", "cd system/manager && ./build.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
||||||
step("model replay", "selfdrive/test/process_replay/model_replay.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
step("model replay", "selfdrive/test/process_replay/model_replay.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
||||||
])
|
])
|
||||||
@@ -253,6 +266,7 @@ node {
|
|||||||
step("build openpilot", "cd system/manager && ./build.py"),
|
step("build openpilot", "cd system/manager && ./build.py"),
|
||||||
step("test pandad loopback", "SINGLE_PANDA=1 pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
step("test pandad loopback", "SINGLE_PANDA=1 pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
||||||
step("test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"),
|
step("test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"),
|
||||||
|
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
|
||||||
step("test amp", "pytest system/hardware/tici/tests/test_amplifier.py"),
|
step("test amp", "pytest system/hardware/tici/tests/test_amplifier.py"),
|
||||||
// TODO: enable once new AGNOS is available
|
// TODO: enable once new AGNOS is available
|
||||||
// step("test esim", "pytest system/hardware/tici/tests/test_esim.py"),
|
// step("test esim", "pytest system/hardware/tici/tests/test_esim.py"),
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
## 🌞 What is sunnypilot?
|
## 🌞 What is sunnypilot?
|
||||||
[sunnypilot](https://github.com/sunnyhaibin/sunnypilot) is a fork of comma.ai's openpilot, an open source driver assistance system. sunnypilot offers the user a unique driving experience for over 300+ supported car makes and models with modified behaviors of driving assist engagements. sunnypilot complies with comma.ai's safety rules as accurately as possible.
|
[sunnypilot](https://github.com/sunnyhaibin/sunnypilot) is a fork of comma.ai's openpilot, an open source driver assistance system. sunnypilot offers the user a unique driving experience for over 300+ supported car makes and models with modified behaviors of driving assist engagements. sunnypilot complies with comma.ai's safety rules as accurately as possible.
|
||||||
|
|
||||||
## 💭 Join our Community Forum
|
## 💭 Join our Discord
|
||||||
Join the official sunnypilot community forum to stay up to date with all the latest features and be a part of shaping the future of sunnypilot!
|
Join the official sunnypilot Discord server to stay up to date with all the latest features and be a part of shaping the future of sunnypilot!
|
||||||
* https://community.sunnypilot.ai/
|
* https://discord.gg/sunnypilot
|
||||||
|
|
||||||
|
 
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
https://docs.sunnypilot.ai/ is your one stop shop for everything from features to installation to FAQ about the sunnypilot
|
https://docs.sunnypilot.ai/ is your one stop shop for everything from features to installation to FAQ about the sunnypilot
|
||||||
@@ -14,54 +16,25 @@ https://docs.sunnypilot.ai/ is your one stop shop for everything from features t
|
|||||||
* A supported device to run this software
|
* A supported device to run this software
|
||||||
* a [comma three](https://comma.ai/shop/products/three) or a [C3X](https://comma.ai/shop/comma-3x)
|
* a [comma three](https://comma.ai/shop/products/three) or a [C3X](https://comma.ai/shop/comma-3x)
|
||||||
* This software
|
* This software
|
||||||
* One of [the 325+ supported cars](https://github.com/sunnypilot/sunnypilot/blob/master/docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford, and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run sunnypilot.
|
* One of [the 300+ supported cars](https://github.com/commaai/openpilot/blob/master/docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run sunnypilot.
|
||||||
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car
|
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car
|
||||||
|
|
||||||
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
|
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
Please refer to [Recommended Branches](#recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `staging` branch.
|
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `release-c3` branch.
|
||||||
|
|
||||||
### If you want to use our newest branches (our rewrite)
|
|
||||||
> [!TIP]
|
|
||||||
>You can see the rewrite state on our [rewrite project board](https://github.com/orgs/sunnypilot/projects/2), and to install the new branches, you can use the following links
|
|
||||||
|
|
||||||
* sunnypilot not installed or you installed a version before 0.8.17?
|
* sunnypilot not installed or you installed a version before 0.8.17?
|
||||||
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
|
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
|
||||||
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
|
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
|
||||||
3. Input the installation URL per [Recommended Branches](#recommended-branches). Example: ```https://staging.sunnypilot.ai```.
|
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```release-c3.sunnypilot.ai```.
|
||||||
4. Complete the rest of the installation following the onscreen instructions.
|
4. Complete the rest of the installation following the onscreen instructions.
|
||||||
|
|
||||||
* sunnypilot already installed and you installed a version after 0.8.17?
|
* sunnypilot already installed and you installed a version after 0.8.17?
|
||||||
1. On the comma three/3X, go to `Settings` ▶️ `Software`.
|
1. On the comma three, go to `Settings` ▶️ `Software`.
|
||||||
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
|
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
|
||||||
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
|
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
|
||||||
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging`
|
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `release-c3`
|
||||||
|
|
||||||
### Recommended Branches
|
|
||||||
| Branch | Installation URL |
|
|
||||||
|:---------------:|:---------------------------------------------:|
|
|
||||||
| `release` | `https://release.sunnypilot.ai` |
|
|
||||||
| `staging` | `https://staging.sunnypilot.ai` |
|
|
||||||
| `dev` | `https://dev.sunnypilot.ai` |
|
|
||||||
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging'.
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> Do you require further assistance with software installation? Join the [sunnypilot community forum](https://community.sunnypilot.ai/new-topic?category=general/qa) and create a topic in the General/Q&A Category channel.
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
|
|
||||||
<summary>Older legacy branches</summary>
|
|
||||||
|
|
||||||
### If you want to use our older legacy branches (*not recommended*)
|
|
||||||
|
|
||||||
> [**IMPORTANT**]
|
|
||||||
> It is recommended to [re-flash AGNOS](https://flash.comma.ai/) if you intend to downgrade from the new branches.
|
|
||||||
> You can still restore the latest sunnylink backup made on the old branches.
|
|
||||||
|
|
||||||
| Branch | Installation URL |
|
| Branch | Installation URL |
|
||||||
|:------------:|:--------------------------------:|
|
|:------------:|:--------------------------------:|
|
||||||
@@ -69,13 +42,29 @@ Please refer to [Recommended Branches](#recommended-branches) to find your prefe
|
|||||||
| `staging-c3` | https://staging-c3.sunnypilot.ai |
|
| `staging-c3` | https://staging-c3.sunnypilot.ai |
|
||||||
| `dev-c3` | https://dev-c3.sunnypilot.ai |
|
| `dev-c3` | https://dev-c3.sunnypilot.ai |
|
||||||
|
|
||||||
</details>
|
### If you want to use our newest branches (our rewrite)
|
||||||
|
> [!TIP]
|
||||||
|
>You can see the rewrite state on our [rewrite project board](https://github.com/orgs/sunnypilot/projects/2), and to install the new branches, you can use the following links
|
||||||
|
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> It is recommended to [re-flash AGNOS](https://flash.comma.ai/) if you intend to downgrade from the new branches.
|
||||||
|
> You can still restore the latest sunnylink backup made on the old branches.
|
||||||
|
|
||||||
|
| Branch | Installation URL |
|
||||||
|
|:----------------:|:---------------------------------------------:|
|
||||||
|
| `staging-c3-new` | `https://staging-c3-new.sunnypilot.ai` |
|
||||||
|
| `dev-c3-new` | `https://dev-c3-new.sunnypilot.ai` |
|
||||||
|
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
||||||
|
| `release-c3-new` | **Not yet available**. |
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Do you require further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
|
||||||
|
|
||||||
## 🎆 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
|
||||||
|
|
||||||
|
|||||||
+4
-21
@@ -1,28 +1,11 @@
|
|||||||
Version 0.10.1 (2025-09-08)
|
Version 0.10.0 (2025-07-07)
|
||||||
========================
|
========================
|
||||||
* New driving model
|
* New driving model
|
||||||
* World Model: removed global localization inputs
|
* Lead car ground-truth fixes
|
||||||
* World Model: 2x the number of parameters
|
* Ported over VAE from the MLSIM stack
|
||||||
* World Model: trained on 4x the number of segments
|
* New training architecture described in CVPR paper
|
||||||
* Driving Vision Model: trained on 4x the number of segments
|
|
||||||
* Honda City 2023 support thanks to vanillagorillaa and drFritz!
|
|
||||||
* Honda N-Box 2018 support thanks to miettal!
|
|
||||||
* Honda Odyssey 2021-25 support thanks to csouers and MVL!
|
|
||||||
|
|
||||||
Version 0.10.0 (2025-08-05)
|
|
||||||
========================
|
|
||||||
* New driving model
|
|
||||||
* New training architecture
|
|
||||||
* Described in our CVPR paper: "Learning to Drive from a World Model"
|
|
||||||
* Longitudinal MPC replaced by E2E planning from World Model in Experimental Mode
|
|
||||||
* Action from lateral MPC as training objective replaced by E2E planning from World Model
|
|
||||||
* Low-speed lead car ground-truth fixes
|
|
||||||
* Enable live-learned steering actuation delay
|
* Enable live-learned steering actuation delay
|
||||||
* Opt-in audio recording for dashcam video
|
* Opt-in audio recording for dashcam video
|
||||||
* Acura MDX 2025 support thanks to vanillagorillaa and MVL!
|
|
||||||
* Honda Accord 2023-25 support thanks to vanillagorillaa and MVL!
|
|
||||||
* Honda CR-V 2023-25 support thanks to vanillagorillaa and MVL!
|
|
||||||
* Honda Pilot 2023-25 support thanks to vanillagorillaa and MVL!
|
|
||||||
|
|
||||||
Version 0.9.9 (2025-05-23)
|
Version 0.9.9 (2025-05-23)
|
||||||
========================
|
========================
|
||||||
|
|||||||
+9
-2
@@ -17,7 +17,7 @@ AGNOS = TICI
|
|||||||
|
|
||||||
Decider('MD5-timestamp')
|
Decider('MD5-timestamp')
|
||||||
|
|
||||||
SetOption('num_jobs', max(1, int(os.cpu_count()/2)))
|
SetOption('num_jobs', int(os.cpu_count()/2))
|
||||||
|
|
||||||
AddOption('--kaitai',
|
AddOption('--kaitai',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@@ -82,6 +82,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 +90,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 +133,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 = [
|
||||||
@@ -359,6 +361,11 @@ SConscript([
|
|||||||
'system/ubloxd/SConscript',
|
'system/ubloxd/SConscript',
|
||||||
'system/loggerd/SConscript',
|
'system/loggerd/SConscript',
|
||||||
])
|
])
|
||||||
|
if arch != "Darwin":
|
||||||
|
SConscript([
|
||||||
|
'system/logcatd/SConscript',
|
||||||
|
'system/proclogd/SConscript',
|
||||||
|
])
|
||||||
|
|
||||||
if arch == "larch64":
|
if arch == "larch64":
|
||||||
SConscript(['system/camerad/SConscript'])
|
SConscript(['system/camerad/SConscript'])
|
||||||
|
|||||||
+2
-218
@@ -25,92 +25,8 @@ struct ModularAssistiveDrivingSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IntelligentCruiseButtonManagement {
|
|
||||||
state @0 :IntelligentCruiseButtonManagementState;
|
|
||||||
sendButton @1 :SendButtonState;
|
|
||||||
vTarget @2 :Float32;
|
|
||||||
|
|
||||||
enum IntelligentCruiseButtonManagementState {
|
|
||||||
inactive @0; # No button press or default state
|
|
||||||
preActive @1; # Pre-active state before transitioning to increasing or decreasing
|
|
||||||
increasing @2; # Increasing speed
|
|
||||||
decreasing @3; # Decreasing speed
|
|
||||||
holding @4; # Holding steady speed
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SendButtonState {
|
|
||||||
none @0;
|
|
||||||
increase @1;
|
|
||||||
decrease @2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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;
|
||||||
intelligentCruiseButtonManagement @1 :IntelligentCruiseButtonManagement;
|
|
||||||
|
|
||||||
enum AudibleAlert {
|
|
||||||
none @0;
|
|
||||||
|
|
||||||
engage @1;
|
|
||||||
disengage @2;
|
|
||||||
refuse @3;
|
|
||||||
|
|
||||||
warningSoft @4;
|
|
||||||
warningImmediate @5;
|
|
||||||
|
|
||||||
prompt @6;
|
|
||||||
promptRepeat @7;
|
|
||||||
promptDistracted @8;
|
|
||||||
|
|
||||||
# unused, these are reserved for upstream events so we don't collide
|
|
||||||
reserved9 @9;
|
|
||||||
reserved10 @10;
|
|
||||||
reserved11 @11;
|
|
||||||
reserved12 @12;
|
|
||||||
reserved13 @13;
|
|
||||||
reserved14 @14;
|
|
||||||
reserved15 @15;
|
|
||||||
reserved16 @16;
|
|
||||||
reserved17 @17;
|
|
||||||
reserved18 @18;
|
|
||||||
reserved19 @19;
|
|
||||||
reserved20 @20;
|
|
||||||
reserved21 @21;
|
|
||||||
reserved22 @22;
|
|
||||||
reserved23 @23;
|
|
||||||
reserved24 @24;
|
|
||||||
reserved25 @25;
|
|
||||||
reserved26 @26;
|
|
||||||
reserved27 @27;
|
|
||||||
reserved28 @28;
|
|
||||||
reserved29 @29;
|
|
||||||
reserved30 @30;
|
|
||||||
|
|
||||||
promptSingleLow @31;
|
|
||||||
promptSingleHigh @32;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModelManagerSP @0xaedffd8f31e7b55d {
|
struct ModelManagerSP @0xaedffd8f31e7b55d {
|
||||||
@@ -185,13 +101,6 @@ struct ModelManagerSP @0xaedffd8f31e7b55d {
|
|||||||
|
|
||||||
struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
||||||
dec @0 :DynamicExperimentalControl;
|
dec @0 :DynamicExperimentalControl;
|
||||||
longitudinalPlanSource @1 :LongitudinalPlanSource;
|
|
||||||
smartCruiseControl @2 :SmartCruiseControl;
|
|
||||||
speedLimit @3 :SpeedLimit;
|
|
||||||
vTarget @4 :Float32;
|
|
||||||
aTarget @5 :Float32;
|
|
||||||
events @6 :List(OnroadEventSP.Event);
|
|
||||||
e2eAlerts @7 :E2eAlerts;
|
|
||||||
|
|
||||||
struct DynamicExperimentalControl {
|
struct DynamicExperimentalControl {
|
||||||
state @0 :DynamicExperimentalControlState;
|
state @0 :DynamicExperimentalControlState;
|
||||||
@@ -203,97 +112,6 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
|||||||
blended @1;
|
blended @1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SmartCruiseControl {
|
|
||||||
vision @0 :Vision;
|
|
||||||
map @1 :Map;
|
|
||||||
|
|
||||||
struct Vision {
|
|
||||||
state @0 :VisionState;
|
|
||||||
vTarget @1 :Float32;
|
|
||||||
aTarget @2 :Float32;
|
|
||||||
currentLateralAccel @3 :Float32;
|
|
||||||
maxPredictedLateralAccel @4 :Float32;
|
|
||||||
enabled @5 :Bool;
|
|
||||||
active @6 :Bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Map {
|
|
||||||
state @0 :MapState;
|
|
||||||
vTarget @1 :Float32;
|
|
||||||
aTarget @2 :Float32;
|
|
||||||
enabled @3 :Bool;
|
|
||||||
active @4 :Bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum VisionState {
|
|
||||||
disabled @0; # System disabled or inactive.
|
|
||||||
enabled @1; # No predicted substantial turn on vision range.
|
|
||||||
entering @2; # A substantial turn is predicted ahead, adapting speed to turn comfort levels.
|
|
||||||
turning @3; # Actively turning. Managing acceleration to provide a roll on turn feeling.
|
|
||||||
leaving @4; # Road ahead straightens. Start to allow positive acceleration.
|
|
||||||
overriding @5; # System overriding with manual control.
|
|
||||||
}
|
|
||||||
|
|
||||||
enum MapState {
|
|
||||||
disabled @0; # System disabled or inactive.
|
|
||||||
enabled @1; # No predicted substantial turn on map range.
|
|
||||||
turning @2; # Actively turning. Managing acceleration to provide a roll on turn feeling.
|
|
||||||
overriding @3; # System overriding with manual control.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SpeedLimit {
|
|
||||||
resolver @0 :Resolver;
|
|
||||||
assist @1 :Assist;
|
|
||||||
|
|
||||||
struct Resolver {
|
|
||||||
speedLimit @0 :Float32;
|
|
||||||
distToSpeedLimit @1 :Float32;
|
|
||||||
source @2 :Source;
|
|
||||||
speedLimitOffset @3 :Float32;
|
|
||||||
speedLimitLast @4 :Float32;
|
|
||||||
speedLimitFinal @5 :Float32;
|
|
||||||
speedLimitFinalLast @6 :Float32;
|
|
||||||
speedLimitValid @7 :Bool;
|
|
||||||
speedLimitLastValid @8 :Bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Assist {
|
|
||||||
state @0 :AssistState;
|
|
||||||
enabled @1 :Bool;
|
|
||||||
active @2 :Bool;
|
|
||||||
vTarget @3 :Float32;
|
|
||||||
aTarget @4 :Float32;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Source {
|
|
||||||
none @0;
|
|
||||||
car @1;
|
|
||||||
map @2;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AssistState {
|
|
||||||
disabled @0;
|
|
||||||
inactive @1; # No speed limit set or not enabled by parameter.
|
|
||||||
preActive @2;
|
|
||||||
pending @3; # Awaiting new speed limit.
|
|
||||||
adapting @4; # Reducing speed to match new speed limit.
|
|
||||||
active @5; # Cruising at speed limit.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LongitudinalPlanSource {
|
|
||||||
cruise @0;
|
|
||||||
sccVision @1;
|
|
||||||
sccMap @2;
|
|
||||||
speedLimitAssist @3;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct E2eAlerts {
|
|
||||||
greenLightAlert @0 :Bool;
|
|
||||||
leadDepartAlert @1 :Bool;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OnroadEventSP @0xda96579883444c35 {
|
struct OnroadEventSP @0xda96579883444c35 {
|
||||||
@@ -333,22 +151,12 @@ struct OnroadEventSP @0xda96579883444c35 {
|
|||||||
experimentalModeSwitched @14;
|
experimentalModeSwitched @14;
|
||||||
wrongCarModeAlertOnly @15;
|
wrongCarModeAlertOnly @15;
|
||||||
pedalPressedAlertOnly @16;
|
pedalPressedAlertOnly @16;
|
||||||
laneTurnLeft @17;
|
|
||||||
laneTurnRight @18;
|
|
||||||
speedLimitPreActive @19;
|
|
||||||
speedLimitActive @20;
|
|
||||||
speedLimitChanged @21;
|
|
||||||
speedLimitPending @22;
|
|
||||||
e2eChime @23;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CarParamsSP @0x80ae746ee2596b11 {
|
struct CarParamsSP @0x80ae746ee2596b11 {
|
||||||
flags @0 :UInt32; # flags for car specific quirks in sunnypilot
|
flags @0 :UInt32; # flags for car specific quirks in sunnypilot
|
||||||
safetyParam @1 : Int16; # flags for sunnypilot's custom safety flags
|
safetyParam @1 : Int16; # flags for sunnypilot's custom safety flags
|
||||||
pcmCruiseSpeed @3 :Bool;
|
|
||||||
intelligentCruiseButtonManagementAvailable @4 :Bool;
|
|
||||||
enableGasInterceptor @5 :Bool;
|
|
||||||
|
|
||||||
neuralNetworkLateralControl @2 :NeuralNetworkLateralControl;
|
neuralNetworkLateralControl @2 :NeuralNetworkLateralControl;
|
||||||
|
|
||||||
@@ -366,26 +174,10 @@ 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;
|
|
||||||
intelligentCruiseButtonManagement @4 :IntelligentCruiseButtonManagement;
|
|
||||||
|
|
||||||
struct Param {
|
struct Param {
|
||||||
key @0 :Text;
|
key @0 :Text;
|
||||||
type @2 :ParamType;
|
value @1 :Text;
|
||||||
value @3 :Data;
|
|
||||||
|
|
||||||
valueDEPRECATED @1 :Text; # The data type change may cause issues with backwards compatibility.
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ParamType {
|
|
||||||
string @0;
|
|
||||||
bool @1;
|
|
||||||
int @2;
|
|
||||||
float @3;
|
|
||||||
time @4;
|
|
||||||
json @5;
|
|
||||||
bytes @6;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,7 +224,6 @@ struct BackupManagerSP @0xf98d843bfd7004a3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct CarStateSP @0xb86e6369214c01c8 {
|
struct CarStateSP @0xb86e6369214c01c8 {
|
||||||
speedLimit @0 :Float32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LiveMapDataSP @0xf416ec09499d9d19 {
|
struct LiveMapDataSP @0xf416ec09499d9d19 {
|
||||||
@@ -444,14 +235,7 @@ struct LiveMapDataSP @0xf416ec09499d9d19 {
|
|||||||
roadName @5 :Text;
|
roadName @5 :Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModelDataV2SP @0xa1680744031fdb2d {
|
struct CustomReserved9 @0xa1680744031fdb2d {
|
||||||
laneTurnDirection @0 :TurnDirection;
|
|
||||||
|
|
||||||
enum TurnDirection {
|
|
||||||
none @0;
|
|
||||||
turnLeft @1;
|
|
||||||
turnRight @2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CustomReserved10 @0xcb9fd56c7057593a {
|
struct CustomReserved10 @0xcb9fd56c7057593a {
|
||||||
|
|||||||
+8
-19
@@ -127,9 +127,7 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
|||||||
espActive @90;
|
espActive @90;
|
||||||
personalityChanged @91;
|
personalityChanged @91;
|
||||||
aeb @92;
|
aeb @92;
|
||||||
userBookmark @95;
|
userFlag @95;
|
||||||
excessiveActuation @96;
|
|
||||||
audioFeedback @97;
|
|
||||||
|
|
||||||
soundsUnavailableDEPRECATED @47;
|
soundsUnavailableDEPRECATED @47;
|
||||||
}
|
}
|
||||||
@@ -494,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;
|
||||||
@@ -569,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 {
|
||||||
@@ -585,8 +583,9 @@ struct PandaState @0xa7649e2575e4591e {
|
|||||||
heartbeatLost @22 :Bool;
|
heartbeatLost @22 :Bool;
|
||||||
interruptLoad @25 :Float32;
|
interruptLoad @25 :Float32;
|
||||||
fanPower @28 :UInt8;
|
fanPower @28 :UInt8;
|
||||||
|
fanStallCount @34 :UInt8;
|
||||||
|
|
||||||
spiErrorCount @33 :UInt16;
|
spiChecksumErrorCount @33 :UInt16;
|
||||||
|
|
||||||
harnessStatus @21 :HarnessStatus;
|
harnessStatus @21 :HarnessStatus;
|
||||||
sbu1Voltage @35 :Float32;
|
sbu1Voltage @35 :Float32;
|
||||||
@@ -713,7 +712,6 @@ struct PandaState @0xa7649e2575e4591e {
|
|||||||
usbPowerModeDEPRECATED @12 :PeripheralState.UsbPowerModeDEPRECATED;
|
usbPowerModeDEPRECATED @12 :PeripheralState.UsbPowerModeDEPRECATED;
|
||||||
safetyParamDEPRECATED @20 :Int16;
|
safetyParamDEPRECATED @20 :Int16;
|
||||||
safetyParam2DEPRECATED @26 :UInt32;
|
safetyParam2DEPRECATED @26 :UInt32;
|
||||||
fanStallCountDEPRECATED @34 :UInt8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PeripheralState {
|
struct PeripheralState {
|
||||||
@@ -2469,7 +2467,7 @@ struct DebugAlert {
|
|||||||
alertText2 @1 :Text;
|
alertText2 @1 :Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UserBookmark @0xfe346a9de48d9b50 {
|
struct UserFlag {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundPressure @0xdc24138990726023 {
|
struct SoundPressure @0xdc24138990726023 {
|
||||||
@@ -2487,11 +2485,6 @@ struct AudioData {
|
|||||||
sampleRate @1 :UInt32;
|
sampleRate @1 :UInt32;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AudioFeedback {
|
|
||||||
audio @0 :AudioData;
|
|
||||||
blockNum @1 :UInt16;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Touch {
|
struct Touch {
|
||||||
sec @0 :Int64;
|
sec @0 :Int64;
|
||||||
usec @1 :Int64;
|
usec @1 :Int64;
|
||||||
@@ -2592,13 +2585,9 @@ struct Event {
|
|||||||
mapRenderState @105: MapRenderState;
|
mapRenderState @105: MapRenderState;
|
||||||
|
|
||||||
# UI services
|
# UI services
|
||||||
|
userFlag @93 :UserFlag;
|
||||||
uiDebug @102 :UIDebug;
|
uiDebug @102 :UIDebug;
|
||||||
|
|
||||||
# driving feedback
|
|
||||||
userBookmark @93 :UserBookmark;
|
|
||||||
bookmarkButton @148 :UserBookmark;
|
|
||||||
audioFeedback @149 :AudioFeedback;
|
|
||||||
|
|
||||||
# *********** debug ***********
|
# *********** debug ***********
|
||||||
testJoystick @52 :Joystick;
|
testJoystick @52 :Joystick;
|
||||||
roadEncodeData @86 :EncodeData;
|
roadEncodeData @86 :EncodeData;
|
||||||
@@ -2631,7 +2620,7 @@ struct Event {
|
|||||||
backupManagerSP @113 :Custom.BackupManagerSP;
|
backupManagerSP @113 :Custom.BackupManagerSP;
|
||||||
carStateSP @114 :Custom.CarStateSP;
|
carStateSP @114 :Custom.CarStateSP;
|
||||||
liveMapDataSP @115 :Custom.LiveMapDataSP;
|
liveMapDataSP @115 :Custom.LiveMapDataSP;
|
||||||
modelDataV2SP @116 :Custom.ModelDataV2SP;
|
customReserved9 @116 :Custom.CustomReserved9;
|
||||||
customReserved10 @136 :Custom.CustomReserved10;
|
customReserved10 @136 :Custom.CustomReserved10;
|
||||||
customReserved11 @137 :Custom.CustomReserved11;
|
customReserved11 @137 :Custom.CustomReserved11;
|
||||||
customReserved12 @138 :Custom.CustomReserved12;
|
customReserved12 @138 :Custom.CustomReserved12;
|
||||||
@@ -2684,7 +2673,7 @@ struct Event {
|
|||||||
lateralPlanDEPRECATED @64 :LateralPlan;
|
lateralPlanDEPRECATED @64 :LateralPlan;
|
||||||
navModelDEPRECATED @104 :NavModelData;
|
navModelDEPRECATED @104 :NavModelData;
|
||||||
uiPlanDEPRECATED @106 :UiPlan;
|
uiPlanDEPRECATED @106 :UiPlan;
|
||||||
liveLocationKalman @72 :LiveLocationKalman;
|
liveLocationKalmanDEPRECATED @72 :LiveLocationKalman;
|
||||||
liveTracksDEPRECATED @16 :List(LiveTracksDEPRECATED);
|
liveTracksDEPRECATED @16 :List(LiveTracksDEPRECATED);
|
||||||
onroadEventsDEPRECATED @68: List(Car.OnroadEventDEPRECATED);
|
onroadEventsDEPRECATED @68: List(Car.OnroadEventDEPRECATED);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ MessageContext message_context;
|
|||||||
struct SubMaster::SubMessage {
|
struct SubMaster::SubMessage {
|
||||||
std::string name;
|
std::string name;
|
||||||
SubSocket *socket = nullptr;
|
SubSocket *socket = nullptr;
|
||||||
float freq = 0.0f;
|
int freq = 0;
|
||||||
bool updated = false, alive = false, valid = false, ignore_alive;
|
bool updated = false, alive = false, valid = false, ignore_alive;
|
||||||
uint64_t rcv_time = 0, rcv_frame = 0;
|
uint64_t rcv_time = 0, rcv_frame = 0;
|
||||||
void *allocated_msg_reader = nullptr;
|
void *allocated_msg_reader = nullptr;
|
||||||
|
|||||||
@@ -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:
|
||||||
@@ -177,8 +177,8 @@ class TestMessaging:
|
|||||||
|
|
||||||
# wait 5 socket timeouts before sending
|
# wait 5 socket timeouts before sending
|
||||||
msg = random_carstate()
|
msg = random_carstate()
|
||||||
start_time = time.monotonic()
|
|
||||||
delayed_send(sock_timeout*5, pub_sock, msg.to_bytes())
|
delayed_send(sock_timeout*5, pub_sock, msg.to_bytes())
|
||||||
|
start_time = time.monotonic()
|
||||||
recvd = messaging.recv_one_retry(sub_sock)
|
recvd = messaging.recv_one_retry(sub_sock)
|
||||||
assert (time.monotonic() - start_time) >= sock_timeout*5
|
assert (time.monotonic() - start_time) >= sock_timeout*5
|
||||||
assert isinstance(recvd, capnp._DynamicStructReader)
|
assert isinstance(recvd, capnp._DynamicStructReader)
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class TestSubMaster:
|
|||||||
"cameraOdometry": (20, 10),
|
"cameraOdometry": (20, 10),
|
||||||
"liveCalibration": (4, 4),
|
"liveCalibration": (4, 4),
|
||||||
"carParams": (None, None),
|
"carParams": (None, None),
|
||||||
"userBookmark": (None, None),
|
"userFlag": (None, None),
|
||||||
}
|
}
|
||||||
|
|
||||||
for service, (max_freq, min_freq) in checks.items():
|
for service, (max_freq, min_freq) in checks.items():
|
||||||
|
|||||||
+3
-7
@@ -72,11 +72,9 @@ _services: dict[str, tuple] = {
|
|||||||
"navRoute": (True, 0.),
|
"navRoute": (True, 0.),
|
||||||
"navThumbnail": (True, 0.),
|
"navThumbnail": (True, 0.),
|
||||||
"qRoadEncodeIdx": (False, 20.),
|
"qRoadEncodeIdx": (False, 20.),
|
||||||
"userBookmark": (True, 0., 1),
|
"userFlag": (True, 0., 1),
|
||||||
"soundPressure": (True, 10., 10),
|
"soundPressure": (True, 10., 10),
|
||||||
"rawAudioData": (False, 20.),
|
"rawAudioData": (False, 20.),
|
||||||
"bookmarkButton": (True, 0., 1),
|
|
||||||
"audioFeedback": (True, 0., 1),
|
|
||||||
|
|
||||||
# sunnypilot
|
# sunnypilot
|
||||||
"modelManagerSP": (False, 1., 1),
|
"modelManagerSP": (False, 1., 1),
|
||||||
@@ -88,8 +86,6 @@ _services: dict[str, tuple] = {
|
|||||||
"carControlSP": (True, 100., 10),
|
"carControlSP": (True, 100., 10),
|
||||||
"carStateSP": (True, 100., 10),
|
"carStateSP": (True, 100., 10),
|
||||||
"liveMapDataSP": (True, 1., 1),
|
"liveMapDataSP": (True, 1., 1),
|
||||||
"modelDataV2SP": (True, 20.),
|
|
||||||
"liveLocationKalman": (True, 20.),
|
|
||||||
|
|
||||||
# debug
|
# debug
|
||||||
"uiDebug": (True, 0., 1),
|
"uiDebug": (True, 0., 1),
|
||||||
@@ -122,12 +118,12 @@ def build_header():
|
|||||||
h += "#include <map>\n"
|
h += "#include <map>\n"
|
||||||
h += "#include <string>\n"
|
h += "#include <string>\n"
|
||||||
|
|
||||||
h += "struct service { std::string name; bool should_log; float frequency; int decimation; };\n"
|
h += "struct service { std::string name; bool should_log; int frequency; int decimation; };\n"
|
||||||
h += "static std::map<std::string, service> services = {\n"
|
h += "static std::map<std::string, service> services = {\n"
|
||||||
for k, v in SERVICE_LIST.items():
|
for k, v in SERVICE_LIST.items():
|
||||||
should_log = "true" if v.should_log else "false"
|
should_log = "true" if v.should_log else "false"
|
||||||
decimation = -1 if v.decimation is None else v.decimation
|
decimation = -1 if v.decimation is None else v.decimation
|
||||||
h += ' { "%s", {"%s", %s, %f, %d}},\n' % \
|
h += ' { "%s", {"%s", %s, %d, %d}},\n' % \
|
||||||
(k, k, should_log, v.frequency, decimation)
|
(k, k, should_log, v.frequency, decimation)
|
||||||
h += "};\n"
|
h += "};\n"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
# conversions
|
class Conversions:
|
||||||
class CV:
|
|
||||||
# Speed
|
# Speed
|
||||||
MPH_TO_KPH = 1.609344
|
MPH_TO_KPH = 1.609344
|
||||||
KPH_TO_MPH = 1. / MPH_TO_KPH
|
KPH_TO_MPH = 1. / MPH_TO_KPH
|
||||||
@@ -18,6 +17,3 @@ class CV:
|
|||||||
|
|
||||||
# Mass
|
# Mass
|
||||||
LB_TO_KG = 0.453592
|
LB_TO_KG = 0.453592
|
||||||
|
|
||||||
|
|
||||||
ACCELERATION_DUE_TO_GRAVITY = 9.81 # m/s^2
|
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
#define DEFAULT_MODEL "TCPv3 + gWMv9 (Default)"
|
#define DEFAULT_MODEL "Tomb Raider 14 (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
|
||||||
|
|
||||||
|
|||||||
+182
-239
@@ -3,261 +3,204 @@
|
|||||||
#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, INT}},
|
{"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, "0"}},
|
{"LiveParametersV2", PERSISTENT},
|
||||||
{"LastUpdateTime", {PERSISTENT, TIME}},
|
{"LiveTorqueParameters", PERSISTENT | DONT_LOG},
|
||||||
{"LastUpdateUptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
|
{"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_TemperatureTooHigh", {CLEAR_ON_MANAGER_START, JSON}},
|
{"OpenpilotEnabledToggle", PERSISTENT | BACKUP},
|
||||||
{"Offroad_UnregisteredHardware", {CLEAR_ON_MANAGER_START, JSON}},
|
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"Offroad_UpdateFailed", {CLEAR_ON_MANAGER_START, JSON}},
|
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"OnroadCycleRequested", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"PandaSignatures", CLEAR_ON_MANAGER_START},
|
||||||
{"OpenpilotEnabledToggle", {PERSISTENT | BACKUP, BOOL, "1"}},
|
{"PrimeType", PERSISTENT},
|
||||||
{"PandaHeartbeatLost", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"RecordAudio", PERSISTENT | BACKUP},
|
||||||
{"PandaSomResetTriggered", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"RecordFront", PERSISTENT | BACKUP},
|
||||||
{"PandaSignatures", {CLEAR_ON_MANAGER_START, BYTES}},
|
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
|
||||||
{"PrimeType", {PERSISTENT, INT}},
|
{"SecOCKey", PERSISTENT | DONT_LOG | BACKUP},
|
||||||
{"RecordAudio", {PERSISTENT | BACKUP, BOOL}},
|
{"RouteCount", PERSISTENT},
|
||||||
{"RecordAudioFeedback", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"RecordFront", {PERSISTENT | BACKUP, BOOL}},
|
{"SshEnabled", PERSISTENT | BACKUP},
|
||||||
{"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet
|
{"TermsVersion", PERSISTENT},
|
||||||
{"SecOCKey", {PERSISTENT | DONT_LOG | BACKUP, STRING}},
|
{"TrainingVersion", PERSISTENT},
|
||||||
{"RouteCount", {PERSISTENT, INT, "0"}},
|
{"UbloxAvailable", PERSISTENT},
|
||||||
{"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"SshEnabled", {PERSISTENT | BACKUP, BOOL}},
|
{"UpdateFailedCount", CLEAR_ON_MANAGER_START},
|
||||||
{"TermsVersion", {PERSISTENT, STRING}},
|
{"UpdaterAvailableBranches", PERSISTENT},
|
||||||
{"TrainingVersion", {PERSISTENT, STRING}},
|
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
|
||||||
{"UbloxAvailable", {PERSISTENT, BOOL}},
|
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdateAvailable", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdateFailedCount", {CLEAR_ON_MANAGER_START, INT}},
|
{"UpdaterNewDescription", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdaterAvailableBranches", {PERSISTENT, STRING}},
|
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdaterCurrentDescription", {CLEAR_ON_MANAGER_START, STRING}},
|
{"UpdaterState", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdaterCurrentReleaseNotes", {CLEAR_ON_MANAGER_START, BYTES}},
|
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdaterFetchAvailable", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"UpdaterLastFetchTime", PERSISTENT},
|
||||||
{"UpdaterNewDescription", {CLEAR_ON_MANAGER_START, STRING}},
|
{"Version", PERSISTENT},
|
||||||
{"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, JSON}},
|
{"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},
|
||||||
{"DevUIInfo", {PERSISTENT | BACKUP, INT, "0"}},
|
{"MaxTimeOffroad", PERSISTENT | BACKUP},
|
||||||
{"EnableCopyparty", {PERSISTENT | BACKUP, BOOL}},
|
{"Brightness", PERSISTENT | BACKUP},
|
||||||
{"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}},
|
{"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"GreenLightAlert", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"OffroadMode", CLEAR_ON_MANAGER_START},
|
||||||
{"GithubRunnerSufficientVoltage", {CLEAR_ON_MANAGER_START , BOOL}},
|
{"QuietMode", PERSISTENT | BACKUP},
|
||||||
{"HideVEgoUI", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"IntelligentCruiseButtonManagement", {PERSISTENT | BACKUP , BOOL}},
|
|
||||||
{"InteractivityTimeout", {PERSISTENT | BACKUP, INT, "0"}},
|
|
||||||
{"IsDevelopmentBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
|
||||||
{"IsReleaseSpBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
|
||||||
{"LastGPSPositionLLK", {PERSISTENT, STRING}},
|
|
||||||
{"LeadDepartAlert", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"MaxTimeOffroad", {PERSISTENT | BACKUP, INT, "1800"}},
|
|
||||||
{"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}},
|
|
||||||
{"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}},
|
|
||||||
{"Offroad_TiciSupport", {CLEAR_ON_MANAGER_START, JSON}},
|
|
||||||
{"OnroadScreenOffBrightness", {PERSISTENT | BACKUP, INT, "0"}},
|
|
||||||
{"OnroadScreenOffControl", {PERSISTENT | BACKUP, BOOL}},
|
|
||||||
{"OnroadScreenOffTimer", {PERSISTENT | BACKUP, INT, "15"}},
|
|
||||||
{"OnroadUploads", {PERSISTENT | BACKUP, BOOL, "1"}},
|
|
||||||
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"ShowTurnSignals", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"TrueVEgoUI", {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, JSON}},
|
{"DynamicModeldOutputs", PERSISTENT | BACKUP},
|
||||||
{"ModelManager_ClearCache", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"ModelManager_ActiveBundle", PERSISTENT},
|
||||||
{"ModelManager_DownloadIndex", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, INT, "0"}},
|
{"ModelManager_DownloadIndex", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"ModelManager_Favs", {PERSISTENT | BACKUP, STRING}},
|
{"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, JSON}},
|
|
||||||
|
|
||||||
// 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, INT}},
|
{"SunnylinkdPid", PERSISTENT},
|
||||||
{"SunnylinkEnabled", {PERSISTENT, BOOL, "1"}},
|
{"SunnylinkEnabled", PERSISTENT},
|
||||||
{"SunnylinkTempFault", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0"}},
|
|
||||||
|
|
||||||
// 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},
|
||||||
{"SubaruStopAndGo", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"SubaruStopAndGoManualParkingBrake", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"TeslaCoopSteering", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
|
|
||||||
{"DynamicExperimentalControl", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"DynamicExperimentalControl", PERSISTENT},
|
||||||
{"BlindSpot", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"BlindSpot", PERSISTENT | BACKUP},
|
||||||
|
|
||||||
// sunnypilot model params
|
// model panel params
|
||||||
{"LagdToggle", {PERSISTENT | BACKUP, BOOL, "1"}},
|
{"LagdToggle", PERSISTENT | BACKUP},
|
||||||
{"LagdToggleDelay", {PERSISTENT | BACKUP, FLOAT, "0.2"}},
|
{"LagdToggleDesc", PERSISTENT},
|
||||||
{"LagdValueCache", {PERSISTENT, FLOAT, "0.2"}},
|
{"LagdToggledelay", PERSISTENT | BACKUP},
|
||||||
{"LaneTurnDesire", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"LaneTurnValue", {PERSISTENT | BACKUP, FLOAT, "19.0"}},
|
|
||||||
|
|
||||||
// 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, JSON}},
|
{"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, JSON}},
|
{"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},
|
||||||
{"RoadNameToggle", {PERSISTENT, STRING}},
|
|
||||||
|
|
||||||
// Speed Limit
|
|
||||||
{"SpeedLimitMode", {PERSISTENT | BACKUP, INT, "1"}},
|
|
||||||
{"SpeedLimitOffsetType", {PERSISTENT | BACKUP, INT, "0"}},
|
|
||||||
{"SpeedLimitPolicy", {PERSISTENT | BACKUP, INT, "3"}},
|
|
||||||
{"SpeedLimitValueOffset", {PERSISTENT | BACKUP, INT, "0"}},
|
|
||||||
|
|
||||||
// Smart Cruise Control
|
|
||||||
{"MapTargetVelocities", {CLEAR_ON_ONROAD_TRANSITION, STRING}},
|
|
||||||
{"SmartCruiseControlMap", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"SmartCruiseControlVision", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
|
|
||||||
// Torque lateral control custom params
|
|
||||||
{"CustomTorqueParams", {PERSISTENT | BACKUP , BOOL}},
|
|
||||||
{"EnforceTorqueControl", {PERSISTENT | BACKUP, BOOL}},
|
|
||||||
{"LiveTorqueParamsToggle", {PERSISTENT | BACKUP , BOOL}},
|
|
||||||
{"LiveTorqueParamsRelaxedToggle", {PERSISTENT | BACKUP , BOOL}},
|
|
||||||
{"TorqueParamsOverrideEnabled", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"TorqueParamsOverrideFriction", {PERSISTENT | BACKUP, FLOAT, "0.1"}},
|
|
||||||
{"TorqueParamsOverrideLatAccelFactor", {PERSISTENT | BACKUP, FLOAT, "2.5"}},
|
|
||||||
};
|
};
|
||||||
|
|||||||
+13
-86
@@ -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,19 +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
|
|
||||||
|
|
||||||
def cpp2python(self, key, value):
|
|
||||||
cdef string k = self.check_key(key)
|
|
||||||
cdef ParamKeyType t = self.p.getKeyType(k)
|
|
||||||
return self._cpp2python(t, value, None, key)
|
|
||||||
|
|||||||
+19
-13
@@ -14,8 +14,10 @@ class PIDController:
|
|||||||
if isinstance(self._k_d, Number):
|
if isinstance(self._k_d, Number):
|
||||||
self._k_d = [[0], [self._k_d]]
|
self._k_d = [[0], [self._k_d]]
|
||||||
|
|
||||||
self.set_limits(pos_limit, neg_limit)
|
self.pos_limit = pos_limit
|
||||||
|
self.neg_limit = neg_limit
|
||||||
|
|
||||||
|
self.i_unwind_rate = 0.3 / rate
|
||||||
self.i_rate = 1.0 / rate
|
self.i_rate = 1.0 / rate
|
||||||
self.speed = 0.0
|
self.speed = 0.0
|
||||||
|
|
||||||
@@ -33,6 +35,10 @@ class PIDController:
|
|||||||
def k_d(self):
|
def k_d(self):
|
||||||
return np.interp(self.speed, self._k_d[0], self._k_d[1])
|
return np.interp(self.speed, self._k_d[0], self._k_d[1])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def error_integral(self):
|
||||||
|
return self.i/self.k_i
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.p = 0.0
|
self.p = 0.0
|
||||||
self.i = 0.0
|
self.i = 0.0
|
||||||
@@ -40,25 +46,25 @@ class PIDController:
|
|||||||
self.f = 0.0
|
self.f = 0.0
|
||||||
self.control = 0
|
self.control = 0
|
||||||
|
|
||||||
def set_limits(self, pos_limit, neg_limit):
|
def update(self, error, error_rate=0.0, speed=0.0, override=False, feedforward=0., freeze_integrator=False):
|
||||||
self.pos_limit = pos_limit
|
|
||||||
self.neg_limit = neg_limit
|
|
||||||
|
|
||||||
def update(self, error, error_rate=0.0, speed=0.0, feedforward=0., freeze_integrator=False):
|
|
||||||
self.speed = speed
|
self.speed = speed
|
||||||
|
|
||||||
self.p = float(error) * self.k_p
|
self.p = float(error) * self.k_p
|
||||||
self.f = feedforward * self.k_f
|
self.f = feedforward * self.k_f
|
||||||
self.d = error_rate * self.k_d
|
self.d = error_rate * self.k_d
|
||||||
|
|
||||||
if not freeze_integrator:
|
if override:
|
||||||
i = self.i + error * self.k_i * self.i_rate
|
self.i -= self.i_unwind_rate * float(np.sign(self.i))
|
||||||
|
else:
|
||||||
|
if not freeze_integrator:
|
||||||
|
self.i = self.i + error * self.k_i * self.i_rate
|
||||||
|
|
||||||
# Don't allow windup if already clipping
|
# Clip i to prevent exceeding control limits
|
||||||
test_control = self.p + i + self.d + self.f
|
control_no_i = self.p + self.d + self.f
|
||||||
i_upperbound = self.i if test_control > self.pos_limit else self.pos_limit
|
control_no_i = np.clip(control_no_i, self.neg_limit, self.pos_limit)
|
||||||
i_lowerbound = self.i if test_control < self.neg_limit else self.neg_limit
|
self.i = np.clip(self.i, self.neg_limit - control_no_i, self.pos_limit - control_no_i)
|
||||||
self.i = np.clip(i, i_lowerbound, i_upperbound)
|
|
||||||
|
|
||||||
control = self.p + self.i + self.d + self.f
|
control = self.p + self.i + self.d + self.f
|
||||||
|
|
||||||
self.control = np.clip(control, self.neg_limit, self.pos_limit)
|
self.control = np.clip(control, self.neg_limit, self.pos_limit)
|
||||||
return self.control
|
return self.control
|
||||||
|
|||||||
+6
-12
@@ -9,19 +9,20 @@ from openpilot.system.hardware.hw import Paths
|
|||||||
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||||
|
|
||||||
class OpenpilotPrefix:
|
class OpenpilotPrefix:
|
||||||
def __init__(self, prefix: str = None, create_dirs_on_enter: bool = True, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
|
def __init__(self, prefix: str = None, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
|
||||||
self.prefix = prefix if prefix else str(uuid.uuid4().hex[0:15])
|
self.prefix = prefix if prefix else str(uuid.uuid4().hex[0:15])
|
||||||
self.msgq_path = os.path.join(Paths.shm_path(), self.prefix)
|
self.msgq_path = os.path.join(Paths.shm_path(), self.prefix)
|
||||||
self.create_dirs_on_enter = create_dirs_on_enter
|
|
||||||
self.clean_dirs_on_exit = clean_dirs_on_exit
|
self.clean_dirs_on_exit = clean_dirs_on_exit
|
||||||
self.shared_download_cache = shared_download_cache
|
self.shared_download_cache = shared_download_cache
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.original_prefix = os.environ.get('OPENPILOT_PREFIX', None)
|
self.original_prefix = os.environ.get('OPENPILOT_PREFIX', None)
|
||||||
os.environ['OPENPILOT_PREFIX'] = self.prefix
|
os.environ['OPENPILOT_PREFIX'] = self.prefix
|
||||||
|
try:
|
||||||
if self.create_dirs_on_enter:
|
os.mkdir(self.msgq_path)
|
||||||
self.create_dirs()
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
os.makedirs(Paths.log_root(), exist_ok=True)
|
||||||
|
|
||||||
if self.shared_download_cache:
|
if self.shared_download_cache:
|
||||||
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
|
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||||
@@ -39,13 +40,6 @@ class OpenpilotPrefix:
|
|||||||
pass
|
pass
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def create_dirs(self):
|
|
||||||
try:
|
|
||||||
os.mkdir(self.msgq_path)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
os.makedirs(Paths.log_root(), exist_ok=True)
|
|
||||||
|
|
||||||
def clean_dirs(self):
|
def clean_dirs(self):
|
||||||
symlink_path = Params().get_param_path()
|
symlink_path = Params().get_param_path()
|
||||||
if os.path.exists(symlink_path):
|
if os.path.exists(symlink_path):
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
from contextlib import contextmanager
|
|
||||||
from subprocess import Popen, PIPE, TimeoutExpired
|
|
||||||
|
|
||||||
|
|
||||||
def run_cmd(cmd: list[str], cwd=None, env=None) -> str:
|
def run_cmd(cmd: list[str], cwd=None, env=None) -> str:
|
||||||
@@ -13,16 +11,3 @@ def run_cmd_default(cmd: list[str], default: str = "", cwd=None, env=None) -> st
|
|||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def managed_proc(cmd: list[str], env: dict[str, str]):
|
|
||||||
proc = Popen(cmd, env=env, stdout=PIPE, stderr=PIPE)
|
|
||||||
try:
|
|
||||||
yield proc
|
|
||||||
finally:
|
|
||||||
if proc.poll() is None:
|
|
||||||
proc.terminate()
|
|
||||||
try:
|
|
||||||
proc.wait(timeout=5)
|
|
||||||
except TimeoutExpired:
|
|
||||||
proc.kill()
|
|
||||||
|
|||||||
+1
-3
@@ -15,8 +15,6 @@
|
|||||||
#include "common/version.h"
|
#include "common/version.h"
|
||||||
#include "system/hardware/hw.h"
|
#include "system/hardware/hw.h"
|
||||||
|
|
||||||
#include "sunnypilot/common/version.h"
|
|
||||||
|
|
||||||
class SwaglogState {
|
class SwaglogState {
|
||||||
public:
|
public:
|
||||||
SwaglogState() {
|
SwaglogState() {
|
||||||
@@ -58,7 +56,7 @@ public:
|
|||||||
if (char* daemon_name = getenv("MANAGER_DAEMON")) {
|
if (char* daemon_name = getenv("MANAGER_DAEMON")) {
|
||||||
ctx_j["daemon"] = daemon_name;
|
ctx_j["daemon"] = daemon_name;
|
||||||
}
|
}
|
||||||
ctx_j["version"] = SUNNYPILOT_VERSION;
|
ctx_j["version"] = COMMA_VERSION;
|
||||||
ctx_j["dirty"] = !getenv("CLEAN");
|
ctx_j["dirty"] = !getenv("CLEAN");
|
||||||
ctx_j["device"] = Hardware::get_name();
|
ctx_j["device"] = Hardware::get_name();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from openpilot.common.markdown import parse_markdown
|
|||||||
|
|
||||||
class TestMarkdown:
|
class TestMarkdown:
|
||||||
def test_all_release_notes(self):
|
def test_all_release_notes(self):
|
||||||
with open(os.path.join(BASEDIR, "CHANGELOG.md")) as f:
|
with open(os.path.join(BASEDIR, "RELEASES.md")) as f:
|
||||||
release_notes = f.read().split("\n\n")
|
release_notes = f.read().split("\n\n")
|
||||||
assert len(release_notes) > 10
|
assert len(release_notes) > 10
|
||||||
|
|
||||||
|
|||||||
+12
-44
@@ -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,24 +29,24 @@ 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)
|
||||||
|
|
||||||
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
|
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
#include "system/hardware/hw.h"
|
#include "system/hardware/hw.h"
|
||||||
#include "third_party/json11/json11.hpp"
|
#include "third_party/json11/json11.hpp"
|
||||||
|
|
||||||
#include "sunnypilot/common/version.h"
|
|
||||||
|
|
||||||
std::string daemon_name = "testy";
|
std::string daemon_name = "testy";
|
||||||
std::string dongle_id = "test_dongle_id";
|
std::string dongle_id = "test_dongle_id";
|
||||||
int LINE_NO = 0;
|
int LINE_NO = 0;
|
||||||
@@ -55,7 +53,7 @@ void recv_log(int thread_cnt, int thread_msg_cnt) {
|
|||||||
REQUIRE(ctx["dongle_id"].string_value() == dongle_id);
|
REQUIRE(ctx["dongle_id"].string_value() == dongle_id);
|
||||||
REQUIRE(ctx["dirty"].bool_value() == true);
|
REQUIRE(ctx["dirty"].bool_value() == true);
|
||||||
|
|
||||||
REQUIRE(ctx["version"].string_value() == SUNNYPILOT_VERSION);
|
REQUIRE(ctx["version"].string_value() == COMMA_VERSION);
|
||||||
|
|
||||||
std::string device = Hardware::get_name();
|
std::string device = Hardware::get_name();
|
||||||
REQUIRE(ctx["device"].string_value() == device);
|
REQUIRE(ctx["device"].string_value() == device);
|
||||||
|
|||||||
+3
-11
@@ -1,5 +1,4 @@
|
|||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
#include "common/swaglog.h"
|
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -13,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>
|
||||||
@@ -80,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);
|
||||||
@@ -152,16 +149,11 @@ int safe_fflush(FILE *stream) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int safe_ioctl(int fd, unsigned long request, void *argp, const char* exception_msg) {
|
int safe_ioctl(int fd, unsigned long request, void *argp) {
|
||||||
int ret;
|
int ret;
|
||||||
do {
|
do {
|
||||||
ret = ioctl(fd, request, argp);
|
ret = ioctl(fd, request, argp);
|
||||||
} while ((ret == -1) && (errno == EINTR));
|
} while ((ret == -1) && (errno == EINTR));
|
||||||
|
|
||||||
if (ret == -1 && exception_msg) {
|
|
||||||
LOGE("safe_ioctl error: %s %s(%d) (fd: %d request: %lx argp: %p)", exception_msg, strerror(errno), errno, fd, request, argp);
|
|
||||||
throw std::runtime_error(exception_msg);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -36,7 +36,6 @@ const double MS_TO_KPH = 3.6;
|
|||||||
const double MS_TO_MPH = MS_TO_KPH * KM_TO_MILE;
|
const double MS_TO_MPH = MS_TO_KPH * KM_TO_MILE;
|
||||||
const double METER_TO_MILE = KM_TO_MILE / 1000.0;
|
const double METER_TO_MILE = KM_TO_MILE / 1000.0;
|
||||||
const double METER_TO_FOOT = 3.28084;
|
const double METER_TO_FOOT = 3.28084;
|
||||||
const double METER_TO_KM = 1. / 1000.0;
|
|
||||||
|
|
||||||
#define ALIGNED_SIZE(x, align) (((x) + (align)-1) & ~((align)-1))
|
#define ALIGNED_SIZE(x, align) (((x) + (align)-1) & ~((align)-1))
|
||||||
|
|
||||||
@@ -89,7 +88,7 @@ int write_file(const char* path, const void* data, size_t size, int flags = O_WR
|
|||||||
FILE* safe_fopen(const char* filename, const char* mode);
|
FILE* safe_fopen(const char* filename, const char* mode);
|
||||||
size_t safe_fwrite(const void * ptr, size_t size, size_t count, FILE * stream);
|
size_t safe_fwrite(const void * ptr, size_t size, size_t count, FILE * stream);
|
||||||
int safe_fflush(FILE *stream);
|
int safe_fflush(FILE *stream);
|
||||||
int safe_ioctl(int fd, unsigned long request, void *argp, const char* exception_msg = nullptr);
|
int safe_ioctl(int fd, unsigned long request, void *argp);
|
||||||
|
|
||||||
std::string readlink(const std::string& path);
|
std::string readlink(const std::string& path);
|
||||||
bool file_exists(const std::string& fn);
|
bool file_exists(const std::string& fn);
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
#define COMMA_VERSION "0.10.1"
|
#define COMMA_VERSION "0.10.0"
|
||||||
|
|||||||
+313
-340
@@ -4,349 +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.
|
||||||
|
|
||||||
# 339 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|MDX 2025|All except Type S|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch 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=Acura MDX 2025">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 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 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>|||
|
||||||
|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>|||
|
|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 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 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|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|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|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|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|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|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|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|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>|||
|
||||||
|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>|||
|
|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 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 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|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|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|Bolt EV Non-ACC 2017|Adaptive Cruise Control (ACC)|Stock|24 mph|7 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 Non-ACC 2017">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|Bolt EV Non-ACC 2018-21|Adaptive Cruise Control (ACC)|Stock|24 mph|7 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 Non-ACC 2018-21">Buy Here</a></sub></details>|||
|
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Trailblazer 2021-22">Buy Here</a></sub></details>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|Chevrolet|Malibu Non-ACC 2016-23|Adaptive Cruise Control (ACC)|Stock|24 mph|7 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 Malibu Non-ACC 2016-23">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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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 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 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>|||
|
||||||
|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>|||
|
|comma|body|All|openpilot|0 mph|0 mph|[](##)|[](##)|None|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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|
|
||||||
|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>|||
|
|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|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|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 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 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 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 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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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 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 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|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|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|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|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|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|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|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|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|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|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|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|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|
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|
|
|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>|||
|
||||||
|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>|
|
|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>||
|
|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|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|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|Accord 2023-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch 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=Honda Accord 2023-25">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|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|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|Accord Hybrid 2023-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch 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=Honda Accord Hybrid 2023-25">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|City (Brazil only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|14 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 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 City (Brazil 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 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|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|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|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|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|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|Civic Hatchback 2017-18|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 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-18">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|Civic Hatchback 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 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 2019-21">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|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|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|Civic Hatchback Hybrid 2025-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 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-26">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|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|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|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|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|Clarity 2018-21|Honda Sensing|openpilot|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector + Honda Clarity Proxy Board<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://shop.retropilot.org/product/honda-clarity-proxy-board-kit">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|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|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|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|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|CR-V 2023-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch 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=Honda CR-V 2023-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|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|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|CR-V Hybrid 2023-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch 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=Honda CR-V Hybrid 2023-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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|Honda|N-Box 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|11 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 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 N-Box 2018">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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|Honda|Odyssey 2021-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|43 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 Odyssey 2021-25">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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|Honda|Pilot 2023-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C 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=Honda Pilot 2023-25">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>|||
|
||||||
|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 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 Non-SCC 2022">Buy Here</a></sub></details>|||
|
|Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|Kona 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 2022-23">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|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|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|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|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|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|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|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 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 Non-SCC 2019">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|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|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|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 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 Non-SCC 2019">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>||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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|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|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|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|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|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|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|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|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 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 Plug-in Hybrid Non-SCC 2022">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|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|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|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|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|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|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|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|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|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|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|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 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 Non-SCC 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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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.html?make=Lexus&model=LC 2024-25">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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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 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=Kia Telluride 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.html?make=Lexus&model=RX Hybrid 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?harness=Lexus CT Hybrid 2017-18">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|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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|
|
||||||
|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>|||
|
|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|
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|Š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)|||
|
||||||
|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>||
|
|Š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)|||
|
||||||
|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>|||
|
|Š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>|||
|
||||||
|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>||
|
|Š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>|||
|
||||||
|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>|||
|
|Š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>|||
|
||||||
|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>|||
|
|Š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>|||
|
||||||
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|32 mph|1 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>|||
|
|Š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>|||
|
||||||
|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|Stock|0 mph|36 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 2500 2020-24">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)|||
|
||||||
|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|36 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 3500 2019-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.html?make=Škoda&model=Superb 2015-22">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?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>|
|
|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>|||
|
||||||
|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>|
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|Subaru|Forester 2017-18|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|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 2017-18">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Toyota|Avalon 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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|Subaru|Legacy 2015-18|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|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 Legacy 2015-18">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Toyota|Avalon 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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|Subaru|Outback 2015-17|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|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 Outback 2015-17">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|
|Toyota|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>|||
|
||||||
|Subaru|Outback 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|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 Outback 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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|Š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)|||
|
|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>||
|
||||||
|Š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)|||
|
|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>|||
|
||||||
|Š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>|||
|
|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>|||
|
||||||
|Š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>|||
|
|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>||
|
||||||
|Š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>|||
|
|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>|||
|
||||||
|Š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>|||
|
|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>|||
|
||||||
|Š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>|||
|
|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>||
|
||||||
|Š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)|||
|
|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>|||
|
||||||
|Š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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|Tesla[<sup>11</sup>](#footnotes)|Model Y (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 Y (with HW4) 2024-25">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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>||
|
|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>||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>||
|
|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>||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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>||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>|||
|
|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>|||
|
||||||
|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>||
|
|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>|||
|
||||||
|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>||
|
|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)|||
|
||||||
|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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?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 />
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Development is coordinated through [Discord](https://discord.comma.ai) and GitHu
|
|||||||
|
|
||||||
### Getting Started
|
### Getting Started
|
||||||
|
|
||||||
* Set up your [development environment](/tools/)
|
* Setup your [development environment](../tools/)
|
||||||
* Join our [Discord](https://discord.comma.ai)
|
* Join our [Discord](https://discord.comma.ai)
|
||||||
* Docs are at https://docs.comma.ai and https://blog.comma.ai
|
* Docs are at https://docs.comma.ai and https://blog.comma.ai
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ All of these are examples of good PRs:
|
|||||||
### First contribution
|
### First contribution
|
||||||
|
|
||||||
[Projects / openpilot bounties](https://github.com/orgs/commaai/projects/26/views/1?pane=info) is the best place to get started and goes in-depth on what's expected when working on a bounty.
|
[Projects / openpilot bounties](https://github.com/orgs/commaai/projects/26/views/1?pane=info) is the best place to get started and goes in-depth on what's expected when working on a bounty.
|
||||||
There's lot of bounties that don't require a comma 3X or a car.
|
There's lot of bounties that don't require a comma 3/3X or a car.
|
||||||
|
|
||||||
## Pull Requests
|
## Pull Requests
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
# Debugging Panda Safety with Replay Drive + LLDB
|
|
||||||
|
|
||||||
## 1. Start the debugger in VS Code
|
|
||||||
|
|
||||||
* Select **Replay drive + Safety LLDB**.
|
|
||||||
* Enter the route or segment when prompted.
|
|
||||||
[<img src="https://github.com/user-attachments/assets/b0cc320a-083e-46a7-a9f8-ca775bbe5604">](https://github.com/user-attachments/assets/b0cc320a-083e-46a7-a9f8-ca775bbe5604)
|
|
||||||
|
|
||||||
## 2. Attach LLDB
|
|
||||||
|
|
||||||
* When prompted, pick the running **`replay_drive` process**.
|
|
||||||
* ⚠️ Attach quickly, or `replay_drive` will start consuming messages.
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> Add a Python breakpoint at the start of `replay_drive.py` to pause execution and give yourself time to attach LLDB.
|
|
||||||
|
|
||||||
## 3. Set breakpoints in VS Code
|
|
||||||
Breakpoints can be set directly in `modes/xxx.h` (or any C file).
|
|
||||||
No extra LLDB commands are required — just place breakpoints in the editor.
|
|
||||||
|
|
||||||
## 4. Resume execution
|
|
||||||
Once attached, you can step through both Python (on the replay) and C safety code as CAN logs are replayed.
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> * Use short routes for quicker iteration.
|
|
||||||
> * Pause `replay_drive` early to avoid wasting log messages.
|
|
||||||
|
|
||||||
## Video
|
|
||||||
|
|
||||||
View a demo of this workflow on the PR that added it: https://github.com/commaai/openpilot/pull/36055#issue-3352911578
|
|
||||||
+4
-14
@@ -16,7 +16,7 @@ industry standards of safety for Level 2 Driver Assistance Systems. In particula
|
|||||||
ISO26262 guidelines, including those from [pertinent documents](https://www.nhtsa.gov/sites/nhtsa.dot.gov/files/documents/13498a_812_573_alcsystemreport.pdf)
|
ISO26262 guidelines, including those from [pertinent documents](https://www.nhtsa.gov/sites/nhtsa.dot.gov/files/documents/13498a_812_573_alcsystemreport.pdf)
|
||||||
released by NHTSA. In addition, we impose strict coding guidelines (like [MISRA C : 2012](https://www.misra.org.uk/what-is-misra/))
|
released by NHTSA. In addition, we impose strict coding guidelines (like [MISRA C : 2012](https://www.misra.org.uk/what-is-misra/))
|
||||||
on parts of openpilot that are safety relevant. We also perform software-in-the-loop,
|
on parts of openpilot that are safety relevant. We also perform software-in-the-loop,
|
||||||
hardware-in-the-loop, and in-vehicle tests before each software release.
|
hardware-in-the-loop and in-vehicle tests before each software release.
|
||||||
|
|
||||||
Following Hazard and Risk Analysis and FMEA, at a very high level, we have designed openpilot
|
Following Hazard and Risk Analysis and FMEA, at a very high level, we have designed openpilot
|
||||||
ensuring two main safety requirements.
|
ensuring two main safety requirements.
|
||||||
@@ -29,18 +29,8 @@ ensuring two main safety requirements.
|
|||||||
|
|
||||||
For additional safety implementation details, refer to [panda safety model](https://github.com/commaai/panda#safety-model). For vehicle specific implementation of the safety concept, refer to [opendbc/safety/safety](https://github.com/commaai/opendbc/tree/master/opendbc/safety/safety).
|
For additional safety implementation details, refer to [panda safety model](https://github.com/commaai/panda#safety-model). For vehicle specific implementation of the safety concept, refer to [opendbc/safety/safety](https://github.com/commaai/opendbc/tree/master/opendbc/safety/safety).
|
||||||
|
|
||||||
[^1]: For these actuator limits we observe ISO11270 and ISO15622. Lateral limits described there translate to 0.9 seconds of maximum actuation to achieve a 1m lateral deviation.
|
**Extra note**: comma.ai strongly discourages the use of openpilot forks with safety code either missing or
|
||||||
|
not fully meeting the above requirements.
|
||||||
|
|
||||||
---
|
[^1]: For these actuator limits we observe ISO11270 and ISO15622. Lateral limits described there translate to 0.9 seconds of maximum actuation to achieve a 1m lateral deviation.
|
||||||
|
|
||||||
### Forks of openpilot
|
|
||||||
|
|
||||||
* Do not disable or nerf [driver monitoring](https://github.com/commaai/openpilot/tree/master/selfdrive/monitoring)
|
|
||||||
* Do not disable or nerf [excessive actuation checks](https://github.com/commaai/openpilot/tree/master/selfdrive/selfdrived/helpers.py)
|
|
||||||
* If your fork modifies any of the code in `opendbc/safety/`:
|
|
||||||
* your fork cannot use the openpilot trademark
|
|
||||||
* your fork must preserve the full [safety test suite](https://github.com/commaai/opendbc/tree/master/opendbc/safety/tests) and all tests must pass, including any new coverage required by the fork's changes
|
|
||||||
|
|
||||||
Failure to comply with these standards will get you and your users banned from comma.ai servers.
|
|
||||||
|
|
||||||
**comma.ai strongly discourages the use of openpilot forks with safety code either missing or not fully meeting the above requirements.**
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# connect to a comma 3X
|
# connect to a comma 3/3X
|
||||||
|
|
||||||
A comma 3X is a normal [Linux](https://github.com/commaai/agnos-builder) computer that exposes [SSH](https://wiki.archlinux.org/title/Secure_Shell) and a [serial console](https://wiki.archlinux.org/title/Working_with_the_serial_console).
|
A comma 3/3X is a normal [Linux](https://github.com/commaai/agnos-builder) computer that exposes [SSH](https://wiki.archlinux.org/title/Secure_Shell) and a [serial console](https://wiki.archlinux.org/title/Working_with_the_serial_console).
|
||||||
|
|
||||||
## Serial Console
|
## Serial Console
|
||||||
|
|
||||||
On both the comma three and 3X, the serial console is accessible from the main OBD-C port.
|
On both the comma three and 3X, the serial console is accessible from the main OBD-C port.
|
||||||
Connect the comma 3X to your computer with a normal USB C cable, or use a [comma serial](https://comma.ai/shop/comma-serial) for steady 12V power.
|
Connect the comma 3/3X to your computer with a normal USB C cable, or use a [comma serial](https://comma.ai/shop/comma-serial) for steady 12V power.
|
||||||
|
|
||||||
On the comma three, the serial console is exposed through a UART-to-USB chip, and `tools/scripts/serial.sh` can be used to connect.
|
On the comma three, the serial console is exposed through a UART-to-USB chip, and `tools/scripts/serial.sh` can be used to connect.
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ In order to use ADB on your device, you'll need to perform the following steps u
|
|||||||
* Here's an example command for connecting to your device using its tethered connection: `adb connect 192.168.43.1:5555`
|
* Here's an example command for connecting to your device using its tethered connection: `adb connect 192.168.43.1:5555`
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> The default port for ADB is 5555 on the comma 3X.
|
> The default port for ADB is 5555 on the comma 3/3X.
|
||||||
|
|
||||||
For more info on ADB, see the [Android Debug Bridge (ADB) documentation](https://developer.android.com/tools/adb).
|
For more info on ADB, see the [Android Debug Bridge (ADB) documentation](https://developer.android.com/tools/adb).
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Replaying is a critical tool for openpilot development and debugging.
|
|||||||
Just run `tools/replay/replay --demo`.
|
Just run `tools/replay/replay --demo`.
|
||||||
|
|
||||||
## Replaying CAN data
|
## Replaying CAN data
|
||||||
*Hardware required: jungle and comma 3X*
|
*Hardware required: jungle and comma 3/3X*
|
||||||
|
|
||||||
1. Connect your PC to a jungle.
|
1. Connect your PC to a jungle.
|
||||||
2.
|
2.
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# Turn the speed blue
|
# Turn the speed blue
|
||||||
*A getting started guide for openpilot development*
|
*A getting started guide for openpilot development*
|
||||||
|
|
||||||
In 30 minutes, we'll get an openpilot development environment set up on your computer and make some changes to openpilot's UI.
|
In 30 minutes, we'll get an openpilot development environment setup on your computer and make some changes to openpilot's UI.
|
||||||
|
|
||||||
And if you have a comma 3X, we'll deploy the change to your device for testing.
|
And if you have a comma 3/3X, we'll deploy the change to your device for testing.
|
||||||
|
|
||||||
## 1. Set up your development environment
|
## 1. Setup your development environment
|
||||||
|
|
||||||
Run this to clone openpilot and install all the dependencies:
|
Run this to clone openpilot and install all the dependencies:
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
|
|||||||
export VECLIB_MAXIMUM_THREADS=1
|
export VECLIB_MAXIMUM_THREADS=1
|
||||||
|
|
||||||
if [ -z "$AGNOS_VERSION" ]; then
|
if [ -z "$AGNOS_VERSION" ]; then
|
||||||
export AGNOS_VERSION="13.1"
|
export AGNOS_VERSION="12.4"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export STAGING_ROOT="/data/safe_staging"
|
export STAGING_ROOT="/data/safe_staging"
|
||||||
|
|||||||
@@ -1,20 +1,3 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
|
||||||
IFS=$'\n\t'
|
|
||||||
|
|
||||||
# On any failure, run the fallback launcher
|
|
||||||
trap 'exec ./launch_chffrplus.sh' ERR
|
|
||||||
C3_LAUNCH_SH="./sunnypilot/system/hardware/c3/launch_chffrplus.sh"
|
|
||||||
|
|
||||||
MODEL="$(tr -d '\0' < "/sys/firmware/devicetree/base/model")"
|
|
||||||
export MODEL
|
|
||||||
|
|
||||||
if [ "$MODEL" = "comma tici" ]; then
|
|
||||||
# Force a failure if the launcher doesn't exist
|
|
||||||
[ -x "$C3_LAUNCH_SH" ] || false
|
|
||||||
|
|
||||||
# If it exists, run it
|
|
||||||
exec "$C3_LAUNCH_SH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec ./launch_chffrplus.sh
|
exec ./launch_chffrplus.sh
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ nav:
|
|||||||
- What is openpilot?: getting-started/what-is-openpilot.md
|
- What is openpilot?: getting-started/what-is-openpilot.md
|
||||||
- How-to:
|
- How-to:
|
||||||
- Turn the speed blue: how-to/turn-the-speed-blue.md
|
- Turn the speed blue: how-to/turn-the-speed-blue.md
|
||||||
- Connect to a comma 3X: how-to/connect-to-comma.md
|
- Connect to a comma 3/3X: how-to/connect-to-comma.md
|
||||||
# - Make your first pull request: how-to/make-first-pr.md
|
# - Make your first pull request: how-to/make-first-pr.md
|
||||||
#- Replay a drive: how-to/replay-a-drive.md
|
#- Replay a drive: how-to/replay-a-drive.md
|
||||||
- Concepts:
|
- Concepts:
|
||||||
|
|||||||
+1
-1
Submodule opendbc_repo updated: c7126f8ba6...b68fab9ea4
+1
-1
Submodule panda updated: 69ab12ee2a...c33cfa0803
+11
-13
@@ -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",
|
||||||
@@ -36,15 +36,13 @@ dependencies = [
|
|||||||
"pyopenssl < 24.3.0",
|
"pyopenssl < 24.3.0",
|
||||||
"pyaudio",
|
"pyaudio",
|
||||||
|
|
||||||
# ubloxd (TODO: just use struct)
|
|
||||||
"kaitaistruct",
|
|
||||||
|
|
||||||
# panda
|
# panda
|
||||||
"libusb1",
|
"libusb1",
|
||||||
"spidev; platform_system == 'Linux'",
|
"spidev; platform_system == 'Linux'",
|
||||||
|
|
||||||
# modeld
|
# modeld
|
||||||
"onnx >= 1.14.0",
|
"onnx >= 1.14.0",
|
||||||
|
"llvmlite",
|
||||||
|
|
||||||
# logging
|
# logging
|
||||||
"pyzmq",
|
"pyzmq",
|
||||||
@@ -88,8 +86,8 @@ testing = [
|
|||||||
"pytest",
|
"pytest",
|
||||||
"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",
|
||||||
@@ -104,9 +102,8 @@ dev = [
|
|||||||
"av",
|
"av",
|
||||||
"azure-identity",
|
"azure-identity",
|
||||||
"azure-storage-blob",
|
"azure-storage-blob",
|
||||||
"dbus-next", # TODO: remove once we moved everything to jeepney
|
"dbus-next",
|
||||||
"dictdiffer",
|
"dictdiffer",
|
||||||
"jeepney",
|
|
||||||
"matplotlib",
|
"matplotlib",
|
||||||
"opencv-python-headless",
|
"opencv-python-headless",
|
||||||
"parameterized >=0.8, <0.9",
|
"parameterized >=0.8, <0.9",
|
||||||
@@ -124,7 +121,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')",
|
||||||
"dearpygui>=2.1.0",
|
"rerun-sdk >= 0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
@@ -156,12 +153,12 @@ markers = [
|
|||||||
testpaths = [
|
testpaths = [
|
||||||
"common",
|
"common",
|
||||||
"selfdrive",
|
"selfdrive",
|
||||||
"system/manager",
|
|
||||||
"system/updated",
|
"system/updated",
|
||||||
"system/athena",
|
"system/athena",
|
||||||
"system/camerad",
|
"system/camerad",
|
||||||
"system/hardware",
|
"system/hardware",
|
||||||
"system/loggerd",
|
"system/loggerd",
|
||||||
|
"system/proclogd",
|
||||||
"system/tests",
|
"system/tests",
|
||||||
"system/ubloxd",
|
"system/ubloxd",
|
||||||
"system/webrtc",
|
"system/webrtc",
|
||||||
@@ -177,10 +174,13 @@ quiet-level = 3
|
|||||||
# if you've got a short variable name that's getting flagged, add it here
|
# if you've got a short variable name that's getting flagged, add it here
|
||||||
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl,lite"
|
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl,lite"
|
||||||
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
|
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
|
||||||
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*, tools/plotjuggler/layouts/*"
|
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*"
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
python_version = "3.11"
|
python_version = "3.11"
|
||||||
|
plugins = [
|
||||||
|
"numpy.typing.mypy_plugin",
|
||||||
|
]
|
||||||
exclude = [
|
exclude = [
|
||||||
"cereal/",
|
"cereal/",
|
||||||
"msgq/",
|
"msgq/",
|
||||||
@@ -251,7 +251,6 @@ exclude = [
|
|||||||
"teleoprtc_repo",
|
"teleoprtc_repo",
|
||||||
"third_party",
|
"third_party",
|
||||||
"*.ipynb",
|
"*.ipynb",
|
||||||
"generated",
|
|
||||||
]
|
]
|
||||||
lint.flake8-implicit-str-concat.allow-multiline = false
|
lint.flake8-implicit-str-concat.allow-multiline = false
|
||||||
|
|
||||||
@@ -264,7 +263,6 @@ 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.ruff.format]
|
[tool.ruff.format]
|
||||||
quote-style = "preserve"
|
quote-style = "preserve"
|
||||||
|
|||||||
+10
-15
@@ -3,34 +3,29 @@
|
|||||||
```
|
```
|
||||||
## release checklist
|
## release checklist
|
||||||
|
|
||||||
### Go to staging
|
**Go to `devel-staging`**
|
||||||
- [ ] make a GitHub issue to track release
|
|
||||||
- [ ] create release master branch
|
|
||||||
- [ ] update RELEASES.md
|
- [ ] update RELEASES.md
|
||||||
|
- [ ] update `devel-staging`: `git reset --hard origin/master-ci`
|
||||||
|
- [ ] open a pull request from `devel-staging` to `devel`
|
||||||
|
- [ ] post on Discord
|
||||||
|
|
||||||
|
**Go to `devel`**
|
||||||
- [ ] bump version on master: `common/version.h` and `RELEASES.md`
|
- [ ] bump version on master: `common/version.h` and `RELEASES.md`
|
||||||
- [ ] build new userdata partition from `release3-staging`
|
- [ ] before merging the pull request
|
||||||
- [ ] post on Discord, tag `@release crew`
|
|
||||||
|
|
||||||
Updating staging:
|
|
||||||
1. either rebase on master or cherry-pick changes
|
|
||||||
2. run this to update: `BRANCH=devel-staging release/build_devel.sh`
|
|
||||||
3. build new userdata partition from `release3-staging`
|
|
||||||
|
|
||||||
### Go to release
|
|
||||||
- [ ] before going to release, test the following:
|
|
||||||
- [ ] update from previous release -> new release
|
- [ ] update from previous release -> new release
|
||||||
- [ ] update from new release -> previous release
|
- [ ] update from new release -> previous release
|
||||||
- [ ] fresh install with `openpilot-test.comma.ai`
|
- [ ] fresh install with `openpilot-test.comma.ai`
|
||||||
- [ ] drive on fresh install
|
- [ ] drive on fresh install
|
||||||
- [ ] no submodules or LFS
|
- [ ] no submodules or LFS
|
||||||
- [ ] check sentry, MTBF, etc.
|
- [ ] check sentry, MTBF, etc.
|
||||||
- [ ] stress test passes in production
|
|
||||||
|
**Go to `release3`**
|
||||||
- [ ] publish the blog post
|
- [ ] publish the blog post
|
||||||
- [ ] `git reset --hard origin/release3-staging`
|
- [ ] `git reset --hard origin/release3-staging`
|
||||||
- [ ] tag the release: `git tag v0.X.X <commit-hash> && git push origin v0.X.X`
|
- [ ] tag the release: `git tag v0.X.X <commit-hash> && git push origin v0.X.X`
|
||||||
- [ ] create GitHub release
|
- [ ] create GitHub release
|
||||||
- [ ] final test install on `openpilot.comma.ai`
|
- [ ] final test install on `openpilot.comma.ai`
|
||||||
- [ ] update factory provisioning
|
- [ ] update factory provisioning
|
||||||
- [ ] close out milestone and issue
|
- [ ] close out milestone
|
||||||
- [ ] post on Discord, X, etc.
|
- [ ] post on Discord, X, etc.
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -17,23 +17,28 @@ rm -rf $TARGET_DIR
|
|||||||
mkdir -p $TARGET_DIR
|
mkdir -p $TARGET_DIR
|
||||||
cd $TARGET_DIR
|
cd $TARGET_DIR
|
||||||
cp -r $SOURCE_DIR/.git $TARGET_DIR
|
cp -r $SOURCE_DIR/.git $TARGET_DIR
|
||||||
|
pre-commit uninstall || true
|
||||||
|
|
||||||
echo "[-] setting up stripped branch sync T=$SECONDS"
|
echo "[-] bringing __nightly and devel in sync T=$SECONDS"
|
||||||
cd $TARGET_DIR
|
cd $TARGET_DIR
|
||||||
|
|
||||||
# tmp branch
|
git fetch --depth 1 origin __nightly
|
||||||
git checkout --orphan tmp
|
git fetch --depth 1 origin devel
|
||||||
|
|
||||||
|
git checkout -f --track origin/__nightly
|
||||||
|
git reset --hard __nightly
|
||||||
|
git checkout __nightly
|
||||||
|
git reset --hard origin/devel
|
||||||
|
git clean -xdff
|
||||||
|
git lfs uninstall
|
||||||
|
|
||||||
# remove everything except .git
|
# remove everything except .git
|
||||||
echo "[-] erasing old sunnypilot T=$SECONDS"
|
echo "[-] erasing old openpilot T=$SECONDS"
|
||||||
git submodule deinit -f --all
|
|
||||||
git rm -rf --cached .
|
|
||||||
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 '{}' \;
|
||||||
|
|
||||||
# cleanup before the copy
|
# reset source tree
|
||||||
cd $SOURCE_DIR
|
cd $SOURCE_DIR
|
||||||
git clean -xdff
|
git clean -xdff
|
||||||
git submodule foreach --recursive git clean -xdff
|
|
||||||
|
|
||||||
# do the files copy
|
# do the files copy
|
||||||
echo "[-] copying files T=$SECONDS"
|
echo "[-] copying files T=$SECONDS"
|
||||||
@@ -42,14 +47,13 @@ cp -pR --parents $(./release/release_files.py) $TARGET_DIR/
|
|||||||
|
|
||||||
# in the directory
|
# in the directory
|
||||||
cd $TARGET_DIR
|
cd $TARGET_DIR
|
||||||
rm -rf .git/modules/
|
|
||||||
rm -f panda/board/obj/panda.bin.signed
|
rm -f panda/board/obj/panda.bin.signed
|
||||||
|
|
||||||
# include source commit hash and build date in commit
|
# include source commit hash and build date in commit
|
||||||
GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD)
|
GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD)
|
||||||
GIT_COMMIT_DATE=$(git --git-dir=$SOURCE_DIR/.git show --no-patch --format='%ct %ci' HEAD)
|
GIT_COMMIT_DATE=$(git --git-dir=$SOURCE_DIR/.git show --no-patch --format='%ct %ci' HEAD)
|
||||||
DATETIME=$(date '+%Y-%m-%dT%H:%M:%S')
|
DATETIME=$(date '+%Y-%m-%dT%H:%M:%S')
|
||||||
VERSION=$(cat $SOURCE_DIR/sunnypilot/common/version.h | awk -F\" '{print $2}')
|
VERSION=$(cat $SOURCE_DIR/common/version.h | awk -F\" '{print $2}')
|
||||||
|
|
||||||
echo -n "$GIT_HASH" > git_src_commit
|
echo -n "$GIT_HASH" > git_src_commit
|
||||||
echo -n "$GIT_COMMIT_DATE" > git_src_commit_date
|
echo -n "$GIT_COMMIT_DATE" > git_src_commit_date
|
||||||
@@ -57,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
|
||||||
@@ -81,7 +85,7 @@ fi
|
|||||||
|
|
||||||
if [ ! -z "$BRANCH" ]; then
|
if [ ! -z "$BRANCH" ]; then
|
||||||
echo "[-] Pushing to $BRANCH T=$SECONDS"
|
echo "[-] Pushing to $BRANCH T=$SECONDS"
|
||||||
git push -f origin tmp:$BRANCH
|
git push -f origin __nightly:$BRANCH
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[-] done T=$SECONDS, ready at $TARGET_DIR"
|
echo "[-] done T=$SECONDS, ready at $TARGET_DIR"
|
||||||
@@ -39,7 +39,7 @@ cd $BUILD_DIR
|
|||||||
rm -f panda/board/obj/panda.bin.signed
|
rm -f panda/board/obj/panda.bin.signed
|
||||||
rm -f panda/board/obj/panda_h7.bin.signed
|
rm -f panda/board/obj/panda_h7.bin.signed
|
||||||
|
|
||||||
VERSION=$(cat sunnypilot/common/version.h | awk -F[\"-] '{print $2}')
|
VERSION=$(cat common/version.h | awk -F[\"-] '{print $2}')
|
||||||
echo "[-] committing version $VERSION T=$SECONDS"
|
echo "[-] committing version $VERSION T=$SECONDS"
|
||||||
git add -f .
|
git add -f .
|
||||||
git commit -a -m "openpilot v$VERSION release"
|
git commit -a -m "openpilot v$VERSION release"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# To build sim and docs, you can run the following to mount the scons cache to the same place as in CI:
|
|
||||||
# mkdir -p .ci_cache/scons_cache
|
|
||||||
# sudo mount --bind /tmp/scons_cache/ .ci_cache/scons_cache
|
|
||||||
|
|
||||||
SCRIPT_DIR=$(dirname "$0")
|
|
||||||
OPENPILOT_DIR=$SCRIPT_DIR/../../
|
|
||||||
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"
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
if [ -n "$PUSH_IMAGE" ]; then
|
|
||||||
docker push $REMOTE_TAG
|
|
||||||
docker tag $REMOTE_TAG $REMOTE_SHA_TAG
|
|
||||||
docker push $REMOTE_SHA_TAG
|
|
||||||
fi
|
|
||||||
@@ -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
|
||||||
|
|||||||
+16
-9
@@ -30,7 +30,7 @@ if [ -z "$GIT_ORIGIN" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# "Tagging"
|
# "Tagging"
|
||||||
echo "#define SUNNYPILOT_VERSION \"$VERSION\"" > ${OUTPUT_DIR}/sunnypilot/common/version.h
|
echo "#define COMMA_VERSION \"$VERSION\"" > ${OUTPUT_DIR}/common/version.h
|
||||||
|
|
||||||
## set git identity
|
## set git identity
|
||||||
#source $DIR/identity.sh
|
#source $DIR/identity.sh
|
||||||
@@ -51,19 +51,26 @@ git fetch origin $DEV_BRANCH || (git checkout -b $DEV_BRANCH && git commit --all
|
|||||||
|
|
||||||
echo "[-] committing version $VERSION T=$SECONDS"
|
echo "[-] committing version $VERSION T=$SECONDS"
|
||||||
git add -f .
|
git add -f .
|
||||||
|
git commit -a -m "sunnypilot v$VERSION release"
|
||||||
|
git branch --set-upstream-to=origin/$DEV_BRANCH
|
||||||
|
|
||||||
# include source commit hash and build date in commit
|
# include source commit hash and build date in commit
|
||||||
GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD)
|
GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD)
|
||||||
DATETIME=$(date '+%Y-%m-%dT%H:%M:%S')
|
DATETIME=$(date '+%Y-%m-%dT%H:%M:%S')
|
||||||
SP_VERSION=$(awk -F\" '{print $2}' $SOURCE_DIR/sunnypilot/common/version.h)
|
SP_VERSION=$(cat $SOURCE_DIR/common/version.h | awk -F\" '{print $2}')
|
||||||
|
|
||||||
# Commit with detailed message
|
# Add built files to git
|
||||||
git commit -a -m "sunnypilot v$VERSION
|
git add -f .
|
||||||
version: sunnypilot v$SP_VERSION (${EXTRA_VERSION_IDENTIFIER})
|
if [ "$EXTRA_VERSION_IDENTIFIER" = "-release" ] || [ "$EXTRA_VERSION_IDENTIFIER" = "-staging" ]; then
|
||||||
date: $DATETIME
|
export VERSION=${VERSION%"$EXTRA_VERSION_IDENTIFIER"}
|
||||||
master commit: $GIT_HASH
|
git commit --amend -m "sunnypilot v$VERSION"
|
||||||
"
|
else
|
||||||
git branch --set-upstream-to=origin/$DEV_BRANCH
|
git commit --amend -m "sunnypilot v$VERSION
|
||||||
|
version: sunnypilot v$SP_VERSION release
|
||||||
|
date: $DATETIME
|
||||||
|
master commit: $GIT_HASH
|
||||||
|
"
|
||||||
|
fi
|
||||||
git branch -m $DEV_BRANCH
|
git branch -m $DEV_BRANCH
|
||||||
|
|
||||||
# Push!
|
# Push!
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ 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-test',
|
parser.add_argument('--target-branch', type=str, default='master-dev-c3-new-test',
|
||||||
help='Target branch for merging')
|
help='Target branch for merging')
|
||||||
parser.add_argument('--squash-script-path', type=str, required=True,
|
parser.add_argument('--squash-script-path', type=str, required=True,
|
||||||
help='Path to the squash_and_merge.py script')
|
help='Path to the squash_and_merge.py script')
|
||||||
|
|||||||
+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:a69514fe68dd1b4c73f28771640dcba10fc40989d1c7e771cb48bfd830fef206
|
|
||||||
size 5713
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:dbfa5858c0a672411ffdc691efdecb06d01ae458cc1df409bcf3fdeaa4756f72
|
|
||||||
size 34638
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:db9671bb03e01f119bba1eb6cc0507e0f039ac4e5b7f9f839a87071c52e86e56
|
|
||||||
size 44416
|
|
||||||
@@ -57,7 +57,7 @@ class CarSpecificEvents:
|
|||||||
events.add(EventName.belowSteerSpeed)
|
events.add(EventName.belowSteerSpeed)
|
||||||
|
|
||||||
elif self.CP.brand == 'honda':
|
elif self.CP.brand == 'honda':
|
||||||
events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.sport], pcm_enable=False)
|
events = self.create_common_events(CS, CS_prev, pcm_enable=False)
|
||||||
|
|
||||||
if self.CP.pcmCruise and CS.vEgo < self.CP.minEnableSpeed:
|
if self.CP.pcmCruise and CS.vEgo < self.CP.minEnableSpeed:
|
||||||
events.add(EventName.belowEngageSpeed)
|
events.add(EventName.belowEngageSpeed)
|
||||||
@@ -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:
|
||||||
|
|||||||
+7
-10
@@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
@@ -71,7 +72,7 @@ class Car:
|
|||||||
|
|
||||||
def __init__(self, CI=None, RI=None) -> None:
|
def __init__(self, CI=None, RI=None) -> None:
|
||||||
self.can_sock = messaging.sub_sock('can', timeout=20)
|
self.can_sock = messaging.sub_sock('can', timeout=20)
|
||||||
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'] + ['carControlSP', 'longitudinalPlanSP'])
|
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'] + ['carControlSP'])
|
||||||
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'liveTracks'] + ['carParamsSP', 'carStateSP'])
|
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'liveTracks'] + ['carParamsSP', 'carStateSP'])
|
||||||
|
|
||||||
self.can_rcv_cum_timeout_counter = 0
|
self.can_rcv_cum_timeout_counter = 0
|
||||||
@@ -88,7 +89,6 @@ class Car:
|
|||||||
self.can_callbacks = can_comm_callbacks(self.can_sock, self.pm.sock['sendcan'])
|
self.can_callbacks = can_comm_callbacks(self.can_sock, self.pm.sock['sendcan'])
|
||||||
|
|
||||||
is_release = self.params.get_bool("IsReleaseBranch")
|
is_release = self.params.get_bool("IsReleaseBranch")
|
||||||
is_release_sp = self.params.get_bool("IsReleaseSpBranch")
|
|
||||||
|
|
||||||
if CI is None:
|
if CI is None:
|
||||||
# wait for one pandaState and one CAN packet
|
# wait for one pandaState and one CAN packet
|
||||||
@@ -107,11 +107,9 @@ 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 = (self.params.get("CarPlatformBundle") or {}).get("platform", None)
|
fixed_fingerprint = json.loads(self.params.get("CarPlatformBundle", encoding='utf-8') or "{}").get("platform", None)
|
||||||
init_params_list_sp = sunnypilot_interfaces.initialize_params(self.params)
|
|
||||||
|
|
||||||
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), alpha_long_allowed, is_release, num_pandas, cached_params,
|
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), alpha_long_allowed, is_release, num_pandas, cached_params, fixed_fingerprint)
|
||||||
fixed_fingerprint, init_params_list_sp, is_release_sp)
|
|
||||||
sunnypilot_interfaces.setup_interfaces(self.CI, self.params)
|
sunnypilot_interfaces.setup_interfaces(self.CI, self.params)
|
||||||
self.RI = interfaces[self.CI.CP.carFingerprint].RadarInterface(self.CI.CP, self.CI.CP_SP)
|
self.RI = interfaces[self.CI.CP.carFingerprint].RadarInterface(self.CI.CP, self.CI.CP_SP)
|
||||||
self.CP = self.CI.CP
|
self.CP = self.CI.CP
|
||||||
@@ -125,7 +123,7 @@ class Car:
|
|||||||
|
|
||||||
self.CP.alternativeExperience = 0
|
self.CP.alternativeExperience = 0
|
||||||
# mads
|
# mads
|
||||||
set_alternative_experience(self.CP, self.CP_SP, self.params)
|
set_alternative_experience(self.CP, self.params)
|
||||||
set_car_specific_params(self.CP, self.CP_SP, self.params)
|
set_car_specific_params(self.CP, self.CP_SP, self.params)
|
||||||
|
|
||||||
# Dynamic Experimental Control
|
# Dynamic Experimental Control
|
||||||
@@ -149,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:
|
||||||
@@ -180,7 +178,7 @@ class Car:
|
|||||||
self.params.put_nonblocking("CarParamsSPPersistent", cp_sp_bytes)
|
self.params.put_nonblocking("CarParamsSPPersistent", cp_sp_bytes)
|
||||||
|
|
||||||
self.mock_carstate = MockCarState()
|
self.mock_carstate = MockCarState()
|
||||||
self.v_cruise_helper = VCruiseHelper(self.CP, self.CP_SP)
|
self.v_cruise_helper = VCruiseHelper(self.CP)
|
||||||
|
|
||||||
self.is_metric = self.params.get_bool("IsMetric")
|
self.is_metric = self.params.get_bool("IsMetric")
|
||||||
self.experimental_mode = self.params.get_bool("ExperimentalMode")
|
self.experimental_mode = self.params.get_bool("ExperimentalMode")
|
||||||
@@ -217,7 +215,6 @@ class Car:
|
|||||||
if can_rcv_valid and REPLAY:
|
if can_rcv_valid and REPLAY:
|
||||||
self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime
|
self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime
|
||||||
|
|
||||||
self.v_cruise_helper.update_speed_limit_assist(self.is_metric, self.sm['longitudinalPlanSP'])
|
|
||||||
self.v_cruise_helper.update_v_cruise(CS, self.sm['carControl'].enabled, self.is_metric)
|
self.v_cruise_helper.update_v_cruise(CS, self.sm['carControl'].enabled, self.is_metric)
|
||||||
if self.sm['carControl'].enabled and not self.CC_prev.enabled:
|
if self.sm['carControl'].enabled and not self.CC_prev.enabled:
|
||||||
# Use CarState w/ buttons from the step selfdrived enables on
|
# Use CarState w/ buttons from the step selfdrived enables on
|
||||||
|
|||||||
+6
-16
@@ -2,7 +2,7 @@ import math
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from openpilot.common.constants import CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
from openpilot.sunnypilot.selfdrive.car.cruise_ext import VCruiseHelperSP
|
from openpilot.sunnypilot.selfdrive.car.cruise_ext import VCruiseHelperSP
|
||||||
|
|
||||||
|
|
||||||
@@ -30,8 +30,8 @@ CRUISE_INTERVAL_SIGN = {
|
|||||||
|
|
||||||
|
|
||||||
class VCruiseHelper(VCruiseHelperSP):
|
class VCruiseHelper(VCruiseHelperSP):
|
||||||
def __init__(self, CP, CP_SP):
|
def __init__(self, CP):
|
||||||
VCruiseHelperSP.__init__(self, CP, CP_SP)
|
VCruiseHelperSP.__init__(self)
|
||||||
self.CP = CP
|
self.CP = CP
|
||||||
self.v_cruise_kph = V_CRUISE_UNSET
|
self.v_cruise_kph = V_CRUISE_UNSET
|
||||||
self.v_cruise_cluster_kph = V_CRUISE_UNSET
|
self.v_cruise_cluster_kph = V_CRUISE_UNSET
|
||||||
@@ -46,14 +46,10 @@ class VCruiseHelper(VCruiseHelperSP):
|
|||||||
def update_v_cruise(self, CS, enabled, is_metric):
|
def update_v_cruise(self, CS, enabled, is_metric):
|
||||||
self.v_cruise_kph_last = self.v_cruise_kph
|
self.v_cruise_kph_last = self.v_cruise_kph
|
||||||
|
|
||||||
self.get_minimum_set_speed(is_metric)
|
|
||||||
|
|
||||||
if CS.cruiseState.available:
|
if CS.cruiseState.available:
|
||||||
_enabled = self.update_enabled_state(CS, enabled)
|
if not self.CP.pcmCruise:
|
||||||
if not self.CP.pcmCruise or (not self.CP_SP.pcmCruiseSpeed and _enabled):
|
|
||||||
# if stock cruise is completely disabled, then we can use our own set speed logic
|
# if stock cruise is completely disabled, then we can use our own set speed logic
|
||||||
self._update_v_cruise_non_pcm(CS, _enabled, is_metric)
|
self._update_v_cruise_non_pcm(CS, enabled, is_metric)
|
||||||
self.update_speed_limit_assist_v_cruise_non_pcm()
|
|
||||||
self.v_cruise_cluster_kph = self.v_cruise_kph
|
self.v_cruise_cluster_kph = self.v_cruise_kph
|
||||||
self.update_button_timers(CS, enabled)
|
self.update_button_timers(CS, enabled)
|
||||||
else:
|
else:
|
||||||
@@ -105,12 +101,6 @@ class VCruiseHelper(VCruiseHelperSP):
|
|||||||
if not self.button_change_states[button_type]["enabled"]:
|
if not self.button_change_states[button_type]["enabled"]:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Speed Limit Assist for Non PCM long cars.
|
|
||||||
# True: Disallow set speed changes when user confirmed the target set speed during preActive state
|
|
||||||
# False: Allow set speed changes as SLA is not requesting user confirmation
|
|
||||||
if self.update_speed_limit_assist_pre_active_confirmed(button_type):
|
|
||||||
return
|
|
||||||
|
|
||||||
long_press, v_cruise_delta = VCruiseHelperSP.update_v_cruise_delta(self, long_press, v_cruise_delta)
|
long_press, v_cruise_delta = VCruiseHelperSP.update_v_cruise_delta(self, long_press, v_cruise_delta)
|
||||||
if long_press and self.v_cruise_kph % v_cruise_delta != 0: # partial interval
|
if long_press and self.v_cruise_kph % v_cruise_delta != 0: # partial interval
|
||||||
self.v_cruise_kph = CRUISE_NEAREST_FUNC[button_type](self.v_cruise_kph / v_cruise_delta) * v_cruise_delta
|
self.v_cruise_kph = CRUISE_NEAREST_FUNC[button_type](self.v_cruise_kph / v_cruise_delta) * v_cruise_delta
|
||||||
@@ -121,7 +111,7 @@ class VCruiseHelper(VCruiseHelperSP):
|
|||||||
if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise):
|
if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise):
|
||||||
self.v_cruise_kph = max(self.v_cruise_kph, CS.vEgo * CV.MS_TO_KPH)
|
self.v_cruise_kph = max(self.v_cruise_kph, CS.vEgo * CV.MS_TO_KPH)
|
||||||
|
|
||||||
self.v_cruise_kph = np.clip(round(self.v_cruise_kph, 1), self.v_cruise_min, V_CRUISE_MAX)
|
self.v_cruise_kph = np.clip(round(self.v_cruise_kph, 1), V_CRUISE_MIN, V_CRUISE_MAX)
|
||||||
|
|
||||||
def update_button_timers(self, CS, enabled):
|
def update_button_timers(self, CS, enabled):
|
||||||
# increment timer for buttons still pressed
|
# increment timer for buttons still pressed
|
||||||
|
|||||||
@@ -57,11 +57,6 @@ def convert_carControlSP(struct: capnp.lib.capnp._DynamicStructReader) -> struct
|
|||||||
struct_dataclass = structs.CarControlSP(**remove_deprecated({k: v for k, v in struct_dict.items() if not isinstance(k, dict)}))
|
struct_dataclass = structs.CarControlSP(**remove_deprecated({k: v for k, v in struct_dict.items() if not isinstance(k, dict)}))
|
||||||
|
|
||||||
struct_dataclass.mads = structs.ModularAssistiveDrivingSystem(**remove_deprecated(struct_dict.get('mads', {})))
|
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', {})))
|
|
||||||
struct_dataclass.intelligentCruiseButtonManagement = structs.IntelligentCruiseButtonManagement(
|
|
||||||
**remove_deprecated(struct_dict.get('intelligentCruiseButtonManagement', {}))
|
|
||||||
)
|
|
||||||
|
|
||||||
return struct_dataclass
|
return struct_dataclass
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import os
|
import os
|
||||||
|
import math
|
||||||
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
|
from parameterized import parameterized
|
||||||
|
|
||||||
from cereal import car, custom
|
from cereal import car, custom
|
||||||
from opendbc.car import DT_CTRL
|
from opendbc.car import DT_CTRL
|
||||||
|
from opendbc.car.car_helpers import interfaces
|
||||||
from opendbc.car.structs import CarParams
|
from opendbc.car.structs import CarParams
|
||||||
from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface
|
from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface_args
|
||||||
|
from opendbc.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS
|
||||||
from opendbc.car.mock.values import CAR as MOCK
|
from opendbc.car.mock.values import CAR as MOCK
|
||||||
from opendbc.car.values import PLATFORMS
|
from opendbc.car.values import PLATFORMS
|
||||||
from openpilot.selfdrive.car.helpers import convert_carControlSP
|
from openpilot.selfdrive.car.helpers import convert_carControlSP
|
||||||
@@ -18,6 +21,11 @@ from openpilot.selfdrive.test.fuzzy_generation import FuzzyGenerator
|
|||||||
|
|
||||||
from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfaces
|
from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfaces
|
||||||
|
|
||||||
|
ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()}
|
||||||
|
ALL_ECUS |= {ecu for config in FW_QUERY_CONFIGS.values() for ecu in config.extra_ecus}
|
||||||
|
|
||||||
|
ALL_REQUESTS = {tuple(r.request) for config in FW_QUERY_CONFIGS.values() for r in config.requests}
|
||||||
|
|
||||||
MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '60'))
|
MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '60'))
|
||||||
|
|
||||||
|
|
||||||
@@ -29,10 +37,43 @@ class TestCarInterfaces:
|
|||||||
phases=(Phase.reuse, Phase.generate, Phase.shrink))
|
phases=(Phase.reuse, Phase.generate, Phase.shrink))
|
||||||
@given(data=st.data())
|
@given(data=st.data())
|
||||||
def test_car_interfaces(self, car_name, data):
|
def test_car_interfaces(self, car_name, data):
|
||||||
car_interface = get_fuzzy_car_interface(car_name, data.draw)
|
CarInterface = interfaces[car_name]
|
||||||
car_params = car_interface.CP.as_reader()
|
|
||||||
car_params_sp = car_interface.CP_SP
|
args = get_fuzzy_car_interface_args(data.draw)
|
||||||
|
|
||||||
|
car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'],
|
||||||
|
alpha_long=args['alpha_long'], is_release=False, docs=False)
|
||||||
|
car_params_sp = CarInterface.get_params_sp(car_params, car_name, args['fingerprints'], args['car_fw'],
|
||||||
|
alpha_long=args['alpha_long'], docs=False)
|
||||||
|
car_params = car_params.as_reader()
|
||||||
|
car_interface = CarInterface(car_params, car_params_sp)
|
||||||
sunnypilot_interfaces.setup_interfaces(car_interface)
|
sunnypilot_interfaces.setup_interfaces(car_interface)
|
||||||
|
assert car_params
|
||||||
|
assert car_params_sp
|
||||||
|
assert car_interface
|
||||||
|
|
||||||
|
assert car_params.mass > 1
|
||||||
|
assert car_params.wheelbase > 0
|
||||||
|
# centerToFront is center of gravity to front wheels, assert a reasonable range
|
||||||
|
assert car_params.wheelbase * 0.3 < car_params.centerToFront < car_params.wheelbase * 0.7
|
||||||
|
assert car_params.maxLateralAccel > 0
|
||||||
|
|
||||||
|
# Longitudinal sanity checks
|
||||||
|
assert len(car_params.longitudinalTuning.kpV) == len(car_params.longitudinalTuning.kpBP)
|
||||||
|
assert len(car_params.longitudinalTuning.kiV) == len(car_params.longitudinalTuning.kiBP)
|
||||||
|
|
||||||
|
# Lateral sanity checks
|
||||||
|
if car_params.steerControlType != CarParams.SteerControlType.angle:
|
||||||
|
tune = car_params.lateralTuning
|
||||||
|
if tune.which() == 'pid':
|
||||||
|
if car_name != MOCK.MOCK:
|
||||||
|
assert not math.isnan(tune.pid.kf) and tune.pid.kf > 0
|
||||||
|
assert len(tune.pid.kpV) > 0 and len(tune.pid.kpV) == len(tune.pid.kpBP)
|
||||||
|
assert len(tune.pid.kiV) > 0 and len(tune.pid.kiV) == len(tune.pid.kiBP)
|
||||||
|
|
||||||
|
elif tune.which() == 'torque':
|
||||||
|
assert not math.isnan(tune.torque.kf) and tune.torque.kf > 0
|
||||||
|
assert not math.isnan(tune.torque.friction) and tune.torque.friction > 0
|
||||||
|
|
||||||
cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True)
|
cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True)
|
||||||
cc_sp_msg = FuzzyGenerator.get_random_msg(data.draw, custom.CarControlSP, real_floats=True)
|
cc_sp_msg = FuzzyGenerator.get_random_msg(data.draw, custom.CarControlSP, real_floats=True)
|
||||||
@@ -60,7 +101,7 @@ class TestCarInterfaces:
|
|||||||
# Test controller initialization
|
# Test controller initialization
|
||||||
# TODO: wait until card refactor is merged to run controller a few times,
|
# TODO: wait until card refactor is merged to run controller a few times,
|
||||||
# hypothesis also slows down significantly with just one more message draw
|
# hypothesis also slows down significantly with just one more message draw
|
||||||
LongControl(car_params, car_params_sp)
|
LongControl(car_params)
|
||||||
if car_params.steerControlType == CarParams.SteerControlType.angle:
|
if car_params.steerControlType == CarParams.SteerControlType.angle:
|
||||||
LatControlAngle(car_params, car_params_sp, car_interface)
|
LatControlAngle(car_params, car_params_sp, car_interface)
|
||||||
elif car_params.lateralTuning.which() == 'pid':
|
elif car_params.lateralTuning.which() == 'pid':
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import numpy as np
|
|||||||
from parameterized import parameterized_class
|
from parameterized import parameterized_class
|
||||||
from cereal import log
|
from cereal import log
|
||||||
from openpilot.selfdrive.car.cruise import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_INITIAL, IMPERIAL_INCREMENT
|
from openpilot.selfdrive.car.cruise import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_INITIAL, IMPERIAL_INCREMENT
|
||||||
from cereal import car, custom
|
from cereal import car
|
||||||
from openpilot.common.constants import CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
from openpilot.selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver
|
from openpilot.selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver
|
||||||
|
|
||||||
ButtonEvent = car.CarState.ButtonEvent
|
ButtonEvent = car.CarState.ButtonEvent
|
||||||
@@ -44,13 +44,12 @@ class TestCruiseSpeed:
|
|||||||
assert simulation_steady_state == pytest.approx(cruise_speed, abs=.01), f'Did not reach {self.speed} m/s'
|
assert simulation_steady_state == pytest.approx(cruise_speed, abs=.01), f'Did not reach {self.speed} m/s'
|
||||||
|
|
||||||
|
|
||||||
# TODO: test pcmCruise and pcmCruiseSpeed
|
# TODO: test pcmCruise
|
||||||
@parameterized_class(('pcm_cruise', 'pcm_cruise_speed'), [(False, True)])
|
@parameterized_class(('pcm_cruise',), [(False,)])
|
||||||
class TestVCruiseHelper:
|
class TestVCruiseHelper:
|
||||||
def setup_method(self):
|
def setup_method(self):
|
||||||
self.CP = car.CarParams(pcmCruise=self.pcm_cruise)
|
self.CP = car.CarParams(pcmCruise=self.pcm_cruise)
|
||||||
self.CP_SP = custom.CarParamsSP(pcmCruiseSpeed=self.pcm_cruise_speed)
|
self.v_cruise_helper = VCruiseHelper(self.CP)
|
||||||
self.v_cruise_helper = VCruiseHelper(self.CP, self.CP_SP)
|
|
||||||
self.reset_cruise_speed_state()
|
self.reset_cruise_speed_state()
|
||||||
|
|
||||||
def reset_cruise_speed_state(self):
|
def reset_cruise_speed_state(self):
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -151,7 +154,7 @@ class TestCarModelBase(unittest.TestCase):
|
|||||||
|
|
||||||
cls.CarInterface = interfaces[cls.platform]
|
cls.CarInterface = interfaces[cls.platform]
|
||||||
cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, alpha_long, False, docs=False)
|
cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, alpha_long, False, docs=False)
|
||||||
cls.CP_SP = cls.CarInterface.get_params_sp(cls.CP, cls.platform, cls.fingerprint, car_fw, alpha_long, False, docs=False)
|
cls.CP_SP = cls.CarInterface.get_params_sp(cls.CP, cls.platform, cls.fingerprint, car_fw, alpha_long, docs=False)
|
||||||
assert cls.CP
|
assert cls.CP
|
||||||
assert cls.CP_SP
|
assert cls.CP_SP
|
||||||
assert cls.CP.carFingerprint == cls.platform
|
assert cls.CP.carFingerprint == cls.platform
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
import math
|
import math
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from numbers import Number
|
from typing import SupportsFloat
|
||||||
|
|
||||||
from cereal import car, log
|
from cereal import car, log
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from openpilot.common.constants import CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper
|
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper
|
||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
@@ -21,8 +21,6 @@ from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
|||||||
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
||||||
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
|
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
|
||||||
|
|
||||||
from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
|
|
||||||
from openpilot.sunnypilot.modeld.modeld_base import ModelStateBase
|
|
||||||
from openpilot.sunnypilot.selfdrive.controls.controlsd_ext import ControlsExt
|
from openpilot.sunnypilot.selfdrive.controls.controlsd_ext import ControlsExt
|
||||||
|
|
||||||
State = log.SelfdriveState.OpenpilotState
|
State = log.SelfdriveState.OpenpilotState
|
||||||
@@ -32,16 +30,15 @@ LaneChangeDirection = log.LaneChangeDirection
|
|||||||
ACTUATOR_FIELDS = tuple(car.CarControl.Actuators.schema.fields.keys())
|
ACTUATOR_FIELDS = tuple(car.CarControl.Actuators.schema.fields.keys())
|
||||||
|
|
||||||
|
|
||||||
class Controls(ControlsExt, ModelStateBase):
|
class Controls(ControlsExt):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.params = Params()
|
self.params = Params()
|
||||||
cloudlog.info("controlsd is waiting for CarParams")
|
cloudlog.info("controlsd is waiting for CarParams")
|
||||||
self.CP = messaging.log_from_bytes(self.params.get("CarParams", block=True), car.CarParams)
|
self.CP = messaging.log_from_bytes(self.params.get("CarParams", block=True), car.CarParams)
|
||||||
cloudlog.info("controlsd got CarParams")
|
cloudlog.info("controlsd got CarParams")
|
||||||
|
|
||||||
# Initialize sunnypilot controlsd extension and base model state
|
# Initialize sunnypilot controlsd extension
|
||||||
ControlsExt.__init__(self, self.CP, self.params)
|
ControlsExt.__init__(self, self.CP, self.params)
|
||||||
ModelStateBase.__init__(self)
|
|
||||||
|
|
||||||
self.CI = interfaces[self.CP.carFingerprint](self.CP, self.CP_SP)
|
self.CI = interfaces[self.CP.carFingerprint](self.CP, self.CP_SP)
|
||||||
|
|
||||||
@@ -51,14 +48,14 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
poll='selfdriveState')
|
poll='selfdriveState')
|
||||||
self.pm = messaging.PubMaster(['carControl', 'controlsState'] + self.pm_services_ext)
|
self.pm = messaging.PubMaster(['carControl', 'controlsState'] + self.pm_services_ext)
|
||||||
|
|
||||||
self.steer_limited_by_safety = False
|
self.steer_limited_by_controls = False
|
||||||
self.curvature = 0.0
|
self.curvature = 0.0
|
||||||
self.desired_curvature = 0.0
|
self.desired_curvature = 0.0
|
||||||
|
|
||||||
self.pose_calibrator = PoseCalibrator()
|
self.pose_calibrator = PoseCalibrator()
|
||||||
self.calibrated_pose: Pose | None = None
|
self.calibrated_pose: Pose | None = None
|
||||||
|
|
||||||
self.LoC = LongControl(self.CP, self.CP_SP)
|
self.LoC = LongControl(self.CP)
|
||||||
self.VM = VehicleModel(self.CP)
|
self.VM = VehicleModel(self.CP)
|
||||||
self.LaC: LatControl
|
self.LaC: LatControl
|
||||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||||
@@ -95,11 +92,9 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
self.LaC.update_live_torque_params(torque_params.latAccelFactorFiltered, torque_params.latAccelOffsetFiltered,
|
self.LaC.update_live_torque_params(torque_params.latAccelFactorFiltered, torque_params.latAccelOffsetFiltered,
|
||||||
torque_params.frictionCoefficientFiltered)
|
torque_params.frictionCoefficientFiltered)
|
||||||
|
|
||||||
self.LaC.extension.update_limits()
|
|
||||||
|
|
||||||
self.LaC.extension.update_model_v2(self.sm['modelV2'])
|
self.LaC.extension.update_model_v2(self.sm['modelV2'])
|
||||||
|
calculated_lag = self.LaC.extension.lagd_torqued_main(self.CP, self.sm['liveDelay'])
|
||||||
self.LaC.extension.update_lateral_lag(self.lat_delay)
|
self.LaC.extension.update_lateral_lag(calculated_lag)
|
||||||
|
|
||||||
long_plan = self.sm['longitudinalPlan']
|
long_plan = self.sm['longitudinalPlan']
|
||||||
model_v2 = self.sm['modelV2']
|
model_v2 = self.sm['modelV2']
|
||||||
@@ -115,8 +110,7 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
|
|
||||||
CC.latActive = _lat_active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
|
CC.latActive = _lat_active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
|
||||||
(not standstill or self.CP.steerAtStandstill)
|
(not standstill or self.CP.steerAtStandstill)
|
||||||
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in self.sm['onroadEvents']) and \
|
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in self.sm['onroadEvents']) and self.CP.openpilotLongitudinalControl
|
||||||
(self.CP.openpilotLongitudinalControl or not self.CP_SP.pcmCruiseSpeed)
|
|
||||||
|
|
||||||
actuators = CC.actuators
|
actuators = CC.actuators
|
||||||
actuators.longControlState = self.LoC.long_control_state
|
actuators.longControlState = self.LoC.long_control_state
|
||||||
@@ -132,7 +126,7 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
self.LoC.reset()
|
self.LoC.reset()
|
||||||
|
|
||||||
# accel PID loop
|
# accel PID loop
|
||||||
pid_accel_limits = self.CI.get_pid_accel_limits(self.CP, self.CP_SP, CS.vEgo, CS.vCruise * CV.KPH_TO_MS)
|
pid_accel_limits = self.CI.get_pid_accel_limits(self.CP, CS.vEgo, CS.vCruise * CV.KPH_TO_MS)
|
||||||
actuators.accel = float(self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop, pid_accel_limits))
|
actuators.accel = float(self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop, pid_accel_limits))
|
||||||
|
|
||||||
# Steering PID loop and lateral MPC
|
# Steering PID loop and lateral MPC
|
||||||
@@ -142,14 +136,14 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
|
|
||||||
actuators.curvature = self.desired_curvature
|
actuators.curvature = self.desired_curvature
|
||||||
steer, steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp,
|
steer, steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp,
|
||||||
self.steer_limited_by_safety, self.desired_curvature,
|
self.steer_limited_by_controls, self.desired_curvature,
|
||||||
self.calibrated_pose, curvature_limited) # TODO what if not available
|
self.calibrated_pose, curvature_limited) # TODO what if not available
|
||||||
actuators.torque = float(steer)
|
actuators.torque = float(steer)
|
||||||
actuators.steeringAngleDeg = float(steeringAngleDeg)
|
actuators.steeringAngleDeg = float(steeringAngleDeg)
|
||||||
# Ensure no NaNs/Infs
|
# Ensure no NaNs/Infs
|
||||||
for p in ACTUATOR_FIELDS:
|
for p in ACTUATOR_FIELDS:
|
||||||
attr = getattr(actuators, p)
|
attr = getattr(actuators, p)
|
||||||
if not isinstance(attr, Number):
|
if not isinstance(attr, SupportsFloat):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not math.isfinite(attr):
|
if not math.isfinite(attr):
|
||||||
@@ -168,9 +162,12 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
CC.orientationNED = self.calibrated_pose.orientation.xyz.tolist()
|
CC.orientationNED = self.calibrated_pose.orientation.xyz.tolist()
|
||||||
CC.angularVelocity = self.calibrated_pose.angular_velocity.xyz.tolist()
|
CC.angularVelocity = self.calibrated_pose.angular_velocity.xyz.tolist()
|
||||||
|
|
||||||
CC.cruiseControl.override = CC.enabled and not CC.longActive and (self.CP.openpilotLongitudinalControl or not self.CP_SP.pcmCruiseSpeed)
|
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)
|
||||||
@@ -189,10 +186,10 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
if self.sm['selfdriveState'].active:
|
if self.sm['selfdriveState'].active:
|
||||||
CO = self.sm['carOutput']
|
CO = self.sm['carOutput']
|
||||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||||
self.steer_limited_by_safety = abs(CC.actuators.steeringAngleDeg - CO.actuatorsOutput.steeringAngleDeg) > \
|
self.steer_limited_by_controls = abs(CC.actuators.steeringAngleDeg - CO.actuatorsOutput.steeringAngleDeg) > \
|
||||||
STEER_ANGLE_SATURATION_THRESHOLD
|
STEER_ANGLE_SATURATION_THRESHOLD
|
||||||
else:
|
else:
|
||||||
self.steer_limited_by_safety = abs(CC.actuators.torque - CO.actuatorsOutput.torque) > 1e-2
|
self.steer_limited_by_controls = abs(CC.actuators.torque - CO.actuatorsOutput.torque) > 1e-2
|
||||||
|
|
||||||
# TODO: both controlsState and carControl valids should be set by
|
# TODO: both controlsState and carControl valids should be set by
|
||||||
# sm.all_checks(), but this creates a circular dependency
|
# sm.all_checks(), but this creates a circular dependency
|
||||||
@@ -233,9 +230,6 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
while not evt.is_set():
|
while not evt.is_set():
|
||||||
self.get_params_sp()
|
self.get_params_sp()
|
||||||
|
|
||||||
if self.CP.lateralTuning.which() == 'torque':
|
|
||||||
self.lat_delay = get_lat_delay(self.params, self.sm["liveDelay"].lateralDelay)
|
|
||||||
|
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
from cereal import log, custom
|
from cereal import log
|
||||||
from openpilot.common.constants import CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
from openpilot.common.realtime import DT_MDL
|
from openpilot.common.realtime import DT_MDL
|
||||||
from openpilot.sunnypilot.selfdrive.controls.lib.auto_lane_change import AutoLaneChangeController, AutoLaneChangeMode
|
from openpilot.sunnypilot.selfdrive.controls.lib.auto_lane_change import AutoLaneChangeController, AutoLaneChangeMode
|
||||||
from openpilot.sunnypilot.selfdrive.controls.lib.lane_turn_desire import LaneTurnController
|
|
||||||
|
|
||||||
LaneChangeState = log.LaneChangeState
|
LaneChangeState = log.LaneChangeState
|
||||||
LaneChangeDirection = log.LaneChangeDirection
|
LaneChangeDirection = log.LaneChangeDirection
|
||||||
TurnDirection = custom.ModelDataV2SP.TurnDirection
|
|
||||||
|
|
||||||
LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS
|
LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS
|
||||||
LANE_CHANGE_TIME_MAX = 10.
|
LANE_CHANGE_TIME_MAX = 10.
|
||||||
@@ -32,12 +30,6 @@ DESIRES = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
TURN_DESIRES = {
|
|
||||||
TurnDirection.none: log.Desire.none,
|
|
||||||
TurnDirection.turnLeft: log.Desire.turnLeft,
|
|
||||||
TurnDirection.turnRight: log.Desire.turnRight,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class DesireHelper:
|
class DesireHelper:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -49,25 +41,13 @@ class DesireHelper:
|
|||||||
self.prev_one_blinker = False
|
self.prev_one_blinker = False
|
||||||
self.desire = log.Desire.none
|
self.desire = log.Desire.none
|
||||||
self.alc = AutoLaneChangeController(self)
|
self.alc = AutoLaneChangeController(self)
|
||||||
self.lane_turn_controller = LaneTurnController(self)
|
|
||||||
self.lane_turn_direction = TurnDirection.none
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_lane_change_direction(CS):
|
|
||||||
return LaneChangeDirection.left if CS.leftBlinker else LaneChangeDirection.right
|
|
||||||
|
|
||||||
def update(self, carstate, lateral_active, lane_change_prob):
|
def update(self, carstate, lateral_active, lane_change_prob):
|
||||||
self.alc.update_params()
|
self.alc.update_params()
|
||||||
self.lane_turn_controller.update_params()
|
|
||||||
v_ego = carstate.vEgo
|
v_ego = carstate.vEgo
|
||||||
one_blinker = carstate.leftBlinker != carstate.rightBlinker
|
one_blinker = carstate.leftBlinker != carstate.rightBlinker
|
||||||
below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN
|
below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN
|
||||||
|
|
||||||
# Lane turn controller update
|
|
||||||
self.lane_turn_controller.update_lane_turn(blindspot_left=carstate.leftBlindspot, blindspot_right=carstate.rightBlindspot,
|
|
||||||
left_blinker=carstate.leftBlinker, right_blinker=carstate.rightBlinker, v_ego=v_ego)
|
|
||||||
self.lane_turn_direction = self.lane_turn_controller.get_turn_direction()
|
|
||||||
|
|
||||||
if not lateral_active or self.lane_change_timer > LANE_CHANGE_TIME_MAX or self.alc.lane_change_set_timer == AutoLaneChangeMode.OFF:
|
if not lateral_active or self.lane_change_timer > LANE_CHANGE_TIME_MAX or self.alc.lane_change_set_timer == AutoLaneChangeMode.OFF:
|
||||||
self.lane_change_state = LaneChangeState.off
|
self.lane_change_state = LaneChangeState.off
|
||||||
self.lane_change_direction = LaneChangeDirection.none
|
self.lane_change_direction = LaneChangeDirection.none
|
||||||
@@ -76,13 +56,12 @@ class DesireHelper:
|
|||||||
if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed:
|
if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed:
|
||||||
self.lane_change_state = LaneChangeState.preLaneChange
|
self.lane_change_state = LaneChangeState.preLaneChange
|
||||||
self.lane_change_ll_prob = 1.0
|
self.lane_change_ll_prob = 1.0
|
||||||
# Initialize lane change direction to prevent UI alert flicker
|
|
||||||
self.lane_change_direction = self.get_lane_change_direction(carstate)
|
|
||||||
|
|
||||||
# LaneChangeState.preLaneChange
|
# LaneChangeState.preLaneChange
|
||||||
elif self.lane_change_state == LaneChangeState.preLaneChange:
|
elif self.lane_change_state == LaneChangeState.preLaneChange:
|
||||||
# Update lane change direction
|
# Set lane change direction
|
||||||
self.lane_change_direction = self.get_lane_change_direction(carstate)
|
self.lane_change_direction = LaneChangeDirection.left if \
|
||||||
|
carstate.leftBlinker else LaneChangeDirection.right
|
||||||
|
|
||||||
torque_applied = carstate.steeringPressed and \
|
torque_applied = carstate.steeringPressed and \
|
||||||
((carstate.steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or
|
((carstate.steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or
|
||||||
@@ -127,10 +106,7 @@ class DesireHelper:
|
|||||||
|
|
||||||
self.prev_one_blinker = one_blinker
|
self.prev_one_blinker = one_blinker
|
||||||
|
|
||||||
if self.lane_turn_direction != TurnDirection.none:
|
self.desire = DESIRES[self.lane_change_direction][self.lane_change_state]
|
||||||
self.desire = TURN_DESIRES[self.lane_turn_direction]
|
|
||||||
else:
|
|
||||||
self.desire = DESIRES[self.lane_change_direction][self.lane_change_state]
|
|
||||||
|
|
||||||
# Send keep pulse once per second during LaneChangeStart.preLaneChange
|
# Send keep pulse once per second during LaneChangeStart.preLaneChange
|
||||||
if self.lane_change_state in (LaneChangeState.off, LaneChangeState.laneChangeStarting):
|
if self.lane_change_state in (LaneChangeState.off, LaneChangeState.laneChangeStarting):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from openpilot.common.constants 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
|
||||||
|
|
||||||
MIN_SPEED = 1.0
|
MIN_SPEED = 1.0
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ class LatControl(ABC):
|
|||||||
self.steer_max = 1.0
|
self.steer_max = 1.0
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
|
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.sat_count = 0.
|
self.sat_count = 0.
|
||||||
|
|
||||||
def _check_saturation(self, saturated, CS, steer_limited_by_safety, curvature_limited):
|
def _check_saturation(self, saturated, CS, steer_limited_by_controls, curvature_limited):
|
||||||
# Saturated only if control output is not being limited by car torque/angle rate limits
|
# Saturated only if control output is not being limited by car torque/angle rate limits
|
||||||
if (saturated or curvature_limited) and CS.vEgo > self.sat_check_min_speed and not steer_limited_by_safety and not CS.steeringPressed:
|
if (saturated or curvature_limited) and CS.vEgo > self.sat_check_min_speed and not steer_limited_by_controls and not CS.steeringPressed:
|
||||||
self.sat_count += self.sat_count_rate
|
self.sat_count += self.sat_count_rate
|
||||||
else:
|
else:
|
||||||
self.sat_count -= self.sat_count_rate
|
self.sat_count -= self.sat_count_rate
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import math
|
|||||||
from cereal import log
|
from cereal import log
|
||||||
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
|
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
|
||||||
|
|
||||||
# TODO This is speed dependent
|
|
||||||
STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees
|
STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees
|
||||||
|
|
||||||
|
|
||||||
@@ -11,9 +10,9 @@ class LatControlAngle(LatControl):
|
|||||||
def __init__(self, CP, CP_SP, CI):
|
def __init__(self, CP, CP_SP, CI):
|
||||||
super().__init__(CP, CP_SP, CI)
|
super().__init__(CP, CP_SP, CI)
|
||||||
self.sat_check_min_speed = 5.
|
self.sat_check_min_speed = 5.
|
||||||
self.use_steer_limited_by_safety = CP.brand == "tesla"
|
self.use_steer_limited_by_controls = CP.brand == "tesla"
|
||||||
|
|
||||||
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
|
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
|
||||||
angle_log = log.ControlsState.LateralAngleState.new_message()
|
angle_log = log.ControlsState.LateralAngleState.new_message()
|
||||||
|
|
||||||
if not active:
|
if not active:
|
||||||
@@ -24,9 +23,9 @@ class LatControlAngle(LatControl):
|
|||||||
angle_steers_des = math.degrees(VM.get_steer_from_curvature(-desired_curvature, CS.vEgo, params.roll))
|
angle_steers_des = math.degrees(VM.get_steer_from_curvature(-desired_curvature, CS.vEgo, params.roll))
|
||||||
angle_steers_des += params.angleOffsetDeg
|
angle_steers_des += params.angleOffsetDeg
|
||||||
|
|
||||||
if self.use_steer_limited_by_safety:
|
if self.use_steer_limited_by_controls:
|
||||||
# these cars' carcontrollers calculate max lateral accel and jerk, so we can rely on carOutput for saturation
|
# these cars' carcontrollers calculate max lateral accel and jerk, so we can rely on carOutput for saturation
|
||||||
angle_control_saturated = steer_limited_by_safety
|
angle_control_saturated = steer_limited_by_controls
|
||||||
else:
|
else:
|
||||||
# for cars which use a method of limiting torque such as a torque signal (Nissan and Toyota)
|
# for cars which use a method of limiting torque such as a torque signal (Nissan and Toyota)
|
||||||
# or relying on EPS (Ford Q3), carOutput does not capture maxing out torque # TODO: this can be improved
|
# or relying on EPS (Ford Q3), carOutput does not capture maxing out torque # TODO: this can be improved
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ class LatControlPID(LatControl):
|
|||||||
k_f=CP.lateralTuning.pid.kf, pos_limit=self.steer_max, neg_limit=-self.steer_max)
|
k_f=CP.lateralTuning.pid.kf, pos_limit=self.steer_max, neg_limit=-self.steer_max)
|
||||||
self.get_steer_feedforward = CI.get_steer_feedforward_function()
|
self.get_steer_feedforward = CI.get_steer_feedforward_function()
|
||||||
|
|
||||||
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
|
def reset(self):
|
||||||
|
super().reset()
|
||||||
|
self.pid.reset()
|
||||||
|
|
||||||
|
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
|
||||||
pid_log = log.ControlsState.LateralPIDState.new_message()
|
pid_log = log.ControlsState.LateralPIDState.new_message()
|
||||||
pid_log.steeringAngleDeg = float(CS.steeringAngleDeg)
|
pid_log.steeringAngleDeg = float(CS.steeringAngleDeg)
|
||||||
pid_log.steeringRateDeg = float(CS.steeringRateDeg)
|
pid_log.steeringRateDeg = float(CS.steeringRateDeg)
|
||||||
@@ -25,24 +29,20 @@ class LatControlPID(LatControl):
|
|||||||
pid_log.steeringAngleDesiredDeg = angle_steers_des
|
pid_log.steeringAngleDesiredDeg = angle_steers_des
|
||||||
pid_log.angleError = error
|
pid_log.angleError = error
|
||||||
if not active:
|
if not active:
|
||||||
output_torque = 0.0
|
output_steer = 0.0
|
||||||
pid_log.active = False
|
pid_log.active = False
|
||||||
|
self.pid.reset()
|
||||||
else:
|
else:
|
||||||
# offset does not contribute to resistive torque
|
# offset does not contribute to resistive torque
|
||||||
ff = self.get_steer_feedforward(angle_steers_des_no_offset, CS.vEgo)
|
steer_feedforward = self.get_steer_feedforward(angle_steers_des_no_offset, CS.vEgo)
|
||||||
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
|
|
||||||
|
|
||||||
output_torque = self.pid.update(error,
|
|
||||||
feedforward=ff,
|
|
||||||
speed=CS.vEgo,
|
|
||||||
freeze_integrator=freeze_integrator)
|
|
||||||
|
|
||||||
|
output_steer = self.pid.update(error, override=CS.steeringPressed,
|
||||||
|
feedforward=steer_feedforward, speed=CS.vEgo)
|
||||||
pid_log.active = True
|
pid_log.active = True
|
||||||
pid_log.p = float(self.pid.p)
|
pid_log.p = float(self.pid.p)
|
||||||
pid_log.i = float(self.pid.i)
|
pid_log.i = float(self.pid.i)
|
||||||
pid_log.f = float(self.pid.f)
|
pid_log.f = float(self.pid.f)
|
||||||
pid_log.output = float(output_torque)
|
pid_log.output = float(output_steer)
|
||||||
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited))
|
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_steer) < 1e-3, CS, steer_limited_by_controls, curvature_limited))
|
||||||
|
|
||||||
return output_torque, angle_steers_des, pid_log
|
return output_steer, angle_steers_des, pid_log
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import math
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
from opendbc.car.lateral import FRICTION_THRESHOLD, get_friction
|
from opendbc.car.interfaces import LatControlInputs
|
||||||
from openpilot.common.constants 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
|
||||||
from openpilot.common.pid import PIDController
|
from openpilot.common.pid import PIDController
|
||||||
|
|
||||||
@@ -28,30 +28,19 @@ class LatControlTorque(LatControl):
|
|||||||
def __init__(self, CP, CP_SP, CI):
|
def __init__(self, CP, CP_SP, CI):
|
||||||
super().__init__(CP, CP_SP, CI)
|
super().__init__(CP, CP_SP, CI)
|
||||||
self.torque_params = CP.lateralTuning.torque.as_builder()
|
self.torque_params = CP.lateralTuning.torque.as_builder()
|
||||||
self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
|
|
||||||
self.lateral_accel_from_torque = CI.lateral_accel_from_torque()
|
|
||||||
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)
|
k_f=self.torque_params.kf, pos_limit=self.steer_max, neg_limit=-self.steer_max)
|
||||||
self.update_limits()
|
self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
|
||||||
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, CI)
|
self.extension = LatControlTorqueExt(self, CP, CP_SP)
|
||||||
|
|
||||||
def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction):
|
def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction):
|
||||||
self.torque_params.latAccelFactor = latAccelFactor
|
self.torque_params.latAccelFactor = latAccelFactor
|
||||||
self.torque_params.latAccelOffset = latAccelOffset
|
self.torque_params.latAccelOffset = latAccelOffset
|
||||||
self.torque_params.friction = friction
|
self.torque_params.friction = friction
|
||||||
self.update_limits()
|
|
||||||
|
|
||||||
def update_limits(self):
|
|
||||||
self.pid.set_limits(self.lateral_accel_from_torque(self.steer_max, self.torque_params),
|
|
||||||
self.lateral_accel_from_torque(-self.steer_max, self.torque_params))
|
|
||||||
|
|
||||||
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
|
|
||||||
# Override torque params from extension
|
|
||||||
if self.extension.update_override_torque_params(self.torque_params):
|
|
||||||
self.update_limits()
|
|
||||||
|
|
||||||
|
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
|
||||||
pid_log = log.ControlsState.LateralTorqueState.new_message()
|
pid_log = log.ControlsState.LateralTorqueState.new_message()
|
||||||
if not active:
|
if not active:
|
||||||
output_torque = 0.0
|
output_torque = 0.0
|
||||||
@@ -60,8 +49,10 @@ class LatControlTorque(LatControl):
|
|||||||
actual_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
|
actual_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
|
||||||
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))
|
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 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_lateral_jerk = desired_curvature_rate * CS.vEgo ** 2
|
||||||
actual_lateral_accel = actual_curvature * CS.vEgo ** 2
|
actual_lateral_accel = actual_curvature * CS.vEgo ** 2
|
||||||
lateral_accel_deadzone = curvature_deadzone * CS.vEgo ** 2
|
lateral_accel_deadzone = curvature_deadzone * CS.vEgo ** 2
|
||||||
|
|
||||||
@@ -69,36 +60,36 @@ class LatControlTorque(LatControl):
|
|||||||
setpoint = desired_lateral_accel + low_speed_factor * desired_curvature
|
setpoint = desired_lateral_accel + low_speed_factor * desired_curvature
|
||||||
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,
|
||||||
|
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,
|
||||||
|
measurement, lateral_accel_deadzone, friction_compensation=False, gravity_adjusted=False)
|
||||||
|
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,
|
||||||
|
desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, friction_compensation=True,
|
||||||
|
gravity_adjusted=True)
|
||||||
|
|
||||||
# do error correction in lateral acceleration space, convert at end to handle non-linear torque responses correctly
|
# Lateral acceleration torque controller extension updates
|
||||||
pid_log.error = float(setpoint - measurement)
|
# Overrides stock ff and pid_log.error
|
||||||
ff = gravity_adjusted_lateral_accel
|
ff, pid_log = self.extension.update(CS, VM, params, ff, pid_log, setpoint, measurement, calibrated_pose, roll_compensation,
|
||||||
# latAccelOffset corrects roll compensation bias from device roll misalignment relative to car roll
|
desired_lateral_accel, actual_lateral_accel, lateral_accel_deadzone, gravity_adjusted_lateral_accel,
|
||||||
ff -= self.torque_params.latAccelOffset
|
desired_curvature, actual_curvature)
|
||||||
ff += get_friction(desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, FRICTION_THRESHOLD, self.torque_params)
|
|
||||||
|
|
||||||
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
|
freeze_integrator = steer_limited_by_controls or CS.steeringPressed or CS.vEgo < 5
|
||||||
output_lataccel = self.pid.update(pid_log.error,
|
output_torque = self.pid.update(pid_log.error,
|
||||||
feedforward=ff,
|
feedforward=ff,
|
||||||
speed=CS.vEgo,
|
speed=CS.vEgo,
|
||||||
freeze_integrator=freeze_integrator)
|
freeze_integrator=freeze_integrator)
|
||||||
output_torque = self.torque_from_lateral_accel(output_lataccel, self.torque_params)
|
|
||||||
|
|
||||||
# Lateral acceleration torque controller extension updates
|
|
||||||
# Overrides pid_log.error and output_torque
|
|
||||||
pid_log, output_torque = self.extension.update(CS, VM, self.pid, params, ff, pid_log, setpoint, measurement, calibrated_pose, roll_compensation,
|
|
||||||
desired_lateral_accel, actual_lateral_accel, lateral_accel_deadzone, gravity_adjusted_lateral_accel,
|
|
||||||
desired_curvature, actual_curvature, steer_limited_by_safety, output_torque)
|
|
||||||
|
|
||||||
pid_log.active = True
|
pid_log.active = True
|
||||||
pid_log.p = float(self.pid.p)
|
pid_log.p = float(self.pid.p)
|
||||||
pid_log.i = float(self.pid.i)
|
pid_log.i = float(self.pid.i)
|
||||||
pid_log.d = float(self.pid.d)
|
pid_log.d = float(self.pid.d)
|
||||||
pid_log.f = float(self.pid.f)
|
pid_log.f = float(self.pid.f)
|
||||||
pid_log.output = float(-output_torque) # TODO: log lat accel?
|
pid_log.output = float(-output_torque)
|
||||||
pid_log.actualLateralAccel = float(actual_lateral_accel)
|
pid_log.actualLateralAccel = float(actual_lateral_accel)
|
||||||
pid_log.desiredLateralAccel = float(desired_lateral_accel)
|
pid_log.desiredLateralAccel = float(desired_lateral_accel)
|
||||||
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited))
|
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_controls, curvature_limited))
|
||||||
|
|
||||||
# TODO left is positive in this convention
|
# TODO left is positive in this convention
|
||||||
return -output_torque, 0.0, pid_log
|
return -output_torque, 0.0, pid_log
|
||||||
|
|||||||
@@ -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,6 +1,6 @@
|
|||||||
from cereal import log
|
from cereal import log
|
||||||
from openpilot.common.realtime import DT_CTRL
|
from openpilot.common.realtime import DT_CTRL
|
||||||
from openpilot.common.constants import CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
|
||||||
|
|
||||||
CAMERA_OFFSET = 0.04
|
CAMERA_OFFSET = 0.04
|
||||||
|
|||||||
@@ -10,11 +10,8 @@ CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
|
|||||||
LongCtrlState = car.CarControl.Actuators.LongControlState
|
LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||||
|
|
||||||
|
|
||||||
def long_control_state_trans(CP, CP_SP, active, long_control_state, v_ego,
|
def long_control_state_trans(CP, active, long_control_state, v_ego,
|
||||||
should_stop, brake_pressed, cruise_standstill):
|
should_stop, brake_pressed, cruise_standstill):
|
||||||
# Gas Interceptor
|
|
||||||
cruise_standstill = cruise_standstill and not CP_SP.enableGasInterceptor
|
|
||||||
|
|
||||||
stopping_condition = should_stop
|
stopping_condition = should_stop
|
||||||
starting_condition = (not should_stop and
|
starting_condition = (not should_stop and
|
||||||
not cruise_standstill and
|
not cruise_standstill and
|
||||||
@@ -48,9 +45,8 @@ def long_control_state_trans(CP, CP_SP, active, long_control_state, v_ego,
|
|||||||
return long_control_state
|
return long_control_state
|
||||||
|
|
||||||
class LongControl:
|
class LongControl:
|
||||||
def __init__(self, CP, CP_SP):
|
def __init__(self, CP):
|
||||||
self.CP = CP
|
self.CP = CP
|
||||||
self.CP_SP = CP_SP
|
|
||||||
self.long_control_state = LongCtrlState.off
|
self.long_control_state = LongCtrlState.off
|
||||||
self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
|
self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
|
||||||
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
|
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
|
||||||
@@ -65,7 +61,7 @@ class LongControl:
|
|||||||
self.pid.neg_limit = accel_limits[0]
|
self.pid.neg_limit = accel_limits[0]
|
||||||
self.pid.pos_limit = accel_limits[1]
|
self.pid.pos_limit = accel_limits[1]
|
||||||
|
|
||||||
self.long_control_state = long_control_state_trans(self.CP, self.CP_SP, active, self.long_control_state, CS.vEgo,
|
self.long_control_state = long_control_state_trans(self.CP, active, self.long_control_state, CS.vEgo,
|
||||||
should_stop, CS.brakePressed,
|
should_stop, CS.brakePressed,
|
||||||
CS.cruiseState.standstill)
|
CS.cruiseState.standstill)
|
||||||
if self.long_control_state == LongCtrlState.off:
|
if self.long_control_state == LongCtrlState.off:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user