Compare commits

..

7 Commits

Author SHA1 Message Date
firestar5683 5fad2a9154 Fix manager toggle startup 2026-08-03 14:07:36 -05:00
firestar5683 9b7f1222e8 dec 2026-08-03 13:46:33 -05:00
firestar5683 ff12e1fe8f build 2026-08-03 13:36:19 -05:00
firestar5683 d7498e7a93 Sync Dom non-planner updates 2026-08-03 13:27:23 -05:00
whoisdomi 22f19ad578 Becca 2026-07-24 16:09:26 -05:00
firestar5683 225e98ed58 The Crimson Night 2026-07-24 02:01:57 -05:00
firestar5683 66af0216b9 fix socket 2026-07-24 01:02:05 -05:00
1592 changed files with 77723 additions and 166554 deletions
-6
View File
@@ -1,6 +0,0 @@
github: firestar5683
patreon: firestar4430
custom:
- "https://cash.app/$domkthompson"
- "https://account.venmo.com/u/firestar4430"
- "https://www.paypal.com/paypalme/firestar4430"
+2 -2
View File
@@ -34,7 +34,7 @@ runs:
- name: setup github cache - name: setup github cache
id: gha-cache id: gha-cache
if: ${{ !contains(runner.name, 'nsc') && inputs.save != 'false' }} if: ${{ !contains(runner.name, 'nsc') && inputs.save != 'false' }}
uses: 'actions/cache@v5' uses: 'actions/cache@v4'
with: with:
path: ${{ inputs.path }} path: ${{ inputs.path }}
key: ${{ inputs.key }} key: ${{ inputs.key }}
@@ -43,7 +43,7 @@ runs:
- name: setup github cache - name: setup github cache
id: gha-cache-ro id: gha-cache-ro
if: ${{ !contains(runner.name, 'nsc') && inputs.save == 'false' }} if: ${{ !contains(runner.name, 'nsc') && inputs.save == 'false' }}
uses: 'actions/cache/restore@v5' uses: 'actions/cache/restore@v4'
with: with:
path: ${{ inputs.path }} path: ${{ inputs.path }}
key: ${{ inputs.key }} key: ${{ inputs.key }}
@@ -14,7 +14,7 @@ runs:
${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \ ${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \
scons -j$(nproc) --cache-populate" scons -j$(nproc) --cache-populate"
- name: Save scons cache - name: Save scons cache
uses: actions/cache/save@v5 uses: actions/cache/save@v4
if: github.ref == 'refs/heads/master' if: github.ref == 'refs/heads/master'
with: with:
path: .ci_cache/scons_cache path: .ci_cache/scons_cache
+9 -3
View File
@@ -23,6 +23,11 @@ on:
type: boolean type: boolean
default: true default: true
required: false required: false
build_ui:
description: "Build UI (selfdrive/ui)"
type: boolean
default: true
required: false
build_params: build_params:
description: "Build params Python extension" description: "Build params Python extension"
type: boolean type: boolean
@@ -83,7 +88,7 @@ jobs:
fi fi
- name: Checkout target branch - name: Checkout target branch
uses: actions/checkout@v6 uses: actions/checkout@v4
with: with:
ref: ${{ env.BUILD_BRANCH }} ref: ${{ env.BUILD_BRANCH }}
fetch-depth: 0 fetch-depth: 0
@@ -151,6 +156,7 @@ jobs:
fi fi
TARGETS=() TARGETS=()
[[ "${{ inputs.build_ui }}" == "true" ]] && TARGETS+=("selfdrive/ui/ui")
[[ "${{ inputs.build_params }}" == "true" ]] && TARGETS+=("common/params_pyx.so") [[ "${{ inputs.build_params }}" == "true" ]] && TARGETS+=("common/params_pyx.so")
[[ "${{ inputs.build_cereal }}" == "true" ]] && TARGETS+=("cereal/messaging/bridge") [[ "${{ inputs.build_cereal }}" == "true" ]] && TARGETS+=("cereal/messaging/bridge")
if [[ "${{ inputs.build_panda }}" == "true" ]]; then if [[ "${{ inputs.build_panda }}" == "true" ]]; then
@@ -178,8 +184,8 @@ jobs:
fi fi
if [[ ${#TARGETS[@]} -eq 0 ]]; then if [[ ${#TARGETS[@]} -eq 0 ]]; then
echo "No partial targets selected; defaulting to panda" echo "No partial targets selected; defaulting to UI + panda"
TARGETS=("panda/board/obj/panda.bin.signed") TARGETS=("selfdrive/ui/ui" "panda/board/obj/panda.bin.signed")
fi fi
echo "Running partial build for targets: ${TARGETS[*]}" echo "Running partial build for targets: ${TARGETS[*]}"
+1 -1
View File
@@ -48,7 +48,7 @@ jobs:
fi fi
- name: Checkout target branch - name: Checkout target branch
uses: actions/checkout@v6 uses: actions/checkout@v4
with: with:
ref: ${{ env.BUILD_BRANCH }} ref: ${{ env.BUILD_BRANCH }}
fetch-depth: 0 fetch-depth: 0
@@ -17,17 +17,17 @@ jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Log in to GHCR - name: Log in to GHCR
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push runner image - name: Build and push runner image
uses: docker/build-push-action@v7 uses: docker/build-push-action@v6
with: with:
context: . context: .
file: tools/truenas_github_runner/Dockerfile file: tools/truenas_github_runner/Dockerfile
+3
View File
@@ -54,6 +54,9 @@ cereal/gen
selfdrive/ui/translations/tmp selfdrive/ui/translations/tmp
selfdrive/car/tests/cars_dump selfdrive/car/tests/cars_dump
system/camerad/test/ae_gray_test system/camerad/test/ae_gray_test
selfdrive/ui/ui.macos
selfdrive/ui/ui.larch64
.coverage* .coverage*
coverage.xml coverage.xml
htmlcov htmlcov
+15
View File
@@ -11,6 +11,14 @@
"tools/sim/run_bridge.py" "tools/sim/run_bridge.py"
] ]
}, },
{
"id": "cpp_process",
"type": "pickString",
"description": "Select the process to debug",
"options": [
"selfdrive/ui/ui"
]
},
{ {
"id": "args", "id": "args",
"description": "Arguments to pass to the process", "description": "Arguments to pass to the process",
@@ -32,6 +40,13 @@
"justMyCode": true, "justMyCode": true,
"args": "${input:args}" "args": "${input:args}"
}, },
{
"name": "C++: openpilot Process",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/${input:cpp_process}",
"cwd": "${workspaceFolder}"
},
{ {
"name": "Attach LLDB to Replay drive", "name": "Attach LLDB to Replay drive",
"type": "lldb", "type": "lldb",
+118 -52
View File
@@ -1,5 +1,4 @@
import os import os
import importlib
import shutil import shutil
import subprocess import subprocess
import sys import sys
@@ -38,6 +37,10 @@ AddOption('--coverage',
action='store_true', action='store_true',
help='build with test coverage options') help='build with test coverage options')
AddOption('--clazy',
action='store_true',
help='build with clazy')
AddOption('--ccflags', AddOption('--ccflags',
action='store', action='store',
type='string', type='string',
@@ -129,41 +132,6 @@ elif arch == "aarch64" and AGNOS:
arch = "larch64" arch = "larch64"
assert arch in ["larch64", "aarch64", "x86_64", "Darwin"] assert arch in ["larch64", "aarch64", "x86_64", "Darwin"]
# AGNOS 19.6 ships native dependencies as versioned Python packages. Link
# Cap'n Proto statically from that managed package so release binaries don't
# depend on the removed libcapnp-1.0.2.so system library.
try:
capnproto = importlib.import_module("capnproto")
except ModuleNotFoundError:
capnproto = None
try:
ffmpeg = importlib.import_module("ffmpeg")
except ModuleNotFoundError:
ffmpeg = None
capnproto_include_dirs = [capnproto.INCLUDE_DIR] if capnproto is not None else []
capnproto_lib_dirs = [capnproto.LIB_DIR] if capnproto is not None else []
ffmpeg_include_dirs = [ffmpeg.INCLUDE_DIR] if ffmpeg is not None else []
ffmpeg_lib_dirs = [ffmpeg.LIB_DIR] if ffmpeg is not None else []
# Cross-builds install managed dependencies in /work/.venv-linux-arm64, but
# comma devices expose the same packages from /usr/local/venv. Never embed the
# host/container mount path in release binaries.
ffmpeg_runtime_lib_dirs = ffmpeg_lib_dirs
if arch == "larch64" and ffmpeg is not None:
ffmpeg_runtime_lib_dirs = [os.path.join("/usr/local/venv", os.path.relpath(ffmpeg.LIB_DIR, sys.prefix))]
# The managed native-dependency packages keep their tools inside the package
# instead of installing them into /usr/local/venv/bin. cereal invokes capnpc
# directly while SConscript files are evaluated, so make the packaged tools
# discoverable to both SCons actions and configure-time subprocesses.
dependency_bin_dirs = [
package.BIN_DIR for package in (capnproto, ffmpeg)
if package is not None and os.path.isdir(package.BIN_DIR)
]
if dependency_bin_dirs:
os.environ["PATH"] = os.pathsep.join([*dependency_bin_dirs, os.environ["PATH"]])
# Homebrew llvm can shadow Apple clang and break macOS SDK header resolution. # Homebrew llvm can shadow Apple clang and break macOS SDK header resolution.
# Use the system toolchain explicitly on macOS for reliable local builds. # Use the system toolchain explicitly on macOS for reliable local builds.
cc = '/usr/bin/clang' if arch == "Darwin" else 'clang' cc = '/usr/bin/clang' if arch == "Darwin" else 'clang'
@@ -305,10 +273,7 @@ env = Environment(
"-Wno-vla-cxx-extension", "-Wno-vla-cxx-extension",
] + cflags + ccflags, ] + cflags + ccflags,
# Managed dependencies must precede the compatibility sysroot. The sysroot CPPPATH=cpppath + [
# can intentionally retain legacy libraries for C3 support, but new release
# binaries must link against the versions shipped in the managed venv.
CPPPATH=capnproto_include_dirs + ffmpeg_include_dirs + cpppath + [
"#", "#",
"#third_party/acados/include", "#third_party/acados/include",
"#third_party/acados/include/blasfeo/include", "#third_party/acados/include/blasfeo/include",
@@ -327,11 +292,11 @@ env = Environment(
RANLIB=ranlib, RANLIB=ranlib,
LINKFLAGS=ldflags, LINKFLAGS=ldflags,
RPATH=ffmpeg_runtime_lib_dirs + rpath, RPATH=rpath,
CFLAGS=["-std=gnu11"] + cflags, CFLAGS=["-std=gnu11"] + cflags,
CXXFLAGS=["-std=c++1z"] + cxxflags, CXXFLAGS=["-std=c++1z"] + cxxflags,
LIBPATH=capnproto_lib_dirs + ffmpeg_lib_dirs + libpath + [ LIBPATH=libpath + [
"#msgq_repo", "#msgq_repo",
"#third_party", "#third_party",
"#selfdrive/pandad", "#selfdrive/pandad",
@@ -389,7 +354,116 @@ else:
np_version = SCons.Script.Value(np.__version__) np_version = SCons.Script.Value(np.__version__)
Export('envCython', 'np_version') Export('envCython', 'np_version')
Export('env', 'arch', 'real_arch') # Qt build environment
qt_env = env.Clone()
qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "DBus", "Xml"]
qt_libs = []
if arch == "Darwin":
qt_env['QTDIR'] = f"{brew_prefix}/opt/qt@5"
qt_dirs = [
os.path.join(qt_env['QTDIR'], "include"),
]
qt_dirs += [f"{qt_env['QTDIR']}/include/Qt{m}" for m in qt_modules]
qt_env["LINKFLAGS"] += ["-F" + os.path.join(qt_env['QTDIR'], "lib")]
qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules] + ["OpenGL"]
qt_env.AppendENVPath('PATH', os.path.join(qt_env['QTDIR'], "bin"))
else:
if arch == "larch64":
qt_env.PrependENVPath('PATH', Dir("#third_party/qt5/larch64/bin/").abspath)
# For laptop/device builds that mount an AGNOS sysroot, always prefer Qt
# headers from that sysroot to keep headers/libs ABI-matched (Qt 5.12.x).
if arch == "larch64" and os.environ.get("SP_TICI_SYSROOT"):
qt_install_prefix = tici_libpath("/usr")
qt_install_headers = tici_libpath("/usr/include/aarch64-linux-gnu/qt5")
else:
qmake = os.environ.get("SP_QMAKE", "qmake")
qt_install_prefix = subprocess.check_output([qmake, '-query', 'QT_INSTALL_PREFIX'], encoding='utf8').strip()
qt_install_headers = subprocess.check_output([qmake, '-query', 'QT_INSTALL_HEADERS'], encoding='utf8').strip()
qt_env['QTDIR'] = qt_install_prefix
qt_dirs = [
f"{qt_install_headers}",
]
qt_gui_path = os.path.join(qt_install_headers, "QtGui")
qt_gui_dirs = [d for d in os.listdir(qt_gui_path) if os.path.isdir(os.path.join(qt_gui_path, d))]
qt_dirs += [f"{qt_install_headers}/QtGui/{qt_gui_dirs[0]}/QtGui", ] if qt_gui_dirs else []
qt_dirs += [f"{qt_install_headers}/Qt{m}" for m in qt_modules]
qt_libs = [f"Qt5{m}" for m in qt_modules]
if arch == "larch64":
qt_libs += ["GLESv2", "wayland-client"]
elif arch != "Darwin":
qt_libs += ["GL"]
qt_env['QT3DIR'] = qt_env['QTDIR']
qt_env.Tool('qt3')
if arch == "larch64" and os.environ.get("SP_TICI_SYSROOT"):
qt_tool_bin = tici_libpath("/usr/lib/qt5/bin")
qt_tool_root = tici_libpath("/")
qt_arm_moc = os.path.join(qt_tool_bin, "moc")
qt_arm_uic = os.path.join(qt_tool_bin, "uic")
qt_arm_rcc = os.path.join(qt_tool_bin, "rcc")
qt_host_bin = os.environ.get("SP_QT_HOST_BIN", "/usr/lib/qt5/bin")
qt_host_moc = os.environ.get("SP_QT_HOST_MOC", os.path.join(qt_host_bin, "moc"))
qt_host_uic = os.environ.get("SP_QT_HOST_UIC", os.path.join(qt_host_bin, "uic"))
qt_host_rcc = os.environ.get("SP_QT_HOST_RCC", "rcc")
if platform.machine() in ("aarch64", "arm64"):
if "SP_QT_HOST_MOC" in os.environ:
qt_env['QT3_MOC'] = qt_host_moc
elif os.path.isfile(qt_arm_moc):
qt_env['QT3_MOC'] = qt_arm_moc
if "SP_QT_HOST_UIC" in os.environ:
qt_env['QT3_UIC'] = qt_host_uic
elif os.path.isfile(qt_arm_uic):
qt_env['QT3_UIC'] = qt_arm_uic
if "SP_QT_HOST_RCC" in os.environ:
qt_env['SP_QT_RCC'] = qt_host_rcc
elif os.path.isfile(qt_arm_rcc):
qt_env['SP_QT_RCC'] = qt_arm_rcc
else:
qt_qemu = shutil.which("qemu-aarch64-static") or shutil.which("qemu-aarch64")
if qt_qemu and os.path.isfile(qt_arm_moc):
qt_env['QT3_MOC'] = f"{qt_qemu} -L {qt_tool_root} {qt_arm_moc}"
else:
qt_env['QT3_MOC'] = qt_host_moc
if qt_qemu and os.path.isfile(qt_arm_uic):
qt_env['QT3_UIC'] = f"{qt_qemu} -L {qt_tool_root} {qt_arm_uic}"
else:
qt_env['QT3_UIC'] = qt_host_uic
if qt_qemu and os.path.isfile(qt_arm_rcc):
qt_env['SP_QT_RCC'] = f"{qt_qemu} -L {qt_tool_root} {qt_arm_rcc}"
else:
qt_env['SP_QT_RCC'] = qt_host_rcc
qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"]
qt_flags = [
"-D_REENTRANT",
"-DQT_NO_DEBUG",
"-DQT_WIDGETS_LIB",
"-DQT_GUI_LIB",
"-DQT_CORE_LIB",
"-DQT_MESSAGELOGCONTEXT",
]
qt_env['CXXFLAGS'] += qt_flags
qt_env['LIBPATH'] += ['#selfdrive/ui', ]
qt_env['LIBS'] = qt_libs
if GetOption("clazy"):
checks = [
"level0",
"level1",
"no-range-loop",
"no-non-pod-global-static",
]
qt_env['CXX'] = 'clazy'
qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0]
qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks)
Export('env', 'qt_env', 'arch', 'real_arch')
# Build common module # Build common module
SConscript(['common/SConscript']) SConscript(['common/SConscript'])
@@ -410,15 +484,7 @@ SConscript(['opendbc_repo/SConscript'], exports={'env': env_swaglog})
SConscript(['cereal/SConscript']) SConscript(['cereal/SConscript'])
Import('socketmaster', 'msgq') Import('socketmaster', 'msgq')
if capnproto is not None: messaging = [socketmaster, msgq, 'capnp', 'kj',]
messaging = [
socketmaster,
msgq,
File(os.path.join(capnproto.LIB_DIR, "libcapnp.a")),
File(os.path.join(capnproto.LIB_DIR, "libkj.a")),
]
else:
messaging = [socketmaster, msgq, 'capnp', 'kj']
Export('messaging') Export('messaging')
+3
View File
@@ -46,6 +46,9 @@ while [[ $# -gt 0 ]]; do
shortcut_includes_panda=1 shortcut_includes_panda=1
add_panda_targets add_panda_targets
;; ;;
--ui|-ui)
shortcut_targets+=("selfdrive/ui/ui")
;;
--cereal|-cereal) --cereal|-cereal)
shortcut_targets+=( shortcut_targets+=(
"cereal/libcereal.a" "cereal/libcereal.a"
+3 -11
View File
@@ -1,5 +1,3 @@
import subprocess
Import('env', 'common', 'msgq') Import('env', 'common', 'msgq')
cereal_dir = Dir('.') cereal_dir = Dir('.')
@@ -7,15 +5,9 @@ gen_dir = Dir('gen')
# Build cereal # Build cereal
schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp'] schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp']
schema_outputs = env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files], env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files],
schema_files, schema_files,
f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/") f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/")
# capnpc embeds an exact compiler-version guard in every generated C++ header.
# Include the tool version in the dependency signature so SCons cannot reuse
# generated headers from a cache populated by another AGNOS/toolchain version.
capnp_compiler_version = subprocess.check_output(['capnpc', '--version'], encoding='utf-8').strip()
env.Depends(schema_outputs, env.Value(capnp_compiler_version))
cereal = env.Library('cereal', [f'gen/cpp/{s}.c++' for s in schema_files]) cereal = env.Library('cereal', [f'gen/cpp/{s}.c++' for s in schema_files])
+1 -27
View File
@@ -98,7 +98,6 @@ struct StarPilotCarState @0xf35cc4560bbf6ec2 {
teslaCCNotArmed @27 :Bool; # lateral engaged but DI_cruiseState != STANDBY/ENABLED teslaCCNotArmed @27 :Bool; # lateral engaged but DI_cruiseState != STANDBY/ENABLED
accelHardCruise @28 :Bool; # current/releasing accel cruise button came from GM hard-press signal accelHardCruise @28 :Bool; # current/releasing accel cruise button came from GM hard-press signal
decelHardCruise @29 :Bool; # current/releasing decel cruise button came from GM hard-press signal decelHardCruise @29 :Bool; # current/releasing decel cruise button came from GM hard-press signal
pulseAndGlide @30 :Bool; # developer-only wheel-button pulse-and-glide mode is enabled
} }
struct StarPilotDeviceState @0xda96579883444c35 { struct StarPilotDeviceState @0xda96579883444c35 {
@@ -220,27 +219,11 @@ struct StarPilotPlan @0xf98d843bfd7004a3 {
disableThrottle @35 :Bool; disableThrottle @35 :Bool;
trackingLead @36 :Bool; trackingLead @36 :Bool;
stopSignConfirmed @37 :Bool; stopSignConfirmed @37 :Bool;
pulseGlideCoasting @38 :Bool; # developer-only P&G phase for on-road status UI
# Curve Speed Controller diagnostics, for tuning and rollout validation
cscOverridden @39 :Bool; # driver cancelled this curve with RES+
cscLearnedLatAccel @40 :Float32; # learned comfort at the current curvature, before margin
cscBindingDistance @41 :Float32; # distance to the horizon point setting the target, m
approachStopLength @42 :Float32; # pre-commit distance to a detected stop, m; 0 when off
} }
struct StarPilotRadarState @0xb86e6369214c01c8 { struct StarPilotRadarState @0xb86e6369214c01c8 {
leadLeft @0 :LeadData; leadLeft @0 :LeadData;
leadRight @1 :LeadData; leadRight @1 :LeadData;
adjacentStopped @2 :AdjacentStopped;
# A vehicle in an adjacent lane that was observed MOVING and then came to rest.
# Distinct from leadLeft/leadRight, which are moving-target-only by design.
struct AdjacentStopped {
status @0 :Bool;
dRel @1 :Float32;
yRel @2 :Float32;
radarTrackId @3 :Int32 = -1;
}
struct LeadData { struct LeadData {
dRel @0 :Float32; dRel @0 :Float32;
@@ -270,7 +253,6 @@ struct StarPilotSelfdriveState @0xf416ec09499d9d19 {
alertSize @3 :AlertSize; alertSize @3 :AlertSize;
alertType @4 :Text; alertType @4 :Text;
alertSound @5 :Car.CarControl.HUDControl.AudibleAlert; alertSound @5 :Car.CarControl.HUDControl.AudibleAlert;
vEgo @6 :Float32;
enum AlertStatus { enum AlertStatus {
normal @0; normal @0;
@@ -300,15 +282,7 @@ struct StarPilotLateralManeuverPlanDEPRECATED @0xcb9fd56c7057593a {
desiredCurvature @0 :Float32; # 1/m desiredCurvature @0 :Float32; # 1/m
} }
struct StarPilotLateralState @0xc2243c65e0340384 { struct CustomReserved11 @0xc2243c65e0340384 {
active @0 :Bool;
frictionThreshold @1 :Float32;
frictionScale @2 :Float32;
feedforward @3 :Float32;
frictionJerk @4 :Float32;
frictionJerkDeadzone @5 :Float32;
lowSpeedFactor @6 :Float32;
unwindDetected @7 :Bool;
} }
struct CustomReserved12 @0x9ccdc8676701b412 { struct CustomReserved12 @0x9ccdc8676701b412 {
Binary file not shown.
Binary file not shown.
+6 -58
View File
@@ -130,13 +130,8 @@ struct OnroadEvent @0xc4fa6047f024e718 {
userBookmark @95; userBookmark @95;
excessiveActuation @96; excessiveActuation @96;
audioFeedback @97; audioFeedback @97;
bigModelLoading @100;
bigModelFailed @102;
soundsUnavailableDEPRECATED @47; soundsUnavailableDEPRECATED @47;
stockLkasDEPRECATED @98;
lateralManeuverDEPRECATED @99;
bigModelReadyDEPRECATED @101;
} }
} }
@@ -472,10 +467,6 @@ struct CanData {
struct DeviceState @0xa4d8b5af2aa492eb { struct DeviceState @0xa4d8b5af2aa492eb {
deviceType @45 :InitData.DeviceType; deviceType @45 :InitData.DeviceType;
# usb
chestnutPresent @51 :Bool;
usbState @52 :UsbState;
networkType @22 :NetworkType; networkType @22 :NetworkType;
networkInfo @31 :NetworkInfo; networkInfo @31 :NetworkInfo;
networkStrength @24 :NetworkStrength; networkStrength @24 :NetworkStrength;
@@ -507,8 +498,7 @@ struct DeviceState @0xa4d8b5af2aa492eb {
pmicTempC @39 :List(Float32); pmicTempC @39 :List(Float32);
intakeTempC @46 :Float32; intakeTempC @46 :Float32;
exhaustTempC @47 :Float32; exhaustTempC @47 :Float32;
gnssTempC @48 :Float32; caseTempC @48 :Float32;
bottomSocTempC @50 :Float32;
maxTempC @44 :Float32; # max of other temps, used to control fan maxTempC @44 :Float32; # max of other temps, used to control fan
thermalZones @38 :List(ThermalZone); thermalZones @38 :List(ThermalZone);
thermalStatus @14 :ThermalStatus; thermalStatus @14 :ThermalStatus;
@@ -522,10 +512,10 @@ struct DeviceState @0xa4d8b5af2aa492eb {
} }
enum ThermalStatus { enum ThermalStatus {
ok @0; green @0;
warmDEPRECATED @1; yellow @1;
overheated @2; red @2;
critical @3; danger @3;
} }
enum NetworkType { enum NetworkType {
@@ -741,41 +731,6 @@ struct PeripheralState {
} }
} }
struct UsbState {
devices @0 :List(Device);
struct Device {
busnum @0 :UInt8;
devnum @1 :UInt8;
vendorId @2 :UInt16;
productId @3 :UInt16;
speedMbps @4 :UInt16;
manufacturer @6 :Text;
product @5 :Text;
linkErrorCount @7 :UInt16;
usb3Lane @8 :Usb3Lane;
enum Usb3Lane {
unknown @0;
a @1;
b @2;
}
}
}
struct ChestnutState {
tempC @0 :Float32;
memoryTempC @1 :Float32;
powerDrawW @2 :Float32;
powerLimitW @3 :Float32;
gpuUsagePercent @4 :UInt8;
gpuClockMhz @5 :UInt16;
fanSpeedRpm @6 :UInt16;
pcieLtssm @7 :UInt8;
supplyVoltage @8 :UInt16; # mV
supplyCurrent @9 :Int16; # mA
}
struct RadarState @0x9a185389d6fdd05f { struct RadarState @0x9a185389d6fdd05f {
mdMonoTime @6 :UInt64; mdMonoTime @6 :UInt64;
carStateMonoTime @11 :UInt64; carStateMonoTime @11 :UInt64;
@@ -1327,11 +1282,6 @@ struct LongitudinalPlan @0xe00b5b3eba12876c {
solverExecutionTime @35 :Float32; solverExecutionTime @35 :Float32;
leadTrajectoryX0 @40 :List(Float32);
leadTrajectoryV0 @41 :List(Float32);
leadTrajectoryX1 @42 :List(Float32);
leadTrajectoryV1 @43 :List(Float32);
enum LongitudinalPlanSource { enum LongitudinalPlanSource {
cruise @0; cruise @0;
lead0 @1; lead0 @1;
@@ -2737,7 +2687,6 @@ struct Event {
procLog @33 :ProcLog; procLog @33 :ProcLog;
clocks @35 :Clocks; clocks @35 :Clocks;
deviceState @6 :DeviceState; deviceState @6 :DeviceState;
chestnutState @152 :ChestnutState;
logMessage @18 :Text; logMessage @18 :Text;
errorLogMessage @85 :Text; errorLogMessage @85 :Text;
@@ -2757,7 +2706,6 @@ struct Event {
userBookmark @93 :UserBookmark; userBookmark @93 :UserBookmark;
bookmarkButton @148 :UserBookmark; bookmarkButton @148 :UserBookmark;
audioFeedback @149 :AudioFeedback; audioFeedback @149 :AudioFeedback;
visionSpeedLimitBookmark @153 :UserBookmark;
lateralManeuverPlan @150 :LateralManeuverPlan; lateralManeuverPlan @150 :LateralManeuverPlan;
# *********** debug *********** # *********** debug ***********
@@ -2794,7 +2742,7 @@ struct Event {
starpilotSelfdriveState @115 :Custom.StarPilotSelfdriveState; starpilotSelfdriveState @115 :Custom.StarPilotSelfdriveState;
customReserved9 @116 :Custom.CustomReserved9; customReserved9 @116 :Custom.CustomReserved9;
starpilotLateralManeuverPlanDEPRECATED @136 :Custom.StarPilotLateralManeuverPlanDEPRECATED; starpilotLateralManeuverPlanDEPRECATED @136 :Custom.StarPilotLateralManeuverPlanDEPRECATED;
starpilotLateralState @137 :Custom.StarPilotLateralState; customReserved11 @137 :Custom.CustomReserved11;
customReserved12 @138 :Custom.CustomReserved12; customReserved12 @138 :Custom.CustomReserved12;
customReserved13 @139 :Custom.CustomReserved13; customReserved13 @139 :Custom.CustomReserved13;
customReserved14 @140 :Custom.CustomReserved14; customReserved14 @140 :Custom.CustomReserved14;
Binary file not shown.
-3
View File
@@ -12,7 +12,6 @@ static std::map<std::string, service> services = {
{ "temperatureSensor", {"temperatureSensor", true, 2.000000, 200, 256000}}, { "temperatureSensor", {"temperatureSensor", true, 2.000000, 200, 256000}},
{ "gpsNMEA", {"gpsNMEA", true, 9.000000, -1, 256000}}, { "gpsNMEA", {"gpsNMEA", true, 9.000000, -1, 256000}},
{ "deviceState", {"deviceState", true, 2.000000, 1, 256000}}, { "deviceState", {"deviceState", true, 2.000000, 1, 256000}},
{ "chestnutState", {"chestnutState", true, 10.000000, 10, 256000}},
{ "touch", {"touch", true, 20.000000, 1, 256000}}, { "touch", {"touch", true, 20.000000, 1, 256000}},
{ "can", {"can", true, 100.000000, 2053, 10485760}}, { "can", {"can", true, 100.000000, 2053, 10485760}},
{ "controlsState", {"controlsState", true, 100.000000, 10, 2097152}}, { "controlsState", {"controlsState", true, 100.000000, 10, 2097152}},
@@ -69,7 +68,6 @@ static std::map<std::string, service> services = {
{ "rawAudioData", {"rawAudioData", false, 20.000000, -1, 256000}}, { "rawAudioData", {"rawAudioData", false, 20.000000, -1, 256000}},
{ "bookmarkButton", {"bookmarkButton", true, 0.000000, 1, 256000}}, { "bookmarkButton", {"bookmarkButton", true, 0.000000, 1, 256000}},
{ "audioFeedback", {"audioFeedback", true, 0.000000, 1, 256000}}, { "audioFeedback", {"audioFeedback", true, 0.000000, 1, 256000}},
{ "visionSpeedLimitBookmark", {"visionSpeedLimitBookmark", false, 0.000000, 1, 256000}},
{ "roadEncodeData", {"roadEncodeData", false, 20.000000, -1, 10485760}}, { "roadEncodeData", {"roadEncodeData", false, 20.000000, -1, 10485760}},
{ "driverEncodeData", {"driverEncodeData", false, 20.000000, -1, 10485760}}, { "driverEncodeData", {"driverEncodeData", false, 20.000000, -1, 10485760}},
{ "wideRoadEncodeData", {"wideRoadEncodeData", false, 20.000000, -1, 10485760}}, { "wideRoadEncodeData", {"wideRoadEncodeData", false, 20.000000, -1, 10485760}},
@@ -84,7 +82,6 @@ static std::map<std::string, service> services = {
{ "livestreamRoadEncodeData", {"livestreamRoadEncodeData", false, 20.000000, -1, 2097152}}, { "livestreamRoadEncodeData", {"livestreamRoadEncodeData", false, 20.000000, -1, 2097152}},
{ "livestreamDriverEncodeData", {"livestreamDriverEncodeData", false, 20.000000, -1, 2097152}}, { "livestreamDriverEncodeData", {"livestreamDriverEncodeData", false, 20.000000, -1, 2097152}},
{ "customReserved9", {"customReserved9", true, 0.000000, 1, 256000}}, { "customReserved9", {"customReserved9", true, 0.000000, 1, 256000}},
{ "starpilotLateralState", {"starpilotLateralState", true, 100.000000, 10, 256000}},
{ "customReservedRawData0", {"customReservedRawData0", true, 0.000000, -1, 256000}}, { "customReservedRawData0", {"customReservedRawData0", true, 0.000000, -1, 256000}},
{ "customReservedRawData1", {"customReservedRawData1", true, 0.000000, -1, 256000}}, { "customReservedRawData1", {"customReservedRawData1", true, 0.000000, -1, 256000}},
{ "customReservedRawData2", {"customReservedRawData2", true, 0.000000, -1, 256000}}, { "customReservedRawData2", {"customReservedRawData2", true, 0.000000, -1, 256000}},
-3
View File
@@ -29,7 +29,6 @@ _services: dict[str, tuple] = {
"temperatureSensor": (True, 2., 200), "temperatureSensor": (True, 2., 200),
"gpsNMEA": (True, 9.), "gpsNMEA": (True, 9.),
"deviceState": (True, 2., 1), "deviceState": (True, 2., 1),
"chestnutState": (True, 10., 10),
"touch": (True, 20., 1), "touch": (True, 20., 1),
"can": (True, 100., 2053, QueueSize.BIG), # decimation gives ~3 msgs in a full segment "can": (True, 100., 2053, QueueSize.BIG), # decimation gives ~3 msgs in a full segment
"controlsState": (True, 100., 10, QueueSize.MEDIUM), "controlsState": (True, 100., 10, QueueSize.MEDIUM),
@@ -86,7 +85,6 @@ _services: dict[str, tuple] = {
"rawAudioData": (False, 20.), "rawAudioData": (False, 20.),
"bookmarkButton": (True, 0., 1), "bookmarkButton": (True, 0., 1),
"audioFeedback": (True, 0., 1), "audioFeedback": (True, 0., 1),
"visionSpeedLimitBookmark": (False, 0., 1),
"roadEncodeData": (False, 20., None, QueueSize.BIG), "roadEncodeData": (False, 20., None, QueueSize.BIG),
"driverEncodeData": (False, 20., None, QueueSize.BIG), "driverEncodeData": (False, 20., None, QueueSize.BIG),
"wideRoadEncodeData": (False, 20., None, QueueSize.BIG), "wideRoadEncodeData": (False, 20., None, QueueSize.BIG),
@@ -103,7 +101,6 @@ _services: dict[str, tuple] = {
"livestreamRoadEncodeData": (False, 20., None, QueueSize.MEDIUM), "livestreamRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
"livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM), "livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM),
"customReserved9": (True, 0., 1), "customReserved9": (True, 0., 1),
"starpilotLateralState": (True, 100., 10),
"customReservedRawData0": (True, 0.), "customReservedRawData0": (True, 0.),
"customReservedRawData1": (True, 0.), "customReservedRawData1": (True, 0.),
"customReservedRawData2": (True, 0.), "customReservedRawData2": (True, 0.),
+1 -1
View File
@@ -2,7 +2,7 @@ from openpilot.common.params import Params
def get_gps_location_service(params: Params) -> str: def get_gps_location_service(params: Params) -> str:
if params.get_bool("UbloxAvailable") or params.get_bool("CarGpsAvailable"): if params.get_bool("UbloxAvailable"):
return "gpsLocationExternal" return "gpsLocationExternal"
else: else:
return "gpsLocation" return "gpsLocation"
Binary file not shown.
+15 -76
View File
@@ -16,14 +16,10 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"AthenadUploadQueue", {PERSISTENT, JSON}}, {"AthenadUploadQueue", {PERSISTENT, JSON}},
{"AthenadRecentlyViewedRoutes", {PERSISTENT, STRING}}, {"AthenadRecentlyViewedRoutes", {PERSISTENT, STRING}},
{"BootCount", {PERSISTENT, INT}}, {"BootCount", {PERSISTENT, INT}},
{"BluetoothAudioAddress", {PERSISTENT, STRING}},
{"BluetoothAudioTestActive", {CLEAR_ON_MANAGER_START | DONT_LOG, BOOL}},
{"BluetoothEnabled", {PERSISTENT, BOOL, "0"}},
{"CalibrationParams", {PERSISTENT, BYTES}}, {"CalibrationParams", {PERSISTENT, BYTES}},
{"CameraDebugExpGain", {CLEAR_ON_MANAGER_START, STRING}}, {"CameraDebugExpGain", {CLEAR_ON_MANAGER_START, STRING}},
{"CameraDebugExpTime", {CLEAR_ON_MANAGER_START, STRING}}, {"CameraDebugExpTime", {CLEAR_ON_MANAGER_START, STRING}},
{"CarBatteryCapacity", {PERSISTENT, INT}}, {"CarBatteryCapacity", {PERSISTENT, INT}},
{"CarGpsAvailable", {CLEAR_ON_MANAGER_START, BOOL}},
{"CarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}}, {"CarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}},
{"CarParamsCache", {CLEAR_ON_MANAGER_START, BYTES}}, {"CarParamsCache", {CLEAR_ON_MANAGER_START, BYTES}},
{"CarParamsPersistent", {PERSISTENT, BYTES}}, {"CarParamsPersistent", {PERSISTENT, BYTES}},
@@ -48,6 +44,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ExperimentalLongitudinalEnabled", {PERSISTENT, BOOL}}, {"ExperimentalLongitudinalEnabled", {PERSISTENT, BOOL}},
{"ExperimentalMode", {PERSISTENT, BOOL}}, {"ExperimentalMode", {PERSISTENT, BOOL}},
{"ExperimentalModeConfirmed", {PERSISTENT, BOOL}}, {"ExperimentalModeConfirmed", {PERSISTENT, BOOL}},
{"LongitudinalModelPreference", {PERSISTENT, INT, "0", "0", 1, SETTINGS_SIMPLE}},
{"LongitudinalModelPreferenceOverride", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, INT, "-1", "-1"}},
{"PersistChillState", {PERSISTENT, BOOL, "0", "0", 1}}, {"PersistChillState", {PERSISTENT, BOOL, "0", "0", 1}},
{"PersistExperimentalState", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}}, {"PersistExperimentalState", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"PersistedCCStatus", {PERSISTENT, INT, "0", "0"}}, {"PersistedCCStatus", {PERSISTENT, INT, "0", "0"}},
@@ -66,8 +64,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"GsmRoaming", {PERSISTENT, BOOL}}, {"GsmRoaming", {PERSISTENT, BOOL}},
{"HardwareSerial", {PERSISTENT, STRING}}, {"HardwareSerial", {PERSISTENT, STRING}},
{"HasAcceptedTerms", {PERSISTENT, STRING, "0"}}, {"HasAcceptedTerms", {PERSISTENT, STRING, "0"}},
// Internal kill switch; the platform verification allowlist remains the hard safety gate.
{"HondaBoschARadar", {PERSISTENT, BOOL, "1"}},
{"HondaGasFactorParams", {PERSISTENT, FLOAT}}, {"HondaGasFactorParams", {PERSISTENT, FLOAT}},
{"HondaLateralPidKiScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}}, {"HondaLateralPidKiScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
{"HondaLateralPidKpScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}}, {"HondaLateralPidKpScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
@@ -76,7 +72,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}}, {"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsEngaged", {PERSISTENT, BOOL}}, {"IsEngaged", {PERSISTENT, BOOL}},
{"IsLdwEnabled", {PERSISTENT, BOOL}}, {"IsLdwEnabled", {PERSISTENT, BOOL}},
{"IsLiveStreaming", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsMetric", {PERSISTENT, BOOL}}, {"IsMetric", {PERSISTENT, BOOL}},
{"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}}, {"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsOnroad", {PERSISTENT, BOOL}}, {"IsOnroad", {PERSISTENT, BOOL}},
@@ -87,7 +82,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}}, {"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}}, {"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}},
{"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, {"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"JoystickControlDevice", {PERSISTENT, STRING}},
{"LanguageSetting", {PERSISTENT, STRING, "main_en"}}, {"LanguageSetting", {PERSISTENT, STRING, "main_en"}},
{"LastAthenaPingTime", {CLEAR_ON_MANAGER_START, INT}}, {"LastAthenaPingTime", {CLEAR_ON_MANAGER_START, INT}},
{"LastGPSPosition", {PERSISTENT, STRING}}, {"LastGPSPosition", {PERSISTENT, STRING}},
@@ -102,8 +96,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"LiveDelay", {PERSISTENT, BYTES}}, {"LiveDelay", {PERSISTENT, BYTES}},
{"LiveParameters", {PERSISTENT, JSON}}, {"LiveParameters", {PERSISTENT, JSON}},
{"LiveParametersV2", {PERSISTENT, BYTES}}, {"LiveParametersV2", {PERSISTENT, BYTES}},
{"LivestreamEncoderBitrate", {CLEAR_ON_MANAGER_START | DONT_LOG, INT}},
{"LivestreamRequestKeyframe", {CLEAR_ON_MANAGER_START | DONT_LOG, BOOL}},
{"LiveTorqueParameters", {PERSISTENT | DONT_LOG, BYTES}}, {"LiveTorqueParameters", {PERSISTENT | DONT_LOG, BYTES}},
{"LateralManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, {"LateralManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"LocationFilterInitialState", {PERSISTENT, BYTES}}, {"LocationFilterInitialState", {PERSISTENT, BYTES}},
@@ -135,17 +127,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"RecordAudioFeedback", {PERSISTENT, BOOL, "0"}}, {"RecordAudioFeedback", {PERSISTENT, BOOL, "0"}},
{"RecordFront", {PERSISTENT, BOOL}}, {"RecordFront", {PERSISTENT, BOOL}},
{"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet {"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet
{"SentryModeEnabled", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"SentryModeCapture", {CLEAR_ON_MANAGER_START, BOOL}},
{"SentryModeLastEvent", {PERSISTENT, JSON, "{}", "{}"}},
{"SentryModeNtfyUrl", {PERSISTENT, STRING}},
{"SentryModeSensitivity", {PERSISTENT, FLOAT, "0.04", "0.04", 0, SETTINGS_SIMPLE}},
{"SentryModeStatus", {CLEAR_ON_MANAGER_START | DONT_LOG, JSON}},
{"SentryModeWarningTime", {PERSISTENT, FLOAT, "1.0", "1.0", 0, SETTINGS_SIMPLE}},
{"SentryModeWebhook", {PERSISTENT, STRING}},
{"SecOCKey", {PERSISTENT | DONT_LOG, STRING}}, {"SecOCKey", {PERSISTENT | DONT_LOG, STRING}},
{"ShowDebugInfo", {PERSISTENT, BOOL}}, {"ShowDebugInfo", {PERSISTENT, BOOL}},
{"ShowAllToggles", {PERSISTENT, BOOL, "0", "0", 3}}, {"ShowAllToggles", {PERSISTENT, BOOL, "0", "0", 3}},
{"TryRaylibUI", {PERSISTENT, BOOL, "1"}},
{"UseOldUI", {PERSISTENT, BOOL, "0", std::nullopt, 0, SETTINGS_SIMPLE}},
{"UsePrebuilt", {PERSISTENT, BOOL, "1"}}, {"UsePrebuilt", {PERSISTENT, BOOL, "1"}},
{"RouteCount", {PERSISTENT, INT, "0"}}, {"RouteCount", {PERSISTENT, INT, "0"}},
{"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, {"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
@@ -168,7 +154,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}}, {"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
{"UsbGpuActive", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, {"UsbGpuActive", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"UsbGpuCompiled", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, {"UsbGpuCompiled", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"UsbGpuLoading", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"UsbGpuPresent", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, {"UsbGpuPresent", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"Version", {PERSISTENT, STRING}}, {"Version", {PERSISTENT, STRING}},
@@ -195,7 +180,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ApiCache_DriveStats", {PERSISTENT, JSON, "{}", "{}"}}, {"ApiCache_DriveStats", {PERSISTENT, JSON, "{}", "{}"}},
{"AutomaticallyDownloadModels", {PERSISTENT, BOOL, "1", "0", 1}}, {"AutomaticallyDownloadModels", {PERSISTENT, BOOL, "1", "0", 1}},
{"AutomaticUpdates", {PERSISTENT, BOOL, "1", "1", 0}}, {"AutomaticUpdates", {PERSISTENT, BOOL, "1", "1", 0}},
{"AllowGpuModelDownloadWithoutGpu", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"AvailableModelNames", {PERSISTENT, STRING, "", "", 1}}, {"AvailableModelNames", {PERSISTENT, STRING, "", "", 1}},
{"AvailableModelSeries", {PERSISTENT, STRING, "", "", 1}}, {"AvailableModelSeries", {PERSISTENT, STRING, "", "", 1}},
{"AvailableModels", {PERSISTENT, STRING, "", "", 1}}, {"AvailableModels", {PERSISTENT, STRING, "", "", 1}},
@@ -211,7 +195,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CalibratedLateralAcceleration", {PERSISTENT, FLOAT, "2.0", "2.0", 2}}, {"CalibratedLateralAcceleration", {PERSISTENT, FLOAT, "2.0", "2.0", 2}},
{"CalibrationProgress", {PERSISTENT, FLOAT, "0.0", "0.0", 3}}, {"CalibrationProgress", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"CameraOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}}, {"CameraOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"CameraView", {PERSISTENT, INT, "2", "0", 2, SETTINGS_SIMPLE}}, {"CameraView", {PERSISTENT, INT, "3", "0", 2, SETTINGS_SIMPLE}},
{"CancelDownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}}, {"CancelDownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"DisableWideRoad", {PERSISTENT, BOOL, "0", "0", 3}}, {"DisableWideRoad", {PERSISTENT, BOOL, "0", "0", 3}},
{"CancelModelDownload", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}}, {"CancelModelDownload", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
@@ -222,8 +206,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CECurves", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}}, {"CECurves", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"CECurvesLead", {PERSISTENT, BOOL, "0", "0", 1}}, {"CECurvesLead", {PERSISTENT, BOOL, "0", "0", 1}},
{"CELead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}}, {"CELead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CEModelStopTime", {PERSISTENT, FLOAT, "7.7", "0.0", 2, SETTINGS_SIMPLE}}, {"CEModelStopTime", {PERSISTENT, FLOAT, "7.0", "0.0", 2, SETTINGS_SIMPLE}},
{"CEOpenRoad", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"CESignalLaneDetection", {PERSISTENT, BOOL, "1", "0", 2}}, {"CESignalLaneDetection", {PERSISTENT, BOOL, "1", "0", 2}},
{"CESignalSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}}, {"CESignalSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"CESlowerLead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}}, {"CESlowerLead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
@@ -248,7 +231,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ConditionalExperimental", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}}, {"ConditionalExperimental", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CurvatureData", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}}, {"CurvatureData", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"CurveSpeedController", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}}, {"CurveSpeedController", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CurveSpeedControllerNoLead", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"CustomAlerts", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}}, {"CustomAlerts", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"CustomAccelProfile", {PERSISTENT, BOOL, "0", "0", 3}}, {"CustomAccelProfile", {PERSISTENT, BOOL, "0", "0", 3}},
{"CustomAccelProfileInitialized", {PERSISTENT, BOOL, "0", "0", 3}}, {"CustomAccelProfileInitialized", {PERSISTENT, BOOL, "0", "0", 3}},
@@ -286,7 +268,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}}, {"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}}, {"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}},
{"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}}, {"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"DeviceShutdown", {PERSISTENT, INT, "6", "6", 1, SETTINGS_SIMPLE}}, {"DeviceShutdown", {PERSISTENT, INT, "9", "33", 1, SETTINGS_SIMPLE}},
{"DisableOnroadUploads", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}}, {"DisableOnroadUploads", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"DisableOpenpilotLongitudinal", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}}, {"DisableOpenpilotLongitudinal", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"DiscordUsername", {PERSISTENT, STRING, "", "", 0}}, {"DiscordUsername", {PERSISTENT, STRING, "", "", 0}},
@@ -304,11 +286,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"DownloadAllModels", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}}, {"DownloadAllModels", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"DownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}}, {"DownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"DriverCamera", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}}, {"DriverCamera", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"Model", {PERSISTENT, STRING, "rdf43", "rdf43", 1}}, {"Model", {PERSISTENT, STRING, "sc2", "sc2", 1}},
{"ModelVersion", {PERSISTENT, STRING, "v15", "v15", 1}}, {"ModelVersion", {PERSISTENT, STRING, "v11", "v11", 1}},
{"DrivingModel", {PERSISTENT, STRING, "rdf43", "rdf43", 1}}, {"DrivingModel", {PERSISTENT, STRING, "sc2", "sc2", 1}},
{"DrivingModelName", {PERSISTENT, STRING, "Regret Driven Framework V4", "Regret Driven Framework V4", 1}}, {"DrivingModelName", {PERSISTENT, STRING, "South Carolina", "South Carolina", 1}},
{"DrivingModelVersion", {PERSISTENT, STRING, "v15", "v15", 1}}, {"DrivingModelVersion", {PERSISTENT, STRING, "v11", "v11", 1}},
{"DynamicPathWidth", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}}, {"DynamicPathWidth", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"DynamicPedalsOnUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}}, {"DynamicPedalsOnUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"EngageVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}}, {"EngageVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
@@ -344,22 +326,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ForceStops", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}}, {"ForceStops", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"ForceStopDistanceOffset", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}}, {"ForceStopDistanceOffset", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ForceStandstill", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}}, {"ForceStandstill", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"FordLKASButtonControlMigrated", {PERSISTENT, BOOL, "0", "0"}},
{"ForceTorqueController", {PERSISTENT, BOOL, "0", "0", 3}}, {"ForceTorqueController", {PERSISTENT, BOOL, "0", "0", 3}},
{"FordAngleBlend", {PERSISTENT, FLOAT, "0.5", "0.5", 2}},
{"FordAngleHighSpeedDamping", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"FordAngleHighSpeedFactor", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"FordAngleLaneChangeFactor", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"FordAngleLowSpeedFactor", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"FordCurvatureBlendHigh", {PERSISTENT, FLOAT, "0.4", "0.4", 2}},
{"FordCurvatureBlendLow", {PERSISTENT, FLOAT, "0.4", "0.4", 2}},
{"FordCurvatureLaneChangeFactor", {PERSISTENT, FLOAT, "0.85", "0.85", 2}},
{"FordHandsFreeCluster", {PERSISTENT, BOOL, "0", "0", 2}},
{"FordHumanTurnDetection", {PERSISTENT, BOOL, "1", "1", 2}},
{"FordLateralMode", {PERSISTENT, INT, "1", "1", 2}},
{"FLMActiveOverrides", {PERSISTENT, JSON, "{}", "{}", 2}}, {"FLMActiveOverrides", {PERSISTENT, JSON, "{}", "{}", 2}},
{"FLMActiveProfileId", {PERSISTENT, STRING, "", "", 2}}, {"FLMActiveProfileId", {PERSISTENT, STRING, "", "", 2}},
{"FLMSubmittedTune", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
{"FLMTrialBaseline", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}}, {"FLMTrialBaseline", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"FLMTrialApplied", {PERSISTENT, BOOL, "0", "0", 2}}, {"FLMTrialApplied", {PERSISTENT, BOOL, "0", "0", 2}},
{"FPSCounter", {PERSISTENT, BOOL, "0", "0", 3}}, {"FPSCounter", {PERSISTENT, BOOL, "0", "0", 3}},
@@ -369,14 +338,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"StarPilotCarParamsPersistent", {PERSISTENT, BYTES, "", ""}}, {"StarPilotCarParamsPersistent", {PERSISTENT, BYTES, "", ""}},
{"StarPilotDongleId", {PERSISTENT | DONT_LOG, STRING, "", "", 0}}, {"StarPilotDongleId", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"StarPilotFavoriteSlots", {PERSISTENT, JSON, "[]", "[]", 1}}, {"StarPilotFavoriteSlots", {PERSISTENT, JSON, "[]", "[]", 1}},
{"ControllerActionSlots", {PERSISTENT, JSON, "[]", "[]", 1}},
{"WheelControlLearnSlot", {CLEAR_ON_MANAGER_START | DONT_LOG, INT}},
{"WheelControlMappings", {PERSISTENT, JSON, "[]", "[]", 1}},
{"WheelControlStatus", {CLEAR_ON_MANAGER_START | DONT_LOG, JSON, "{}", "{}"}},
{"WheelControlTestActive", {CLEAR_ON_MANAGER_START | DONT_LOG, BOOL}},
{"WheelControlsEnabled", {PERSISTENT, BOOL, "0"}},
{"StarPilotStats", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}}, {"StarPilotStats", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"StarPilotTogglesUpdated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}}, {"StarPilotTogglesUpdated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"FrogsGoMoosTweak", {PERSISTENT, BOOL, "1", "0", 2}},
{"GoatScream", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}}, {"GoatScream", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"GoatScreamCriticalAlerts", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}}, {"GoatScreamCriticalAlerts", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"GreenLightAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}}, {"GreenLightAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
@@ -410,20 +374,15 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"KonikDongleId", {PERSISTENT, STRING, "", "", 0}}, {"KonikDongleId", {PERSISTENT, STRING, "", "", 0}},
{"KonikMinutes", {PERSISTENT, INT, "0", "0", 0}}, {"KonikMinutes", {PERSISTENT, INT, "0", "0", 0}},
{"LaneCentering", {PERSISTENT, BOOL, "0", "0", 2}}, {"LaneCentering", {PERSISTENT, BOOL, "0", "0", 2}},
{"LaneCenteringPauseOnSignal", {PERSISTENT, BOOL, "1", "1", 2}},
{"LaneCenteringE2EAuthority", {PERSISTENT, FLOAT, "1.0", "1.0", 3}}, {"LaneCenteringE2EAuthority", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
{"LaneCenterOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}}, {"LaneCenterOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"LaneChanges", {PERSISTENT, BOOL, "1", "1", 0, SETTINGS_SIMPLE}}, {"LaneChanges", {PERSISTENT, BOOL, "1", "1", 0, SETTINGS_SIMPLE}},
{"LaneChangeCloseGap", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"LaneChangeCloseGapSeconds", {PERSISTENT, FLOAT, "0.6", "0.6", 1, SETTINGS_SIMPLE}},
{"LaneChangeSmoothing", {PERSISTENT, INT, "5", "10", 1, SETTINGS_SIMPLE}}, {"LaneChangeSmoothing", {PERSISTENT, INT, "5", "10", 1, SETTINGS_SIMPLE}},
{"LaneChangeTime", {PERSISTENT, FLOAT, "1.0", "0.0", 1, SETTINGS_SIMPLE}}, {"LaneChangeTime", {PERSISTENT, FLOAT, "1.0", "0.0", 1, SETTINGS_SIMPLE}},
{"LaneDetectionWidth", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}}, {"LaneDetectionWidth", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
{"LaneLinesColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}}, {"LaneLinesColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
{"LaneLinesWidth", {PERSISTENT, FLOAT, "4.0", "2.0", 2, SETTINGS_SIMPLE}}, {"LaneLinesWidth", {PERSISTENT, FLOAT, "4.0", "2.0", 2, SETTINGS_SIMPLE}},
{"LastMapsUpdate", {PERSISTENT, STRING, "", ""}}, {"LastMapsUpdate", {PERSISTENT, STRING, "", ""}},
{"MapsDownloadProgress", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"MapsDownloadSizeCache", {PERSISTENT, STRING, "{}", "{}"}},
{"LateralTune", {PERSISTENT, BOOL, "1", "0", 1}}, {"LateralTune", {PERSISTENT, BOOL, "1", "0", 1}},
{"LeadDepartingAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}}, {"LeadDepartingAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"LeadDetectionThreshold", {PERSISTENT, INT, "35", "50", 3}}, {"LeadDetectionThreshold", {PERSISTENT, INT, "35", "50", 3}},
@@ -461,7 +420,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"MapsSelected", {PERSISTENT, STRING, "", "", 0}}, {"MapsSelected", {PERSISTENT, STRING, "", "", 0}},
{"MapSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}}, {"MapSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
{"NavDesiresAllowed", {PERSISTENT, BOOL, "1", "0", 2}}, {"NavDesiresAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
{"NavLanePositioningAllowed", {PERSISTENT, BOOL, "0", "0", 2}},
{"NavLongitudinalAllowed", {PERSISTENT, BOOL, "1", "0", 2}}, {"NavLongitudinalAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
{"ClearNavOnOffroad", {PERSISTENT, BOOL, "1", "1", 2, SETTINGS_SIMPLE}}, {"ClearNavOnOffroad", {PERSISTENT, BOOL, "1", "1", 2, SETTINGS_SIMPLE}},
{"ClearNavOnOffroadTimeoutMinutes", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}}, {"ClearNavOnOffroadTimeoutMinutes", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
@@ -486,8 +444,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ModelDrivesAndScores", {PERSISTENT, JSON, "{}", "{}"}}, {"ModelDrivesAndScores", {PERSISTENT, JSON, "{}", "{}"}},
{"ModelReleasedDates", {PERSISTENT, STRING, "", "", 1}}, {"ModelReleasedDates", {PERSISTENT, STRING, "", "", 1}},
{"ModelRandomizer", {PERSISTENT, BOOL, "0", "0", 2}}, {"ModelRandomizer", {PERSISTENT, BOOL, "0", "0", 2}},
{"LatSmoothSeconds", {PERSISTENT, FLOAT, "0.1", "0.1", 3}},
{"LongSmoothSeconds", {PERSISTENT, FLOAT, "0.3", "0.3", 3}},
{"ModelSortMode", {PERSISTENT, STRING, "alphabetical", "alphabetical", 1}}, {"ModelSortMode", {PERSISTENT, STRING, "alphabetical", "alphabetical", 1}},
{"ModelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}}, {"ModelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"ModelUI", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}}, {"ModelUI", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
@@ -515,11 +471,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"OnroadDistanceButtonPressed", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}}, {"OnroadDistanceButtonPressed", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"FavoriteVirtualAccelCruiseCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}}, {"FavoriteVirtualAccelCruiseCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"FavoriteVirtualDecelCruiseCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}}, {"FavoriteVirtualDecelCruiseCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"FavoriteTrafficModeCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"WheelButtonBookmarkCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}}, {"WheelButtonBookmarkCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"WheelControlAOLCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"WheelControlForceCoastCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"WheelControlPulseGlideCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"openpilotMinutes", {PERSISTENT, INT, "0", "0", 0}}, {"openpilotMinutes", {PERSISTENT, INT, "0", "0", 0}},
{"OverpassRequests", {PERSISTENT, JSON, "{}", "{}"}}, {"OverpassRequests", {PERSISTENT, JSON, "{}", "{}"}},
{"PathColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}}, {"PathColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
@@ -531,18 +483,12 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"PauseLateralSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}}, {"PauseLateralSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
{"LateralResumeDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}}, {"LateralResumeDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
{"PedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}}, {"PedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"PIPPreviewEnabled", {PERSISTENT, BOOL, "0", "0", 1}},
{"PIPPreviewMask", {PERSISTENT, JSON, "{\"width\":1928,\"height\":1208,\"center_left\":[315,548],\"center_right\":[1571,539],\"crop_size\":580}", "{\"width\":1928,\"height\":1208,\"center_left\":[315,548],\"center_right\":[1571,539],\"crop_size\":580}", 2}},
{"PIPPreviewShowOnBlinker", {PERSISTENT, BOOL, "0", "0", 1}},
{"PIPPreviewShowOnBSM", {PERSISTENT, BOOL, "0", "0", 1}},
{"PIPPreviewInvert", {PERSISTENT, BOOL, "0", "0", 1}},
{"GalaxyPaired", {PERSISTENT, BOOL, "0", "0", 0}}, {"GalaxyPaired", {PERSISTENT, BOOL, "0", "0", 0}},
{"GalaxyUploadPending", {PERSISTENT, BOOL, "0", "0", 0}}, {"GalaxyUploadPending", {PERSISTENT, BOOL, "0", "0", 0}},
{"PreferredSchedule", {PERSISTENT, INT, "2", "0", 0}}, {"PreferredSchedule", {PERSISTENT, INT, "2", "0", 0}},
{"PreviousSpeedLimit", {PERSISTENT, FLOAT, "0.0", "0.0"}}, {"PreviousSpeedLimit", {PERSISTENT, FLOAT, "0.0", "0.0"}},
{"PromptDistractedVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}}, {"PromptDistractedVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"PromptVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}}, {"PromptVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"PulseGlideSpeedDelta", {PERSISTENT, FLOAT, "5.0", "5.0", 3}},
{"QOLLateral", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}}, {"QOLLateral", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"QOLLongitudinal", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}}, {"QOLLongitudinal", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"QOLVisuals", {PERSISTENT, BOOL, "1", "0", 0, SETTINGS_SIMPLE}}, {"QOLVisuals", {PERSISTENT, BOOL, "1", "0", 0, SETTINGS_SIMPLE}},
@@ -568,9 +514,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"RelaxedJerkDeceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}}, {"RelaxedJerkDeceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"RelaxedJerkSpeed", {PERSISTENT, FLOAT, "100.0", "100.0", 3}}, {"RelaxedJerkSpeed", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"RelaxedJerkSpeedDecrease", {PERSISTENT, FLOAT, "100.0", "100.0", 3}}, {"RelaxedJerkSpeedDecrease", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"RivianAngleControl", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}}, {"ReverseCruise", {PERSISTENT, BOOL, "0", "0", 1}},
{"RivianAngleSaturated", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL, "0", "0"}},
{"RivianToiRecoveryFailed", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL, "0", "0"}},
{"RecoveryPower", {PERSISTENT, FLOAT, "1.0", "1.0", 2}}, {"RecoveryPower", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"RoadEdgesWidth", {PERSISTENT, FLOAT, "2.0", "2.0", 2, SETTINGS_SIMPLE}}, {"RoadEdgesWidth", {PERSISTENT, FLOAT, "2.0", "2.0", 2, SETTINGS_SIMPLE}},
{"RoadNameUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}}, {"RoadNameUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
@@ -636,8 +580,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"VisionSpeedLimitAutoBookmark", {PERSISTENT, BOOL, "0", "0", 0}}, {"VisionSpeedLimitAutoBookmark", {PERSISTENT, BOOL, "0", "0", 0}},
{"VisionSpeedLimitAutoPreserveSegment", {PERSISTENT, BOOL, "0", "0", 0}}, {"VisionSpeedLimitAutoPreserveSegment", {PERSISTENT, BOOL, "0", "0", 0}},
{"VisionSpeedLimitDetection", {PERSISTENT, BOOL, "1", "0", 0}}, {"VisionSpeedLimitDetection", {PERSISTENT, BOOL, "1", "0", 0}},
{"VisionSpeedLimitLowLimitFilter", {PERSISTENT, BOOL, "0", "0", 0}},
{"VisionSpeedLimitLowLimitThreshold", {PERSISTENT, INT, "25", "25", 0}},
{"VisionSpeedLimitTrainingCollector", {PERSISTENT, BOOL, "1", "1", 0}}, {"VisionSpeedLimitTrainingCollector", {PERSISTENT, BOOL, "1", "1", 0}},
{"StandardFollow", {PERSISTENT, FLOAT, "1.45", "1.45", 2}}, {"StandardFollow", {PERSISTENT, FLOAT, "1.45", "1.45", 2}},
{"StandardFollowHigh", {PERSISTENT, FLOAT, "1.2", "1.2", 2}}, {"StandardFollowHigh", {PERSISTENT, FLOAT, "1.2", "1.2", 2}},
@@ -678,8 +620,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"SwitchbackModeEnabled", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}}, {"SwitchbackModeEnabled", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
{"SubaruSNG", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}}, {"SubaruSNG", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"SubaruSNGManualParkingBrake", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}}, {"SubaruSNGManualParkingBrake", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"SubaruStopStartOff", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"SubaruAvhOnAtStartup", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"TacoTune", {PERSISTENT, BOOL, "0", "0", 2}}, {"TacoTune", {PERSISTENT, BOOL, "0", "0", 2}},
{"TeslaCoopSteering", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}}, {"TeslaCoopSteering", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"TestAlert", {CLEAR_ON_MANAGER_START, STRING, "", ""}}, {"TestAlert", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
@@ -700,7 +640,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"TuningLevel", {PERSISTENT, INT, "0", "0", 0}}, {"TuningLevel", {PERSISTENT, INT, "0", "0", 0}},
{"TuningLevelConfirmed", {PERSISTENT, BOOL, "0", "0", 0}}, {"TuningLevelConfirmed", {PERSISTENT, BOOL, "0", "0", 0}},
{"TurnDesires", {PERSISTENT, BOOL, "0", "0", 2}}, {"TurnDesires", {PERSISTENT, BOOL, "0", "0", 2}},
{"TurnSteeringLimitMuteSpeed", {PERSISTENT, INT, "0", "0", 0}},
{"UnlockDoors", {PERSISTENT, BOOL, "1", "0", 0}}, {"UnlockDoors", {PERSISTENT, BOOL, "1", "0", 0}},
{"Updated", {PERSISTENT, STRING, "0", "0"}}, {"Updated", {PERSISTENT, STRING, "0", "0"}},
{"UpdateSpeedLimits", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}}, {"UpdateSpeedLimits", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
@@ -714,7 +653,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"UserFavorites", {PERSISTENT, STRING, "", "", 1}}, {"UserFavorites", {PERSISTENT, STRING, "", "", 1}},
{"UseVienna", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}}, {"UseVienna", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"VASMAnnotationConfig", {PERSISTENT, JSON, "{}", "{}", 2}}, {"VASMAnnotationConfig", {PERSISTENT, JSON, "{}", "{}", 2}},
{"VASMConfidenceThreshold", {PERSISTENT, FLOAT, "0.94", "0.94", 2}}, {"VASMConfidenceThreshold", {PERSISTENT, FLOAT, "0.85", "0.85", 2}},
{"VASMEnabled", {PERSISTENT, BOOL, "0", "0", 1}}, {"VASMEnabled", {PERSISTENT, BOOL, "0", "0", 1}},
{"VASMLeftActive", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}}, {"VASMLeftActive", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VASMLeftConfidence", {CLEAR_ON_MANAGER_START, STRING, "0.0", "0.0", 2}}, {"VASMLeftConfidence", {CLEAR_ON_MANAGER_START, STRING, "0.0", "0.0", 2}},
Binary file not shown.
+1 -4
View File
@@ -50,10 +50,7 @@ class OpenpilotPrefix:
symlink_path = Params().get_param_path() symlink_path = Params().get_param_path()
if os.path.exists(symlink_path): if os.path.exists(symlink_path):
shutil.rmtree(os.path.realpath(symlink_path), ignore_errors=True) shutil.rmtree(os.path.realpath(symlink_path), ignore_errors=True)
# when the params path is a real directory rather than a symlink, rmtree above already os.remove(symlink_path)
# removed it and there is no link left to unlink
if os.path.islink(symlink_path):
os.remove(symlink_path)
shutil.rmtree(self.msgq_path, ignore_errors=True) shutil.rmtree(self.msgq_path, ignore_errors=True)
if PC: if PC:
shutil.rmtree(Paths.log_root(), ignore_errors=True) shutil.rmtree(Paths.log_root(), ignore_errors=True)
-1
View File
@@ -22,7 +22,6 @@ class Priority:
# - modeld = 55 # - modeld = 55
# - camerad = 54 # - camerad = 54
CTRL_LOW = 51 # plannerd & radard CTRL_LOW = 51 # plannerd & radard
UI = 50
# CORE 3 # CORE 3
# - pandad = 55 # - pandad = 55
+13
View File
@@ -7,6 +7,19 @@ class Spinner:
def __init__(self): def __init__(self):
self.spinner_proc = None self.spinner_proc = None
# Prefer the legacy compiled spinner on device.
legacy_spinner = os.path.join(BASEDIR, "selfdrive", "ui", "spinner")
if os.path.isfile("/TICI") and os.path.isfile(legacy_spinner) and os.access(legacy_spinner, os.X_OK):
try:
self.spinner_proc = subprocess.Popen([legacy_spinner],
stdin=subprocess.PIPE,
cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
close_fds=True)
return
except OSError:
self.spinner_proc = None
# Raylib spinner requires Python deps from the repo virtualenv.
spinner_cwd = os.path.join(BASEDIR, "system", "ui") spinner_cwd = os.path.join(BASEDIR, "system", "ui")
venv_python = os.path.join(BASEDIR, ".venv", "bin", "python") venv_python = os.path.join(BASEDIR, ".venv", "bin", "python")
python_exec = venv_python if os.path.isfile(venv_python) else "python3" python_exec = venv_python if os.path.isfile(venv_python) else "python3"
@@ -1,44 +0,0 @@
from types import SimpleNamespace
from opendbc.car.hyundai.values import CAR as HYUNDAI_CAR
from openpilot.starpilot.common.lateral_only_experimental import (
experimental_mode_available,
lateral_only_experimental_available,
)
def test_telluride_platform_allows_lateral_only_experimental_mode():
CP = SimpleNamespace(
carFingerprint=HYUNDAI_CAR.HYUNDAI_PALISADE_2023,
openpilotLongitudinalControl=False,
)
assert lateral_only_experimental_available(CP)
assert experimental_mode_available(CP)
def test_lateral_only_mode_does_not_expand_other_stock_acc_cars():
CP = SimpleNamespace(
carFingerprint=HYUNDAI_CAR.HYUNDAI_SONATA,
openpilotLongitudinalControl=False,
)
assert not lateral_only_experimental_available(CP)
assert not experimental_mode_available(CP)
old_palisade = SimpleNamespace(
carFingerprint=HYUNDAI_CAR.HYUNDAI_PALISADE,
openpilotLongitudinalControl=False,
)
assert not lateral_only_experimental_available(old_palisade)
def test_normal_experimental_mode_remains_available_with_openpilot_long():
CP = SimpleNamespace(
carFingerprint=HYUNDAI_CAR.HYUNDAI_SONATA,
openpilotLongitudinalControl=True,
)
assert not lateral_only_experimental_available(CP)
assert experimental_mode_available(CP)
+12
View File
@@ -9,6 +9,18 @@ class TextWindow:
def __init__(self, text): def __init__(self, text):
self.text_proc = None self.text_proc = None
# Prefer the legacy compiled text window on device.
legacy_text = os.path.join(BASEDIR, "selfdrive", "ui", "text")
if os.path.isfile("/TICI") and os.path.isfile(legacy_text) and os.access(legacy_text, os.X_OK):
try:
self.text_proc = subprocess.Popen([legacy_text, text],
stdin=subprocess.PIPE,
cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
close_fds=True)
return
except OSError:
self.text_proc = None
text_cwd = os.path.join(BASEDIR, "system", "ui") text_cwd = os.path.join(BASEDIR, "system", "ui")
venv_python = os.path.join(BASEDIR, ".venv", "bin", "python") venv_python = os.path.join(BASEDIR, ".venv", "bin", "python")
python_exec = venv_python if os.path.isfile(venv_python) else "python3" python_exec = venv_python if os.path.isfile(venv_python) else "python3"
+2 -6
View File
@@ -2,18 +2,14 @@ import datetime
from pathlib import Path from pathlib import Path
MIN_DATE = datetime.datetime(year=2025, month=2, day=21) MIN_DATE = datetime.datetime(year=2025, month=2, day=21)
MAX_DATE = datetime.datetime(year=2035, month=1, day=1)
def _utc_now_naive():
return datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
def min_date(): def min_date():
# on systemd systems, the default time is the systemd build time # on systemd systems, the default time is the systemd build time
systemd_path = Path("/lib/systemd/systemd") systemd_path = Path("/lib/systemd/systemd")
if systemd_path.exists(): if systemd_path.exists():
d = datetime.datetime.fromtimestamp(systemd_path.stat().st_mtime, datetime.UTC).replace(tzinfo=None) d = datetime.datetime.fromtimestamp(systemd_path.stat().st_mtime)
return max(MIN_DATE, d + datetime.timedelta(days=1)) return max(MIN_DATE, d + datetime.timedelta(days=1))
return MIN_DATE return MIN_DATE
def system_time_valid(): def system_time_valid():
return min_date() < _utc_now_naive() < MAX_DATE return datetime.datetime.now() > min_date()
Binary file not shown.
+10 -14
View File
@@ -5,7 +5,7 @@ import contextlib
import subprocess import subprocess
import time import time
import functools import functools
from subprocess import Popen, PIPE, STDOUT, TimeoutExpired from subprocess import Popen, PIPE, TimeoutExpired
import zstandard as zstd import zstandard as zstd
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
@@ -87,20 +87,16 @@ def run_cmd_default(cmd: list[str], default: str = "", cwd=None, env=None) -> st
@contextlib.contextmanager @contextlib.contextmanager
def managed_proc(cmd: list[str], env: dict[str, str]): def managed_proc(cmd: list[str], env: dict[str, str]):
# capture output to a temp file rather than a pipe. nothing drains the pipe while the process proc = Popen(cmd, env=env, stdout=PIPE, stderr=PIPE)
# runs, so a long lived, chatty child would eventually fill the pipe buffer and block forever. try:
with tempfile.TemporaryFile() as log_file: yield proc
proc = Popen(cmd, env=env, stdout=log_file, stderr=STDOUT) finally:
proc.log_file = log_file if proc.poll() is None:
proc.terminate()
try: try:
yield proc proc.wait(timeout=5)
finally: except TimeoutExpired:
if proc.poll() is None: proc.kill()
proc.terminate()
try:
proc.wait(timeout=5)
except TimeoutExpired:
proc.kill()
def retry(attempts=3, delay=1.0, ignore_failure=False): def retry(attempts=3, delay=1.0, ignore_failure=False):
+1 -1
View File
@@ -1 +1 @@
#define COMMA_VERSION "0.11.2" #define COMMA_VERSION "0.10.3"
+150 -296
View File
@@ -4,183 +4,108 @@
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.
# 453 Supported Cars # 326 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br>&nbsp;|Video|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>&nbsp;|Video|Setup Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Acura|ADX 2025-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ADX 2025-26">Buy Here</a></sub></details>|||
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ILX 2016-18">Buy Here</a></sub></details>||| |Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ILX 2016-18">Buy Here</a></sub></details>|||
|Acura|ILX 2019|All|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ILX 2019">Buy Here</a></sub></details>||| |Acura|ILX 2019|All|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ILX 2019">Buy Here</a></sub></details>|||
|Acura|Integra 2023-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura Integra 2023-26">Buy Here</a></sub></details>||| |Acura|MDX 2025|All except Type S|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2025">Buy Here</a></sub></details>|||
|Acura|MDX 2014-16|Advance Package|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2014-16">Buy Here</a></sub></details>|||
|Acura|MDX 2017-19|All|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2017-19">Buy Here</a></sub></details>|||
|Acura|MDX 2020|All|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2020">Buy Here</a></sub></details>|||
|Acura|MDX 2022-24|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|43 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2022-24">Buy Here</a></sub></details>|||
|Acura|MDX 2025|All except Type S|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2025">Buy Here</a></sub></details>|||
|Acura|MDX Hybrid 2017-19|All|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX Hybrid 2017-19">Buy Here</a></sub></details>|||
|Acura|MDX Hybrid 2020|All|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX Hybrid 2020">Buy Here</a></sub></details>|||
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2016-18">Buy Here</a></sub></details>||| |Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2016-18">Buy Here</a></sub></details>|||
|Acura|RDX 2019-21|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2019-21">Buy Here</a></sub></details>||| |Acura|RDX 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2019-21">Buy Here</a></sub></details>|||
|Acura|RDX 2022-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|43 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2022-26">Buy Here</a></sub></details>||| |Acura|TLX 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura TLX 2021">Buy Here</a></sub></details>|||
|Acura|TLX 2015-17|Advance Package|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura TLX 2015-17">Buy Here</a></sub></details>||| |Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi A3 2014-19">Buy Here</a></sub></details>|||
|Acura|TLX 2018-20|All|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura TLX 2018-20">Buy Here</a></sub></details>||| |Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>|||
|Acura|TLX 2021|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura TLX 2021">Buy Here</a></sub></details>||| |Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q2 2018">Buy Here</a></sub></details>|||
|Acura|TLX 2024-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Acura TLX 2024-25">Buy Here</a></sub></details>||| |Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q3 2019-24">Buy Here</a></sub></details>|||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi A3 2014-19">Buy Here</a></sub></details>||| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi RS3 2018">Buy Here</a></sub></details>|||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>||| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi S3 2015-17">Buy Here</a></sub></details>|||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q2 2018">Buy Here</a></sub></details>||| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EUV 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q3 2019-24">Buy Here</a></sub></details>||| |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV 2022-23">Buy Here</a></sub></details>|||
|Audi|Q4 e-tron 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q4 e-tron 2021-23">Buy Here</a></sub></details>|||
|Audi|Q4 e-tron 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi Q4 e-tron 2024-25">Buy Here</a></sub></details>|||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi RS3 2018">Buy Here</a></sub></details>|||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi S3 2015-17">Buy Here</a></sub></details>|||
|Buick|Baby Enclave 2020-23|Driver Assist Package|Stock|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Buick Baby Enclave 2020-23">Buy Here</a></sub></details>|||
|Buick[<sup>3</sup>](#footnotes)|LaCrosse 2017-19|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Buick LaCrosse 2017-19">Buy Here</a></sub></details>|||
|Buick|LaCrosse ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|Stock|3 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Buick LaCrosse ASCM Harness 2017-19">Buy Here</a></sub></details>|||
|Buick|LaCrosse US ASCM Harness 2019|Adaptive Cruise Control (ACC)|Stock|3 mph|27 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Buick LaCrosse US ASCM Harness 2019">Buy Here</a></sub></details>|||
|Buick[<sup>3</sup>](#footnotes)|Regal Essence 2018|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Buick Regal Essence 2018">Buy Here</a></sub></details>|||
|Cadillac[<sup>3</sup>](#footnotes)|ATS Premium Performance 2018|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac ATS Premium Performance 2018">Buy Here</a></sub></details>|||
|Cadillac[<sup>3</sup>](#footnotes)|CT6 No-ACC 2016-20|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac CT6 No-ACC 2016-20">Buy Here</a></sub></details>|||
|Cadillac[<sup>3</sup>](#footnotes)|Escalade 2017|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac Escalade 2017">Buy Here</a></sub></details>|||
|Cadillac|Escalade ASCM Harness 2018|Driver Assist Package|Stock|3 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac Escalade ASCM Harness 2018">Buy Here</a></sub></details>|||
|Cadillac[<sup>3</sup>](#footnotes)|Escalade ESV 2016|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac Escalade ESV 2016">Buy Here</a></sub></details>|||
|Cadillac[<sup>3</sup>](#footnotes)|Escalade ESV 2019|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac Escalade ESV 2019">Buy Here</a></sub></details>|||
|Cadillac|Escalade ESV Platinum ASCM Harness 2019|Adaptive Cruise Control (ACC) & LKAS|Stock|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac Escalade ESV Platinum ASCM Harness 2019">Buy Here</a></sub></details>|||
|Cadillac|XT4 2023|Driver Assist Package|Stock|0 mph|30 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac XT4 2023">Buy Here</a></sub></details>|||
|Cadillac[<sup>3</sup>](#footnotes)|XT4 No-ACC 2023|Adaptive Cruise Control (ACC)|openpilot|24 mph|30 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac XT4 No-ACC 2023">Buy Here</a></sub></details>|||
|Cadillac|XT5 2022|Driver Assist Package|Stock|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac XT5 2022">Buy Here</a></sub></details>|||
|Cadillac[<sup>3</sup>](#footnotes)|XT5 No-ACC 2022|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac XT5 No-ACC 2022">Buy Here</a></sub></details>|||
|Cadillac|XT6 2020|Driver Assist Package|Stock|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Cadillac XT6 2020">Buy Here</a></sub></details>|||
|Chevrolet|Blazer 2019-25|Driver Assist Package|Stock|3 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Blazer 2019-25">Buy Here</a></sub></details>|||
|Chevrolet|Bolt EV & EUV ACC 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV & EUV ACC 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Chevrolet|Bolt EV & EUV ACC w Pedal 2022-23|Adaptive Cruise Control (ACC)|openpilot|24 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV & EUV ACC w Pedal 2022-23">Buy Here</a></sub></details>|||
|Chevrolet|Bolt EV & EUV No-ACC 2022-23|Adaptive Cruise Control (ACC)|openpilot|24 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV & EUV No-ACC 2022-23">Buy Here</a></sub></details>|||
|Chevrolet|Bolt EV No-ACC 2017|Adaptive Cruise Control (ACC)|openpilot|24 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV No-ACC 2017">Buy Here</a></sub></details>|||
|Chevrolet|Bolt EV No-ACC 2018-21|Adaptive Cruise Control (ACC)|openpilot|24 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV No-ACC 2018-21">Buy Here</a></sub></details>|||
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Equinox 2019-22">Buy Here</a></sub></details>||| |Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Equinox 2019-22">Buy Here</a></sub></details>|||
|Chevrolet[<sup>3</sup>](#footnotes)|Equinox No-ACC 2019-22|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Equinox No-ACC 2019-22">Buy Here</a></sub></details>||| |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Silverado 1500 2020-21">Buy Here</a></sub></details>|||
|Chevrolet|Malibu 2019|SDGM Harness (Optional SASCM)|Stock|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu 2019">Buy Here</a></sub></details>|||
|Chevrolet|Malibu ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|Stock|3 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu ASCM Harness 2017-19">Buy Here</a></sub></details>|||
|Chevrolet|Malibu Hybrid No-ACC 2017|Adaptive Cruise Control (ACC)|openpilot|24 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu Hybrid No-ACC 2017">Buy Here</a></sub></details>|||
|Chevrolet[<sup>3</sup>](#footnotes)|Malibu No-ACC 2023|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu No-ACC 2023">Buy Here</a></sub></details>|||
|Chevrolet[<sup>3</sup>](#footnotes)|Malibu Premier 2017|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu Premier 2017">Buy Here</a></sub></details>|||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Silverado 1500 2020-21">Buy Here</a></sub></details>|||
|Chevrolet[<sup>3</sup>](#footnotes)|Silverado 1500 No-ACC 2020-21|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Silverado 1500 No-ACC 2020-21">Buy Here</a></sub></details>|||
|Chevrolet[<sup>3</sup>](#footnotes)|Suburban Premier 2016-20|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Suburban Premier 2016-20">Buy Here</a></sub></details>|||
|Chevrolet[<sup>3</sup>](#footnotes)|Suburban Premier No-ACC 2016-20|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Suburban Premier No-ACC 2016-20">Buy Here</a></sub></details>|||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Trailblazer 2021-22">Buy Here</a></sub></details>||| |Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Trailblazer 2021-22">Buy Here</a></sub></details>|||
|Chevrolet[<sup>3</sup>](#footnotes)|Trailblazer No-ACC 2021-22|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Trailblazer No-ACC 2021-22">Buy Here</a></sub></details>|||
|Chevrolet|Traverse 2022-23|RS, Premier, or High Country Trim|Stock|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Traverse 2022-23">Buy Here</a></sub></details>|||
|Chevrolet|TRAX 2024-25|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet TRAX 2024-25">Buy Here</a></sub></details>|||
|Chevrolet[<sup>3</sup>](#footnotes)|Volt 2017-18|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Volt 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/QeMCN_4TFfQ" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Chevrolet|Volt 2019|Adaptive Cruise Control (ACC) & LKAS|Stock|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM SDGM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Volt 2019">Buy Here</a></sub></details>|||
|Chevrolet|Volt ASCM Harness 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Volt ASCM Harness 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/QeMCN_4TFfQ" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Chevrolet|Volt Camera Harness 2017-18|Flashed camera-forward integration with ACC|openpilot available[<sup>1</sup>](#footnotes)|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Volt Camera Harness 2017-18">Buy Here</a></sub></details>|||
|Chevrolet|Volt No-ACC 2016-18 (OBD Harness)|Redneck ACC|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Volt No-ACC 2016-18 (OBD Harness)">Buy Here</a></sub></details>|||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2017-18">Buy Here</a></sub></details>||| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2017-18">Buy Here</a></sub></details>|||
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2019-20">Buy Here</a></sub></details>||| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2019-20">Buy Here</a></sub></details>|||
|Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2021-23">Buy Here</a></sub></details>||| |Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2021-23">Buy Here</a></sub></details>|||
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica Hybrid 2017-18">Buy Here</a></sub></details>||| |Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica Hybrid 2017-18">Buy Here</a></sub></details>|||
|Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica Hybrid 2019-25">Buy Here</a></sub></details>||| |Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica Hybrid 2019-25">Buy Here</a></sub></details>|||
|comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|<a href="https://youtu.be/VT-i3yRsX2s?t=2736" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|<a href="https://youtu.be/VT-i3yRsX2s?t=2736" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=CUPRA Ateca 2018-23">Buy Here</a></sub></details>||| |CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=CUPRA Ateca 2018-23">Buy Here</a></sub></details>|||
|CUPRA|Born 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=CUPRA Born 2021-23">Buy Here</a></sub></details>|||
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Dodge Durango 2020-21">Buy Here</a></sub></details>||| |Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Dodge Durango 2020-21">Buy Here</a></sub></details>|||
|Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Bronco Sport 2021-24">Buy Here</a></sub></details>||| |Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Bronco Sport 2021-24">Buy Here</a></sub></details>|||
|Ford|Edge 2022|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Edge 2022">Buy Here</a></sub></details>||| |Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape 2020-22">Buy Here</a></sub></details>|||
|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape 2020-22">Buy Here</a></sub></details>|||
|Ford|Escape 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|Escape 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Hybrid 2020-22">Buy Here</a></sub></details>||| |Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Hybrid 2020-22">Buy Here</a></sub></details>|||
|Ford|Escape Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Hybrid 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|Escape Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Hybrid 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|Escape Plug-in Hybrid 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||| |Ford|Escape Plug-in Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|||
|Ford|Escape Plug-in Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Plug-in Hybrid 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|Escape Plug-in Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Escape Plug-in Hybrid 2023-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|Expedition 2022-24|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Expedition 2022-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|Expedition 2022-24|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Expedition 2022-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|Explorer 2020-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Explorer 2020-24">Buy Here</a></sub></details>||| |Ford|Explorer 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Explorer 2020-24">Buy Here</a></sub></details>|||
|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Explorer Hybrid 2020-24">Buy Here</a></sub></details>||| |Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Explorer Hybrid 2020-24">Buy Here</a></sub></details>|||
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford F-150 2021-23">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford F-150 2021-23">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford F-150 Hybrid 2021-23">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford F-150 Hybrid 2021-23">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|F-150 Lightning 2022-25|Co-Pilot360 Assist 2.0|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford F-150 Lightning 2022-25">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=MewJc9LYp9M" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|Focus 2018[<sup>2</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Focus 2018">Buy Here</a></sub></details>|||
|Ford|Focus 2018-22[<sup>2</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Focus 2018-22">Buy Here</a></sub></details>||| |Ford|Focus Hybrid 2018[<sup>2</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Focus Hybrid 2018">Buy Here</a></sub></details>|||
|Ford|Focus Hybrid 2018-22[<sup>2</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Focus Hybrid 2018-22">Buy Here</a></sub></details>||| |Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga 2020-23">Buy Here</a></sub></details>|||
|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga 2020-23">Buy Here</a></sub></details>||| |Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Hybrid 2020-23">Buy Here</a></sub></details>|||
|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Hybrid 2020-23">Buy Here</a></sub></details>|||
|Ford|Kuga Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Hybrid 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|Kuga Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Hybrid 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|Kuga Plug-in Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Plug-in Hybrid 2020-23">Buy Here</a></sub></details>||| |Ford|Kuga Plug-in Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Plug-in Hybrid 2020-23">Buy Here</a></sub></details>|||
|Ford|Kuga Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Plug-in Hybrid 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|Kuga Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Kuga Plug-in Hybrid 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|Maverick 2022|LARIAT Luxury|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick 2022">Buy Here</a></sub></details>||| |Ford|Maverick 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick 2022">Buy Here</a></sub></details>|||
|Ford|Maverick 2023-24|Co-Pilot360 Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick 2023-24">Buy Here</a></sub></details>||| |Ford|Maverick 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick 2023-24">Buy Here</a></sub></details>|||
|Ford|Maverick Hybrid 2022|LARIAT Luxury|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick Hybrid 2022">Buy Here</a></sub></details>||| |Ford|Maverick Hybrid 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick Hybrid 2022">Buy Here</a></sub></details>|||
|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick Hybrid 2023-24">Buy Here</a></sub></details>||| |Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Maverick Hybrid 2023-24">Buy Here</a></sub></details>|||
|Ford|Mondeo 2014-22|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Mondeo 2014-22">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|Mustang Mach-E 2021-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Mustang Mach-E 2021-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|Mustang Mach-E 2021-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Mustang Mach-E 2021-24">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Ranger 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q4 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Ranger 2024">Buy Here</a></sub></details>||<a href="https://www.youtube.com/watch?v=uUGkH6C_EQU" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Ford|Transit 2025|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ford Transit 2025">Buy Here</a></sub></details>|||
|Genesis|G70 2018|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2018">Buy Here</a></sub></details>||| |Genesis|G70 2018|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2018">Buy Here</a></sub></details>|||
|Genesis|G70 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2019-21">Buy Here</a></sub></details>||| |Genesis|G70 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2019-21">Buy Here</a></sub></details>|||
|Genesis|G70 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2022-23">Buy Here</a></sub></details>||| |Genesis|G70 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 2022-23">Buy Here</a></sub></details>|||
|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 2017">Buy Here</a></sub></details>||| |Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 2017">Buy Here</a></sub></details>|||
|Genesis|G80 2018-19|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 2018-19">Buy Here</a></sub></details>||| |Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 2018-19">Buy Here</a></sub></details>|||
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 (2.5T Advanced Trim, with HDA II) 2024">Buy Here</a></sub></details>||| |Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G80 (2.5T Advanced Trim, with HDA II) 2024">Buy Here</a></sub></details>|||
|Genesis|G90 2017-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G90 2017-20">Buy Here</a></sub></details>||| |Genesis|G90 2017-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G90 2017-20">Buy Here</a></sub></details>|||
|Genesis|GV60 (Advanced Trim) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV60 (Advanced Trim) 2023">Buy Here</a></sub></details>||| |Genesis|GV60 (Advanced Trim) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV60 (Advanced Trim) 2023">Buy Here</a></sub></details>|||
|Genesis|GV60 (Performance Trim) 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV60 (Performance Trim) 2022-23">Buy Here</a></sub></details>||| |Genesis|GV60 (Performance Trim) 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV60 (Performance Trim) 2022-23">Buy Here</a></sub></details>|||
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 (2.5T Trim, without HDA II) 2022-24">Buy Here</a></sub></details>||| |Genesis|GV70 (2.5T Trim, without HDA II) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 (2.5T Trim, without HDA II) 2022-24">Buy Here</a></sub></details>|||
|Genesis|GV70 (3.5T Sport Prestige Trim, with HDA II & LFA2) 2026|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 (3.5T Sport Prestige Trim, with HDA II & LFA2) 2026">Buy Here</a></sub></details>|||
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 (3.5T Trim, without HDA II) 2022-23">Buy Here</a></sub></details>||| |Genesis|GV70 (3.5T Trim, without HDA II) 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 (3.5T Trim, without HDA II) 2022-23">Buy Here</a></sub></details>|||
|Genesis|GV70 Electrified 2026|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 Electrified 2026">Buy Here</a></sub></details>|||
|Genesis|GV70 Electrified (Australia Only) 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 Electrified (Australia Only) 2022">Buy Here</a></sub></details>||| |Genesis|GV70 Electrified (Australia Only) 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 Electrified (Australia Only) 2022">Buy Here</a></sub></details>|||
|Genesis|GV70 Electrified (with HDA II) 2023-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 Electrified (with HDA II) 2023-24">Buy Here</a></sub></details>||| |Genesis|GV70 Electrified (with HDA II) 2023-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV70 Electrified (with HDA II) 2023-24">Buy Here</a></sub></details>|||
|Genesis|GV80 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV80 2023">Buy Here</a></sub></details>||| |Genesis|GV80 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV80 2023">Buy Here</a></sub></details>|||
|Genesis|GV80 (3.5T Prestige Trim, with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV80 (3.5T Prestige Trim, with HDA II & LFA2) 2025">Buy Here</a></sub></details>||| |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Sierra 1500 2020-21">Buy Here</a></sub></details>|<a href="https://youtu.be/5HbNoBLzRwE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Genesis|GV80 Coupe (with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV80 Coupe (with HDA II & LFA2) 2025">Buy Here</a></sub></details>||| |Honda|Accord 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2018-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=mrUwlj3Mi58" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|GMC[<sup>3</sup>](#footnotes)|Acadia 2018|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Acadia 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=0ZN6DdsBUZo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Honda|Accord 2023-25|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2023-25">Buy Here</a></sub></details>|||
|GMC|Acadia ASCM Harness 2018|Adaptive Cruise Control (ACC)|Stock|3 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Acadia ASCM Harness 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=0ZN6DdsBUZo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Honda|Accord Hybrid 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2018-22">Buy Here</a></sub></details>|||
|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Sierra 1500 2020-21">Buy Here</a></sub></details>|<a href="https://youtu.be/5HbNoBLzRwE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Honda|Accord Hybrid 2023-25|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2023-25">Buy Here</a></sub></details>|||
|GMC[<sup>3</sup>](#footnotes)|Sierra 1500 No-ACC 2020-21|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Sierra 1500 No-ACC 2020-21">Buy Here</a></sub></details>||| |Honda|City (Brazil only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|14 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda City (Brazil only) 2023">Buy Here</a></sub></details>|||
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|Stock|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Yukon 2019-20">Buy Here</a></sub></details>|||
|GMC[<sup>3</sup>](#footnotes)|Yukon No-ACC 2019-20|Adaptive Cruise Control (ACC)|openpilot|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Yukon No-ACC 2019-20">Buy Here</a></sub></details>|||
|Holden[<sup>3</sup>](#footnotes)|Astra 2017|Adaptive Cruise Control (ACC)|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 OBD-II connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Holden Astra 2017">Buy Here</a></sub></details>|||
|Honda|Accord 2016-17|Honda Sensing|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2016-17">Buy Here</a></sub></details>|||
|Honda|Accord 2018-22|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2018-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=mrUwlj3Mi58" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Accord 2023-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2023-25">Buy Here</a></sub></details>|||
|Honda|Accord Hybrid 2017|All|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2017">Buy Here</a></sub></details>|||
|Honda|Accord Hybrid 2018-22|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2018-22">Buy Here</a></sub></details>|||
|Honda|Accord Hybrid 2023-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2023-25">Buy Here</a></sub></details>|||
|Honda|City (Brazil only) 2023|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|14 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda City (Brazil only) 2023">Buy Here</a></sub></details>|||
|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2016-18">Buy Here</a></sub></details>|<a href="https://youtu.be/-IkImTe1NYE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2016-18">Buy Here</a></sub></details>|<a href="https://youtu.be/-IkImTe1NYE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic 2019-21|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|2 mph[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=4Iz1Mz5LGF8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Honda|Civic 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|2 mph[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=4Iz1Mz5LGF8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic 2022-24|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Honda|Civic 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic Hatchback 2017-18|Honda Sensing|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2017-18">Buy Here</a></sub></details>||| |Honda|Civic Hatchback 2017-18|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2017-18">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback 2019-21|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2019-21">Buy Here</a></sub></details>||| |Honda|Civic Hatchback 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2019-21">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback 2022-24|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Honda|Civic Hatchback 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic Hatchback Hybrid 2025-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid 2025-26">Buy Here</a></sub></details>||| |Honda|Civic Hatchback Hybrid 2025-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid 2025-26">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid (Europe only) 2023">Buy Here</a></sub></details>||| |Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid (Europe only) 2023">Buy Here</a></sub></details>|||
|Honda|Civic Hybrid 2025-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hybrid 2025-26">Buy Here</a></sub></details>||| |Honda|Civic Hybrid 2025-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hybrid 2025-26">Buy Here</a></sub></details>|||
|Honda|Clarity 2018-21|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Clarity 2018-21">Buy Here</a></sub></details>|||
|Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2015-16">Buy Here</a></sub></details>||| |Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2015-16">Buy Here</a></sub></details>|||
|Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|15 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2017-22">Buy Here</a></sub></details>||| |Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|15 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2017-22">Buy Here</a></sub></details>|||
|Honda|CR-V 2023-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2023-26">Buy Here</a></sub></details>||| |Honda|CR-V 2023-26|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2023-26">Buy Here</a></sub></details>|||
|Honda|CR-V Hybrid 2017-22|Honda Sensing|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V Hybrid 2017-22">Buy Here</a></sub></details>||| |Honda|CR-V Hybrid 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V Hybrid 2017-22">Buy Here</a></sub></details>|||
|Honda|CR-V Hybrid 2023-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V Hybrid 2023-25">Buy Here</a></sub></details>||| |Honda|CR-V Hybrid 2023-25|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V Hybrid 2023-25">Buy Here</a></sub></details>|||
|Honda|e 2020|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda e 2020">Buy Here</a></sub></details>||| |Honda|e 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda e 2020">Buy Here</a></sub></details>|||
|Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Fit 2018-20">Buy Here</a></sub></details>||| |Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Fit 2018-20">Buy Here</a></sub></details>|||
|Honda|Fit (Taiwan) 2021|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|14 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Fit (Taiwan) 2021">Buy Here</a></sub></details>|||
|Honda|Fit (Taiwan) 2024-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|14 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Fit (Taiwan) 2024-25">Buy Here</a></sub></details>|||
|Honda|Freed 2020|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Freed 2020">Buy Here</a></sub></details>||| |Honda|Freed 2020|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Freed 2020">Buy Here</a></sub></details>|||
|Honda|HR-V 2019-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda HR-V 2019-22">Buy Here</a></sub></details>||| |Honda|HR-V 2019-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda HR-V 2019-22">Buy Here</a></sub></details>|||
|Honda|HR-V 2023-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda HR-V 2023-25">Buy Here</a></sub></details>||| |Honda|HR-V 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda HR-V 2023-25">Buy Here</a></sub></details>|||
|Honda|Insight 2019-22|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Insight 2019-22">Buy Here</a></sub></details>||| |Honda|Insight 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Insight 2019-22">Buy Here</a></sub></details>|||
|Honda|Inspire 2018|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Inspire 2018">Buy Here</a></sub></details>||| |Honda|Inspire 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Inspire 2018">Buy Here</a></sub></details>|||
|Honda|N-Box 2018|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|11 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda N-Box 2018">Buy Here</a></sub></details>||| |Honda|N-Box 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|11 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda N-Box 2018">Buy Here</a></sub></details>|||
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2018-20">Buy Here</a></sub></details>||| |Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2018-20">Buy Here</a></sub></details>|||
|Honda|Odyssey 2021-26|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|43 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2021-26">Buy Here</a></sub></details>||| |Honda|Odyssey 2021-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|43 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2021-26">Buy Here</a></sub></details>|||
|Honda|Odyssey (Singapore) 2021|Honda Sensing|openpilot|19 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey (Singapore) 2021">Buy Here</a></sub></details>|||
|Honda|Odyssey (Taiwan) 2018-19|Honda Sensing|openpilot|19 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey (Taiwan) 2018-19">Buy Here</a></sub></details>|||
|Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Passport 2019-25">Buy Here</a></sub></details>||| |Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Passport 2019-25">Buy Here</a></sub></details>|||
|Honda|Passport 2026|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Passport 2026">Buy Here</a></sub></details>||| |Honda|Passport 2026|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Passport 2026">Buy Here</a></sub></details>|||
|Honda|Pilot 2016-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2016-22">Buy Here</a></sub></details>||| |Honda|Pilot 2016-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2016-22">Buy Here</a></sub></details>|||
|Honda|Pilot 2023-25|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2023-25">Buy Here</a></sub></details>||| |Honda|Pilot 2023-25|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2023-25">Buy Here</a></sub></details>|||
|Honda|Prelude 2026|All|openpilot available[<sup>1,5</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Prelude 2026">Buy Here</a></sub></details>|||
|Honda|Ridgeline 2017-25|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Ridgeline 2017-25">Buy Here</a></sub></details>||| |Honda|Ridgeline 2017-25|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Ridgeline 2017-25">Buy Here</a></sub></details>|||
|Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera 2022">Buy Here</a></sub></details>||| |Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera 2022">Buy Here</a></sub></details>|||
|Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid 2019">Buy Here</a></sub></details>||| |Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid 2019">Buy Here</a></sub></details>|||
@@ -190,20 +115,14 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2017-18">Buy Here</a></sub></details>||| |Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2017-18">Buy Here</a></sub></details>|||
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2019">Buy Here</a></sub></details>||| |Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2019">Buy Here</a></sub></details>|||
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Elantra 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2024-25">Buy Here</a></sub></details>|||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra GT 2017-20">Buy Here</a></sub></details>||| |Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra GT 2017-20">Buy Here</a></sub></details>|||
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Elantra Hybrid 2024-26|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Hybrid 2024-26">Buy Here</a></sub></details>|||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Genesis 2015-16">Buy Here</a></sub></details>||| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Genesis 2015-16">Buy Here</a></sub></details>|||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai i30 2017-19">Buy Here</a></sub></details>||| |Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai i30 2017-19">Buy Here</a></sub></details>|||
|Hyundai|i30 Hybrid 2024|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai i30 Hybrid 2024">Buy Here</a></sub></details>|||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (Southeast Asia and Europe only) 2022-24">Buy Here</a></sub></details>||| |Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (Southeast Asia and Europe only) 2022-24">Buy Here</a></sub></details>|||
|Hyundai|Ioniq 5 (with HDA II) 2022-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (with HDA II) 2022-24">Buy Here</a></sub></details>||| |Hyundai|Ioniq 5 (with HDA II) 2022-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|Hyundai|Ioniq 5 (without HDA II) 2022-24|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (without HDA II) 2022-24">Buy Here</a></sub></details>||| |Hyundai|Ioniq 5 (without HDA II) 2022-24|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
|Hyundai|Ioniq 5 N (with HDA II) 2024|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai S connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 N (with HDA II) 2024">Buy Here</a></sub></details>||| |Hyundai|Ioniq 6 (with HDA II) 2023-24|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 6 (with HDA II) 2023-24">Buy Here</a></sub></details>|||
|Hyundai|Ioniq 5 PE (with HDA II & LFA2) 2025-26|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 PE (with HDA II & LFA2) 2025-26">Buy Here</a></sub></details>|||
|Hyundai|Ioniq 6 (with HDA II) 2023-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 6 (with HDA II) 2023-24">Buy Here</a></sub></details>|||
|Hyundai|Ioniq 9 (with HDA II & LFA2) 2025-26|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 9 (with HDA II & LFA2) 2025-26">Buy Here</a></sub></details>|||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Electric 2019">Buy Here</a></sub></details>||| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Electric 2019">Buy Here</a></sub></details>|||
|Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Electric 2020">Buy Here</a></sub></details>||| |Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Electric 2020">Buy Here</a></sub></details>|||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Hybrid 2017-19">Buy Here</a></sub></details>||| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Hybrid 2017-19">Buy Here</a></sub></details>|||
@@ -211,62 +130,39 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>||| |Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>|||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||| |Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona 2020">Buy Here</a></sub></details>||| |Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona 2020">Buy Here</a></sub></details>|||
|Hyundai|Kona (without HDA II) 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona (without HDA II) 2024-25">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2018-21">Buy Here</a></sub></details>||| |Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2018-21">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2022-23">Buy Here</a></sub></details>||| |Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Kona Electric (without HDA II) 2024|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric (without HDA II) 2024">Buy Here</a></sub></details>|||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Hybrid 2020">Buy Here</a></sub></details>||| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Hybrid 2020">Buy Here</a></sub></details>|||
|Hyundai|Kona Hybrid (without HDA II) 2024|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Hybrid (without HDA II) 2024">Buy Here</a></sub></details>|||
|Hyundai|Nexo 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Nexo 2021">Buy Here</a></sub></details>||| |Hyundai|Nexo 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Nexo 2021">Buy Here</a></sub></details>|||
|Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Palisade (with HDA II) 2023-25|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Palisade (with HDA II) 2023-25">Buy Here</a></sub></details>|||
|Hyundai|Palisade (without HDA II) 2023-25|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Palisade (without HDA II) 2023-25">Buy Here</a></sub></details>|||
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Cruz 2022-24">Buy Here</a></sub></details>||| |Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Cruz 2022-24">Buy Here</a></sub></details>|||
|Hyundai|Santa Cruz (without HDA II) 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Cruz (without HDA II) 2025">Buy Here</a></sub></details>|||
|Hyundai|Santa Fe 2019-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe 2019-20">Buy Here</a></sub></details>|<a href="https://youtu.be/bjDR0YjM__s" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Hyundai|Santa Fe 2019-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe 2019-20">Buy Here</a></sub></details>|<a href="https://youtu.be/bjDR0YjM__s" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Santa Fe 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Hyundai|Santa Fe 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>||| |Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Santa Fe Hybrid (with HDA II & LFA2) 2024-25|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Hybrid (with HDA II & LFA2) 2024-25">Buy Here</a></sub></details>|||
|Hyundai|Santa Fe Hybrid (without HDA II, LFA2) 2025-26|Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Hybrid (without HDA II, LFA2) 2025-26">Buy Here</a></sub></details>|||
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||| |Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata 2018-19">Buy Here</a></sub></details>||| |Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata 2018-19">Buy Here</a></sub></details>|||
|Hyundai|Sonata 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Hyundai|Sonata 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Sonata (without HDA II) 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata (without HDA II) 2024-25">Buy Here</a></sub></details>|||
|Hyundai|Sonata Hybrid 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata Hybrid 2020-23">Buy Here</a></sub></details>||| |Hyundai|Sonata Hybrid 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata Hybrid 2020-23">Buy Here</a></sub></details>|||
|Hyundai|Sonata Hybrid (without HDA II) 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Sonata Hybrid (without HDA II) 2024-25">Buy Here</a></sub></details>|||
|Hyundai|Staria 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Staria 2023">Buy Here</a></sub></details>||| |Hyundai|Staria 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Staria 2023">Buy Here</a></sub></details>|||
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2021">Buy Here</a></sub></details>||| |Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2021">Buy Here</a></sub></details>|||
|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2022">Buy Here</a></sub></details>||| |Hyundai|Tucson 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2022">Buy Here</a></sub></details>|||
|Hyundai|Tucson 2023-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2023-24">Buy Here</a></sub></details>||| |Hyundai|Tucson 2023-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson 2023-24">Buy Here</a></sub></details>|||
|Hyundai|Tucson (without HDA II) 2025-26|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson (without HDA II) 2025-26">Buy Here</a></sub></details>|||
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Diesel 2019">Buy Here</a></sub></details>||| |Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Diesel 2019">Buy Here</a></sub></details>|||
|Hyundai|Tucson Hybrid 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Hybrid 2022-24">Buy Here</a></sub></details>||| |Hyundai|Tucson Hybrid 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Hybrid 2022-24">Buy Here</a></sub></details>|||
|Hyundai|Tucson Hybrid (without HDA II) 2025-26|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Hybrid (without HDA II) 2025-26">Buy Here</a></sub></details>|||
|Hyundai|Tucson Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Plug-in Hybrid 2024">Buy Here</a></sub></details>||| |Hyundai|Tucson Plug-in Hybrid 2024|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Plug-in Hybrid 2024">Buy Here</a></sub></details>|||
|Hyundai|Tucson Plug-in Hybrid (without HDA II) 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Tucson Plug-in Hybrid (without HDA II) 2025">Buy Here</a></sub></details>|||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Veloster 2019-20">Buy Here</a></sub></details>||| |Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Veloster 2019-20">Buy Here</a></sub></details>|||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Jeep Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Jeep Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Jeep Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Jeep Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Kia|Carnival 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival 2022-24">Buy Here</a></sub></details>||| |Kia|Carnival 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival 2022-24">Buy Here</a></sub></details>|||
|Kia|Carnival 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival 2025">Buy Here</a></sub></details>|||
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival (China only) 2023">Buy Here</a></sub></details>||| |Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival (China only) 2023">Buy Here</a></sub></details>|||
|Kia|Carnival (with HDA II) 2025|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival (with HDA II) 2025">Buy Here</a></sub></details>|||
|Kia|Carnival Hybrid 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival Hybrid 2025">Buy Here</a></sub></details>|||
|Kia|Carnival Hybrid 2026|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival Hybrid 2026">Buy Here</a></sub></details>|||
|Kia|Carnival Hybrid (with HDA II) 2025-26|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival Hybrid (with HDA II) 2025-26">Buy Here</a></sub></details>|||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed 2019-21">Buy Here</a></sub></details>||| |Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed 2019-21">Buy Here</a></sub></details>|||
|Kia|EV6 (Southeast Asia only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>||| |Kia|EV6 (Southeast Asia only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>|||
|Kia|EV6 (with HDA I) 2025|Highway Driving Assist I|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (with HDA I) 2025">Buy Here</a></sub></details>|||
|Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>||| |Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>||| |Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
|Kia|EV9 2025-26|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV9 2025-26">Buy Here</a></sub></details>|||
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2019-21">Buy Here</a></sub></details>||| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2019-21">Buy Here</a></sub></details>|||
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2022-23">Buy Here</a></sub></details>||| |Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2022-23">Buy Here</a></sub></details>|||
|Kia|K4 (with HDA II) 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K4 (with HDA II) 2025">Buy Here</a></sub></details>|||
|Kia|K4 (without HDA II) 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K4 (without HDA II) 2025">Buy Here</a></sub></details>|||
|Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 2021-24">Buy Here</a></sub></details>||| |Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 2021-24">Buy Here</a></sub></details>|||
|Kia|K5 (without HDA II) 2025|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 (without HDA II) 2025">Buy Here</a></sub></details>|||
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 Hybrid 2020-22">Buy Here</a></sub></details>||| |Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 Hybrid 2020-22">Buy Here</a></sub></details>|||
|Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K8 Hybrid (with HDA II) 2023">Buy Here</a></sub></details>||| |Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K8 Hybrid (with HDA II) 2023">Buy Here</a></sub></details>|||
|Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Niro EV 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Niro EV 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
@@ -290,20 +186,13 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento 2018">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento 2019">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Kia|Sorento 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento 2021-23">Buy Here</a></sub></details>||| |Kia|Sorento 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento 2021-23">Buy Here</a></sub></details>|||
|Kia|Sorento (without HDA II) 2024-25|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento (without HDA II) 2024-25">Buy Here</a></sub></details>|||
|Kia|Sorento Hybrid 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento Hybrid 2021-23">Buy Here</a></sub></details>||| |Kia|Sorento Hybrid 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento Hybrid 2021-23">Buy Here</a></sub></details>|||
|Kia|Sorento Hybrid 2026|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento Hybrid 2026">Buy Here</a></sub></details>|||
|Kia|Sorento Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||| |Kia|Sorento Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>|||
|Kia|Sportage 2023-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage 2023-24">Buy Here</a></sub></details>||| |Kia|Sportage 2023-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage 2023-24">Buy Here</a></sub></details>|||
|Kia|Sportage (without HDA II) 2026|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage (without HDA II) 2026">Buy Here</a></sub></details>|||
|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage Hybrid 2023">Buy Here</a></sub></details>||| |Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage Hybrid 2023">Buy Here</a></sub></details>|||
|Kia|Sportage Hybrid 2026|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Sportage Hybrid 2026">Buy Here</a></sub></details>|||
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Stinger 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Stinger 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Kia|Stinger 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Stinger 2022-23">Buy Here</a></sub></details>||| |Kia|Stinger 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Stinger 2022-23">Buy Here</a></sub></details>|||
|Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Telluride 2020-22">Buy Here</a></sub></details>||| |Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Telluride 2020-22">Buy Here</a></sub></details>|||
|Kia|Telluride (with HDA II) 2023-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Telluride (with HDA II) 2023-24">Buy Here</a></sub></details>|||
|Kia|Telluride (without HDA II) 2023-25|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Telluride (without HDA II) 2023-25">Buy Here</a></sub></details>|||
|Kia|XCeed Plug-in Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia XCeed Plug-in Hybrid 2021">Buy Here</a></sub></details>|||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus CT Hybrid 2017-18">Buy Here</a></sub></details>||| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus CT Hybrid 2017-18">Buy Here</a></sub></details>|||
|Lexus|ES 2017-18|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus ES 2017-18">Buy Here</a></sub></details>||| |Lexus|ES 2017-18|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus ES 2017-18">Buy Here</a></sub></details>|||
|Lexus|ES 2019-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus ES 2019-25">Buy Here</a></sub></details>||| |Lexus|ES 2019-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus ES 2019-25">Buy Here</a></sub></details>|||
@@ -326,54 +215,48 @@ A supported vehicle is one that just works when you install a comma device. All
|Lexus|RX Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus RX Hybrid 2017-19">Buy Here</a></sub></details>||| |Lexus|RX Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus RX Hybrid 2017-19">Buy Here</a></sub></details>|||
|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus RX Hybrid 2020-22">Buy Here</a></sub></details>||| |Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus RX Hybrid 2020-22">Buy Here</a></sub></details>|||
|Lexus|UX Hybrid 2019-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus UX Hybrid 2019-24">Buy Here</a></sub></details>||| |Lexus|UX Hybrid 2019-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lexus UX Hybrid 2019-24">Buy Here</a></sub></details>|||
|Lincoln|Aviator 2020-24|Co-Pilot360 Plus|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lincoln Aviator 2020-24">Buy Here</a></sub></details>||| |Lincoln|Aviator 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lincoln Aviator 2020-24">Buy Here</a></sub></details>|||
|Lincoln|Aviator Plug-in Hybrid 2020-24|Co-Pilot360 Plus|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lincoln Aviator Plug-in Hybrid 2020-24">Buy Here</a></sub></details>||| |Lincoln|Aviator Plug-in Hybrid 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Lincoln Aviator Plug-in Hybrid 2020-24">Buy Here</a></sub></details>|||
|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=MAN eTGE 2020-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=MAN eTGE 2020-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=MAN TGE 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=MAN TGE 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Mazda|CX-5 2022-25|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Mazda CX-5 2022-25">Buy Here</a></sub></details>||| |Mazda|CX-5 2022-25|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Mazda CX-5 2022-25">Buy Here</a></sub></details>|||
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Mazda CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Mazda CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Nissan[<sup>6</sup>](#footnotes)|Altima 2019-20, 2024|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Altima 2019-20, 2024">Buy Here</a></sub></details>||| |Nissan[<sup>5</sup>](#footnotes)|Altima 2019-20, 2024|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Altima 2019-20, 2024">Buy Here</a></sub></details>|||
|Nissan[<sup>6</sup>](#footnotes)|Leaf 2018-25|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Leaf 2018-25">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Nissan[<sup>5</sup>](#footnotes)|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Leaf 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Nissan[<sup>6</sup>](#footnotes)|Leaf Instrument Cluster 2018-25|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Leaf Instrument Cluster 2018-25">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Nissan[<sup>5</sup>](#footnotes)|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Rogue 2018-20">Buy Here</a></sub></details>|||
|Nissan[<sup>6</sup>](#footnotes)|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan Rogue 2018-20">Buy Here</a></sub></details>||| |Nissan[<sup>5</sup>](#footnotes)|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan X-Trail 2017">Buy Here</a></sub></details>|||
|Nissan[<sup>6</sup>](#footnotes)|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Nissan X-Trail 2017">Buy Here</a></sub></details>||| |Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Ram connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ram 1500 2019-24">Buy Here</a></sub></details>|||
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|32 mph|1 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Ram connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Ram 1500 2019-24">Buy Here</a></sub></details>||| |Rivian|R1S 2022-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1S 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Rivian|R1S 2022-24|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1S 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Rivian|R1T 2022-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1T 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Rivian|R1S 2025|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1S 2025">Buy Here</a></sub></details>||| |SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=SEAT Ateca 2016-23">Buy Here</a></sub></details>|||
|Rivian|R1T 2022-24|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1T 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=SEAT Leon 2014-20">Buy Here</a></sub></details>|||
|Rivian|R1T 2025|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Rivian B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1T 2025">Buy Here</a></sub></details>||| |Subaru|Ascent 2019-21|All[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=SEAT Ateca 2016-23">Buy Here</a></sub></details>||| |Subaru|Ascent 2023|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Ascent 2023">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=SEAT Leon 2014-20">Buy Here</a></sub></details>||| |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Subaru|Ascent 2019-21|All[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Ascent 2023-25|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Ascent 2023-25">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Subaru|Crosstrek 2025|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Crosstrek 2025">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Subaru|Forester 2019-21|All[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Subaru|Forester 2022-24|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru C connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Forester 2022-24">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Crosstrek 2025|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Crosstrek 2025">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Forester 2019-21|All[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Forester 2022-24|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru C connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Forester 2022-24">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Subaru|Legacy 2020-22|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru B connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Legacy 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Subaru|Outback 2020-22|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru B connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Subaru|Outback 2023|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 2023">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Legacy 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru B connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Legacy 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Subaru|Legacy 2025|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Legacy 2025">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Outback 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru B connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Škoda|Fabia 2022-23[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Fabia 2022-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|Subaru|Outback 2023-24|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 2023-24">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Škoda|Kamiq 2021-23[<sup>11,13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Kamiq 2021-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Škoda|Karoq 2019-23[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Karoq 2019-23">Buy Here</a></sub></details>|||
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||| |Škoda|Kodiaq 2017-23[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Kodiaq 2017-23">Buy Here</a></sub></details>|||
|Škoda|Enyaq 2021-23[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Enyaq 2021-23">Buy Here</a></sub></details>||| |Škoda|Octavia 2015-19[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia 2015-19">Buy Here</a></sub></details>|||
|Škoda|Enyaq 2024-25[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Enyaq 2024-25">Buy Here</a></sub></details>||| |Škoda|Octavia RS 2016[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia RS 2016">Buy Here</a></sub></details>|||
|Škoda|Fabia 2022-23[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Fabia 2022-23">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)||| |Škoda|Octavia Scout 2017-19[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia Scout 2017-19">Buy Here</a></sub></details>|||
|Škoda|Kamiq 2021-23[<sup>12,14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Kamiq 2021-23">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)||| |Škoda|Scala 2020-23[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Scala 2020-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|Škoda|Karoq 2019-23[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Karoq 2019-23">Buy Here</a></sub></details>||| |Škoda|Superb 2015-22[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Superb 2015-22">Buy Here</a></sub></details>|||
|Škoda|Kodiaq 2017-23[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Kodiaq 2017-23">Buy Here</a></sub></details>||| |Tesla[<sup>9</sup>](#footnotes)|Model 3 (with HW3) 2019-23[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model 3 (with HW3) 2019-23">Buy Here</a></sub></details>|||
|Škoda|Octavia 2015-19[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia 2015-19">Buy Here</a></sub></details>||| |Tesla[<sup>9</sup>](#footnotes)|Model 3 (with HW4) 2024-25[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model 3 (with HW4) 2024-25">Buy Here</a></sub></details>|||
|Škoda|Octavia RS 2016[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia RS 2016">Buy Here</a></sub></details>||| |Tesla[<sup>9</sup>](#footnotes)|Model Y (with HW3) 2020-23[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW3) 2020-23">Buy Here</a></sub></details>|||
|Škoda|Octavia Scout 2017-19[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Octavia Scout 2017-19">Buy Here</a></sub></details>||| |Tesla[<sup>9</sup>](#footnotes)|Model Y (with HW4) 2024-25[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW4) 2024-25">Buy Here</a></sub></details>|||
|Škoda|Scala 2020-23[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Scala 2020-23">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)|||
|Škoda|Superb 2015-22[<sup>14</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Superb 2015-22">Buy Here</a></sub></details>|||
|Tesla[<sup>10</sup>](#footnotes)|Model 3 (with HW3) 2019-23[<sup>9</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model 3 (with HW3) 2019-23">Buy Here</a></sub></details>|||
|Tesla[<sup>10</sup>](#footnotes)|Model 3 (with HW4) 2024-26[<sup>9</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model 3 (with HW4) 2024-26">Buy Here</a></sub></details>|||
|Tesla[<sup>10</sup>](#footnotes)|Model Y (with HW3) 2020-23[<sup>9</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW3) 2020-23">Buy Here</a></sub></details>|||
|Tesla[<sup>10</sup>](#footnotes)|Model Y (with HW4) 2024-25[<sup>9</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW4) 2024-25">Buy Here</a></sub></details>|||
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Alphard 2019-20">Buy Here</a></sub></details>||| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Alphard 2019-20">Buy Here</a></sub></details>|||
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Alphard Hybrid 2021">Buy Here</a></sub></details>||| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Alphard Hybrid 2021">Buy Here</a></sub></details>|||
|Toyota|Avalon 2016|Toyota Safety Sense P|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Avalon 2016">Buy Here</a></sub></details>||| |Toyota|Avalon 2016|Toyota Safety Sense P|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Avalon 2016">Buy Here</a></sub></details>|||
@@ -386,8 +269,8 @@ A supported vehicle is one that just works when you install a comma device. All
|Toyota|C-HR 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR 2021">Buy Here</a></sub></details>||| |Toyota|C-HR 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR 2021">Buy Here</a></sub></details>|||
|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR Hybrid 2017-20">Buy Here</a></sub></details>||| |Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR Hybrid 2017-20">Buy Here</a></sub></details>|||
|Toyota|C-HR Hybrid 2021-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR Hybrid 2021-22">Buy Here</a></sub></details>||| |Toyota|C-HR Hybrid 2021-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota C-HR Hybrid 2021-22">Buy Here</a></sub></details>|||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>11</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Toyota|Camry 2018-20|All|Stock|0 mph[<sup>10</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>11</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry 2021-24">Buy Here</a></sub></details>||| |Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>10</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry 2021-24">Buy Here</a></sub></details>|||
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry Hybrid 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry Hybrid 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry Hybrid 2021-24">Buy Here</a></sub></details>||| |Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Camry Hybrid 2021-24">Buy Here</a></sub></details>|||
|Toyota|Corolla 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Corolla 2017-19">Buy Here</a></sub></details>||| |Toyota|Corolla 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Corolla 2017-19">Buy Here</a></sub></details>|||
@@ -419,91 +302,62 @@ A supported vehicle is one that just works when you install a comma device. All
|Toyota|RAV4 Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Toyota|RAV4 Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Toyota|RAV4 Hybrid 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Hybrid 2023-25">Buy Here</a></sub></details>|<a href="https://youtu.be/4eIsEq4L4Ng" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Toyota|RAV4 Hybrid 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Hybrid 2023-25">Buy Here</a></sub></details>|<a href="https://youtu.be/4eIsEq4L4Ng" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Toyota|Sienna 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Toyota|Sienna 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon Shooting Brake 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Volkswagen|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon Shooting Brake 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Atlas 2018-23">Buy Here</a></sub></details>||| |Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Atlas 2018-23">Buy Here</a></sub></details>|||
|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Atlas Cross Sport 2020-22">Buy Here</a></sub></details>||| |Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Atlas Cross Sport 2020-22">Buy Here</a></sub></details>|||
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen California 2021-23">Buy Here</a></sub></details>||| |Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen California 2021-23">Buy Here</a></sub></details>|||
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Caravelle 2020">Buy Here</a></sub></details>||| |Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Caravelle 2020">Buy Here</a></sub></details>|||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Crafter 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Crafter 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|e-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen e-Crafter 2018-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Volkswagen|e-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen e-Crafter 2018-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen e-Golf 2014-20">Buy Here</a></sub></details>||| |Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen e-Golf 2014-20">Buy Here</a></sub></details>|||
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf 2015-20">Buy Here</a></sub></details>||| |Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf 2015-20">Buy Here</a></sub></details>|||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf Alltrack 2015-19">Buy Here</a></sub></details>||| |Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf Alltrack 2015-19">Buy Here</a></sub></details>|||
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTD 2015-20">Buy Here</a></sub></details>||| |Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTD 2015-20">Buy Here</a></sub></details>|||
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTE 2015-20">Buy Here</a></sub></details>||| |Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTE 2015-20">Buy Here</a></sub></details>|||
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTI 2015-21">Buy Here</a></sub></details>||| |Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf GTI 2015-21">Buy Here</a></sub></details>|||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf R 2015-19">Buy Here</a></sub></details>||| |Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf R 2015-19">Buy Here</a></sub></details>|||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf SportsVan 2015-20">Buy Here</a></sub></details>||| |Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Golf SportsVan 2015-20">Buy Here</a></sub></details>|||
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Grand California 2019-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|| |Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Grand California 2019-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|ID.3 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen ID.3 2020-23">Buy Here</a></sub></details>||| |Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Jetta 2018-23">Buy Here</a></sub></details>|||
|Volkswagen|ID.3 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen ID.3 2024-25">Buy Here</a></sub></details>||| |Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Jetta GLI 2021-23">Buy Here</a></sub></details>|||
|Volkswagen|ID.4 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen ID.4 2021-23">Buy Here</a></sub></details>||| |Volkswagen|Passat 2015-22[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat 2015-22">Buy Here</a></sub></details>|||
|Volkswagen|ID.4 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen ID.4 2024-25">Buy Here</a></sub></details>||| |Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat Alltrack 2015-22">Buy Here</a></sub></details>|||
|Volkswagen|ID.5 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen ID.5 2022-23">Buy Here</a></sub></details>||| |Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat GTE 2015-22">Buy Here</a></sub></details>|||
|Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Jetta 2018-23">Buy Here</a></sub></details>||| |Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Polo 2018-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Jetta GLI 2021-23">Buy Here</a></sub></details>||| |Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|Volkswagen|Passat 2015-22[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat 2015-22">Buy Here</a></sub></details>||| |Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen T-Cross 2021">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat Alltrack 2015-22">Buy Here</a></sub></details>||| |Volkswagen|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen T-Roc 2018-23">Buy Here</a></sub></details>|||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Passat GTE 2015-22">Buy Here</a></sub></details>||| |Volkswagen|Taos 2022-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Taos 2022-24">Buy Here</a></sub></details>|||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Polo 2018-23">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)||| |Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont 2018-22">Buy Here</a></sub></details>|||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)||| |Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont Cross Sport 2021-22">Buy Here</a></sub></details>|||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen T-Cross 2021">Buy Here</a></sub></details>[<sup>16</sup>](#footnotes)||| |Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont X 2021-22">Buy Here</a></sub></details>|||
|Volkswagen|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen T-Roc 2018-23">Buy Here</a></sub></details>||| |Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Tiguan 2018-24">Buy Here</a></sub></details>|||
|Volkswagen|Taos 2022-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Taos 2022-24">Buy Here</a></sub></details>||| |Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Tiguan eHybrid 2021-23">Buy Here</a></sub></details>|||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont 2018-22">Buy Here</a></sub></details>||| |Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Touran 2016-23">Buy Here</a></sub></details>|||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont Cross Sport 2021-22">Buy Here</a></sub></details>|||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Teramont X 2021-22">Buy Here</a></sub></details>|||
|Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Tiguan 2018-24">Buy Here</a></sub></details>|||
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Tiguan eHybrid 2021-23">Buy Here</a></sub></details>|||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,15</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Touran 2016-23">Buy Here</a></sub></details>|||
## StarPilot Community Cars
These additional vehicle ports are maintained by StarPilot rather than upstream openpilot.
# 17 Community Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br>&nbsp;|Video|Setup Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Genesis|G70 Non-SCC 2021|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis G70 Non-SCC 2021">Buy Here</a></sub></details>|||
|Hyundai|Bayon Non-SCC 2021|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Bayon Non-SCC 2021">Buy Here</a></sub></details>|||
|Hyundai|Elantra Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Hybrid Non-SCC 2022">Buy Here</a></sub></details>|||
|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Non-SCC 2022">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric Non-SCC 2019">Buy Here</a></sub></details>|||
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Non-SCC 2019">Buy Here</a></sub></details>|||
|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed Plug-in Hybrid Non-SCC 2022">Buy Here</a></sub></details>|||
|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte Non-SCC 2019">Buy Here</a></sub></details>|||
|Kia|Forte Non-SCC 2021|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte Non-SCC 2021">Buy Here</a></sub></details>|||
|Kia|Ray EV 2025|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ray EV 2025">Buy Here</a></sub></details>|||
|Kia|Seltos Non-SCC 2023-24|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Seltos Non-SCC 2023-24">Buy Here</a></sub></details>|||
|Tesla|Model S (Pre-AP) 2012-14|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|||
|Toyota|Matrix Retrofit 2005|Custom retrofit|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Matrix Retrofit 2005">Buy Here</a></sub></details>|||
|Toyota|Prius 2016-20 with TSS2 EPS retrofit|Custom retrofit|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Prius 2016-20 with TSS2 EPS retrofit">Buy Here</a></sub></details>|||
|Toyota|RAV4 Prime 2021-23|All|openpilot|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Prime 2021-23">Buy Here</a></sub></details>|||
|Toyota|Sienna 2021-25|All|openpilot|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Sienna 2021-25">Buy Here</a></sub></details>|||
|Toyota|Yaris (Non-US only) 2020, 2023|All|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Toyota A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Yaris (Non-US only) 2020, 2023">Buy Here</a></sub></details>|||
### Footnotes ### Footnotes
<sup>1</sup>openpilot Longitudinal Control (Alpha) is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `nightly-dev`. <br /> <sup>1</sup>openpilot Longitudinal Control (Alpha) is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `nightly-dev`. <br />
<sup>2</sup>Refers only to the Focus Mk4 (C519) available in Europe/China/Taiwan/Australasia, not the Focus Mk3 (C346) in North and South America/Southeast Asia. <br /> <sup>2</sup>Refers only to the Focus Mk4 (C519) available in Europe/China/Taiwan/Australasia, not the Focus Mk3 (C346) in North and South America/Southeast Asia. <br />
<sup>3</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/gm" target="_blank">GM</a>. <br /> <sup>3</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/gm" target="_blank">GM</a>. <br />
<sup>4</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br /> <sup>4</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
<sup>5</sup>Enabling longitudinal control (alpha) will disable all CMBS functionality, including AEB and FCW. <br /> <sup>5</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/nissan" target="_blank">Nissan</a>. <br />
<sup>6</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/nissan" target="_blank">Nissan</a>. <br /> <sup>6</sup>In the non-US market, openpilot requires the car to come equipped with EyeSight with Lane Keep Assistance. <br />
<sup>7</sup>In the non-US market, openpilot requires the car to come equipped with EyeSight with Lane Keep Assistance. <br /> <sup>7</sup>Enabling longitudinal control (alpha) will disable all EyeSight functionality, including AEB, LDW, and RAB. <br />
<sup>8</sup>Enabling longitudinal control (alpha) will disable all EyeSight functionality, including AEB, LDW, and RAB. <br /> <sup>8</sup>Some 2023 model years have HW4. To check which hardware type your vehicle has, look for <b>Autopilot computer</b> under <b>Software -> Additional Vehicle Information</b> on your vehicle's touchscreen. See <a href="https://www.notateslaapp.com/news/2173/how-to-check-if-your-tesla-has-hardware-4-ai4-or-hardware-3">this page</a> for more information. <br />
<sup>9</sup>Some 2023 model years have HW4. To check which hardware type your vehicle has, look for <b>Autopilot computer</b> under <b>Software -> Additional Vehicle Information</b> on your vehicle's touchscreen. See <a href="https://www.notateslaapp.com/news/2173/how-to-check-if-your-tesla-has-hardware-4-ai4-or-hardware-3">this page</a> for more information. <br /> <sup>9</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/tesla" target="_blank">Tesla</a>. <br />
<sup>10</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/tesla" target="_blank">Tesla</a>. <br /> <sup>10</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>11</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br /> <sup>11</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>12</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br /> <sup>12</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
<sup>13</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br /> <sup>13</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma four functionality. <br />
<sup>14</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma four functionality. <br /> <sup>14</sup>Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC. <br />
<sup>15</sup>Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC. <br /> <sup>15</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br />
<sup>16</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br />
## Community Maintained Cars
Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/).
# Don't see your car here? # Don't see your car here?
+10 -50
View File
@@ -4,8 +4,8 @@ This workflow rebuilds StarPilot driving and driver-monitoring artifacts for the
## Safety ## Safety
- The supported build device is `comma@192.168.3.109`. - The supported build device is `comma@192.168.3.110`.
- Never run these commands against `192.168.3.110`. - Never run these commands against `192.168.3.109`.
- Normal artifacts target QCOM. External-GPU artifacts must be compiled explicitly and tagged in the manifest. - Normal artifacts target QCOM. External-GPU artifacts must be compiled explicitly and tagged in the manifest.
- Keep source ONNX files and compiled PKLs on the T5 workspace, not the comma. - Keep source ONNX files and compiled PKLs on the T5 workspace, not the comma.
@@ -26,8 +26,7 @@ Important directories:
- Oversized models are represented by repository-safe `.p00`, `.p01`, and `.sha256` files in `ready-for-resources/`. - Oversized models are represented by repository-safe `.p00`, `.p01`, and `.sha256` files in `ready-for-resources/`.
- `logs/`: one remote compilation log per model. - `logs/`: one remote compilation log per model.
- `results/`: source and artifact checksum records. - `results/`: source and artifact checksum records.
- `manifests/`: source `model_names_v22.json` and namespaced release `model_names_v23.json`. - `manifests/`: generated `model_names_v22.json`.
- The v23 manifest and compiled artifacts are published together in the resource repository's `Models` branch.
## Initialize And Extract ## Initialize And Extract
@@ -47,10 +46,7 @@ python3 scripts/model_rebuild_pipeline.py extract \
--base-manifest /path/to/model_names_v21.json --base-manifest /path/to/model_names_v21.json
``` ```
The original catalog sources are defined in `scripts/model_source_map_v22.json`. Source commits are defined in `scripts/model_source_map_v22.json`.
Recovered late-model and supercombo sources, including RDF2, are defined in
`scripts/model_source_map_v23.json`. The v23 map is intentionally separate so
adding a recovered iteration cannot alter the older model source history.
## Compile ## Compile
@@ -69,7 +65,7 @@ python3 scripts/model_rebuild_pipeline.py compile \
--base-manifest /path/to/model_names_v21.json --base-manifest /path/to/model_names_v21.json
``` ```
Existing artifacts are skipped unless `--force` is passed. Each model is staged in its own remote input directory, compiled on `.109`, copied back to the T5, hashed, and copied into `ready-for-resources/`. Failures are written to `results/<id>_failure.json`; rerunning the same command resumes incomplete models. Existing artifacts are skipped unless `--force` is passed. Each model is staged in its own remote input directory, compiled on `.110`, copied back to the T5, hashed, and copied into `ready-for-resources/`. Failures are written to `results/<id>_failure.json`; rerunning the same command resumes incomplete models.
Validate one or all completed artifacts with synthetic camera inputs on QCOM: Validate one or all completed artifacts with synthetic camera inputs on QCOM:
@@ -159,51 +155,15 @@ All four files must be updated together.
## Manifest ## Manifest
The current test branch uses manifest v25 and requests v25 only. Seed the new Generate v22 after compilation:
manifest from the previous catalog, then replace entries as artifacts are
rebuilt with the pinned runtime:
```bash
cp /path/to/model_names_v24.json /path/to/model_names_v25.json
```
The current tinygrad pin is `f6fc4e3f2c3db5fae1e19cbfbc3ad9fc579a12ae`, from
`openpilot` `origin/master` (`bump tg + TC_MIN_GLOBALS`). StarPilot's
multi-model `modeld` remains in place; do not replace it with upstream's
single-model `modeld`.
For the older namespace migration workflow, generate the base manifest after
compilation and namespace the release artifacts as v23:
```bash ```bash
python3 scripts/model_rebuild_pipeline.py manifest \ python3 scripts/model_rebuild_pipeline.py manifest \
--base-manifest /path/to/model_names_v21.json --base-manifest /path/to/model_names_v21.json
``` ```
```bash The generator preserves existing IDs and behavioral metadata and adds
python3 scripts/namespace_model_artifacts.py \ `deeprl3v2`. Manifest v22 implies the unified single-PKL runtime layout.
--workspace /Volumes/T5/StarPilot-Model-Rebuild-2026-06-22 \
--base-manifest /Volumes/T5/StarPilot-Model-Rebuild-2026-06-22/manifests/model_names_v22.json \
--manifest-version v23 --suffix 3
```
The namespace command changes IDs such as `tr1422` to `tr14223`, renames the
compiled and upload-ready files, and writes an ID map. It preserves display
names and behavioral versions. The current model manager requests v25 only; the
manifest is fetched from `Models/model_names_v25.json`. Devices still running
the prior branch continue to request their existing manifest version.
After importing newly compiled sources, normalize the release namespace before
copying files into either resource repository:
```bash
python3 scripts/reconcile_v23_artifacts.py \
--workspace /Volumes/T5/StarPilot-Model-Rebuild-2026-06-22
```
This maps recovered source IDs to their v23 release IDs, removes duplicate
macOS metadata files, and adds `rdf23` for Regret Driven Framework V2. It does
not overwrite a conflicting artifact.
Repository-hosted multipart files are discovered by naming convention, so no Repository-hosted multipart files are discovered by naming convention, so no
size, hash, format, or part-count metadata is required. size, hash, format, or part-count metadata is required.
@@ -217,6 +177,6 @@ Compilation validates JIT capture/replay, pickle round-trip, finite outputs, met
2. Confirm `modeld` stays running. 2. Confirm `modeld` stays running.
3. Confirm finite `modelV2` path, lane-line, lead, pose, and action data. 3. Confirm finite `modelV2` path, lane-line, lead, pose, and action data.
4. Confirm `driverStateV2` on both supported camera resolutions. 4. Confirm `driverStateV2` on both supported camera resolutions.
5. Test download, selection, deletion, randomization, migration, and fallback in both device UIs and Galaxy. 5. Test download, selection, deletion, randomization, migration, and fallback in QT, raylib/mici, and Galaxy.
The built-in RDF artifact is `selfdrive/modeld/models/driving_tinygrad.pkl`. If migration cannot download the selected v25 artifact, StarPilot switches to that built-in model. The built-in South Carolina artifact is `selfdrive/modeld/models/driving_tinygrad.pkl`. If migration cannot download the selected v22 artifact, StarPilot switches to that built-in model.
+1 -1
View File
@@ -48,7 +48,7 @@ Use `./dev` for host-native tools. It creates and reuses an isolated environment
./dev shell ./dev shell
``` ```
For desktop UI work, use `./c3` or `./c4`. These commands use the same isolated host environment. For desktop UI work, use `./c3`, `./c4`, or `./raybig`. These commands use the same isolated host environment.
Use `./build` when you need comma-compatible device artifacts. This is the expected validation for changes that affect compiled device code or runtime behavior: Use `./build` when you need comma-compatible device artifacts. This is the expected validation for changes that affect compiled device code or runtime behavior:
+7 -5
View File
@@ -2,7 +2,7 @@
This flow builds **device-target (`larch64`) binaries on your laptop** using a Linux/aarch64 container and a synced comma sysroot. This flow builds **device-target (`larch64`) binaries on your laptop** using a Linux/aarch64 container and a synced comma sysroot.
For the full StarPilot branch workflow, including host-native shorthand tools such as `./dev`, `./c3`, and `./c4`, see the [StarPilot development guide](https://github.com/firestar5683/StarPilot/blob/Dom/tools/STARPILOT_DEVELOPMENT.md). For the full StarPilot branch workflow, including host-native shorthand tools such as `./dev`, `./c3`, `./c4`, and `./raybig`, see the [StarPilot development guide](https://github.com/firestar5683/StarPilot/blob/Dom/tools/STARPILOT_DEVELOPMENT.md).
## Prerequisites ## Prerequisites
@@ -71,10 +71,10 @@ This runs:
- `SP_TICI_SYSROOT=/opt/tici-sysroot` - `SP_TICI_SYSROOT=/opt/tici-sysroot`
- `touch prebuilt` - `touch prebuilt`
To run SCons targets explicitly in the same device-compatible environment: To run `scons` targets explicitly in the same device-compatible environment:
```bash ```bash
scripts/laptop_device_build.sh scons common/params_pyx.so scripts/laptop_device_build.sh scons selfdrive/ui/ui
``` ```
On macOS, once `.comma_sysroot` is present, plain `scons ...` auto-routes to this containerized device build. On macOS, once `.comma_sysroot` is present, plain `scons ...` auto-routes to this containerized device build.
@@ -112,6 +112,7 @@ Preferred host-side shorthand commands on this branch:
```bash ```bash
./c3 ./c3
./c4 ./c4
./raybig
./dev replay ./dev replay
./dev cabana ./dev cabana
./dev plotjuggler ./dev plotjuggler
@@ -119,9 +120,10 @@ Preferred host-side shorthand commands on this branch:
These commands use the isolated `.host_runtime` cache so host-native artifacts do not churn the main tree. These commands use the isolated `.host_runtime` cache so host-native artifacts do not churn the main tree.
Direct script entrypoints are also available: Legacy direct script entrypoints still exist if needed:
```bash ```bash
scripts/launch_ui_c3_desktop.sh scripts/launch_ui_desktop.sh
scripts/launch_ui_c4_desktop.sh scripts/launch_ui_c4_desktop.sh
scripts/launch_ui_raybig_desktop.sh
``` ```
+79 -3
View File
@@ -147,10 +147,86 @@ function launch {
while true; do sleep 1; done while true; do sleep 1; done
fi fi
function prebuilt_runtime_compatible {
python3 - <<'PY'
import importlib
import os
from pathlib import Path
import sys
import time
start = time.monotonic()
last = start
log_path = os.environ.get("SP_BOOT_TIMING_LOG")
def emit(line):
print(line, flush=True)
if log_path:
try:
with open(log_path, "a") as f:
f.write(line + "\n")
except OSError:
pass
def log_step(label):
global last
now = time.monotonic()
emit(f"SP_BOOT_TIMING prebuilt_compat {label} +{now - last:.3f}s total={now - start:.3f}s")
last = now
mods = [
"openpilot.common.params_pyx",
"msgq.ipc_pyx",
"msgq.visionipc.visionipc_pyx",
"openpilot.common.transformations.transformations",
"openpilot.selfdrive.pandad.pandad_api_impl",
"openpilot.selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx",
"openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx",
]
for mod in mods:
try:
importlib.import_module(mod)
except Exception as e:
print(f"Prebuilt compatibility failure in {mod}: {e}", file=sys.stderr)
raise
log_step(f"import:{mod}")
repo_root = Path.cwd().parents[1]
required_files = [
repo_root / "selfdrive/modeld/models/driving_tinygrad.pkl",
repo_root / "selfdrive/modeld/models/dmonitoring_model_metadata.pkl",
repo_root / "selfdrive/modeld/models/dmonitoring_model_tinygrad.pkl",
repo_root / "selfdrive/modeld/models/dm_warp_1928x1208_tinygrad.pkl",
repo_root / "selfdrive/modeld/models/dm_warp_1344x760_tinygrad.pkl",
repo_root / "selfdrive/pandad/pandad_api_impl.so",
repo_root / "selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/acados_ocp_solver_pyx.so",
repo_root / "selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/libacados_ocp_solver_lat.so",
repo_root / "selfdrive/controls/lib/longitudinal_mpc_lib/c_generated_code/acados_ocp_solver_pyx.so",
repo_root / "selfdrive/controls/lib/longitudinal_mpc_lib/c_generated_code/libacados_ocp_solver_long.so",
repo_root / "opendbc_repo/opendbc/dbc/gm_global_a_powertrain_generated.dbc",
]
for path in required_files:
if not path.is_file():
raise FileNotFoundError(f"Missing prebuilt runtime artifact: {path}")
log_step("required_files")
PY
}
USE_PREBUILT=1
if [ -f /data/params/d/UsePrebuilt ]; then
USE_PREBUILT=$(tr -d '\n' < /data/params/d/UsePrebuilt)
fi
sp_launch_timing "prebuilt_decision_done" sp_launch_timing "prebuilt_decision_done"
# Published trees carry this marker and must never compile on-device. if [ "$USE_PREBUILT" = "1" ] && [ -f $DIR/prebuilt ] && ! prebuilt_runtime_compatible; then
# Developers can remove it explicitly when working from a source tree. echo "Prebuilt runtime artifacts are incompatible on this device; rebuilding locally."
if [ ! -f "$DIR/prebuilt" ]; then USE_PREBUILT=0
fi
sp_launch_timing "prebuilt_compat_done"
if [ "$USE_PREBUILT" != "1" ] || [ ! -f $DIR/prebuilt ]; then
sp_launch_timing "build_start" sp_launch_timing "build_start"
./build.py ./build.py
sp_launch_timing "build_done" sp_launch_timing "build_done"
+1 -1
View File
@@ -21,7 +21,7 @@ fi
export QCOM_PRIORITY=12 export QCOM_PRIORITY=12
if [ -z "$AGNOS_VERSION" ]; then if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="19.6.16" export AGNOS_VERSION="12.8.28"
fi fi
if [ -z "$AGNOS_ACCEPTED_VERSIONS" ]; then if [ -z "$AGNOS_ACCEPTED_VERSIONS" ]; then
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
exec python3 "$DIR/scripts/model_release.py" "$@"
Binary file not shown.
Binary file not shown.
+13 -147
View File
@@ -1,36 +1,24 @@
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. ---> <!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
# Support Information for 518 Known Cars # Support Information for 384 Known Cars
|Make|Model|Package|Support Level| |Make|Model|Package|Support Level|
|---|---|---|:---:| |---|---|---|:---:|
|Acura|ADX 2025-26|All|[Upstream](#upstream)|
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|[Upstream](#upstream)| |Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|[Upstream](#upstream)|
|Acura|ILX 2019|All|[Upstream](#upstream)| |Acura|ILX 2019|All|[Upstream](#upstream)|
|Acura|Integra 2023-25|All|[Community](#community)| |Acura|Integra 2023-25|All|[Community](#community)|
|Acura|Integra 2023-26|All|[Upstream](#upstream)|
|Acura|MDX 2014-16|Advance Package|[Upstream](#upstream)|
|Acura|MDX 2015-16|Advance Package|[Community](#community)| |Acura|MDX 2015-16|Advance Package|[Community](#community)|
|Acura|MDX 2017-19|All|[Upstream](#upstream)|
|Acura|MDX 2017-20|All|[Community](#community)| |Acura|MDX 2017-20|All|[Community](#community)|
|Acura|MDX 2020|All|[Upstream](#upstream)|
|Acura|MDX 2022-24|All|[Upstream](#upstream)|
|Acura|MDX 2022-24|All|[Community](#community)| |Acura|MDX 2022-24|All|[Community](#community)|
|Acura|MDX 2025|All except Type S|[Upstream](#upstream)| |Acura|MDX 2025|All except Type S|[Upstream](#upstream)|
|Acura|MDX Hybrid 2017-19|All|[Upstream](#upstream)|
|Acura|MDX Hybrid 2020|All|[Upstream](#upstream)|
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|[Upstream](#upstream)| |Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|[Upstream](#upstream)|
|Acura|RDX 2019-21|All|[Upstream](#upstream)| |Acura|RDX 2019-21|All|[Upstream](#upstream)|
|Acura|RDX 2022-25|All|[Community](#community)| |Acura|RDX 2022-25|All|[Community](#community)|
|Acura|RDX 2022-26|All|[Upstream](#upstream)|
|Acura|RLX 2017|Advance Package or Technology Package|[Community](#community)| |Acura|RLX 2017|Advance Package or Technology Package|[Community](#community)|
|Acura|TLX 2015-17|Advance Package|[Upstream](#upstream)|
|Acura|TLX 2015-17|Advance Package|[Community](#community)| |Acura|TLX 2015-17|Advance Package|[Community](#community)|
|Acura|TLX 2018-20|All|[Upstream](#upstream)|
|Acura|TLX 2018-20|All|[Community](#community)| |Acura|TLX 2018-20|All|[Community](#community)|
|Acura|TLX 2021|All|[Upstream](#upstream)| |Acura|TLX 2021|All|[Upstream](#upstream)|
|Acura|TLX 2022-23|All|[Community](#community)| |Acura|TLX 2022-23|All|[Community](#community)|
|Acura|TLX 2024-25|All|[Upstream](#upstream)|
|Acura|ZDX 2024|All|[Not compatible](#can-bus-security)| |Acura|ZDX 2024|All|[Not compatible](#can-bus-security)|
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
@@ -38,54 +26,14 @@
|Audi|A5 2016-24|All|[Not compatible](#flexray)| |Audi|A5 2016-24|All|[Not compatible](#flexray)|
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Audi|Q4 e-tron 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Audi|Q4 e-tron 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Audi|Q5 2017-24|All|[Not compatible](#flexray)| |Audi|Q5 2017-24|All|[Not compatible](#flexray)|
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Buick|Baby Enclave 2020-23|Driver Assist Package|[Upstream](#upstream)| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|[Upstream](#upstream)|
|Buick|LaCrosse 2017-19|Driver Confidence Package 2|[Upstream](#upstream)| |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|[Upstream](#upstream)|
|Buick|LaCrosse ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Buick|LaCrosse US ASCM Harness 2019|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Buick|Regal Essence 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Cadillac|ATS Premium Performance 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Cadillac|CT6 No-ACC 2016-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Cadillac|Escalade 2017|Driver Assist Package|[Upstream](#upstream)|
|Cadillac|Escalade ASCM Harness 2018|Driver Assist Package|[Upstream](#upstream)|
|Cadillac|Escalade ESV 2016|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|Cadillac|Escalade ESV 2019|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|Cadillac|Escalade ESV Platinum ASCM Harness 2019|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|Cadillac|XT4 2023|Driver Assist Package|[Upstream](#upstream)|
|Cadillac|XT4 No-ACC 2023|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Cadillac|XT5 2022|Driver Assist Package|[Upstream](#upstream)|
|Cadillac|XT5 No-ACC 2022|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Cadillac|XT6 2020|Driver Assist Package|[Upstream](#upstream)|
|Chevrolet|Blazer 2019-25|Driver Assist Package|[Upstream](#upstream)|
|Chevrolet|Bolt EV & EUV ACC 2022-23|Premier or Premier Redline Trim without Super Cruise Package|[Upstream](#upstream)|
|Chevrolet|Bolt EV & EUV ACC w Pedal 2022-23|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Bolt EV & EUV No-ACC 2022-23|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Bolt EV No-ACC 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Bolt EV No-ACC 2018-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Equinox No-ACC 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Malibu 2019|SDGM Harness (Optional SASCM)|[Upstream](#upstream)|
|Chevrolet|Malibu ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Malibu Hybrid No-ACC 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Malibu No-ACC 2023|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Malibu Premier 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Silverado 1500 2020-21|Safety Package II|[Upstream](#upstream)| |Chevrolet|Silverado 1500 2020-21|Safety Package II|[Upstream](#upstream)|
|Chevrolet|Silverado 1500 No-ACC 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Suburban Premier 2016-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Suburban Premier No-ACC 2016-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Trailblazer No-ACC 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Traverse 2022-23|RS, Premier, or High Country Trim|[Upstream](#upstream)|
|Chevrolet|TRAX 2024-25|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Volt 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Volt 2019|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|Chevrolet|Volt ASCM Harness 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Volt Camera Harness 2017-18|Flashed camera-forward integration with ACC|[Upstream](#upstream)|
|Chevrolet|Volt No-ACC 2016-18 (OBD Harness)|Redneck ACC|[Upstream](#upstream)|
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chrysler|Pacifica 2021-23|All|[Upstream](#upstream)| |Chrysler|Pacifica 2021-23|All|[Upstream](#upstream)|
@@ -93,10 +41,8 @@
|Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|comma|body|All|[Upstream](#upstream)| |comma|body|All|[Upstream](#upstream)|
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|CUPRA|Born 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|[Upstream](#upstream)| |Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|Ford|Edge 2022|Co-Pilot360 Assist+|[Upstream](#upstream)|
|Ford|Escape 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)| |Ford|Escape 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)|
|Ford|Escape 2023-24|Co-Pilot360 Assist+|[Upstream](#upstream)| |Ford|Escape 2023-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)| |Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)|
@@ -108,9 +54,8 @@
|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|[Upstream](#upstream)| |Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)| |Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)| |Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|Ford|F-150 Lightning 2022-25|Co-Pilot360 Assist 2.0|[Upstream](#upstream)| |Ford|Focus 2018|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|Ford|Focus 2018-22|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)| |Ford|Focus Hybrid 2018|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|Ford|Focus Hybrid 2018-22|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)| |Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)| |Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|Ford|Kuga Hybrid 2024|All|[Upstream](#upstream)| |Ford|Kuga Hybrid 2024|All|[Upstream](#upstream)|
@@ -120,14 +65,11 @@
|Ford|Maverick 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)| |Ford|Maverick 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
|Ford|Maverick Hybrid 2022|LARIAT Luxury|[Upstream](#upstream)| |Ford|Maverick Hybrid 2022|LARIAT Luxury|[Upstream](#upstream)|
|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)| |Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
|Ford|Mondeo 2014-22|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|Ford|Mustang Mach-E 2021-24|All|[Upstream](#upstream)| |Ford|Mustang Mach-E 2021-24|All|[Upstream](#upstream)|
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)| |Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|Ford|Transit 2025|Co-Pilot360 Assist+|[Upstream](#upstream)|
|Genesis|G70 2018|All|[Upstream](#upstream)| |Genesis|G70 2018|All|[Upstream](#upstream)|
|Genesis|G70 2019-21|All|[Upstream](#upstream)| |Genesis|G70 2019-21|All|[Upstream](#upstream)|
|Genesis|G70 2022-23|All|[Upstream](#upstream)| |Genesis|G70 2022-23|All|[Upstream](#upstream)|
|Genesis|G70 Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Community](community)|
|Genesis|G80 2017|All|[Upstream](#upstream)| |Genesis|G80 2017|All|[Upstream](#upstream)|
|Genesis|G80 2018-19|All|[Upstream](#upstream)| |Genesis|G80 2018-19|All|[Upstream](#upstream)|
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|[Upstream](#upstream)| |Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|[Upstream](#upstream)|
@@ -136,24 +78,14 @@
|Genesis|GV60 (Performance Trim) 2022-23|All|[Upstream](#upstream)| |Genesis|GV60 (Performance Trim) 2022-23|All|[Upstream](#upstream)|
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24|All|[Upstream](#upstream)| |Genesis|GV70 (2.5T Trim, without HDA II) 2022-24|All|[Upstream](#upstream)|
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23|All|[Upstream](#upstream)| |Genesis|GV70 (3.5T Trim, without HDA II) 2022-23|All|[Upstream](#upstream)|
|Genesis|GV70 Electrified 2026|All|[Upstream](#upstream)|
|Genesis|GV70 Electrified (Australia Only) 2022|All|[Upstream](#upstream)| |Genesis|GV70 Electrified (Australia Only) 2022|All|[Upstream](#upstream)|
|Genesis|GV70 Electrified (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)| |Genesis|GV70 Electrified (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|Genesis|GV80 2023|All|[Upstream](#upstream)| |Genesis|GV80 2023|All|[Upstream](#upstream)|
|Genesis|GV80 (3.5T Prestige Trim, with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|Genesis|GV80 Coupe (with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|GMC|Acadia 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|GMC|Acadia ASCM Harness 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|GMC|Sierra 1500 2020-21|Driver Alert Package II|[Upstream](#upstream)| |GMC|Sierra 1500 2020-21|Driver Alert Package II|[Upstream](#upstream)|
|GMC|Sierra 1500 No-ACC 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|[Dashcam mode](#dashcam)|
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|GMC|Yukon No-ACC 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Holden|Astra 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Honda|Accord 2016-17|Honda Sensing|[Upstream](#upstream)|
|Honda|Accord 2016-17|Honda Sensing|[Community](#community)| |Honda|Accord 2016-17|Honda Sensing|[Community](#community)|
|Honda|Accord 2018-22|All|[Upstream](#upstream)| |Honda|Accord 2018-22|All|[Upstream](#upstream)|
|Honda|Accord 2023-25|All|[Upstream](#upstream)| |Honda|Accord 2023-25|All|[Upstream](#upstream)|
|Honda|Accord Hybrid 2017|All|[Upstream](#upstream)|
|Honda|Accord Hybrid 2018-22|All|[Upstream](#upstream)| |Honda|Accord Hybrid 2018-22|All|[Upstream](#upstream)|
|Honda|Accord Hybrid 2023-25|All|[Upstream](#upstream)| |Honda|Accord Hybrid 2023-25|All|[Upstream](#upstream)|
|Honda|City (Brazil only) 2023|All|[Upstream](#upstream)| |Honda|City (Brazil only) 2023|All|[Upstream](#upstream)|
@@ -166,7 +98,6 @@
|Honda|Civic Hatchback Hybrid 2025-26|All|[Upstream](#upstream)| |Honda|Civic Hatchback Hybrid 2025-26|All|[Upstream](#upstream)|
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|[Upstream](#upstream)| |Honda|Civic Hatchback Hybrid (Europe only) 2023|All|[Upstream](#upstream)|
|Honda|Civic Hybrid 2025-26|All|[Upstream](#upstream)| |Honda|Civic Hybrid 2025-26|All|[Upstream](#upstream)|
|Honda|Clarity 2018-21|All|[Upstream](#upstream)|
|Honda|Clarity 2018-21|All|[Community](#community)| |Honda|Clarity 2018-21|All|[Community](#community)|
|Honda|CR-V 2015-16|Touring Trim|[Upstream](#upstream)| |Honda|CR-V 2015-16|Touring Trim|[Upstream](#upstream)|
|Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)| |Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)|
@@ -175,8 +106,6 @@
|Honda|CR-V Hybrid 2023-25|All|[Upstream](#upstream)| |Honda|CR-V Hybrid 2023-25|All|[Upstream](#upstream)|
|Honda|e 2020|All|[Upstream](#upstream)| |Honda|e 2020|All|[Upstream](#upstream)|
|Honda|Fit 2018-20|Honda Sensing|[Upstream](#upstream)| |Honda|Fit 2018-20|Honda Sensing|[Upstream](#upstream)|
|Honda|Fit (Taiwan) 2021|All|[Upstream](#upstream)|
|Honda|Fit (Taiwan) 2024-25|All|[Upstream](#upstream)|
|Honda|Freed 2020|Honda Sensing|[Upstream](#upstream)| |Honda|Freed 2020|Honda Sensing|[Upstream](#upstream)|
|Honda|HR-V 2019-22|Honda Sensing|[Upstream](#upstream)| |Honda|HR-V 2019-22|Honda Sensing|[Upstream](#upstream)|
|Honda|HR-V 2023-25|All|[Upstream](#upstream)| |Honda|HR-V 2023-25|All|[Upstream](#upstream)|
@@ -185,40 +114,27 @@
|Honda|N-Box 2018|All|[Upstream](#upstream)| |Honda|N-Box 2018|All|[Upstream](#upstream)|
|Honda|Odyssey 2018-20|Honda Sensing|[Upstream](#upstream)| |Honda|Odyssey 2018-20|Honda Sensing|[Upstream](#upstream)|
|Honda|Odyssey 2021-26|All|[Upstream](#upstream)| |Honda|Odyssey 2021-26|All|[Upstream](#upstream)|
|Honda|Odyssey (Singapore) 2021|Honda Sensing|[Upstream](#upstream)|
|Honda|Odyssey (Taiwan) 2018-19|Honda Sensing|[Upstream](#upstream)|
|Honda|Passport 2019-25|All|[Upstream](#upstream)| |Honda|Passport 2019-25|All|[Upstream](#upstream)|
|Honda|Passport 2026|All|[Upstream](#upstream)| |Honda|Passport 2026|All|[Upstream](#upstream)|
|Honda|Pilot 2016-22|Honda Sensing|[Upstream](#upstream)| |Honda|Pilot 2016-22|Honda Sensing|[Upstream](#upstream)|
|Honda|Pilot 2023-25|All|[Upstream](#upstream)| |Honda|Pilot 2023-25|All|[Upstream](#upstream)|
|Honda|Prelude 2026|All|[Upstream](#upstream)|
|Honda|Prologue 2024-25|All|[Not compatible](#can-bus-security)| |Honda|Prologue 2024-25|All|[Not compatible](#can-bus-security)|
|Honda|Ridgeline 2017-25|Honda Sensing|[Upstream](#upstream)| |Honda|Ridgeline 2017-25|Honda Sensing|[Upstream](#upstream)|
|Hyundai|Azera 2022|All|[Upstream](#upstream)| |Hyundai|Azera 2022|All|[Upstream](#upstream)|
|Hyundai|Azera Hybrid 2019|All|[Upstream](#upstream)| |Hyundai|Azera Hybrid 2019|All|[Upstream](#upstream)|
|Hyundai|Azera Hybrid 2020|All|[Upstream](#upstream)| |Hyundai|Azera Hybrid 2020|All|[Upstream](#upstream)|
|Hyundai|Azera Hybrid (with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|Hyundai|Bayon Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Community](community)|
|Hyundai|Custin 2023|All|[Upstream](#upstream)| |Hyundai|Custin 2023|All|[Upstream](#upstream)|
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Elantra 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Elantra Hybrid 2024-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Elantra Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|i30 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|i30 Hybrid 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|[Upstream](#upstream)| |Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|[Upstream](#upstream)|
|Hyundai|Ioniq 5 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)| |Hyundai|Ioniq 5 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|Hyundai|Ioniq 5 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)| |Hyundai|Ioniq 5 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|Hyundai|Ioniq 5 N (with HDA II) 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Ioniq 5 PE (with HDA II & LFA2) 2025-26|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|Hyundai|Ioniq 6 (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)| |Hyundai|Ioniq 6 (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|Hyundai|Ioniq 9 (with HDA II & LFA2) 2025-26|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Ioniq Electric 2020|All|[Upstream](#upstream)| |Hyundai|Ioniq Electric 2020|All|[Upstream](#upstream)|
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
@@ -227,68 +143,40 @@
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|[Upstream](#upstream)| |Hyundai|Ioniq Plug-in Hybrid 2020-22|All|[Upstream](#upstream)|
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Kona 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Dashcam mode](#dashcam)| |Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Dashcam mode](#dashcam)|
|Hyundai|Kona (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona Electric (without HDA II) 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona Hybrid (without HDA II) 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|Hyundai|Nexo 2021|All|[Upstream](#upstream)| |Hyundai|Nexo 2021|All|[Upstream](#upstream)|
|Hyundai|Palisade 2020-22|All|[Upstream](#upstream)| |Hyundai|Palisade 2020-22|All|[Upstream](#upstream)|
|Hyundai|Palisade 2023-25|HDA2|[Community](#community)| |Hyundai|Palisade 2023-24|HDA2|[Community](#community)|
|Hyundai|Palisade (with HDA II) 2023-25|Highway Driving Assist II|[Upstream](#upstream)|
|Hyundai|Palisade (without HDA II) 2023-25|Highway Driving Assist|[Upstream](#upstream)|
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Santa Cruz (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Santa Fe 2019-20|All|[Upstream](#upstream)| |Hyundai|Santa Fe 2019-20|All|[Upstream](#upstream)|
|Hyundai|Santa Fe 2021-23|All|[Upstream](#upstream)| |Hyundai|Santa Fe 2021-23|All|[Upstream](#upstream)|
|Hyundai|Santa Fe Hybrid 2022-23|All|[Upstream](#upstream)| |Hyundai|Santa Fe Hybrid 2022-23|All|[Upstream](#upstream)|
|Hyundai|Santa Fe Hybrid (with HDA II & LFA2) 2024-25|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|Hyundai|Santa Fe Hybrid (without HDA II, LFA2) 2025-26|Lane Follow Assist 2|[Upstream](#upstream)|
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|[Upstream](#upstream)| |Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|[Upstream](#upstream)|
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Sonata 2020-23|All|[Upstream](#upstream)| |Hyundai|Sonata 2020-23|All|[Upstream](#upstream)|
|Hyundai|Sonata (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Sonata Hybrid 2020-23|All|[Upstream](#upstream)| |Hyundai|Sonata Hybrid 2020-23|All|[Upstream](#upstream)|
|Hyundai|Sonata Hybrid (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Staria 2023|All|[Upstream](#upstream)| |Hyundai|Staria 2023|All|[Upstream](#upstream)|
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Tucson 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Tucson 2022|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Tucson 2023-24|All|[Upstream](#upstream)| |Hyundai|Tucson 2023-24|All|[Upstream](#upstream)|
|Hyundai|Tucson (without HDA II) 2025-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Tucson Hybrid 2022-24|All|[Upstream](#upstream)| |Hyundai|Tucson Hybrid 2022-24|All|[Upstream](#upstream)|
|Hyundai|Tucson Hybrid (without HDA II) 2025-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Tucson Plug-in Hybrid 2024|All|[Upstream](#upstream)| |Hyundai|Tucson Plug-in Hybrid 2024|All|[Upstream](#upstream)|
|Hyundai|Tucson Plug-in Hybrid (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Kia|Carnival 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Carnival 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Carnival 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Carnival (with HDA II) 2025|Highway Driving Assist II|[Upstream](#upstream)|
|Kia|Carnival Hybrid 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Carnival Hybrid 2026|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Carnival Hybrid (with HDA II) 2025-26|Highway Driving Assist II|[Upstream](#upstream)|
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Ceed 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|Kia|EV6 (Southeast Asia only) 2022-24|All|[Upstream](#upstream)| |Kia|EV6 (Southeast Asia only) 2022-24|All|[Upstream](#upstream)|
|Kia|EV6 (with HDA I) 2025|Highway Driving Assist I|[Upstream](#upstream)|
|Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)| |Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)| |Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|Kia|EV9 2025-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Forte 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|Kia|Forte Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Community](community)|
|Kia|K4 (with HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|K4 (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|K5 2021-24|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|K5 2021-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|K5 (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|[Upstream](#upstream)| |Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|[Upstream](#upstream)|
|Kia|Niro EV 2019|All|[Upstream](#upstream)| |Kia|Niro EV 2019|All|[Upstream](#upstream)|
@@ -310,25 +198,17 @@
|Kia|Optima Hybrid 2017|Advanced Smart Cruise Control|[Dashcam mode](#dashcam)| |Kia|Optima Hybrid 2017|Advanced Smart Cruise Control|[Dashcam mode](#dashcam)|
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Seltos 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Seltos 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Seltos Non-SCC 2023-24|No Smart Cruise Control (Non-SCC)|[Community](community)|
|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|[Upstream](#upstream)| |Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|[Upstream](#upstream)|
|Kia|Sorento 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Sorento 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Sorento 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Sorento 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Sorento (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Sorento Hybrid 2021-23|All|[Upstream](#upstream)| |Kia|Sorento Hybrid 2021-23|All|[Upstream](#upstream)|
|Kia|Sorento Hybrid 2026|All|[Upstream](#upstream)|
|Kia|Sorento Plug-in Hybrid 2022-23|All|[Upstream](#upstream)| |Kia|Sorento Plug-in Hybrid 2022-23|All|[Upstream](#upstream)|
|Kia|Sportage 2023-24|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Sportage 2023-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Sportage (without HDA II) 2026|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Sportage Hybrid 2026|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Kia|Stinger 2022-23|All|[Upstream](#upstream)| |Kia|Stinger 2022-23|All|[Upstream](#upstream)|
|Kia|Telluride 2020-22|All|[Upstream](#upstream)| |Kia|Telluride 2020-22|All|[Upstream](#upstream)|
|Kia|Telluride 2023-24|HDA2|[Community](#community)| |Kia|Telluride 2023-24|HDA2|[Community](#community)|
|Kia|Telluride (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|Kia|Telluride (without HDA II) 2023-25|Highway Driving Assist|[Upstream](#upstream)|
|Kia|XCeed Plug-in Hybrid 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|[Upstream](#upstream)| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|[Upstream](#upstream)|
|Lexus|ES 2017-18|All|[Upstream](#upstream)| |Lexus|ES 2017-18|All|[Upstream](#upstream)|
|Lexus|ES 2019-25|All|[Upstream](#upstream)| |Lexus|ES 2019-25|All|[Upstream](#upstream)|
@@ -363,8 +243,7 @@
|Mazda|CX-9 2016-20|All|[Dashcam mode](#dashcam)| |Mazda|CX-9 2016-20|All|[Dashcam mode](#dashcam)|
|Mazda|CX-9 2021-23|All|[Upstream](#upstream)| |Mazda|CX-9 2021-23|All|[Upstream](#upstream)|
|Nissan|Altima 2019-20, 2024|ProPILOT Assist|[Upstream](#upstream)| |Nissan|Altima 2019-20, 2024|ProPILOT Assist|[Upstream](#upstream)|
|Nissan|Leaf 2018-25|ProPILOT Assist|[Upstream](#upstream)| |Nissan|Leaf 2018-23|ProPILOT Assist|[Upstream](#upstream)|
|Nissan|Leaf Instrument Cluster 2018-25|ProPILOT Assist|[Upstream](#upstream)|
|Nissan|Rogue 2018-20|ProPILOT Assist|[Upstream](#upstream)| |Nissan|Rogue 2018-20|ProPILOT Assist|[Upstream](#upstream)|
|Nissan|X-Trail 2017|ProPILOT Assist|[Upstream](#upstream)| |Nissan|X-Trail 2017|ProPILOT Assist|[Upstream](#upstream)|
|Peugeot|208 2019-25|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)| |Peugeot|208 2019-25|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
@@ -373,36 +252,30 @@
|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| |Ram|2500 2020-24|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)|
|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| |Ram|3500 2019-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)|
|Rivian|R1S 2022-24|All|[Upstream](#upstream)| |Rivian|R1S 2022-24|All|[Upstream](#upstream)|
|Rivian|R1S 2025|All|[Upstream](#upstream)|
|Rivian|R1T 2022-24|All|[Upstream](#upstream)| |Rivian|R1T 2022-24|All|[Upstream](#upstream)|
|Rivian|R1T 2025|All|[Upstream](#upstream)|
|SEAT|Alhambra 2018-20|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)| |SEAT|Alhambra 2018-20|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Subaru|Ascent 2019-21|All|[Upstream](#upstream)| |Subaru|Ascent 2019-21|All|[Upstream](#upstream)|
|Subaru|Ascent 2023-25|All|[Upstream](#upstream)| |Subaru|Ascent 2023|All|[Dashcam mode](#dashcam)|
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|[Upstream](#upstream)|
|Subaru|Crosstrek 2025|All|[Upstream](#upstream)|
|Subaru|Crosstrek Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| |Subaru|Crosstrek Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|Subaru|Forester 2017-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| |Subaru|Forester 2017-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|Subaru|Forester 2019-21|All|[Upstream](#upstream)| |Subaru|Forester 2019-21|All|[Upstream](#upstream)|
|Subaru|Forester 2022-24|All|[Upstream](#upstream)| |Subaru|Forester 2022-24|All|[Dashcam mode](#dashcam)|
|Subaru|Forester Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| |Subaru|Forester Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|Subaru|Impreza 2017-19|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|Impreza 2017-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|Subaru|Impreza 2020-22|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|Impreza 2020-22|EyeSight Driver Assistance|[Upstream](#upstream)|
|Subaru|Legacy 2015-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| |Subaru|Legacy 2015-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|Subaru|Legacy 2020-22|All|[Upstream](#upstream)| |Subaru|Legacy 2020-22|All|[Upstream](#upstream)|
|Subaru|Legacy 2025|All|[Upstream](#upstream)|
|Subaru|Outback 2015-17|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| |Subaru|Outback 2015-17|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|Subaru|Outback 2018-19|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| |Subaru|Outback 2018-19|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|Subaru|Outback 2020-22|All|[Upstream](#upstream)| |Subaru|Outback 2020-22|All|[Upstream](#upstream)|
|Subaru|Outback 2023-24|All|[Upstream](#upstream)| |Subaru|Outback 2023|All|[Dashcam mode](#dashcam)|
|Subaru|Solterra 2023-25|Any|[Not compatible](#can-bus-security)| |Subaru|Solterra 2023-25|Any|[Not compatible](#can-bus-security)|
|Subaru|XV 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|XV 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|Subaru|XV 2020-21|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|XV 2020-21|EyeSight Driver Assistance|[Upstream](#upstream)|
|Škoda|Enyaq 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Škoda|Enyaq 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Škoda|Kamiq 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Škoda|Kamiq 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Škoda|Karoq 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Škoda|Karoq 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
@@ -413,8 +286,7 @@
|Škoda|Scala 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Škoda|Scala 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Tesla|Model 3 (with HW3) 2019-23|All|[Upstream](#upstream)| |Tesla|Model 3 (with HW3) 2019-23|All|[Upstream](#upstream)|
|Tesla|Model 3 (with HW4) 2024-26|All|[Upstream](#upstream)| |Tesla|Model 3 (with HW4) 2024-25|All|[Upstream](#upstream)|
|Tesla|Model S (Pre-AP) 2012-14|All|[Community](#community)|
|Tesla|Model X (with HW4) 2024|All|[Dashcam mode](#dashcam)| |Tesla|Model X (with HW4) 2024|All|[Dashcam mode](#dashcam)|
|Tesla|Model Y (with HW3) 2020-23|All|[Upstream](#upstream)| |Tesla|Model Y (with HW3) 2020-23|All|[Upstream](#upstream)|
|Tesla|Model Y (with HW4) 2024-25|All|[Upstream](#upstream)| |Tesla|Model Y (with HW4) 2024-25|All|[Upstream](#upstream)|
@@ -449,7 +321,6 @@
|Toyota|Highlander 2025|Any|[Not compatible](#can-bus-security)| |Toyota|Highlander 2025|Any|[Not compatible](#can-bus-security)|
|Toyota|Highlander Hybrid 2017-19|All|[Upstream](#upstream)| |Toyota|Highlander Hybrid 2017-19|All|[Upstream](#upstream)|
|Toyota|Highlander Hybrid 2020-23|All|[Upstream](#upstream)| |Toyota|Highlander Hybrid 2020-23|All|[Upstream](#upstream)|
|Toyota|Matrix Retrofit 2005|Custom retrofit|[Community](#community)|
|Toyota|Mirai 2021|All|[Upstream](#upstream)| |Toyota|Mirai 2021|All|[Upstream](#upstream)|
|Toyota|Prius 2016|Toyota Safety Sense P|[Upstream](#upstream)| |Toyota|Prius 2016|Toyota Safety Sense P|[Upstream](#upstream)|
|Toyota|Prius 2017-20|All|[Upstream](#upstream)| |Toyota|Prius 2017-20|All|[Upstream](#upstream)|
@@ -471,7 +342,7 @@
|Toyota|RAV4 Prime 2024-25|Any|[Not compatible](#can-bus-security)| |Toyota|RAV4 Prime 2024-25|Any|[Not compatible](#can-bus-security)|
|Toyota|Sequoia 2023-25|Any|[Not compatible](#can-bus-security)| |Toyota|Sequoia 2023-25|Any|[Not compatible](#can-bus-security)|
|Toyota|Sienna 2018-20|All|[Upstream](#upstream)| |Toyota|Sienna 2018-20|All|[Upstream](#upstream)|
|Toyota|Sienna 2021-25|All|[Community](#community)| |Toyota|Sienna 2021-23|All|[Community](#community)|
|Toyota|Sienna 2024-25|Any|[Not compatible](#can-bus-security)| |Toyota|Sienna 2024-25|Any|[Not compatible](#can-bus-security)|
|Toyota|Tundra 2022-25|Any|[Not compatible](#can-bus-security)| |Toyota|Tundra 2022-25|Any|[Not compatible](#can-bus-security)|
|Toyota|Venza 2021-25|Any|[Not compatible](#can-bus-security)| |Toyota|Venza 2021-25|Any|[Not compatible](#can-bus-security)|
@@ -498,11 +369,6 @@
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|ID.3 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|ID.3 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|ID.4 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|ID.4 2024-25|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|ID.5 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|Jetta 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)| |Volkswagen|Jetta 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
-5
View File
@@ -132,7 +132,6 @@ class CANParser:
self.dbc: DBC = DBC(dbc_name) self.dbc: DBC = DBC(dbc_name)
self.vl: dict[int | str, dict[str, float]] = VLDict(self) self.vl: dict[int | str, dict[str, float]] = VLDict(self)
self.vl_raw: dict[int | str, bytes] = {}
self.vl_all: dict[int | str, dict[str, list[float]]] = {} self.vl_all: dict[int | str, dict[str, list[float]]] = {}
self.ts_nanos: dict[int | str, dict[str, int]] = {} self.ts_nanos: dict[int | str, dict[str, int]] = {}
self.addresses: set[int] = set() self.addresses: set[int] = set()
@@ -167,8 +166,6 @@ class CANParser:
signals_dict = {s: 0.0 for s in signal_names} signals_dict = {s: 0.0 for s in signal_names}
dict.__setitem__(self.vl, msg.address, signals_dict) dict.__setitem__(self.vl, msg.address, signals_dict)
dict.__setitem__(self.vl, msg.name, signals_dict) dict.__setitem__(self.vl, msg.name, signals_dict)
self.vl_raw[msg.address] = bytes(msg.size)
self.vl_raw[msg.name] = bytes(msg.size)
self.vl_all[msg.address] = defaultdict(list) self.vl_all[msg.address] = defaultdict(list)
self.vl_all[msg.name] = self.vl_all[msg.address] self.vl_all[msg.name] = self.vl_all[msg.address]
self.ts_nanos[msg.address] = {s: 0 for s in signal_names} self.ts_nanos[msg.address] = {s: 0 for s in signal_names}
@@ -250,8 +247,6 @@ class CANParser:
vl_addr[sig.name] = state.vals[i] vl_addr[sig.name] = state.vals[i]
vl_all_addr[sig.name] = state.all_vals[i] vl_all_addr[sig.name] = state.all_vals[i]
ts_addr[sig.name] = state.timestamps[-1] ts_addr[sig.name] = state.timestamps[-1]
self.vl_raw[address] = bytes(dat)
self.vl_raw[state.name] = bytes(dat)
if not bus_empty: if not bus_empty:
self.last_nonempty_nanos = t self.last_nonempty_nanos = t
@@ -1,6 +1,5 @@
import copy import copy
from opendbc.can import CANPacker, CANParser from opendbc.can import CANPacker, CANParser
from opendbc.car.honda.hondacan import honda_checksum
class TestCanChecksums: class TestCanChecksums:
@@ -91,13 +90,6 @@ class TestCanChecksums:
assert parser.vl['LKAS_HUD']['CHECKSUM'] == std assert parser.vl['LKAS_HUD']['CHECKSUM'] == std
assert parser.vl['LKAS_HUD_A']['CHECKSUM'] == ext assert parser.vl['LKAS_HUD_A']['CHECKSUM'] == ext
def test_honda_canfd_checksum_offset_is_scoped_to_mvl_messages(self):
# Existing high-ID Honda messages retain the legacy extended-ID offset;
# only the Accord MVL replacement-radar IDs use the CAN-FD offset.
payload = bytearray(8)
assert honda_checksum(0xF31AA54, None, payload) == 11 # existing radarless LKAS_HUD_2
assert honda_checksum(0xF31AA52, None, payload) == 4 # Accord MVL RADAR_LEAD2
def verify_volkswagen_mqb_crc(self, subtests, msg_name: str, msg_addr: int, test_messages: list[bytes], counter_field: str = 'COUNTER'): def verify_volkswagen_mqb_crc(self, subtests, msg_name: str, msg_addr: int, test_messages: list[bytes], counter_field: str = 'COUNTER'):
"""Test AUTOSAR E2E Profile 2 CRCs""" """Test AUTOSAR E2E Profile 2 CRCs"""
assert len(test_messages) == 16 # All counter values must be tested assert len(test_messages) == 16 # All counter values must be tested
-11
View File
@@ -374,7 +374,6 @@ struct CarControl {
brake @1: Float32; # [0.0, 1.0] brake @1: Float32; # [0.0, 1.0]
torqueOutputCan @8: Float32; # value sent over can to the car torqueOutputCan @8: Float32; # value sent over can to the car
speed @6: Float32; # m/s speed @6: Float32; # m/s
lateralControlMode @9: LateralControlMode;
enum LongControlState @0xe40f3a917d908282{ enum LongControlState @0xe40f3a917d908282{
off @0; off @0;
@@ -382,13 +381,6 @@ struct CarControl {
stopping @2; stopping @2;
starting @3; starting @3;
} }
enum LateralControlMode {
inactive @0;
torque @1;
angle @2;
torqueRecovering @3;
}
} }
struct CruiseControl { struct CruiseControl {
@@ -518,7 +510,6 @@ struct CarParams {
startingState @70 :Bool; # Does this car make use of special starting state startingState @70 :Bool; # Does this car make use of special starting state
steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds
lateralSmoothSeconds @78 :Float32; # Speed-scheduled curvature smoothing used by select angle-control platforms
longitudinalActuatorDelay @58 :Float32; # Gas/Brake actuator delay in seconds longitudinalActuatorDelay @58 :Float32; # Gas/Brake actuator delay in seconds
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control? openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
carVin @38 :Text; # VIN number queried during fingerprinting carVin @38 :Text; # VIN number queried during fingerprinting
@@ -644,8 +635,6 @@ struct CarParams {
fcaGiorgio @32; fcaGiorgio @32;
rivian @33; rivian @33;
volkswagenMeb @34; volkswagenMeb @34;
teslaPreAP @35;
volvo @36;
} }
enum SteerControlType { enum SteerControlType {
+2 -17
View File
@@ -66,7 +66,7 @@ def _normalize_forced_candidate(candidate: str | None) -> str | None:
return LEGACY_FORCED_CANDIDATE_MAP.get(candidate, candidate) return LEGACY_FORCED_CANDIDATE_MAP.get(candidate, candidate)
def _normalize_gm_bolt_candidate(candidate: str | None, fingerprints: dict[int, dict], vin: str | None = None) -> str | None: def _normalize_gm_bolt_candidate(candidate: str | None, fingerprints: dict[int, dict]) -> str | None:
""" """
Normalize ambiguous/mismatched Bolt candidates using robust PT message signatures. Normalize ambiguous/mismatched Bolt candidates using robust PT message signatures.
This guards against occasional wrong variant selection causing persistent canError. This guards against occasional wrong variant selection causing persistent canError.
@@ -79,22 +79,7 @@ def _normalize_gm_bolt_candidate(candidate: str | None, fingerprints: dict[int,
msg_304_len = pt.get(304) # 8 on 2017 Gen1, 1 on 2018-2021 Gen1 msg_304_len = pt.get(304) # 8 on 2017 Gen1, 1 on 2018-2021 Gen1
has_pedal = 513 in pt has_pedal = 513 in pt
# The 2022-23 Bolt ACC, pedal, and CC variants share the same FPv1
# fingerprint. Recover an ambiguous match when the observed traffic
# matches the Bolt family and the VIN confirms model year 2022/2023.
bolt_2022_2023_signature = (
pt.get(190) == 7 and
msg_211_len == 3 and
pt.get(566) == 8 and
pt.get(458) == 5
)
vin_year = vin[9] if isinstance(vin, str) and len(vin) > 9 else None
# VIN model-year codes: N=2022, P=2023.
if candidate is None and bolt_2022_2023_signature and vin_year in ("N", "P"):
return "CHEVROLET_BOLT_ACC_2022_2023_PEDAL" if has_pedal else "CHEVROLET_BOLT_ACC_2022_2023"
# If detection failed entirely but the signature is clearly Bolt, recover to a sane default. # If detection failed entirely but the signature is clearly Bolt, recover to a sane default.
if candidate is None and 170 in pt and 188 in pt and msg_211_len in (2, 3): if candidate is None and 170 in pt and 188 in pt and msg_211_len in (2, 3):
if msg_211_len == 3: if msg_211_len == 3:
return "CHEVROLET_BOLT_ACC_2022_2023_PEDAL" if has_pedal else "CHEVROLET_BOLT_ACC_2022_2023" return "CHEVROLET_BOLT_ACC_2022_2023_PEDAL" if has_pedal else "CHEVROLET_BOLT_ACC_2022_2023"
@@ -294,7 +279,7 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, alpha_long_allowed: bool, def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, alpha_long_allowed: bool,
is_release: bool, params: Params, num_pandas: int = 1, cached_params: CarParamsT | None = None, starpilot_toggles: SimpleNamespace = None): is_release: bool, params: Params, num_pandas: int = 1, cached_params: CarParamsT | None = None, starpilot_toggles: SimpleNamespace = None):
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params) candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params)
candidate = _normalize_gm_bolt_candidate(candidate, fingerprints, vin) candidate = _normalize_gm_bolt_candidate(candidate, fingerprints)
candidate = _normalize_gm_volt_candidate(candidate, fingerprints) candidate = _normalize_gm_volt_candidate(candidate, fingerprints)
candidate = _normalize_forced_candidate(candidate) candidate = _normalize_forced_candidate(candidate)
fingerprinted_candidate = candidate fingerprinted_candidate = candidate
+5 -13
View File
@@ -23,11 +23,9 @@ def ecu_log(msg):
pass pass
def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_req=b'\x28\x83\x01', timeout=0.1, retry=10, reset=False, def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_req=b'\x28\x83\x01', timeout=0.1, retry=10, reset=False):
require_response=False, diag_request=EXT_DIAG_REQUEST, diag_response=EXT_DIAG_RESPONSE, response_offset=0x8):
"""Silence an ECU by disabling sending and receiving messages using UDS 0x28. """Silence an ECU by disabling sending and receiving messages using UDS 0x28.
The ECU will stay silent as long as openpilot keeps sending Tester Present. The ECU will stay silent as long as openpilot keeps sending Tester Present.
Set require_response for takeovers that must fail closed unless the ECU confirms communication control.
This is used to disable the radar in some cars. Openpilot will emulate the radar. This is used to disable the radar in some cars. Openpilot will emulate the radar.
WARNING: THIS DISABLES AEB!""" WARNING: THIS DISABLES AEB!"""
@@ -36,8 +34,7 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
if reset: if reset:
try: try:
ecu_log("sending ECU reset before communication control...") ecu_log("sending ECU reset before communication control...")
reset_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [RESET_REQUEST], [RESET_RESPONSE], reset_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [RESET_REQUEST], [RESET_RESPONSE])
response_offset=response_offset)
reset_query.get_data(timeout=timeout) reset_query.get_data(timeout=timeout)
time.sleep(0.2) time.sleep(0.2)
except Exception as e: except Exception as e:
@@ -48,8 +45,7 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
try: try:
# Enter extended diagnostic session # Enter extended diagnostic session
ecu_log(f"attempt {i+1}/{retry}: diag session...") ecu_log(f"attempt {i+1}/{retry}: diag session...")
query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [diag_request], [diag_response], query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [EXT_DIAG_REQUEST], [EXT_DIAG_RESPONSE])
response_offset=response_offset)
for _, _ in query.get_data(timeout).items(): for _, _ in query.get_data(timeout).items():
ecu_log("diag session OK") ecu_log("diag session OK")
@@ -59,15 +55,14 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
# Send CC command and log the response # Send CC command and log the response
ecu_log("sending CC...") ecu_log("sending CC...")
cc_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [com_cont_req], [b''], cc_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [com_cont_req], [b''])
response_offset=response_offset)
cc_response = cc_query.get_data(timeout) cc_response = cc_query.get_data(timeout)
# Log what we got back # Log what we got back
cc_success = False cc_success = False
cc_rejected = False cc_rejected = False
cc_nrc = None cc_nrc = None
for (_rx_addr, _), data in cc_response.items(): for (rx_addr, _), data in cc_response.items():
ecu_log(f"CC response: {data.hex() if data else 'empty'}") ecu_log(f"CC response: {data.hex() if data else 'empty'}")
# Check for positive response (0x68 = 0x28 + 0x40) # Check for positive response (0x68 = 0x28 + 0x40)
if len(data) >= 1 and data[0] == 0x68: if len(data) >= 1 and data[0] == 0x68:
@@ -98,9 +93,6 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
# ECU explicitly rejected - don't retry, it won't work # ECU explicitly rejected - don't retry, it won't work
ecu_log("=== ECU DISABLE REJECTED ===") ecu_log("=== ECU DISABLE REJECTED ===")
return False return False
elif require_response:
ecu_log("CC response required but none received; retrying...")
continue
else: else:
# No response - consider it sent (ECU might have stopped responding) # No response - consider it sent (ECU might have stopped responding)
ecu_log("=== ECU DISABLE SENT (no response) ===") ecu_log("=== ECU DISABLE SENT (no response) ===")
@@ -142,7 +142,6 @@ class CarHarness(EnumBase):
ford_q3 = BaseCarHarness("Ford Q3 connector") ford_q3 = BaseCarHarness("Ford Q3 connector")
ford_q4 = BaseCarHarness("Ford Q4 connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler]) ford_q4 = BaseCarHarness("Ford Q4 connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
rivian = BaseCarHarness("Rivian A connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler]) rivian = BaseCarHarness("Rivian A connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
rivian_b = BaseCarHarness("Rivian B connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
tesla_a = BaseCarHarness("Tesla A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler]) tesla_a = BaseCarHarness("Tesla A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
tesla_b = BaseCarHarness("Tesla B connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler]) tesla_b = BaseCarHarness("Tesla B connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
psa_a = BaseCarHarness("PSA A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler]) psa_a = BaseCarHarness("PSA A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
+1 -1
View File
@@ -55,7 +55,7 @@ class CAR(Platforms):
EXTRA_HYUNDAI = ExtraPlatformConfig( EXTRA_HYUNDAI = ExtraPlatformConfig(
[ [
CommunityCarDocs("Hyundai Palisade 2023-25", package="HDA2"), CommunityCarDocs("Hyundai Palisade 2023-24", package="HDA2"),
CommunityCarDocs("Kia Telluride 2023-24", package="HDA2"), CommunityCarDocs("Kia Telluride 2023-24", package="HDA2"),
], ],
) )
-1
View File
@@ -264,7 +264,6 @@ MIGRATION = {
"GENESIS G70 2020": HYUNDAI.GENESIS_G70_2020, "GENESIS G70 2020": HYUNDAI.GENESIS_G70_2020,
"GENESIS GV70 1ST GEN": HYUNDAI.GENESIS_GV70_1ST_GEN, "GENESIS GV70 1ST GEN": HYUNDAI.GENESIS_GV70_1ST_GEN,
"GENESIS GV70 ELECTRIFIED 2026": HYUNDAI.GENESIS_GV70_ELECTRIFIED_2ND_GEN, "GENESIS GV70 ELECTRIFIED 2026": HYUNDAI.GENESIS_GV70_ELECTRIFIED_2ND_GEN,
"GENESIS GV70 2026": HYUNDAI.GENESIS_GV70_2026,
"GENESIS G80 2017": HYUNDAI.GENESIS_G80, "GENESIS G80 2017": HYUNDAI.GENESIS_G80,
"GENESIS G90 2017": HYUNDAI.GENESIS_G90, "GENESIS G90 2017": HYUNDAI.GENESIS_G90,
"GENESIS GV80 2023": HYUNDAI.GENESIS_GV80, "GENESIS GV80 2023": HYUNDAI.GENESIS_GV80,
+26 -72
View File
@@ -6,8 +6,6 @@ from opendbc.car.lateral import ISO_LATERAL_ACCEL, apply_std_steer_angle_limits
from opendbc.car.ford import fordcan from opendbc.car.ford import fordcan
from opendbc.car.ford.values import CarControllerParams, FordFlags, CAR from opendbc.car.ford.values import CarControllerParams, FordFlags, CAR
from opendbc.car.interfaces import CarControllerBase, V_CRUISE_MAX from opendbc.car.interfaces import CarControllerBase, V_CRUISE_MAX
from openpilot.starpilot.car.ford import fordcan as starpilot_fordcan
from openpilot.starpilot.car.ford.lateral import FordLateralController, FordLateralMode, FordLateralResult
LongCtrlState = structs.CarControl.Actuators.LongControlState LongCtrlState = structs.CarControl.Actuators.LongControlState
VisualAlert = structs.CarControl.HUDControl.VisualAlert VisualAlert = structs.CarControl.HUDControl.VisualAlert
@@ -82,9 +80,6 @@ class CarController(CarControllerBase):
self.steer_alert_last = False self.steer_alert_last = False
self.lead_distance_bars_last = None self.lead_distance_bars_last = None
self.distance_bar_frame = 0 self.distance_bar_frame = 0
self.ford_lateral = None if CP.flags & FordFlags.LKA_STEERING else FordLateralController(CP)
self.ford_shadow_curvature = 0.0
self.ford_lateral_announced_mode = FordLateralMode.native
def update(self, CC, CS, now_nanos, starpilot_toggles): def update(self, CC, CS, now_nanos, starpilot_toggles):
can_sends = [] can_sends = []
@@ -96,9 +91,6 @@ class CarController(CarControllerBase):
steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw)
fcw_alert = hud_control.visualAlert == VisualAlert.fcw fcw_alert = hud_control.visualAlert == VisualAlert.fcw
if self.ford_lateral is not None:
self.ford_lateral.update_inputs()
### acc buttons ### ### acc buttons ###
if CC.cruiseControl.cancel: if CC.cruiseControl.cancel:
can_sends.append(fordcan.create_button_msg(self.packer, self.CAN.camera, CS.buttons_stock_values, cancel=True)) can_sends.append(fordcan.create_button_msg(self.packer, self.CAN.camera, CS.buttons_stock_values, cancel=True))
@@ -136,70 +128,38 @@ class CarController(CarControllerBase):
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN, active=lka_active, apply_angle=self.apply_angle_last, can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN, active=lka_active, apply_angle=self.apply_angle_last,
direction=direction, ramp_type=ramp_type, curvature=-self.apply_curvature_last)) direction=direction, ramp_type=ramp_type, curvature=-self.apply_curvature_last))
else: else:
lateral_mode = self.ford_lateral.mode # send steer msg at 20Hz
lateral_mode_ready = lateral_mode == self.ford_lateral_announced_mode if (self.frame % CarControllerParams.STEER_STEP) == 0:
# Bronco and some other cars consistently overshoot curv requests
# Keep the original Ford path available without changing its command behavior. # Apply some deadzone + smoothing convergence to avoid oscillations
if lateral_mode == FordLateralMode.native: if self.CP.carFingerprint in (CAR.FORD_BRONCO_SPORT_MK1, CAR.FORD_F_150_MK14):
if (self.frame % CarControllerParams.STEER_STEP) == 0: self.anti_overshoot_curvature_last = anti_overshoot(actuators.curvature, self.anti_overshoot_curvature_last, CS.out.vEgoRaw)
if not lateral_mode_ready: apply_curvature = self.anti_overshoot_curvature_last
self.apply_curvature_last = 0.0
apply_curvature = 0.0
elif self.CP.carFingerprint in (CAR.FORD_BRONCO_SPORT_MK1, CAR.FORD_F_150_MK14):
self.anti_overshoot_curvature_last = anti_overshoot(
actuators.curvature, self.anti_overshoot_curvature_last, CS.out.vEgoRaw)
apply_curvature = self.anti_overshoot_curvature_last
else:
apply_curvature = actuators.curvature
current_curvature = -CS.out.yawRate / max(CS.out.vEgoRaw, 0.1)
self.apply_curvature_last = apply_ford_curvature_limits(
apply_curvature, self.apply_curvature_last, current_curvature,
CS.out.vEgoRaw, 0., CC.latActive and lateral_mode_ready, self.CP)
if self.CP.flags & FordFlags.CANFD:
mode = 1 if CC.latActive and lateral_mode_ready else 0
counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10
can_sends.append(fordcan.create_lat_ctl2_msg(
self.packer, self.CAN, mode, 0., 0., -self.apply_curvature_last, 0., counter))
else:
can_sends.append(fordcan.create_lat_ctl_msg(
self.packer, self.CAN, CC.latActive and lateral_mode_ready, 0., 0., -self.apply_curvature_last, 0.))
elif (self.frame % CarControllerParams.STEER_STEP) == 0:
if not lateral_mode_ready:
lateral = FordLateralResult(shadow_curvature=self.ford_lateral._current_curvature(CS))
elif lateral_mode == FordLateralMode.angle:
lateral = self.ford_lateral.update_angle(CC, CS, actuators)
else: else:
lateral = self.ford_lateral.update_curvature(CC, CS, actuators) apply_curvature = actuators.curvature
# apply rate limits, curvature error limit, and clip to signal range
current_curvature = -CS.out.yawRate / max(CS.out.vEgoRaw, 0.1)
self.apply_curvature_last = apply_ford_curvature_limits(apply_curvature, self.apply_curvature_last, current_curvature,
CS.out.vEgoRaw, 0., CC.latActive, self.CP)
self.apply_curvature_last = lateral.curvature
self.ford_shadow_curvature = lateral.shadow_curvature
if self.CP.flags & FordFlags.CANFD: if self.CP.flags & FordFlags.CANFD:
# TODO: extended mode
# Ford uses four individual signals to dictate how to drive to the car. Curvature alone (limited to 0.02m/s^2)
# can actuate the steering for a large portion of any lateral movements. However, in order to get further control on
# steer actuation, the other three signals are necessary. Ford controls vehicles differently than most other makes.
# A detailed explanation on ford control can be found here:
# https://www.f150gen14.com/forum/threads/introducing-bluepilot-a-ford-specific-fork-for-comma3x-openpilot.24241/#post-457706
mode = 1 if CC.latActive else 0
counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10 counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10
can_sends.append(starpilot_fordcan.create_lat_ctl2_msg( can_sends.append(fordcan.create_lat_ctl2_msg(self.packer, self.CAN, mode, 0., 0., -self.apply_curvature_last, 0., counter))
self.packer, self.CAN, 1 if lateral.active else 0,
lateral.ramp_type, lateral.precision_type,
-lateral.path_offset, -lateral.path_angle,
-lateral.curvature, -lateral.curvature_rate, counter))
else: else:
can_sends.append(starpilot_fordcan.create_lat_ctl_msg( can_sends.append(fordcan.create_lat_ctl_msg(self.packer, self.CAN, CC.latActive, 0., 0., -self.apply_curvature_last, 0.))
self.packer, self.CAN, lateral.active,
lateral.ramp_type, lateral.precision_type,
-lateral.path_offset, -lateral.path_angle,
-lateral.curvature, -lateral.curvature_rate))
# send lka msg at 33Hz
if (self.frame % CarControllerParams.LKA_STEP) == 0: if (self.frame % CarControllerParams.LKA_STEP) == 0:
if lateral_mode == FordLateralMode.native: can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN))
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN))
else:
angle_mode = lateral_mode == FordLateralMode.angle
shadow_curvature = -self.ford_lateral._current_curvature(CS)
if angle_mode:
shadow_curvature = -self.ford_shadow_curvature
can_sends.append(starpilot_fordcan.create_lka_msg(
self.packer, self.CAN, angle_mode=angle_mode, shadow_curvature=shadow_curvature))
self.ford_lateral_announced_mode = lateral_mode
### longitudinal control ### ### longitudinal control ###
# send acc msg at 50Hz # send acc msg at 50Hz
@@ -255,15 +215,9 @@ class CarController(CarControllerBase):
if (self.frame % CarControllerParams.ACC_UI_STEP) == 0 or send_ui: if (self.frame % CarControllerParams.ACC_UI_STEP) == 0 or send_ui:
show_distance_bars = self.frame - self.distance_bar_frame < 400 show_distance_bars = self.frame - self.distance_bar_frame < 400
hands_free_cluster = bool(
self.ford_lateral is not None
and self.ford_lateral.mode != FordLateralMode.native
and self.ford_lateral.mode == self.ford_lateral_announced_mode
and self.ford_lateral.hands_free_cluster_enabled)
can_sends.append(fordcan.create_acc_ui_msg(self.packer, self.CAN, self.CP, main_on, CC.latActive, can_sends.append(fordcan.create_acc_ui_msg(self.packer, self.CAN, self.CP, main_on, CC.latActive,
fcw_alert, CS.out.cruiseState.standstill, show_distance_bars, fcw_alert, CS.out.cruiseState.standstill, show_distance_bars,
hud_control, CS.acc_tja_status_stock_values, hud_control, CS.acc_tja_status_stock_values))
hands_free_cluster))
self.main_on_last = main_on self.main_on_last = main_on
self.lkas_enabled_last = CC.latActive self.lkas_enabled_last = CC.latActive
+10 -160
View File
@@ -4,7 +4,6 @@ from opendbc.car import Bus, create_button_events, structs
from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.ford.fordcan import CanBus from opendbc.car.ford.fordcan import CanBus
from opendbc.car.ford.values import DBC, CarControllerParams, FordFlags from opendbc.car.ford.values import DBC, CarControllerParams, FordFlags
from opendbc.car.gps import get_car_gps_config
from opendbc.car.interfaces import CarStateBase from opendbc.car.interfaces import CarStateBase
ButtonType = structs.CarState.ButtonEvent.Type ButtonType = structs.CarState.ButtonEvent.Type
@@ -17,71 +16,26 @@ class CarState(CarStateBase):
super().__init__(CP, FPCP) super().__init__(CP, FPCP)
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt]) can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
if CP.transmissionType == TransmissionType.automatic: if CP.transmissionType == TransmissionType.automatic:
if CP.flags & FordFlags.CANFD: self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"]
self.shifter_values = can_define.dv["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"]
elif CP.flags & FordFlags.ALT_STEER_ANGLE:
self.shifter_values = can_define.dv["TransGearData"]["GearLvrPos_D_Actl"]
else:
self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"]
self.distance_button = 0 self.distance_button = 0
self.lc_button = 0 self.lc_button = 0
self.lkas_available = False self.lkas_available = False
self.lateral_motion_control = None self.lateral_motion_control = None
self.lateral_control_status = None
self.steering_angle_offset_deg = 0.0
self.car_gps_config = get_car_gps_config(CP)
self.car_gps_supported = self.car_gps_config is not None
self.car_gps = None
self._car_gps_timestamp_nanos = 0
def _update_car_gps(self, cp) -> None:
if self.car_gps_config is None:
return
timestamps = [max(cp.ts_nanos[name].values(), default=0) for name in self.car_gps_config.messages]
if not all(timestamps) or max(timestamps) - min(timestamps) > 2_000_000_000:
return
timestamp_nanos = max(timestamps)
if timestamp_nanos <= self._car_gps_timestamp_nanos:
return
gps = self.car_gps_config.decoder(*(cp.vl[name] for name in self.car_gps_config.messages))
if gps is not None:
gps["timestamp_nanos"] = timestamp_nanos
self.car_gps = gps
self._car_gps_timestamp_nanos = timestamp_nanos
def get_car_gps(self):
return self.car_gps
def update(self, can_parsers, starpilot_toggles) -> structs.CarState: def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
cp = can_parsers[Bus.pt] cp = can_parsers[Bus.pt]
cp_cam = can_parsers[Bus.cam] cp_cam = can_parsers[Bus.cam]
self._update_car_gps(cp)
ret = structs.CarState() ret = structs.CarState()
if self.CP.flags & FordFlags.ALT_STEER_ANGLE: # Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement
sensors_valid = ( # The vehicle usually recovers out of this state within a minute of normal driving
int((cp.vl["ParkAid_Data"]["ExtSteeringAngleReq2"] + 1000) * 10) not in (32766, 32767) ret.vehicleSensorsInvalid = cp.vl["SteeringPinion_Data"]["StePinCompAnEst_D_Qf"] != 3
and cp.vl["ParkAid_Data"]["EPASExtAngleStatReq"] == 0
and cp.vl["ParkAid_Data"]["ApaSys_D_Stat"] in (0, 1)
)
ret.vehicleSensorsInvalid = not sensors_valid
else:
# The ABS can recalibrate the steering pinion offset briefly after startup.
ret.vehicleSensorsInvalid = cp.vl["SteeringPinion_Data"]["StePinCompAnEst_D_Qf"] != 3
# car speed # car speed
ret.vEgoRaw = cp.vl["BrakeSysFeatures"]["Veh_V_ActlBrk"] * CV.KPH_TO_MS ret.vEgoRaw = cp.vl["BrakeSysFeatures"]["Veh_V_ActlBrk"] * CV.KPH_TO_MS
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
if self.CP.flags & FordFlags.CANFD:
ret.vEgoCluster = ((cp.vl["Cluster_Info_3_FD1"]["DISPLAY_SPEED_SCALING"] / 100) *
cp.vl["EngVehicleSpThrottle2"]["Veh_V_ActlEng"] +
cp.vl["Cluster_Info_3_FD1"]["DISPLAY_SPEED_OFFSET"]) * CV.KPH_TO_MS
ret.yawRate = cp.vl["Yaw_Data_FD1"]["VehYaw_W_Actl"] ret.yawRate = cp.vl["Yaw_Data_FD1"]["VehYaw_W_Actl"]
ret.standstill = cp.vl["DesiredTorqBrk"]["VehStop_D_Stat"] == 1 ret.standstill = cp.vl["DesiredTorqBrk"]["VehStop_D_Stat"] == 1
@@ -94,14 +48,7 @@ class CarState(CarStateBase):
ret.parkingBrake = cp.vl["DesiredTorqBrk"]["PrkBrkStatus"] in (1, 2) ret.parkingBrake = cp.vl["DesiredTorqBrk"]["PrkBrkStatus"] in (1, 2)
# steering wheel # steering wheel
if self.CP.flags & FordFlags.ALT_STEER_ANGLE: ret.steeringAngleDeg = cp.vl["SteeringPinion_Data"]["StePinComp_An_Est"]
steering_angle_init = cp.vl["SteeringPinion_Data_Alt"]["StePinRelInit_An_Sns"]
if not ret.vehicleSensorsInvalid:
steering_angle_est = cp.vl["ParkAid_Data"]["ExtSteeringAngleReq2"]
self.steering_angle_offset_deg = steering_angle_est - steering_angle_init
ret.steeringAngleDeg = steering_angle_init + self.steering_angle_offset_deg
else:
ret.steeringAngleDeg = cp.vl["SteeringPinion_Data"]["StePinComp_An_Est"]
ret.steeringTorque = cp.vl["EPAS_INFO"]["SteeringColumnTorque"] ret.steeringTorque = cp.vl["EPAS_INFO"]["SteeringColumnTorque"]
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE, 5) ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE, 5)
ret.steerFaultTemporary = cp.vl["EPAS_INFO"]["EPAS_Failure"] == 1 ret.steerFaultTemporary = cp.vl["EPAS_INFO"]["EPAS_Failure"] == 1
@@ -110,12 +57,10 @@ class CarState(CarStateBase):
if self.CP.flags & FordFlags.CANFD: if self.CP.flags & FordFlags.CANFD:
# this signal is always 0 on non-CAN FD cars # this signal is always 0 on non-CAN FD cars
self.lateral_control_status = int(cp.vl["Lane_Assist_Data3_FD1"]["LatCtlSte_D_Stat"]) ret.steerFaultTemporary |= cp.vl["Lane_Assist_Data3_FD1"]["LatCtlSte_D_Stat"] not in (1, 2, 3)
ret.steerFaultTemporary |= self.lateral_control_status not in (1, 2, 3)
# cruise state # cruise state
is_metric = cp.vl["INSTRUMENT_PANEL"]["METRIC_UNITS"] == 1 if not self.CP.flags & FordFlags.CANFD else \ is_metric = cp.vl["INSTRUMENT_PANEL"]["METRIC_UNITS"] == 1 if not self.CP.flags & FordFlags.CANFD else False
cp_cam.vl["IPMA_Data2"]["IsaVLimUnit_D_Rq"] == 1
ret.cruiseState.speed = cp.vl["EngBrakeData"]["Veh_V_DsplyCcSet"] * (CV.KPH_TO_MS if is_metric else CV.MPH_TO_MS) ret.cruiseState.speed = cp.vl["EngBrakeData"]["Veh_V_DsplyCcSet"] * (CV.KPH_TO_MS if is_metric else CV.MPH_TO_MS)
ret.cruiseState.enabled = cp.vl["EngBrakeData"]["CcStat_D_Actl"] in (4, 5) ret.cruiseState.enabled = cp.vl["EngBrakeData"]["CcStat_D_Actl"] in (4, 5)
ret.cruiseState.available = cp.vl["EngBrakeData"]["CcStat_D_Actl"] in (3, 4, 5) ret.cruiseState.available = cp.vl["EngBrakeData"]["CcStat_D_Actl"] in (3, 4, 5)
@@ -127,12 +72,7 @@ class CarState(CarStateBase):
# gear # gear
if self.CP.transmissionType == TransmissionType.automatic: if self.CP.transmissionType == TransmissionType.automatic:
if self.CP.flags & FordFlags.CANFD: gear = self.shifter_values.get(cp.vl["PowertrainData_10"]["TrnRng_D_Rq"])
gear = self.shifter_values.get(cp.vl["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"])
elif self.CP.flags & FordFlags.ALT_STEER_ANGLE:
gear = self.shifter_values.get(cp.vl["TransGearData"]["GearLvrPos_D_Actl"])
else:
gear = self.shifter_values.get(cp.vl["PowertrainData_10"]["TrnRng_D_Rq"])
ret.gearShifter = self.parse_gear_shifter(gear) ret.gearShifter = self.parse_gear_shifter(gear)
elif self.CP.transmissionType == TransmissionType.manual: elif self.CP.transmissionType == TransmissionType.manual:
if bool(cp.vl["BCM_Lamp_Stat_FD1"]["RvrseLghtOn_B_Stat"]): if bool(cp.vl["BCM_Lamp_Stat_FD1"]["RvrseLghtOn_B_Stat"]):
@@ -186,102 +126,12 @@ class CarState(CarStateBase):
] ]
fp_ret = custom.StarPilotCarState.new_message() fp_ret = custom.StarPilotCarState.new_message()
fp_ret.brakeLights = ret.brakePressed
try:
fp_ret.brakeLights = bool(cp.vl["BCM_Lamp_Stat_FD1"]["StopLghtOn_B_Stat"])
except (KeyError, AttributeError):
try:
fp_ret.brakeLights = cp.vl["BrakeSysFeatures_2"]["BrkLamp_B_Rq"] == 1
except (KeyError, AttributeError):
pass
try:
speed_limit = cp_cam.vl["Traffic_RecognitnData"]["TsrVLim1MsgTxt_D_Rq"]
speed_limit_unit = cp_cam.vl["Traffic_RecognitnData"]["TsrVlUnitMsgTxt_D_Rq"]
speed_factor = CV.MPH_TO_MS if speed_limit_unit == 2 else CV.KPH_TO_MS if speed_limit_unit == 1 else 0.0
fp_ret.dashboardSpeedLimit = speed_limit * speed_factor if speed_limit not in (0, 255) else 0.0
except (KeyError, AttributeError):
fp_ret.dashboardSpeedLimit = 0.0
return ret, fp_ret return ret, fp_ret
@staticmethod @staticmethod
def get_can_parsers(CP): def get_can_parsers(CP):
gps_config = get_car_gps_config(CP)
gps_messages = [(name, 0) for name in gps_config.messages] if gps_config is not None else []
pt_messages = [
("BrakeSysFeatures", 50),
("Yaw_Data_FD1", 100),
("DesiredTorqBrk", 50),
("EngVehicleSpThrottle", 100),
("EngVehicleSpThrottle2", 50),
("BrakeSnData_4", 50),
("EngBrakeData", 10),
("EPAS_INFO", 50),
("Cluster_Info1_FD1", 10),
("Steering_Data_FD1", 10),
("BodyInfo_3_FD1", 2),
("RCMStatusMessage2_FD1", 10),
("BCM_Lamp_Stat_FD1", 0),
*gps_messages,
]
if CP.flags & FordFlags.ALT_STEER_ANGLE:
pt_messages += [
("SteeringPinion_Data_Alt", 100),
("ParkAid_Data", 50),
]
else:
pt_messages += [("SteeringPinion_Data", 100)]
if CP.flags & FordFlags.CANFD:
pt_messages += [
("Lane_Assist_Data3_FD1", 33),
("Cluster_Info_3_FD1", 10),
]
else:
pt_messages += [("INSTRUMENT_PANEL", 1)]
if CP.transmissionType == TransmissionType.automatic:
if CP.flags & FordFlags.CANFD:
pt_messages += [("Gear_Shift_by_Wire_FD1", 10)]
elif CP.flags & FordFlags.ALT_STEER_ANGLE:
pt_messages += [("TransGearData", 10)]
else:
pt_messages += [("PowertrainData_10", 10)]
if CP.enableBsm and not (CP.flags & FordFlags.CANFD):
pt_messages += [
("Side_Detect_L_Stat", 5),
("Side_Detect_R_Stat", 5),
]
cam_messages = [
("ACCDATA", 50),
("ACCDATA_2", 50),
("ACCDATA_3", 5),
("IPMA_Data", 1),
]
if CP.flags & FordFlags.CANFD:
cam_messages += [
("Traffic_RecognitnData", 1),
("IPMA_Data2", 1),
]
else:
cam_messages += [("Traffic_RecognitnData", 0)]
if CP.enableBsm and CP.flags & FordFlags.CANFD:
cam_messages += [
("Side_Detect_L_Stat", 5),
("Side_Detect_R_Stat", 5),
]
if CP.flags & FordFlags.LKA_STEERING:
cam_messages += [("LateralMotionControl", 20)]
return { return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CanBus(CP).main), Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).main),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, CanBus(CP).camera), Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).camera),
} }
@@ -12,8 +12,6 @@ FW_VERSIONS = {
b'LX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.abs, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'LX6C-2D053-KF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX6C-2D053-KG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX6C-2D053-RD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6C-2D053-RD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX6C-2D053-RE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6C-2D053-RE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX6C-2D053-RF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6C-2D053-RF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -26,21 +24,6 @@ FW_VERSIONS = {
b'M1PT-14F397-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'M1PT-14F397-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
}, },
CAR.FORD_EDGE_MK2: {
(Ecu.eps, 0x730, None): [
b'M2GC-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.abs, 0x760, None): [
b'M2GC-2D053-CB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'M2GC-2D053-EA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x764, None): [
b'JX7T-14D049-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x706, None): [
b'KT4T-14F397-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
},
CAR.FORD_ESCAPE_MK4: { CAR.FORD_ESCAPE_MK4: {
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
b'LX6C-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6C-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -66,9 +49,7 @@ FW_VERSIONS = {
}, },
CAR.FORD_ESCAPE_MK4_5: { CAR.FORD_ESCAPE_MK4_5: {
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
b'PZ11-14D003-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PZ11-14D003-EA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PZ11-14D003-EA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PZ11-14D003-FA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.abs, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'PZ1C-2D053-EJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PZ1C-2D053-EJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -77,20 +58,11 @@ FW_VERSIONS = {
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdCamera, 0x706, None): [ (Ecu.fwdCamera, 0x706, None): [
b'PJ6T-14H102-ABE\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PJ6T-14H102-ABL\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PJ6T-14H102-ABL\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PJ6T-14H102-MDC\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PJ6T-14H102-MDF\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PJ6T-14H102-SCD\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PJ6T-14H102-SCG\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
}, },
CAR.FORD_EXPLORER_MK6: { CAR.FORD_EXPLORER_MK6: {
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
b'R1MC-14D003-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'R1MC-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'R1MC-14D003-AG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'R1MC-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'L1MC-14D003-AJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-14D003-AJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'L1MC-14D003-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-14D003-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'L1MC-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -124,7 +96,6 @@ FW_VERSIONS = {
], ],
(Ecu.abs, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'RL14-2D053-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'RL14-2D053-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PL14-2D053-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdRadar, 0x764, None): [ (Ecu.fwdRadar, 0x764, None): [
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -135,7 +106,6 @@ FW_VERSIONS = {
}, },
CAR.FORD_F_150_MK14: { CAR.FORD_F_150_MK14: {
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
b'MB3C-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3V-14D003-BA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'ML3V-14D003-BA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3V-14D003-BC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'ML3V-14D003-BC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3V-14D003-BD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'ML3V-14D003-BD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -166,11 +136,8 @@ FW_VERSIONS = {
}, },
CAR.FORD_F_150_LIGHTNING_MK1: { CAR.FORD_F_150_LIGHTNING_MK1: {
(Ecu.abs, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'NL38-2D053-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PL38-2D053-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PL38-2D053-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'RL38-2D053-BC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'RL38-2D053-BD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'RL38-2D053-BD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'TL38-2D053-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdCamera, 0x706, None): [ (Ecu.fwdCamera, 0x706, None): [
b'ML3T-14H102-ABT\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'ML3T-14H102-ABT\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -178,13 +145,9 @@ FW_VERSIONS = {
b'RJ6T-14H102-BBC\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'RJ6T-14H102-BBC\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdRadar, 0x764, None): [ (Ecu.fwdRadar, 0x764, None): [
b'ML3T-14D049-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'RB5T-14D049-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
b'NL38-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NL38-14D003-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'RL38-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'RL38-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
}, },
@@ -201,8 +164,6 @@ FW_VERSIONS = {
b'LK9C-2D053-CN\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LK9C-2D053-CN\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdRadar, 0x764, None): [ (Ecu.fwdRadar, 0x764, None): [
b'ML3T-14D049-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14D049-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdCamera, 0x706, None): [ (Ecu.fwdCamera, 0x706, None): [
@@ -213,42 +174,15 @@ FW_VERSIONS = {
CAR.FORD_FOCUS_MK4: { CAR.FORD_FOCUS_MK4: {
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
b'JX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'JX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'JX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'JX6C-14D003-BB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.abs, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'JX61-2D053-CJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'JX61-2D053-CJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX61-2D053-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NX61-2D053-MD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdRadar, 0x764, None): [ (Ecu.fwdRadar, 0x764, None): [
b'JX7T-14D049-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'JX7T-14D049-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'JX7T-14D049-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdCamera, 0x706, None): [ (Ecu.fwdCamera, 0x706, None): [
b'JX7T-14F397-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'JX7T-14F397-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'N1BT-14F397-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
},
CAR.FORD_MONDEO_MK5: {
(Ecu.fwdCamera, 0x706, None): [
b'KT4T-14F397-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.abs, 0x760, None): [
b'KG9C-2D053-DF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.eps, 0x730, None): [
b'K2GC-14D003-AJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x764, None): [
b'JX7T-14D049-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.engine, 0x7e0, None): [
b'HS7A-14C204-CJD\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.debug, 0x7d0, None): [
b'1U5T-14G374-DA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
}, },
CAR.FORD_MAVERICK_MK1: { CAR.FORD_MAVERICK_MK1: {
@@ -273,25 +207,17 @@ FW_VERSIONS = {
}, },
CAR.FORD_RANGER_MK2: { CAR.FORD_RANGER_MK2: {
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
b'JR3C-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NB3C-14D003-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'NB3C-14D003-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NL14-14D003-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NL14-14D003-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'NL14-14D003-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'RB3C-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'RB3C-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.abs, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'MB3C-2D053-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'MB3C-2D053-ZJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PB3C-2D053-ZB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PB3C-2D053-ZC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PB3C-2D053-ZD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PB3C-2D053-ZD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PB3C-2D053-ZG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PB3C-2D053-ZG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PB3C-2D053-ZJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PB3C-2D053-ZJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PB9C-2D053-ZG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'RB3C-2D053-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'RB3C-2D053-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdRadar, 0x764, None): [ (Ecu.fwdRadar, 0x764, None): [
b'JX7T-14D049-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdCamera, 0x706, None): [ (Ecu.fwdCamera, 0x706, None): [
+1 -3
View File
@@ -181,7 +181,7 @@ def create_acc_msg(packer, CAN: CanBus, long_active: bool, gas: float, accel: fl
def create_acc_ui_msg(packer, CAN: CanBus, CP, main_on: bool, enabled: bool, fcw_alert: bool, standstill: bool, def create_acc_ui_msg(packer, CAN: CanBus, CP, main_on: bool, enabled: bool, fcw_alert: bool, standstill: bool,
show_distance_bars: bool, hud_control, stock_values: dict, hands_free_cluster: bool = False): show_distance_bars: bool, hud_control, stock_values: dict):
""" """
Creates a CAN message for the Ford IPC adaptive cruise, forward collision warning and traffic jam Creates a CAN message for the Ford IPC adaptive cruise, forward collision warning and traffic jam
assist status. assist status.
@@ -197,8 +197,6 @@ def create_acc_ui_msg(packer, CAN: CanBus, CP, main_on: bool, enabled: bool, fcw
status = 3 # ActiveInterventionLeft status = 3 # ActiveInterventionLeft
elif hud_control.rightLaneDepart: elif hud_control.rightLaneDepart:
status = 4 # ActiveInterventionRight status = 4 # ActiveInterventionRight
elif hands_free_cluster:
status = 7 # Hands-free assistance display
else: else:
status = 2 # Active status = 2 # Active
elif main_on: elif main_on:
+4 -9
View File
@@ -31,13 +31,12 @@ class CarInterface(CarInterfaceBase):
ret.radarUnavailable = Bus.radar not in DBC[candidate] ret.radarUnavailable = Bus.radar not in DBC[candidate]
ret.steerControlType = structs.CarParams.SteerControlType.angle ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.steerActuatorDelay = 0.05 if ret.flags & FordFlags.LKA_STEERING else 0.22 ret.steerActuatorDelay = 0.05 if ret.flags & FordFlags.LKA_STEERING else 0.2
ret.steerLimitTimer = 1.0 ret.steerLimitTimer = 1.0
ret.steerAtStandstill = True ret.steerAtStandstill = True
ret.longitudinalTuning.kiBP = [0.] ret.longitudinalTuning.kiBP = [0.]
ret.longitudinalTuning.kiV = [0.5] ret.longitudinalTuning.kiV = [0.5]
ret.longitudinalTuning.kpV = [0.]
if not ret.radarUnavailable and DBC[candidate][Bus.radar] == RADAR.DELPHI_MRR: if not ret.radarUnavailable and DBC[candidate][Bus.radar] == RADAR.DELPHI_MRR:
# average of 33.3 Hz radar timestep / 4 scan modes = 60 ms # average of 33.3 Hz radar timestep / 4 scan modes = 60 ms
@@ -45,19 +44,15 @@ class CarInterface(CarInterfaceBase):
ret.radarDelay = 0.06 ret.radarDelay = 0.06
CAN = CanBus(fingerprint=fingerprint) CAN = CanBus(fingerprint=fingerprint)
if 0x365 in fingerprint[CAN.main]:
ret.flags |= int(FordFlags.HEV_CLUSTER_DATA)
if all(address in fingerprint[CAN.main] for address in (0x07A, 0x24B, 0x24C)):
ret.flags |= int(FordFlags.HEV_BATTERY_DATA)
cfgs = [get_safety_config(structs.CarParams.SafetyModel.ford)] cfgs = [get_safety_config(structs.CarParams.SafetyModel.ford)]
if CAN.main >= 4: if CAN.main >= 4:
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput)) cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
ret.safetyConfigs = cfgs ret.safetyConfigs = cfgs
ret.alphaLongitudinalAvailable = True ret.alphaLongitudinalAvailable = ret.radarUnavailable
ret.openpilotLongitudinalControl = bool(alpha_long) if alpha_long or not ret.radarUnavailable:
if ret.openpilotLongitudinalControl:
ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.LONG_CONTROL.value ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.LONG_CONTROL.value
ret.openpilotLongitudinalControl = True
if ret.flags & FordFlags.CANFD: if ret.flags & FordFlags.CANFD:
ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.CANFD.value ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.CANFD.value
@@ -1,5 +1,4 @@
import numpy as np import numpy as np
from collections import deque
from typing import cast from typing import cast
from collections import defaultdict from collections import defaultdict
from math import cos, sin from math import cos, sin
@@ -20,7 +19,6 @@ DELPHI_MRR_RADAR_MSG_COUNT = 64
DELPHI_MRR_RADAR_RANGE_COVERAGE = {0: 42, 1: 164, 2: 45, 3: 175} # scan index to detection range (m) DELPHI_MRR_RADAR_RANGE_COVERAGE = {0: 42, 1: 164, 2: 45, 3: 175} # scan index to detection range (m)
DELPHI_MRR_MIN_LONG_RANGE_DIST = 30 # meters DELPHI_MRR_MIN_LONG_RANGE_DIST = 30 # meters
DELPHI_MRR_CLUSTER_THRESHOLD = 5 # meters, lateral distance and relative velocity are weighted DELPHI_MRR_CLUSTER_THRESHOLD = 5 # meters, lateral distance and relative velocity are weighted
STEER_ASSIST_DATA_ADDR = 0x3D7
@dataclass @dataclass
@@ -91,17 +89,12 @@ def _create_delphi_mrr_radar_can_parser(CP) -> CANParser:
return CANParser(RADAR.DELPHI_MRR, messages, CanBus(CP).radar) return CANParser(RADAR.DELPHI_MRR, messages, CanBus(CP).radar)
def _create_steer_assist_radar_can_parser(CP) -> CANParser:
return CANParser(RADAR.STEER_ASSIST_DATA, [("Steer_Assist_Data", 20)], CanBus(CP).camera)
class RadarInterface(RadarInterfaceBase): class RadarInterface(RadarInterfaceBase):
def __init__(self, CP): def __init__(self, CP):
super().__init__(CP) super().__init__(CP)
self.points: list[list[float]] = [] self.points: list[list[float]] = []
self.clusters: list[Cluster] = [] self.clusters: list[Cluster] = []
self.v_rel_history = deque(maxlen=20)
self.updated_messages = set() self.updated_messages = set()
self.track_id = 0 self.track_id = 0
@@ -118,9 +111,6 @@ class RadarInterface(RadarInterfaceBase):
elif self.radar == RADAR.DELPHI_MRR: elif self.radar == RADAR.DELPHI_MRR:
self.rcp = _create_delphi_mrr_radar_can_parser(CP) self.rcp = _create_delphi_mrr_radar_can_parser(CP)
self.trigger_msg = DELPHI_MRR_RADAR_HEADER_ADDR self.trigger_msg = DELPHI_MRR_RADAR_HEADER_ADDR
elif self.radar == RADAR.STEER_ASSIST_DATA:
self.rcp = _create_steer_assist_radar_can_parser(CP)
self.trigger_msg = STEER_ASSIST_DATA_ADDR
else: else:
raise ValueError(f"Unsupported radar: {self.radar}") raise ValueError(f"Unsupported radar: {self.radar}")
@@ -145,45 +135,10 @@ class RadarInterface(RadarInterfaceBase):
_update = self._update_delphi_mrr(ret) _update = self._update_delphi_mrr(ret)
if not _update: if not _update:
return None return None
elif self.radar == RADAR.STEER_ASSIST_DATA:
self._update_steer_assist()
ret.points = list(self.pts.values()) ret.points = list(self.pts.values())
return ret return ret
def _update_steer_assist(self):
msg = self.rcp.vl["Steer_Assist_Data"]
confidence = msg["CmbbObjConfdnc_D_Stat"]
if confidence <= 0:
self.pts.pop(0, None)
self.v_rel_history.clear()
return
d_rel = msg["CmbbObjDistLong_L_Actl"]
v_rel = msg["CmbbObjRelLong_V_Actl"]
new_track = 0 not in self.pts
if new_track:
self.pts[0] = structs.RadarData.RadarPoint()
self.pts[0].trackId = self.track_id
self.track_id += 1
elif abs(v_rel) < 1e-2:
self.v_rel_history.append(d_rel - self.pts[0].dRel)
v_rel = sum(self.v_rel_history)
else:
self.v_rel_history.clear()
if not new_track and (abs(self.pts[0].vRel - v_rel) > 2.0 or abs(self.pts[0].dRel - d_rel) > 5.0):
self.pts[0].trackId = self.track_id
self.track_id += 1
self.v_rel_history.clear()
self.pts[0].dRel = d_rel
self.pts[0].yRel = msg["CmbbObjDistLat_L_Actl"]
self.pts[0].vRel = v_rel
self.pts[0].aRel = float('nan')
self.pts[0].yvRel = msg["CmbbObjRelLat_V_Actl"]
self.pts[0].measured = True
def _update_delphi_esr(self): def _update_delphi_esr(self):
for ii in sorted(self.updated_messages): for ii in sorted(self.updated_messages):
cpt = self.rcp.vl[ii] cpt = self.rcp.vl[ii]
@@ -1,19 +1,12 @@
import random import random
from collections.abc import Iterable from collections.abc import Iterable
from types import SimpleNamespace
from hypothesis import settings, given, strategies as st from hypothesis import settings, given, strategies as st
from parameterized import parameterized from parameterized import parameterized
import pytest
from opendbc.car import Bus, gen_empty_fingerprint
from opendbc.can import CANPacker
from opendbc.car.ford import fordcan
from opendbc.car.gps import FORD_MACH_E_GPS_MESSAGES, get_car_gps_config, parse_ford_can_gps
from opendbc.car.structs import CarParams from opendbc.car.structs import CarParams
from opendbc.car.fw_versions import build_fw_dict from opendbc.car.fw_versions import build_fw_dict
from opendbc.car.ford.interface import CarInterface from opendbc.car.ford.values import CAR, FW_QUERY_CONFIG, FW_PATTERN, get_platform_codes
from opendbc.car.ford.values import CAR, FW_QUERY_CONFIG, FW_PATTERN, FordSafetyFlags, get_platform_codes, match_vin_to_car
from opendbc.car.ford.fingerprints import FW_VERSIONS from opendbc.car.ford.fingerprints import FW_VERSIONS
Ecu = CarParams.Ecu Ecu = CarParams.Ecu
@@ -27,7 +20,6 @@ ECU_ADDRESSES = {
Ecu.engine: 0x7E0, # Powertrain Control Module (PCM) Ecu.engine: 0x7E0, # Powertrain Control Module (PCM)
Ecu.shiftByWire: 0x732, # Gear Shift Module (GSM) Ecu.shiftByWire: 0x732, # Gear Shift Module (GSM)
Ecu.debug: 0x7D0, # Accessory Protocol Interface Module (APIM) Ecu.debug: 0x7D0, # Accessory Protocol Interface Module (APIM)
Ecu.hud: 0x720, # Instrument Cluster Module (ICM)
} }
@@ -49,16 +41,6 @@ ECU_PART_NUMBER = {
class TestFordFW: class TestFordFW:
def test_vin_fallback(self):
def vin(wmi, vds, powertrain, year):
return f"{wmi}{vds}{powertrain}0{year}1234567"
assert match_vin_to_car(vin("2FM", "PK4A", "A", "N")) == {str(CAR.FORD_EDGE_MK2)}
assert match_vin_to_car(vin("3FM", "K1RA", "A", "M")) == {str(CAR.FORD_MUSTANG_MACH_E_MK1)}
assert match_vin_to_car(vin("1FT", "F1CA", "A", "M")) == {str(CAR.FORD_F_150_MK14)}
assert match_vin_to_car(vin("1FT", "F1CA", "L", "N")) == {str(CAR.FORD_F_150_LIGHTNING_MK1)}
assert match_vin_to_car("0" * 17) == set()
def test_fw_query_config(self): def test_fw_query_config(self):
for (ecu, addr, subaddr) in FW_QUERY_CONFIG.extra_ecus: for (ecu, addr, subaddr) in FW_QUERY_CONFIG.extra_ecus:
assert ecu in ECU_ADDRESSES, "Unknown ECU" assert ecu in ECU_ADDRESSES, "Unknown ECU"
@@ -68,13 +50,10 @@ class TestFordFW:
@parameterized.expand(FW_VERSIONS.items()) @parameterized.expand(FW_VERSIONS.items())
def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[int, int, int | None], Iterable[bytes]]): def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[int, int, int | None], Iterable[bytes]]):
for (ecu, addr, subaddr), fws in fw_versions.items(): for (ecu, addr, subaddr), fws in fw_versions.items():
assert ecu in ECU_ADDRESSES, "Unknown ECU" assert ecu in ECU_PART_NUMBER, "Unexpected ECU"
assert addr == ECU_ADDRESSES[ecu], "ECU address mismatch" assert addr == ECU_ADDRESSES[ecu], "ECU address mismatch"
assert subaddr is None, "Unexpected ECU subaddress" assert subaddr is None, "Unexpected ECU subaddress"
if ecu not in ECU_PART_NUMBER:
continue
for fw in fws: for fw in fws:
assert len(fw) == 24, "Expected ECU response to be 24 bytes" assert len(fw) == 24, "Expected ECU response to be 24 bytes"
@@ -161,158 +140,3 @@ class TestFordFW:
live_fw[(0x760, None)] = {b"M1MC-2D053-XX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"} live_fw[(0x760, None)] = {b"M1MC-2D053-XX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}
candidates = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fw, '', {expected_fingerprint: offline_fw}) candidates = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fw, '', {expected_fingerprint: offline_fw})
assert len(candidates) == 0, "Should not match new model year hint" assert len(candidates) == 0, "Should not match new model year hint"
def test_mach_e_longitudinal_toggle_controls_stock_acc_selection():
stock = CarInterface.get_params(
CAR.FORD_MUSTANG_MACH_E_MK1, gen_empty_fingerprint(), [], False, False, False, None)
enhanced = CarInterface.get_params(
CAR.FORD_MUSTANG_MACH_E_MK1, gen_empty_fingerprint(), [], True, False, False, None)
assert stock.alphaLongitudinalAvailable
assert not stock.openpilotLongitudinalControl
assert stock.pcmCruise
assert not (stock.safetyConfigs[-1].safetyParam & FordSafetyFlags.LONG_CONTROL)
assert enhanced.alphaLongitudinalAvailable
assert enhanced.openpilotLongitudinalControl
assert enhanced.safetyConfigs[-1].safetyParam & FordSafetyFlags.LONG_CONTROL
def test_mach_e_can_gps_decode():
nav1 = {
"GpsHsphLattSth_D_Actl": 2,
"GpsHsphLongEast_D_Actl": 2,
"GPS_Latitude_Degrees": 37,
"GPS_Latitude_Minutes": 57,
"GPS_Latitude_Min_dec": 0.8864,
"GPS_Longitude_Degrees": -121,
"GPS_Longitude_Minutes": 44,
"GPS_Longitude_Min_dec": 0.22,
}
nav2 = {
"GpsUtcYr_No_Actl": 2026,
"GpsUtcMnth_No_Actl": 8,
"GpsUtcDay_No_Actl": 26,
"GPS_UTC_hours": 0,
"GPS_UTC_minutes": 24,
"GPS_UTC_seconds": 38,
"Gps_B_Falt": 0,
}
nav3 = {
"GPS_dimension": 2,
"GPS_Hdop": 0.6,
"GPS_Vdop": 0.8,
"GPS_Sat_num_in_view": 31,
"GPS_MSL_altitude": 90,
"GPS_Speed": 10,
"GPS_Heading": 180,
}
gps = parse_ford_can_gps(nav1, nav2, nav3)
assert gps is not None
assert gps["latitude"] == 37.96477333333333
assert gps["longitude"] == -121.737
assert abs(gps["altitude"] - 27.432) < 1e-9
assert abs(gps["speed"] - 10 * 0.44704) < 1e-9
assert gps["hasFix"]
assert gps["satelliteCount"] == 0 # 31 is Ford's invalid sentinel.
def test_mach_e_can_gps_fault_invalidates_fix():
nav1 = {
"GpsHsphLattSth_D_Actl": 2,
"GpsHsphLongEast_D_Actl": 2,
"GPS_Latitude_Degrees": 37,
"GPS_Latitude_Minutes": 57,
"GPS_Latitude_Min_dec": 0.8864,
"GPS_Longitude_Degrees": -121,
"GPS_Longitude_Minutes": 44,
"GPS_Longitude_Min_dec": 0.22,
}
nav2 = {
"GpsUtcYr_No_Actl": 2026,
"GpsUtcMnth_No_Actl": 8,
"GpsUtcDay_No_Actl": 26,
"GPS_UTC_hours": 0,
"GPS_UTC_minutes": 24,
"GPS_UTC_seconds": 38,
"Gps_B_Falt": 1,
}
nav3 = {
"GPS_dimension": 2,
"GPS_Hdop": 0.6,
"GPS_Vdop": 0.8,
"GPS_Sat_num_in_view": 31,
"GPS_MSL_altitude": 90,
"GPS_Speed": 0,
"GPS_Heading": 180,
}
gps = parse_ford_can_gps(nav1, nav2, nav3)
assert gps is not None
assert not gps["hasFix"]
assert gps["latitude"] == 37.96477333333333
assert gps["altitude"] == 0.0
def test_mach_e_can_gps_messages_are_optional_main_bus_inputs():
cp = CarInterface.get_params(CAR.FORD_MUSTANG_MACH_E_MK1, gen_empty_fingerprint(), [], False, False, False, None)
parser = CarInterface.CarState.get_can_parsers(cp)[Bus.pt]
gps_config = get_car_gps_config(cp)
assert gps_config is not None
assert gps_config.messages == FORD_MACH_E_GPS_MESSAGES
assert gps_config.decoder is parse_ford_can_gps
assert set(parser.addresses) >= {0x462, 0x463, 0x464}
assert set(FORD_MACH_E_GPS_MESSAGES) == set(gps_config.messages) == {
parser.dbc.addr_to_msg[0x462].name,
parser.dbc.addr_to_msg[0x463].name,
parser.dbc.addr_to_msg[0x464].name,
}
assert all(parser.message_states[address].ignore_alive for address in (0x462, 0x463, 0x464))
def test_lightning_low_rate_camera_messages_use_declared_frequencies():
cp = CarInterface.get_params(CAR.FORD_F_150_LIGHTNING_MK1, gen_empty_fingerprint(), [], True, False, False, None)
cp.enableBsm = True
parser = CarInterface.CarState.get_can_parsers(cp)[Bus.cam]
expected_frequencies = {
"IPMA_Data": 1,
"Traffic_RecognitnData": 1,
"Side_Detect_L_Stat": 5,
"Side_Detect_R_Stat": 5,
}
for message, frequency in expected_frequencies.items():
state = parser.message_states[parser.dbc.name_to_msg[message].address]
assert state.frequency == frequency
assert state.timeout_threshold == pytest.approx(10e9 / frequency)
def test_hands_free_cluster_status_is_opt_in():
packer = CANPacker("ford_lincoln_base_pt")
CAN = SimpleNamespace(main=0)
CP = SimpleNamespace(openpilotLongitudinalControl=False)
hud = SimpleNamespace(leftLaneDepart=False, rightLaneDepart=False)
stock_values = dict.fromkeys([
"HaDsply_No_Cs", "HaDsply_No_Cnt", "AccStopStat_D_Dsply", "AccTrgDist2_D_Dsply",
"AccStopRes_B_Dsply", "TjaWarn_D_Rq", "TjaMsgTxt_D_Dsply", "IaccLamp_D_Rq",
"AccMsgTxt_D2_Rq", "FcwDeny_B_Dsply", "FcwMemStat_B_Actl", "AccTGap_B_Dsply",
"CadsAlignIncplt_B_Actl", "AccFllwMde_B_Dsply", "CadsRadrBlck_B_Actl",
"CmbbPostEvnt_B_Dsply", "AccStopMde_B_Dsply", "FcwMemSens_D_Actl",
"FcwMsgTxt_D_Rq", "AccWarn_D_Dsply", "FcwVisblWarn_B_Rq", "FcwAudioWarn_B_Rq",
"AccTGap_D_Dsply", "AccMemEnbl_B_RqDrv", "FdaMem_B_Stat",
], 0)
regular = fordcan.create_acc_ui_msg(
packer, CAN, CP, True, True, False, False, False, hud, stock_values)
hands_free = fordcan.create_acc_ui_msg(
packer, CAN, CP, True, True, False, False, False, hud, stock_values, True)
expected_regular = packer.make_can_msg("ACCDATA_3", 0, {"Tja_D_Stat": 2})
expected_hands_free = packer.make_can_msg("ACCDATA_3", 0, {"Tja_D_Stat": 7})
assert regular == expected_regular
assert hands_free == expected_hands_free
+14 -67
View File
@@ -8,7 +8,6 @@ from opendbc.car.lateral import AngleSteeringLimits
from opendbc.car.structs import CarParams from opendbc.car.structs import CarParams
from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
from opendbc.car.fw_query_definitions import FwQueryConfig, LiveFwVersions, OfflineFwVersions, Request, StdQueries, p16 from opendbc.car.fw_query_definitions import FwQueryConfig, LiveFwVersions, OfflineFwVersions, Request, StdQueries, p16
from opendbc.car.vin import Vin, is_valid_vin
Ecu = CarParams.Ecu Ecu = CarParams.Ecu
@@ -54,15 +53,11 @@ class FordFlags(IntFlag):
# Static flags # Static flags
CANFD = 1 CANFD = 1
LKA_STEERING = 2 LKA_STEERING = 2
ALT_STEER_ANGLE = 4
HEV_CLUSTER_DATA = 8
HEV_BATTERY_DATA = 16
class RADAR: class RADAR:
DELPHI_ESR = 'ford_fusion_2018_adas' DELPHI_ESR = 'ford_fusion_2018_adas'
DELPHI_MRR = 'FORD_CADS' DELPHI_MRR = 'FORD_CADS'
STEER_ASSIST_DATA = 'ford_lincoln_base_pt'
class Footnote(Enum): class Footnote(Enum):
@@ -92,10 +87,6 @@ class FordCarDocs(CarDocs):
@dataclass @dataclass
class FordPlatformConfig(PlatformConfig): class FordPlatformConfig(PlatformConfig):
wmis: set[str] = field(default_factory=set)
vds_codes: set[str] = field(default_factory=set)
years: set[str] = field(default_factory=set)
dbc_dict: DbcDict = field(default_factory=lambda: { dbc_dict: DbcDict = field(default_factory=lambda: {
Bus.pt: 'ford_lincoln_base_pt', Bus.pt: 'ford_lincoln_base_pt',
Bus.radar: RADAR.DELPHI_MRR, Bus.radar: RADAR.DELPHI_MRR,
@@ -115,7 +106,6 @@ class FordPlatformConfig(PlatformConfig):
class FordCANFDPlatformConfig(FordPlatformConfig): class FordCANFDPlatformConfig(FordPlatformConfig):
dbc_dict: DbcDict = field(default_factory=lambda: { dbc_dict: DbcDict = field(default_factory=lambda: {
Bus.pt: 'ford_lincoln_base_pt', Bus.pt: 'ford_lincoln_base_pt',
Bus.radar: RADAR.STEER_ASSIST_DATA,
}) })
def init(self): def init(self):
@@ -132,26 +122,17 @@ class FordLKASteeringPlatformConfig(FordPlatformConfig):
@dataclass @dataclass
class FordF150LightningPlatform(FordCANFDPlatformConfig): class FordF150LightningPlatform(FordCANFDPlatformConfig):
pass def init(self):
super().init()
# Don't show in docs until this issue is resolved. See https://github.com/commaai/openpilot/issues/30302
MY_2020, MY_2021, MY_2022, MY_2023, MY_2024, MY_2025 = 'L', 'M', 'N', 'P', 'R', 'S' self.car_docs = []
F150_VDS_CODES = {'F1C', 'F1E', 'W1C', 'W1E', 'X1C', 'X1E', 'W1R', 'W1P', 'W1S', 'W1T'}
F150_ELECTRIC_CODES = {'L', 'V'}
MACH_E_VDS_CODES = {'K1R', 'K1S', 'K2S', 'K3R', 'K3S', 'K4S'}
class CAR(Platforms): class CAR(Platforms):
FORD_BRONCO_SPORT_MK1 = FordPlatformConfig( FORD_BRONCO_SPORT_MK1 = FordPlatformConfig(
[FordCarDocs("Ford Bronco Sport 2021-24")], [FordCarDocs("Ford Bronco Sport 2021-24")],
CarSpecs(mass=1625, wheelbase=2.67, steerRatio=17.7), CarSpecs(mass=1625, wheelbase=2.67, steerRatio=17.7),
wmis={'3FM'}, vds_codes={'CR9'}, years={MY_2021, MY_2022, MY_2023, MY_2024},
)
FORD_EDGE_MK2 = FordPlatformConfig(
[FordCarDocs("Ford Edge 2022")],
CarSpecs(mass=1933, wheelbase=2.824, steerRatio=15.3),
flags=FordFlags.ALT_STEER_ANGLE,
wmis={'2FM'}, vds_codes={'PK4'}, years={MY_2022},
) )
FORD_ESCAPE_MK4 = FordPlatformConfig( FORD_ESCAPE_MK4 = FordPlatformConfig(
[ [
@@ -159,7 +140,6 @@ class CAR(Platforms):
FordCarDocs("Ford Kuga 2020-23", "Adaptive Cruise Control with Lane Centering", hybrid=True, plug_in_hybrid=True), FordCarDocs("Ford Kuga 2020-23", "Adaptive Cruise Control with Lane Centering", hybrid=True, plug_in_hybrid=True),
], ],
CarSpecs(mass=1750, wheelbase=2.71, steerRatio=16.7), CarSpecs(mass=1750, wheelbase=2.71, steerRatio=16.7),
wmis={'1FM'}, vds_codes={'CU0', 'CU9'}, years={MY_2020, MY_2021, MY_2022},
) )
FORD_ESCAPE_MK4_5 = FordCANFDPlatformConfig( FORD_ESCAPE_MK4_5 = FordCANFDPlatformConfig(
[ [
@@ -168,7 +148,6 @@ class CAR(Platforms):
FordCarDocs("Ford Kuga Plug-in Hybrid 2024", "All"), FordCarDocs("Ford Kuga Plug-in Hybrid 2024", "All"),
], ],
CarSpecs(mass=1750, wheelbase=2.71, steerRatio=16.7), CarSpecs(mass=1750, wheelbase=2.71, steerRatio=16.7),
wmis={'1FM'}, vds_codes={'CU0', 'CU9'}, years={MY_2023, MY_2024},
) )
FORD_EXPLORER_MK6 = FordPlatformConfig( FORD_EXPLORER_MK6 = FordPlatformConfig(
[ [
@@ -176,49 +155,37 @@ class CAR(Platforms):
FordCarDocs("Lincoln Aviator 2020-24", "Co-Pilot360 Plus", plug_in_hybrid=True), # Hybrid: Grand Touring only FordCarDocs("Lincoln Aviator 2020-24", "Co-Pilot360 Plus", plug_in_hybrid=True), # Hybrid: Grand Touring only
], ],
CarSpecs(mass=2050, wheelbase=3.025, steerRatio=16.8), CarSpecs(mass=2050, wheelbase=3.025, steerRatio=16.8),
wmis={'1FM', '5LM'}, vds_codes={'5K7', '5K8', '5J7'},
years={MY_2020, MY_2021, MY_2022, MY_2023, MY_2024},
) )
FORD_EXPEDITION_MK4 = FordCANFDPlatformConfig( FORD_EXPEDITION_MK4 = FordCANFDPlatformConfig(
[FordCarDocs("Ford Expedition 2022-24", "Co-Pilot360 Assist 2.0", hybrid=False)], [FordCarDocs("Ford Expedition 2022-24", "Co-Pilot360 Assist 2.0", hybrid=False)],
CarSpecs(mass=2000, wheelbase=3.69, steerRatio=17.0), CarSpecs(mass=2000, wheelbase=3.69, steerRatio=17.0),
wmis={'1FM'}, vds_codes={'JU1', 'JU2', 'JK1'}, years={MY_2022, MY_2023, MY_2024},
) )
FORD_F_150_MK14 = FordCANFDPlatformConfig( FORD_F_150_MK14 = FordCANFDPlatformConfig(
[FordCarDocs("Ford F-150 2021-23", "Co-Pilot360 Assist 2.0", hybrid=True)], [FordCarDocs("Ford F-150 2021-23", "Co-Pilot360 Assist 2.0", hybrid=True)],
CarSpecs(mass=3334, wheelbase=3.99, steerRatio=17.0), CarSpecs(mass=2000, wheelbase=3.69, steerRatio=17.0),
wmis={'1FT'}, vds_codes=F150_VDS_CODES, years={MY_2021, MY_2022, MY_2023},
) )
FORD_F_150_LIGHTNING_MK1 = FordF150LightningPlatform( FORD_F_150_LIGHTNING_MK1 = FordF150LightningPlatform(
[FordCarDocs("Ford F-150 Lightning 2022-25", "Co-Pilot360 Assist 2.0")], [FordCarDocs("Ford F-150 Lightning 2022-23", "Co-Pilot360 Assist 2.0")],
CarSpecs(mass=2948, wheelbase=3.70, steerRatio=16.9), CarSpecs(mass=2948, wheelbase=3.70, steerRatio=16.9),
wmis={'1FT'}, vds_codes=F150_VDS_CODES, years={MY_2022, MY_2023, MY_2024, MY_2025},
) )
FORD_FOCUS_MK4 = FordPlatformConfig( FORD_FOCUS_MK4 = FordPlatformConfig(
[FordCarDocs("Ford Focus 2018-22", "Adaptive Cruise Control with Lane Centering", footnotes=[Footnote.FOCUS], hybrid=True)], # mHEV only [FordCarDocs("Ford Focus 2018", "Adaptive Cruise Control with Lane Centering", footnotes=[Footnote.FOCUS], hybrid=True)], # mHEV only
CarSpecs(mass=1350, wheelbase=2.7, steerRatio=15.0), CarSpecs(mass=1350, wheelbase=2.7, steerRatio=15.0),
) )
FORD_MONDEO_MK5 = FordCANFDPlatformConfig(
[FordCarDocs("Ford Mondeo 2014-22", "Adaptive Cruise Control with Lane Centering")],
CarSpecs(mass=1550, wheelbase=2.85, steerRatio=14.8),
)
FORD_MAVERICK_MK1 = FordPlatformConfig( FORD_MAVERICK_MK1 = FordPlatformConfig(
[ [
FordCarDocs("Ford Maverick 2022", "LARIAT Luxury", hybrid=True), FordCarDocs("Ford Maverick 2022", "LARIAT Luxury", hybrid=True),
FordCarDocs("Ford Maverick 2023-24", "Co-Pilot360 Assist", hybrid=True), FordCarDocs("Ford Maverick 2023-24", "Co-Pilot360 Assist", hybrid=True),
], ],
CarSpecs(mass=1650, wheelbase=3.076, steerRatio=17.0), CarSpecs(mass=1650, wheelbase=3.076, steerRatio=17.0),
wmis={'3FT'}, vds_codes={'TW8'}, years={MY_2022, MY_2023, MY_2024},
) )
FORD_MUSTANG_MACH_E_MK1 = FordCANFDPlatformConfig( FORD_MUSTANG_MACH_E_MK1 = FordCANFDPlatformConfig(
[FordCarDocs("Ford Mustang Mach-E 2021-24", "All", setup_video="https://www.youtube.com/watch?v=AR4_eTF3b_A")], [FordCarDocs("Ford Mustang Mach-E 2021-24", "All", setup_video="https://www.youtube.com/watch?v=AR4_eTF3b_A")],
CarSpecs(mass=2200, wheelbase=2.984, steerRatio=17.0), # TODO: check steer ratio CarSpecs(mass=2200, wheelbase=2.984, steerRatio=17.0), # TODO: check steer ratio
wmis={'3FM'}, vds_codes=MACH_E_VDS_CODES, years={MY_2021, MY_2022, MY_2023, MY_2024},
) )
FORD_RANGER_MK2 = FordCANFDPlatformConfig( FORD_RANGER_MK2 = FordCANFDPlatformConfig(
[FordCarDocs("Ford Ranger 2024", "Adaptive Cruise Control with Lane Centering", setup_video="https://www.youtube.com/watch?v=2oJlXCKYOy0")], [FordCarDocs("Ford Ranger 2024", "Adaptive Cruise Control with Lane Centering", setup_video="https://www.youtube.com/watch?v=2oJlXCKYOy0")],
CarSpecs(mass=2000, wheelbase=3.27, steerRatio=17.0), CarSpecs(mass=2000, wheelbase=3.27, steerRatio=17.0),
wmis={'1FT'}, vds_codes={'ER4'}, years={MY_2024},
) )
FORD_TRANSIT_MK5 = FordLKASteeringPlatformConfig( FORD_TRANSIT_MK5 = FordLKASteeringPlatformConfig(
[FordCarDocs("Ford Transit 2025", "Co-Pilot360 Assist+")], [FordCarDocs("Ford Transit 2025", "Co-Pilot360 Assist+")],
@@ -290,25 +257,7 @@ def match_fw_to_car_fuzzy(live_fw_versions: LiveFwVersions, vin: str, offline_fw
if valid_expected_ecus.issubset(valid_found_ecus): if valid_expected_ecus.issubset(valid_found_ecus):
candidates.add(candidate) candidates.add(candidate)
return candidates or match_vin_to_car(vin) return candidates
def match_vin_to_car(vin: str) -> set[str]:
if not is_valid_vin(vin):
return set()
vin_obj = Vin(vin)
vds = vin[3:7]
model_year = vin[9]
candidates = {platform for platform in CAR if vin_obj.wmi in platform.config.wmis and
model_year in platform.config.years and
any(code in vds for code in platform.config.vds_codes)}
if {CAR.FORD_F_150_MK14, CAR.FORD_F_150_LIGHTNING_MK1} & candidates:
electric = vin[7] in F150_ELECTRIC_CODES
candidates.discard(CAR.FORD_F_150_MK14 if electric else CAR.FORD_F_150_LIGHTNING_MK1)
return {str(candidate) for candidate in candidates}
# All of these ECUs must be present and are expected to have platform codes we can match # All of these ECUs must be present and are expected to have platform codes we can match
@@ -317,10 +266,10 @@ PLATFORM_CODE_ECUS = (Ecu.abs, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.eps)
DATA_IDENTIFIER_FORD_ASBUILT = 0xDE00 DATA_IDENTIFIER_FORD_ASBUILT = 0xDE00
ASBUILT_BLOCKS: list[tuple[int, list]] = [ ASBUILT_BLOCKS: list[tuple[int, list]] = [
(1, [Ecu.debug, Ecu.fwdCamera, Ecu.eps, Ecu.hud]), (1, [Ecu.debug, Ecu.fwdCamera, Ecu.eps]),
(2, [Ecu.abs, Ecu.debug, Ecu.eps, Ecu.hud]), (2, [Ecu.abs, Ecu.debug, Ecu.eps]),
(3, [Ecu.abs, Ecu.debug, Ecu.eps, Ecu.hud]), (3, [Ecu.abs, Ecu.debug, Ecu.eps]),
(4, [Ecu.debug, Ecu.fwdCamera, Ecu.hud]), (4, [Ecu.debug, Ecu.fwdCamera]),
(5, [Ecu.debug]), (5, [Ecu.debug]),
(6, [Ecu.debug]), (6, [Ecu.debug]),
(7, [Ecu.debug]), (7, [Ecu.debug]),
@@ -348,13 +297,13 @@ FW_QUERY_CONFIG = FwQueryConfig(
Request( Request(
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST], [StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST],
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE], [StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE],
whitelist_ecus=[Ecu.abs, Ecu.debug, Ecu.engine, Ecu.eps, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.shiftByWire, Ecu.hud], whitelist_ecus=[Ecu.abs, Ecu.debug, Ecu.engine, Ecu.eps, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.shiftByWire],
logging=True, logging=True,
), ),
Request( Request(
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST], [StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST],
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE], [StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE],
whitelist_ecus=[Ecu.abs, Ecu.debug, Ecu.engine, Ecu.eps, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.shiftByWire, Ecu.hud], whitelist_ecus=[Ecu.abs, Ecu.debug, Ecu.engine, Ecu.eps, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.shiftByWire],
bus=0, bus=0,
auxiliary=True, auxiliary=True,
), ),
@@ -371,9 +320,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
# Note: We are unlikely to get a response from behind the gateway # Note: We are unlikely to get a response from behind the gateway
(Ecu.shiftByWire, 0x732, None), # Gear Shift Module (Ecu.shiftByWire, 0x732, None), # Gear Shift Module
(Ecu.debug, 0x7d0, None), # Accessory Protocol Interface Module (Ecu.debug, 0x7d0, None), # Accessory Protocol Interface Module
(Ecu.hud, 0x720, None), # Instrument Cluster Module
], ],
non_essential_ecus={Ecu.eps: [CAR.FORD_F_150_LIGHTNING_MK1, CAR.FORD_EXPEDITION_MK4]},
# Custom fuzzy fingerprinting function using platform and model year hints # Custom fuzzy fingerprinting function using platform and model year hints
match_fw_to_car_fuzzy=match_fw_to_car_fuzzy, match_fw_to_car_fuzzy=match_fw_to_car_fuzzy,
) )
@@ -101,7 +101,6 @@ class Request:
@dataclass @dataclass
class FwQueryConfig: class FwQueryConfig:
requests: list[Request] requests: list[Request]
non_tester_present_ecus: list[Ecu] = field(default_factory=list)
# TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus # TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus
# Overrides and removes from essential ecus for specific models and ecus (exact matching) # Overrides and removes from essential ecus for specific models and ecus (exact matching)
non_essential_ecus: dict[Ecu, list[str]] = field(default_factory=dict) non_essential_ecus: dict[Ecu, list[str]] = field(default_factory=dict)
@@ -110,13 +109,8 @@ class FwQueryConfig:
# Function a brand can implement to provide better fuzzy matching. Takes in FW versions and VIN, # Function a brand can implement to provide better fuzzy matching. Takes in FW versions and VIN,
# returns set of candidates. Only will match if one candidate is returned # returns set of candidates. Only will match if one candidate is returned
match_fw_to_car_fuzzy: Callable[[LiveFwVersions, str, OfflineFwVersions], set[str]] | None = None match_fw_to_car_fuzzy: Callable[[LiveFwVersions, str, OfflineFwVersions], set[str]] | None = None
# Platforms whose shared firmware must be disambiguated by the brand fuzzy matcher.
fuzzy_only_platforms: set[str] = field(default_factory=set)
def __post_init__(self): def __post_init__(self):
assert not self.fuzzy_only_platforms or self.match_fw_to_car_fuzzy is not None, \
"Fuzzy-only platforms require a brand fuzzy matcher"
# Asserts that a request exists if extra ecus are used # Asserts that a request exists if extra ecus are used
if len(self.extra_ecus): if len(self.extra_ecus):
assert len(self.requests), "Must define a request with extra ecus" assert len(self.requests), "Must define a request with extra ecus"
+1 -8
View File
@@ -111,8 +111,7 @@ def match_fw_to_car_exact(live_fw_versions: LiveFwVersions, match_brand: str = N
invalid = set() invalid = set()
candidates = {c: f for c, f in FW_VERSIONS.items() if candidates = {c: f for c, f in FW_VERSIONS.items() if
is_brand(MODEL_TO_BRAND[c], match_brand) and is_brand(MODEL_TO_BRAND[c], match_brand)}
c not in FW_QUERY_CONFIGS[MODEL_TO_BRAND[c]].fuzzy_only_platforms}
for candidate, fws in candidates.items(): for candidate, fws in candidates.items():
config = FW_QUERY_CONFIGS[MODEL_TO_BRAND[candidate]] config = FW_QUERY_CONFIGS[MODEL_TO_BRAND[candidate]]
@@ -182,9 +181,6 @@ def get_present_ecus(can_recv: CanRecvCallable, can_send: CanSendCallable, set_o
continue continue
for ecu_type, addr, sub_addr in config.get_all_ecus(VERSIONS[brand]): for ecu_type, addr, sub_addr in config.get_all_ecus(VERSIONS[brand]):
if ecu_type in config.non_tester_present_ecus:
continue
# Only query ecus in whitelist if whitelist is not empty # Only query ecus in whitelist if whitelist is not empty
if len(r.whitelist_ecus) == 0 or ecu_type in r.whitelist_ecus: if len(r.whitelist_ecus) == 0 or ecu_type in r.whitelist_ecus:
a = (addr, sub_addr, r.bus) a = (addr, sub_addr, r.bus)
@@ -220,9 +216,6 @@ def get_brand_ecu_matches(ecu_rx_addrs: set[EcuAddrBusType]) -> dict[str, list[b
# Since we can't know what request an ecu responded to, add matches for all possible rx offsets # Since we can't know what request an ecu responded to, add matches for all possible rx offsets
for brand, config, r in REQUESTS: for brand, config, r in REQUESTS:
for ecu in config.get_all_ecus(VERSIONS[brand]): for ecu in config.get_all_ecus(VERSIONS[brand]):
if ecu[0] in config.non_tester_present_ecus:
continue
if len(r.whitelist_ecus) == 0 or ecu[0] in r.whitelist_ecus: if len(r.whitelist_ecus) == 0 or ecu[0] in r.whitelist_ecus:
brand_rx_addrs[brand].add((uds.get_rx_addr_for_tx_addr(ecu[1], r.rx_offset), ecu[2])) brand_rx_addrs[brand].add((uds.get_rx_addr_for_tx_addr(ecu[1], r.rx_offset), ecu[2]))
+3 -32
View File
@@ -69,9 +69,6 @@ TRUCK_LONG_SMOOTH_CARS = {
TRUCK_FRICTION_BRAKE_ENGAGE = 40 TRUCK_FRICTION_BRAKE_ENGAGE = 40
TRUCK_FRICTION_BRAKE_RELEASE = 8 TRUCK_FRICTION_BRAKE_RELEASE = 8
TRUCK_FRICTION_BRAKE_IMMEDIATE_ACCEL = -0.85 TRUCK_FRICTION_BRAKE_IMMEDIATE_ACCEL = -0.85
TRUCK_FOLLOW_MICRO_ACCEL_MAX = 0.55
TRUCK_FOLLOW_MICRO_ACCEL_MIN = -0.10
TRUCK_FOLLOW_MICRO_ACCEL_SLEW = 1.5
ACC_DASHBOARD_ZERO_RESERVED_CARS = { ACC_DASHBOARD_ZERO_RESERVED_CARS = {
CAR.CHEVROLET_BLAZER, CAR.CHEVROLET_BLAZER,
CAR.CHEVROLET_EQUINOX, CAR.CHEVROLET_EQUINOX,
@@ -218,11 +215,11 @@ def shape_truck_positive_accel(accel: float, v_ego: float, enabled: bool,
if not enabled or accel <= 0.0 or v_ego < 12.0: if not enabled or accel <= 0.0 or v_ego < 12.0:
return accel return accel
low_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.93, 0.84, 0.76, 0.76])) low_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.93, 0.84, 0.76, 0.70]))
mid_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.97, 0.91, 0.85, 0.85])) mid_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.97, 0.91, 0.85, 0.79]))
if lead_visible and set_speed_error > 0.0: if lead_visible and set_speed_error > 0.0:
follow_relief = float(np.interp(set_speed_error, [0.0, 1.0, 2.5, 4.0, 6.0], [0.0, 0.04, 0.10, 0.24, 0.42])) follow_relief = float(np.interp(set_speed_error, [0.0, 1.0, 2.5, 4.0, 6.0], [0.0, 0.04, 0.10, 0.18, 0.30]))
low_scale += (1.0 - low_scale) * follow_relief low_scale += (1.0 - low_scale) * follow_relief
mid_scale += (1.0 - mid_scale) * follow_relief mid_scale += (1.0 - mid_scale) * follow_relief
@@ -235,19 +232,6 @@ def shape_truck_positive_accel(accel: float, v_ego: float, enabled: bool,
return accel return accel
def smooth_truck_follow_accel(accel: float, previous_accel: float, v_ego: float,
enabled: bool, lead_visible: bool, stopping: bool) -> float:
if (
not enabled or not lead_visible or stopping or v_ego < 25.0 or
accel > TRUCK_FOLLOW_MICRO_ACCEL_MAX or accel < TRUCK_FOLLOW_MICRO_ACCEL_MIN or
previous_accel > TRUCK_FOLLOW_MICRO_ACCEL_MAX or previous_accel < TRUCK_FOLLOW_MICRO_ACCEL_MIN
):
return accel
max_delta = TRUCK_FOLLOW_MICRO_ACCEL_SLEW * DT_CTRL * 4
return previous_accel + float(np.clip(accel - previous_accel, -max_delta, max_delta))
def shape_truck_pitch_accel(pitch_accel: float, v_ego: float, enabled: bool) -> float: def shape_truck_pitch_accel(pitch_accel: float, v_ego: float, enabled: bool) -> float:
if not enabled: if not enabled:
return pitch_accel return pitch_accel
@@ -573,7 +557,6 @@ class CarController(CarControllerBase):
self.bolt_acc_pedal_friction_release_frames = 0 self.bolt_acc_pedal_friction_release_frames = 0
self.bolt_acc_pedal_friction_low_speed_active = False self.bolt_acc_pedal_friction_low_speed_active = False
self.truck_friction_brake_active = False self.truck_friction_brake_active = False
self.truck_follow_accel = 0.0
def _reset_volt_one_pedal(self): def _reset_volt_one_pedal(self):
self.volt_one_pedal_pid.reset() self.volt_one_pedal_pid.reset()
@@ -995,12 +978,10 @@ class CarController(CarControllerBase):
self.regen_release_counter = 0 self.regen_release_counter = 0
self.regen_min_on_frames = 0 self.regen_min_on_frames = 0
self.regen_min_off_frames = 0 self.regen_min_off_frames = 0
self.truck_follow_accel = 0.0
elif should_use_fixed_stopping_brake(self.CP, near_stop, stopping, CC.cruiseControl.resume): elif should_use_fixed_stopping_brake(self.CP, near_stop, stopping, CC.cruiseControl.resume):
stop_accel = getattr(starpilot_toggles, "stopAccel", self.CP.stopAccel) stop_accel = getattr(starpilot_toggles, "stopAccel", self.CP.stopAccel)
self.apply_gas = self.params.INACTIVE_REGEN self.apply_gas = self.params.INACTIVE_REGEN
self.apply_brake = int(min(-100 * stop_accel, self.params.MAX_BRAKE)) self.apply_brake = int(min(-100 * stop_accel, self.params.MAX_BRAKE))
self.truck_follow_accel = 0.0
else: else:
long_pitch_enabled = bool(getattr(starpilot_toggles, "long_pitch", True)) long_pitch_enabled = bool(getattr(starpilot_toggles, "long_pitch", True))
pedal_long_path = bool(self.CP.enableGasInterceptorDEPRECATED and (self.CP.flags & GMFlags.PEDAL_LONG.value)) pedal_long_path = bool(self.CP.enableGasInterceptorDEPRECATED and (self.CP.flags & GMFlags.PEDAL_LONG.value))
@@ -1059,16 +1040,6 @@ class CarController(CarControllerBase):
) )
accel_cmd = float(np.clip(accel_input, self.params.ACCEL_MIN, accel_max)) accel_cmd = float(np.clip(accel_input, self.params.ACCEL_MIN, accel_max))
if truck_long_smoothing:
accel_cmd = smooth_truck_follow_accel(
accel_cmd,
self.truck_follow_accel,
CS.out.vEgo,
True,
CC.hudControl.leadVisible,
stopping,
)
self.truck_follow_accel = accel_cmd
torque = self.tireRadius * ((self.mass * accel_cmd) + (0.5 * self.coeffDrag * self.frontalArea * self.airDensity * CS.out.vEgo ** 2)) torque = self.tireRadius * ((self.mass * accel_cmd) + (0.5 * self.coeffDrag * self.frontalArea * self.airDensity * CS.out.vEgo ** 2))
scaled_torque = torque + self.params.ZERO_GAS scaled_torque = torque + self.params.ZERO_GAS
apply_gas_torque = np.clip(scaled_torque, self.params.MAX_ACC_REGEN, gas_max) apply_gas_torque = np.clip(scaled_torque, self.params.MAX_ACC_REGEN, gas_max)
-32
View File
@@ -4,7 +4,6 @@ from opendbc.can import CANDefine, CANParser
from opendbc.car import Bus, create_button_events, structs from opendbc.car import Bus, create_button_events, structs
from opendbc.car import DT_CTRL from opendbc.car import DT_CTRL
from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.gps import get_car_gps_config
from opendbc.car.interfaces import CarStateBase from opendbc.car.interfaces import CarStateBase
from opendbc.car.gm.values import ( from opendbc.car.gm.values import (
ALT_ACCS, ALT_ACCS,
@@ -105,31 +104,6 @@ class CarState(CarStateBase):
self.lkas_enabled = 0 self.lkas_enabled = 0
self.pcm_acc_status = AccState.OFF self.pcm_acc_status = AccState.OFF
self.stock_fcw_alert = 0 self.stock_fcw_alert = 0
self.car_gps_config = get_car_gps_config(CP)
self.car_gps_supported = self.car_gps_config is not None
self.car_gps = None
self._car_gps_timestamp_nanos = 0
def _update_car_gps(self, cp) -> None:
if self.car_gps_config is None:
return
timestamps = [max(cp.ts_nanos[name].values(), default=0) for name in self.car_gps_config.messages]
if not all(timestamps) or max(timestamps) - min(timestamps) > 2_000_000_000:
return
timestamp_nanos = max(timestamps)
if timestamp_nanos <= self._car_gps_timestamp_nanos:
return
gps = self.car_gps_config.decoder(*(cp.vl[name] for name in self.car_gps_config.messages))
if gps is not None:
gps["timestamp_nanos"] = timestamp_nanos
self.car_gps = gps
self._car_gps_timestamp_nanos = timestamp_nanos
def get_car_gps(self):
return self.car_gps
def update_button_enable(self, buttonEvents: list[structs.CarState.ButtonEvent]): def update_button_enable(self, buttonEvents: list[structs.CarState.ButtonEvent]):
if not self.CP.pcmCruise: if not self.CP.pcmCruise:
@@ -145,8 +119,6 @@ class CarState(CarStateBase):
cam_cp = can_parsers[Bus.cam] cam_cp = can_parsers[Bus.cam]
loopback_cp = can_parsers[Bus.loopback] loopback_cp = can_parsers[Bus.loopback]
self._update_car_gps(pt_cp)
ret = structs.CarState() ret = structs.CarState()
volt_like = { volt_like = {
@@ -456,9 +428,6 @@ class CarState(CarStateBase):
@staticmethod @staticmethod
def get_can_parsers(CP): def get_can_parsers(CP):
gps_config = get_car_gps_config(CP)
gps_messages = [(name, 0) for name in gps_config.messages] if gps_config is not None else []
volt_like = { volt_like = {
CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_VOLT_2019,
@@ -482,7 +451,6 @@ class CarState(CarStateBase):
("PSCMSteeringAngle", 100), ("PSCMSteeringAngle", 100),
("ECMAcceleratorPos", 80), ("ECMAcceleratorPos", 80),
("SportMode", 0), ("SportMode", 0),
*gps_messages,
] ]
prndl2_rate = 10 if CP.carFingerprint in kaofui_state_cars else 40 prndl2_rate = 10 if CP.carFingerprint in kaofui_state_cars else 40
+15 -14
View File
@@ -30,20 +30,20 @@ FINGERPRINTS = {
CAR.BUICK_LACROSSE: [{ CAR.BUICK_LACROSSE: [{
190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 510: 8, 528: 5, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 5, 707: 8, 753: 5, 761: 7, 801: 8, 804: 3, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 872: 1, 882: 8, 890: 1, 892: 2, 893: 1, 894: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1904: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1914: 7, 1916: 7, 1918: 7, 1919: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 510: 8, 528: 5, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 5, 707: 8, 753: 5, 761: 7, 801: 8, 804: 3, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 872: 1, 882: 8, 890: 1, 892: 2, 893: 1, 894: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1904: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1914: 7, 1916: 7, 1918: 7, 1919: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8
}], }],
CAR.CHEVROLET_VOLT_CC: [ # CAR.CHEVROLET_VOLT_CC: [
# Captured no-ACC Volt fingerprints for OBD-C/L&P harness installations # FIXME: Need a message to distinguish flashed from non-flashed
# Volt Premier w/o ACC 2016 # Volt Premier w/o acc 2016
{ # {
170: 8, 171: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 209: 7, 211: 2, 241: 6, 288: 5, 289: 1, 290: 1, 298: 2, 304: 8, 308: 4, 309: 8, 311: 8, 313: 8, 320: 8, 328: 1, 352: 5, 368: 8, 381: 6, 384: 8, 386: 5, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 3, 508: 8, 512: 3, 528: 4, 530: 8, 532: 6, 537: 4, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 8, 563: 5, 564: 5, 565: 8, 566: 5, 567: 3, 568: 1, 577: 8, 578: 8, 594: 8, 647: 3, 707: 8, 711: 6, 717: 5, 761: 7, 800: 6, 810: 8, 821: 4, 823: 7, 832: 8, 840: 5, 842: 6, 844: 8, 866: 4, 869: 4, 961: 8, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1602: 8, 1618: 8, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1928: 7, 1930: 7, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2024: 8, 2025: 8, 2028: 8 # 170: 8, 171: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 209: 7, 211: 2, 241: 6, 288: 5, 289: 1, 290: 1, 298: 2, 304: 8, 308: 4, 309: 8, 311: 8, 313: 8, 320: 8, 328: 1, 352: 5, 368: 8, 381: 6, 384: 8, 386: 5, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 3, 508: 8, 512: 3, 528: 4, 530: 8, 532: 6, 537: 4, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 8, 563: 5, 564: 5, 565: 8, 566: 5, 567: 3, 568: 1, 577: 8, 578: 8, 594: 8, 647: 3, 707: 8, 711: 6, 717: 5, 761: 7, 800: 6, 810: 8, 821: 4, 823: 7, 832: 8, 840: 5, 842: 6, 844: 8, 866: 4, 869: 4, 961: 8, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1602: 8, 1618: 8, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1928: 7, 1930: 7, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2024: 8, 2025: 8, 2028: 8
}, # },
{ # {
201: 8, 493: 8, 495: 4, 193: 8, 197: 8, 209: 7, 171: 8, 456: 8, 199: 4, 489: 8, 211: 2, 499: 3, 390: 7, 532: 6, 568: 1, 761: 7, 381: 6, 485: 8, 189: 7, 479: 3, 711: 6, 501: 8, 241: 6, 717: 5, 869: 4, 389: 2, 454: 8, 170: 8, 190: 6, 497: 8, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 500: 6, 508: 8, 528: 4, 647: 3, 1105: 6, 1005: 6, 481: 7, 844: 8, 866: 4, 564: 5, 969: 8, 388: 8, 352: 5, 562: 8, 961: 8, 386: 8, 707: 8, 977: 8, 979: 7, 298: 8, 840: 5, 842: 5, 988: 6, 1001: 8, 560: 8, 546: 7, 558: 8, 309: 8, 995: 7, 311: 8, 566: 5, 567:3, 989: 8, 384: 4, 800: 6, 1033: 7, 1034: 7, 313: 8, 554: 3, 810: 8, 1017: 8, 1019: 2, 1020: 8, 1217: 8, 1223: 3, 1233: 8, 1227: 4, 1417: 8, 1009: 8, 1221: 5, 1275: 3, 1225: 7, 289: 8, 550: 8, 1273: 3, 1928: 7, 1187: 4, 1265: 8, 1927: 7, 1267: 1, 1906: 7, 288: 5, 304: 1, 328: 1, 1912: 7, 320: 3, 1910: 7, 563: 5, 1249: 8, 1930: 7, 1257: 6, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 565: 5, 1280: 4, 1907: 7 # 201: 8, 493: 8, 495: 4, 193: 8, 197: 8, 209: 7, 171: 8, 456: 8, 199: 4, 489: 8, 211: 2, 499: 3, 390: 7, 532: 6, 568: 1, 761: 7, 381: 6, 485: 8, 189: 7, 479: 3, 711: 6, 501: 8, 241: 6, 717: 5, 869: 4, 389: 2, 454: 8, 170: 8, 190: 6, 497: 8, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 500: 6, 508: 8, 528: 4, 647: 3, 1105: 6, 1005: 6, 481: 7, 844: 8, 866: 4, 564: 5, 969: 8, 388: 8, 352: 5, 562: 8, 961: 8, 386: 8, 707: 8, 977: 8, 979: 7, 298: 8, 840: 5, 842: 5, 988: 6, 1001: 8, 560: 8, 546: 7, 558: 8, 309: 8, 995: 7, 311: 8, 566: 5, 567:3, 989: 8, 384: 4, 800: 6, 1033: 7, 1034: 7, 313: 8, 554: 3, 810: 8, 1017: 8, 1019: 2, 1020: 8, 1217: 8, 1223: 3, 1233: 8, 1227: 4, 1417: 8, 1009: 8, 1221: 5, 1275: 3, 1225: 7, 289: 8, 550: 8, 1273: 3, 1928: 7, 1187: 4, 1265: 8, 1927: 7, 1267: 1, 1906: 7, 288: 5, 304: 1, 328: 1, 1912: 7, 320: 3, 1910: 7, 563: 5, 1249: 8, 1930: 7, 1257: 6, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 565: 5, 1280: 4, 1907: 7
}, # },
# Volt Premier w/o ACC 2018 + Pedal # # Volt Premier w/o ACC 2018 + Pedal
{ # {
189: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 497: 8, 500: 6, 501: 8, 513: 6, 528: 4, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 566: 5, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 717: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1922: 7, 1930: 7 # 189: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 497: 8, 500: 6, 501: 8, 513: 6, 528: 4, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 566: 5, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 717: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1922: 7, 1930: 7
} # }
], # ],
CAR.BUICK_REGAL: [{ CAR.BUICK_REGAL: [{
190: 8, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 8, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 8, 419: 8, 422: 4, 426: 8, 431: 8, 442: 8, 451: 8, 452: 8, 453: 8, 455: 7, 456: 8, 463: 3, 479: 8, 481: 7, 485: 8, 487: 8, 489: 8, 495: 8, 497: 8, 499: 3, 500: 8, 501: 8, 508: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 569: 3, 573: 1, 577: 8, 578: 8, 579: 8, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 882: 8, 884: 8, 890: 1, 892: 2, 893: 2, 894: 1, 961: 8, 967: 8, 969: 8, 977: 8, 979: 8, 985: 8, 1001: 8, 1005: 6, 1009: 8, 1011: 8, 1013: 3, 1017: 8, 1020: 8, 1024: 8, 1025: 8, 1026: 8, 1027: 8, 1028: 8, 1029: 8, 1030: 8, 1031: 8, 1032: 2, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 8, 1225: 7, 1233: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 8, 1263: 8, 1265: 8, 1267: 8, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1601: 8, 1602: 8, 1603: 7, 1611: 8, 1618: 8, 1906: 8, 1907: 7, 1912: 7, 1914: 7, 1916: 7, 1919: 7, 1930: 7, 2016: 8, 2018: 8, 2019: 8, 2024: 8, 2026: 8 190: 8, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 8, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 8, 419: 8, 422: 4, 426: 8, 431: 8, 442: 8, 451: 8, 452: 8, 453: 8, 455: 7, 456: 8, 463: 3, 479: 8, 481: 7, 485: 8, 487: 8, 489: 8, 495: 8, 497: 8, 499: 3, 500: 8, 501: 8, 508: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 569: 3, 573: 1, 577: 8, 578: 8, 579: 8, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 882: 8, 884: 8, 890: 1, 892: 2, 893: 2, 894: 1, 961: 8, 967: 8, 969: 8, 977: 8, 979: 8, 985: 8, 1001: 8, 1005: 6, 1009: 8, 1011: 8, 1013: 3, 1017: 8, 1020: 8, 1024: 8, 1025: 8, 1026: 8, 1027: 8, 1028: 8, 1029: 8, 1030: 8, 1031: 8, 1032: 2, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 8, 1225: 7, 1233: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 8, 1263: 8, 1265: 8, 1267: 8, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1601: 8, 1602: 8, 1603: 7, 1611: 8, 1618: 8, 1906: 8, 1907: 7, 1912: 7, 1914: 7, 1916: 7, 1919: 7, 1930: 7, 2016: 8, 2018: 8, 2019: 8, 2024: 8, 2026: 8
}], }],
@@ -207,6 +207,7 @@ FINGERPRINTS = {
FINGERPRINTS.update({ FINGERPRINTS.update({
CAR.CHEVROLET_VOLT_ASCM: FINGERPRINTS[CAR.CHEVROLET_VOLT], CAR.CHEVROLET_VOLT_ASCM: FINGERPRINTS[CAR.CHEVROLET_VOLT],
CAR.CHEVROLET_VOLT_CAMERA: [{**fp, CAMERA_DIAGNOSTIC_ADDRESS: 8, CAMERA_DIAGNOSTIC_RX_ADDRESS: 8} for fp in FINGERPRINTS[CAR.CHEVROLET_VOLT]], CAR.CHEVROLET_VOLT_CAMERA: [{**fp, CAMERA_DIAGNOSTIC_ADDRESS: 8, CAMERA_DIAGNOSTIC_RX_ADDRESS: 8} for fp in FINGERPRINTS[CAR.CHEVROLET_VOLT]],
CAR.CHEVROLET_VOLT_CC: FINGERPRINTS[CAR.CHEVROLET_VOLT],
CAR.GMC_ACADIA_ASCM: FINGERPRINTS[CAR.GMC_ACADIA], CAR.GMC_ACADIA_ASCM: FINGERPRINTS[CAR.GMC_ACADIA],
CAR.CHEVROLET_MALIBU_ASCM: FINGERPRINTS[CAR.CHEVROLET_MALIBU], CAR.CHEVROLET_MALIBU_ASCM: FINGERPRINTS[CAR.CHEVROLET_MALIBU],
CAR.CADILLAC_ESCALADE_ASCM: FINGERPRINTS[CAR.CADILLAC_ESCALADE], CAR.CADILLAC_ESCALADE_ASCM: FINGERPRINTS[CAR.CADILLAC_ESCALADE],
+4 -6
View File
@@ -1,4 +1,4 @@
from opendbc.car import DT_CTRL, structs from opendbc.car import DT_CTRL
from opendbc.car.can_definitions import CanData from opendbc.car.can_definitions import CanData
from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.gm.values import CAR, CanBus, CruiseButtons, GMFlags from opendbc.car.gm.values import CAR, CanBus, CruiseButtons, GMFlags
@@ -420,11 +420,9 @@ def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggl
idx = (CS.buttons_counter + 1) % 4 # Need to predict the next idx for '22-23 EUV idx = (CS.buttons_counter + 1) % 4 # Need to predict the next idx for '22-23 EUV
msgs = [create_buttons(packer, CanBus.POWERTRAIN, idx, cruise_btn)] msgs = [create_buttons(packer, CanBus.POWERTRAIN, idx, cruise_btn)]
# A camera-forward Volt CC install needs the button spoof on both sides. # Flashed camera-forward Volt CC installs also need the button spoof on the
# The OBD-C/L&P gateway variant has no camera bus and remains PT-only. # camera side. Removed-camera installs set NO_CAMERA and keep this PT-only.
if (CS.CP.carFingerprint == CAR.CHEVROLET_VOLT_CC and if CS.CP.carFingerprint == CAR.CHEVROLET_VOLT_CC and not (CS.CP.flags & GMFlags.NO_CAMERA.value):
getattr(CS.CP, "networkLocation", None) == structs.CarParams.NetworkLocation.fwdCamera and
not (CS.CP.flags & GMFlags.NO_CAMERA.value)):
msgs.append(create_buttons(packer, CanBus.CAMERA, idx, cruise_btn)) msgs.append(create_buttons(packer, CanBus.CAMERA, idx, cruise_btn))
return msgs return msgs
else: else:
+2 -8
View File
@@ -70,10 +70,6 @@ NON_LINEAR_TORQUE_PARAMS = {
"left": [1.525, 1.05, 0.155, 0.0], "left": [1.525, 1.05, 0.155, 0.0],
"right": [1.525, 0.95, 0.150, 0.0], "right": [1.525, 0.95, 0.150, 0.0],
}, },
CAR.CHEVROLET_TRAX: {
"left": [3.8060, 0.8282, 0.1702, 0],
"right": [3.8060, 0.8282, 0.1702, 0],
},
} }
NON_LINEAR_TORQUE_PARAM_ALIASES = { NON_LINEAR_TORQUE_PARAM_ALIASES = {
@@ -273,6 +269,7 @@ class CarInterface(CarInterfaceBase):
kaofui_camera_cars = { kaofui_camera_cars = {
CAR.CHEVROLET_VOLT_CAMERA, CAR.CHEVROLET_VOLT_CAMERA,
CAR.CHEVROLET_VOLT_CC,
CAR.CHEVROLET_MALIBU_HYBRID_CC, CAR.CHEVROLET_MALIBU_HYBRID_CC,
} }
bolt_cc_camera_cars = { bolt_cc_camera_cars = {
@@ -684,8 +681,6 @@ class CarInterface(CarInterfaceBase):
if candidate in CC_ONLY_CAR: if candidate in CC_ONLY_CAR:
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_ACC.value ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_ACC.value
if candidate == CAR.CHEVROLET_VOLT_CC and ret.networkLocation == NetworkLocation.gateway:
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_VOLT_CC_GATEWAY.value
if candidate in SDGM_CAR and ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]: if candidate in SDGM_CAR and ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]:
ret.flags |= GMFlags.FORCE_BRAKE_C9.value ret.flags |= GMFlags.FORCE_BRAKE_C9.value
@@ -699,7 +694,7 @@ class CarInterface(CarInterfaceBase):
if ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]: if ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]:
ret.flags |= GMFlags.NO_ACCELERATOR_POS_MSG.value ret.flags |= GMFlags.NO_ACCELERATOR_POS_MSG.value
if candidate in (CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_CC) and ret.networkLocation == NetworkLocation.gateway: if candidate == CAR.CHEVROLET_VOLT and ret.networkLocation == NetworkLocation.gateway:
# Reuse the no-camera safety bit as an ASCM Volt selector for the alternate EBCM brake path. # Reuse the no-camera safety bit as an ASCM Volt selector for the alternate EBCM brake path.
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_CAMERA.value ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_CAMERA.value
@@ -785,7 +780,6 @@ class CarInterface(CarInterfaceBase):
ret.alternativeExperience |= ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE ret.alternativeExperience |= ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE
if candidate == CAR.CHEVROLET_TRAX: if candidate == CAR.CHEVROLET_TRAX:
ret.steerActuatorDelay = 0.46
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
return ret return ret
@@ -57,7 +57,6 @@ from opendbc.car.gm.carcontroller import (
shape_truck_friction_brake, shape_truck_friction_brake,
shape_truck_pitch_accel, shape_truck_pitch_accel,
shape_truck_positive_accel, shape_truck_positive_accel,
smooth_truck_follow_accel,
should_use_fixed_stopping_brake, should_use_fixed_stopping_brake,
should_activate_auto_hold, should_activate_auto_hold,
should_activate_volt_one_pedal, should_activate_volt_one_pedal,
@@ -363,8 +362,6 @@ def test_live_camera_path_does_not_send_pt_keepalive():
def test_acc_2cd_replacement_only_used_with_live_camera_path(): def test_acc_2cd_replacement_only_used_with_live_camera_path():
assert should_send_acc_2cd(SimpleNamespace( assert should_send_acc_2cd(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=0)) carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=0))
assert should_send_acc_2cd(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_SILVERADO, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=0))
assert not should_send_acc_2cd(SimpleNamespace( assert not should_send_acc_2cd(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=GMFlags.NO_CAMERA.value)) carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=GMFlags.NO_CAMERA.value))
assert not should_send_acc_2cd(SimpleNamespace( assert not should_send_acc_2cd(SimpleNamespace(
@@ -865,27 +862,6 @@ def test_shape_truck_positive_accel_does_not_relax_without_speed_error():
assert no_error == base assert no_error == base
def test_shape_truck_positive_accel_keeps_more_highway_follow_authority():
city = shape_truck_positive_accel(0.28, 26.0, True)
highway = shape_truck_positive_accel(0.28, 34.0, True)
assert highway >= city
def test_smooth_truck_follow_accel_slews_small_highway_commands():
shaped = smooth_truck_follow_accel(0.50, 0.0, 30.0, True, True, False)
assert shaped == pytest.approx(0.06)
def test_smooth_truck_follow_accel_does_not_delay_safety_requests():
assert smooth_truck_follow_accel(-0.40, 0.20, 30.0, True, True, False) == -0.40
assert smooth_truck_follow_accel(0.20, -0.40, 30.0, True, True, False) == 0.20
assert smooth_truck_follow_accel(-0.20, 0.20, 30.0, True, True, True) == -0.20
assert smooth_truck_follow_accel(-0.20, 0.20, 20.0, True, True, False) == -0.20
assert smooth_truck_follow_accel(-0.20, 0.20, 30.0, True, False, False) == -0.20
def test_shape_truck_pitch_accel_attenuates_highway_grade_feedforward(): def test_shape_truck_pitch_accel_attenuates_highway_grade_feedforward():
assert shape_truck_pitch_accel(-0.30, 30.0, True) == pytest.approx(-0.0825) assert shape_truck_pitch_accel(-0.30, 30.0, True) == pytest.approx(-0.0825)
assert shape_truck_pitch_accel(0.30, 30.0, True) == pytest.approx(0.0825) assert shape_truck_pitch_accel(0.30, 30.0, True) == pytest.approx(0.0825)
@@ -20,7 +20,6 @@ from opendbc.car.gm.carcontroller import (
) )
import opendbc.car.gm.interface as gm_interface import opendbc.car.gm.interface as gm_interface
from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.gps import CHEVROLET_BOLT_GPS_CARS, CHEVROLET_BOLT_GPS_MESSAGES, get_car_gps_config, parse_chevrolet_bolt_can_gps
from opendbc.car.gm.fingerprints import FINGERPRINTS from opendbc.car.gm.fingerprints import FINGERPRINTS
from opendbc.car.gm.values import ASCM_INT, CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, DBC, GM_RX_OFFSET, CarControllerParams, CruiseButtons, GMFlags, GMSafetyFlags from opendbc.car.gm.values import ASCM_INT, CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, DBC, GM_RX_OFFSET, CarControllerParams, CruiseButtons, GMFlags, GMSafetyFlags
from opendbc.safety import ALTERNATIVE_EXPERIENCE from opendbc.safety import ALTERNATIVE_EXPERIENCE
@@ -66,43 +65,6 @@ class TestGMFingerprint:
assert finger.get(required_addr) == 8, required_addr assert finger.get(required_addr) == 8, required_addr
class TestBoltGps:
@parameterized.expand(CHEVROLET_BOLT_GPS_CARS)
def test_all_bolt_generations_are_registered(self, car_model):
config = get_car_gps_config(SimpleNamespace(carFingerprint=car_model, brand="gm"))
assert config is not None
assert config.messages == CHEVROLET_BOLT_GPS_MESSAGES
gps = parse_chevrolet_bolt_can_gps({
"GPSLatitude": 145292743.0,
"GPSLongitude": -267520892.0,
})
assert gps is not None
assert gps["hasFix"]
assert gps["latitude"] == pytest.approx(40.3590953)
assert gps["longitude"] == pytest.approx(-74.3113589)
def test_invalid_bolt_position_does_not_become_a_fix(self):
gps = parse_chevrolet_bolt_can_gps({"GPSLatitude": 0.0, "GPSLongitude": -2147483648.0})
assert gps is not None
assert not gps["hasFix"]
assert gps["latitude"] == 0.0
assert gps["longitude"] == 0.0
@parameterized.expand(CHEVROLET_BOLT_GPS_CARS)
def test_gps_message_is_added_to_powertrain_parser(self, car_model):
cp = SimpleNamespace(
brand="gm",
carFingerprint=car_model,
flags=0,
networkLocation=structs.CarParams.NetworkLocation.gateway,
transmissionType=structs.CarParams.TransmissionType.direct,
enableBsm=False,
enableGasInterceptorDEPRECATED=False,
)
parsers = GMCarState.get_can_parsers(cp)
assert all(message in parsers[Bus.pt].vl for message in CHEVROLET_BOLT_GPS_MESSAGES)
class TestGMInterface: class TestGMInterface:
@parameterized.expand([ @parameterized.expand([
CAR.CHEVROLET_BOLT_CC_2017, CAR.CHEVROLET_BOLT_CC_2017,
@@ -239,45 +201,6 @@ class TestGMInterface:
assert car_params.flags & GMFlags.NO_CAMERA.value assert car_params.flags & GMFlags.NO_CAMERA.value
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_CAMERA.value assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_CAMERA.value
def test_volt_cc_obd_gateway_uses_cc_long_no_camera_path(self):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_CC]
car_params = CarInterface.get_params(
CAR.CHEVROLET_VOLT_CC,
_empty_fingerprint(),
[],
alpha_long=False,
is_release=False,
docs=False,
starpilot_toggles=_test_starpilot_toggles(),
)
assert car_params.networkLocation == structs.CarParams.NetworkLocation.gateway
assert car_params.flags & GMFlags.CC_LONG.value
assert car_params.flags & GMFlags.NO_CAMERA.value
assert not (car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_CAM.value)
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_CC_LONG.value
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_ACC.value
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_CAMERA.value
parsers = CarInterface.CarState.get_can_parsers(car_params)
assert "ECMCruiseControl" in parsers[Bus.pt].vl
assert not parsers[Bus.cam].vl
def test_other_cc_only_gateway_does_not_use_volt_cc_safety_path(self):
CarInterface = interfaces[CAR.CHEVROLET_SILVERADO_CC]
car_params = CarInterface.get_params(
CAR.CHEVROLET_SILVERADO_CC,
_empty_fingerprint(),
[],
alpha_long=False,
is_release=False,
docs=False,
starpilot_toggles=_test_starpilot_toggles(),
)
assert car_params.networkLocation == structs.CarParams.NetworkLocation.gateway
assert not (car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_VOLT_CC_GATEWAY.value)
def test_volt_ascm_sparse_fingerprint_without_camera_does_not_set_no_camera(self): def test_volt_ascm_sparse_fingerprint_without_camera_does_not_set_no_camera(self):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM] CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
fingerprint = { fingerprint = {
@@ -610,7 +533,6 @@ class TestGMCarController:
CP=SimpleNamespace( CP=SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CC, carFingerprint=CAR.CHEVROLET_VOLT_CC,
flags=0, flags=0,
networkLocation=structs.CarParams.NetworkLocation.fwdCamera,
minEnableSpeed=24 * CV.MPH_TO_MS, minEnableSpeed=24 * CV.MPH_TO_MS,
), ),
buttons_counter=2, buttons_counter=2,
@@ -632,7 +554,6 @@ class TestGMCarController:
CP=SimpleNamespace( CP=SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CC, carFingerprint=CAR.CHEVROLET_VOLT_CC,
flags=GMFlags.NO_CAMERA.value, flags=GMFlags.NO_CAMERA.value,
networkLocation=structs.CarParams.NetworkLocation.gateway,
minEnableSpeed=24 * CV.MPH_TO_MS, minEnableSpeed=24 * CV.MPH_TO_MS,
), ),
buttons_counter=2, buttons_counter=2,
+11 -8
View File
@@ -175,7 +175,6 @@ class GMSafetyFlags(IntFlag):
FLAG_GM_REMOTE_START_BOOTS_COMMA = 8192 FLAG_GM_REMOTE_START_BOOTS_COMMA = 8192
FLAG_GM_PANDA_3D1_SCHED = 16384 FLAG_GM_PANDA_3D1_SCHED = 16384
FLAG_GM_PANDA_PADDLE_SCHED = 32768 FLAG_GM_PANDA_PADDLE_SCHED = 32768
FLAG_GM_VOLT_CC_GATEWAY = 16384
class Footnote(Enum): class Footnote(Enum):
@@ -215,12 +214,16 @@ class GMPlatformConfig(PlatformConfig):
@dataclass @dataclass
class GMASCMPlatformConfig(GMPlatformConfig): class GMASCMPlatformConfig(GMPlatformConfig):
pass def init(self):
# ASCM is supported, but due to a janky install and hardware configuration, we are not showing in the car docs
self.car_docs = []
@dataclass @dataclass
class GMSDGMPlatformConfig(GMPlatformConfig): class GMSDGMPlatformConfig(GMPlatformConfig):
pass def init(self):
# Don't show in docs until the harness is sold. See https://github.com/commaai/openpilot/issues/32471
self.car_docs = []
class CAR(Platforms): class CAR(Platforms):
@@ -248,7 +251,7 @@ class CAR(Platforms):
dbc_dict=CHEVROLET_VOLT.dbc_dict, dbc_dict=CHEVROLET_VOLT.dbc_dict,
) )
CHEVROLET_VOLT_CC = GMPlatformConfig( CHEVROLET_VOLT_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Volt No-ACC 2016-18 (OBD Harness)", "Redneck ACC", min_enable_speed=0)], [GMCarDocs("Chevrolet Volt No-ACC 2017-18", min_enable_speed=0)],
CHEVROLET_VOLT.specs, CHEVROLET_VOLT.specs,
dbc_dict=CHEVROLET_VOLT.dbc_dict, dbc_dict=CHEVROLET_VOLT.dbc_dict,
) )
@@ -310,16 +313,16 @@ class CAR(Platforms):
) )
CHEVROLET_BOLT_ACC_2022_2023 = GMPlatformConfig( CHEVROLET_BOLT_ACC_2022_2023 = GMPlatformConfig(
[ [
GMCarDocs("Chevrolet Bolt EV & EUV ACC 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", video="https://youtu.be/xvwzGMUA210"), GMCarDocs("Chevrolet Bolt ACC 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", video="https://youtu.be/xvwzGMUA210"),
], ],
GMCarSpecs(mass=1669, wheelbase=2.63779, steerRatio=16.8, centerToFrontRatio=0.4, tireStiffnessFactor=1.0), GMCarSpecs(mass=1669, wheelbase=2.63779, steerRatio=16.8, centerToFrontRatio=0.4, tireStiffnessFactor=1.0),
) )
CHEVROLET_BOLT_ACC_2022_2023_PEDAL = GMPlatformConfig( CHEVROLET_BOLT_ACC_2022_2023_PEDAL = GMPlatformConfig(
[GMCarDocs("Chevrolet Bolt EV & EUV ACC w Pedal 2022-23")], [GMCarDocs("Chevrolet Bolt EV ACC w Pedal 2022-23")],
CHEVROLET_BOLT_ACC_2022_2023.specs, CHEVROLET_BOLT_ACC_2022_2023.specs,
) )
CHEVROLET_BOLT_CC_2022_2023 = GMPlatformConfig( CHEVROLET_BOLT_CC_2022_2023 = GMPlatformConfig(
[GMCarDocs("Chevrolet Bolt EV & EUV No-ACC 2022-23")], [GMCarDocs("Chevrolet Bolt EV No-ACC 2022-23")],
CHEVROLET_BOLT_ACC_2022_2023.specs, CHEVROLET_BOLT_ACC_2022_2023.specs,
) )
CHEVROLET_BOLT_CC_2018_2021 = GMPlatformConfig( CHEVROLET_BOLT_CC_2018_2021 = GMPlatformConfig(
@@ -430,7 +433,7 @@ class CAR(Platforms):
CHEVROLET_TRAILBLAZER.specs, CHEVROLET_TRAILBLAZER.specs,
) )
CHEVROLET_TRAX = GMPlatformConfig( CHEVROLET_TRAX = GMPlatformConfig(
[GMCarDocs("Chevrolet TRAX 2024-25")], [GMCarDocs("Chevrolet TRAX 2024")],
CarSpecs(mass=1365, wheelbase=2.7, steerRatio=16.4, centerToFrontRatio=0.4), CarSpecs(mass=1365, wheelbase=2.7, steerRatio=16.4, centerToFrontRatio=0.4),
) )
-166
View File
@@ -1,166 +0,0 @@
import math
from dataclasses import dataclass
from datetime import UTC, datetime
from collections.abc import Callable, Mapping
from typing import Any
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.ford.values import CAR as FORD_CAR
from opendbc.car.gm.values import CAR as GM_CAR
CarGpsSample = dict[str, Any]
CanGpsDecoder = Callable[..., CarGpsSample | None]
@dataclass(frozen=True)
class CarGpsConfig:
"""Vehicle-specific CAN GPS inputs and decoder."""
brand: str
messages: tuple[str, ...]
decoder: CanGpsDecoder
def _dop_accuracy(dop: float, default: float = 500.0) -> float:
"""Convert Ford's dimensionless DOP into a conservative meter estimate."""
return max(1.0, dop * 5.0) if 0.0 <= dop <= 5.8 else default
def parse_ford_can_gps(nav1: Mapping[str, float], nav2: Mapping[str, float], nav3: Mapping[str, float]) -> CarGpsSample | None:
"""Decode the Ford APIM GPS messages into the fields used by gpsLocationExternal."""
year = int(nav2["GpsUtcYr_No_Actl"])
month = int(nav2["GpsUtcMnth_No_Actl"])
day = int(nav2["GpsUtcDay_No_Actl"])
hour = int(nav2["GPS_UTC_hours"])
minute = int(nav2["GPS_UTC_minutes"])
second = int(nav2["GPS_UTC_seconds"])
try:
timestamp_ms = int(datetime(year, month, day, hour, minute, second, tzinfo=UTC).timestamp() * 1000)
except ValueError:
return None
latitude_direction = int(nav1["GpsHsphLattSth_D_Actl"])
longitude_direction = int(nav1["GpsHsphLongEast_D_Actl"])
latitude_degrees = abs(float(nav1["GPS_Latitude_Degrees"]))
longitude_degrees = abs(float(nav1["GPS_Longitude_Degrees"]))
latitude_minutes = float(nav1["GPS_Latitude_Minutes"]) + float(nav1["GPS_Latitude_Min_dec"])
longitude_minutes = float(nav1["GPS_Longitude_Minutes"]) + float(nav1["GPS_Longitude_Min_dec"])
coordinates_valid = (
latitude_direction in (1, 2) and longitude_direction in (1, 2) and
0.0 <= latitude_degrees <= 90.0 and 0.0 <= longitude_degrees <= 180.0 and
0.0 <= latitude_minutes < 60.0 and 0.0 <= longitude_minutes < 60.0
)
latitude = (1.0 if latitude_direction == 2 else -1.0) * (latitude_degrees + latitude_minutes / 60.0) if coordinates_valid else 0.0
longitude = (1.0 if longitude_direction == 1 else -1.0) * (longitude_degrees + longitude_minutes / 60.0) if coordinates_valid else 0.0
dimension = int(nav3["GPS_dimension"])
has_fix = coordinates_valid and dimension in (1, 2) and int(nav2["Gps_B_Falt"]) == 0
speed_mph = float(nav3["GPS_Speed"])
speed_mps = speed_mph * CV.MPH_TO_MS
heading = float(nav3["GPS_Heading"])
if speed_mph in (254.0, 255.0) or not math.isfinite(speed_mps) or not 0.0 <= speed_mps <= 200.0:
speed_mps = 0.0
if not math.isfinite(heading) or not 0.0 <= heading < 360.0:
heading = 0.0
vertical_accuracy = _dop_accuracy(float(nav3["GPS_Vdop"]))
horizontal_accuracy = _dop_accuracy(float(nav3["GPS_Hdop"]))
satellite_count = int(nav3["GPS_Sat_num_in_view"])
if not 0 <= satellite_count < 30: # 30 and 31 are Ford's unknown/invalid values.
satellite_count = 0
heading_rad = math.radians(heading)
return {
"latitude": latitude,
"longitude": longitude,
"altitude": (float(nav3["GPS_MSL_altitude"]) * 0.3048) if has_fix else 0.0,
"speed": speed_mps,
"bearingDeg": heading,
"horizontalAccuracy": horizontal_accuracy,
"unixTimestampMillis": timestamp_ms,
"verticalAccuracy": vertical_accuracy,
"bearingAccuracyDeg": max(5.0, horizontal_accuracy * 2.0) if speed_mps > 1.0 else 180.0,
"speedAccuracy": max(0.5, horizontal_accuracy),
"hasFix": has_fix,
"satelliteCount": satellite_count,
"vNED": [speed_mps * math.cos(heading_rad), speed_mps * math.sin(heading_rad), 0.0],
}
def parse_chevrolet_bolt_can_gps(position: Mapping[str, float]) -> CarGpsSample | None:
"""Decode the Bolt's OnStar GPS position message."""
try:
latitude = float(position["GPSLatitude"]) / 3_600_000.0
longitude = float(position["GPSLongitude"]) / 3_600_000.0
except (KeyError, TypeError, ValueError):
return None
coordinates_valid = (
math.isfinite(latitude) and math.isfinite(longitude) and
-90.0 <= latitude <= 90.0 and -180.0 <= longitude <= 180.0 and
(latitude != 0.0 or longitude != 0.0)
)
if not coordinates_valid:
latitude = longitude = 0.0
return {
"latitude": latitude,
"longitude": longitude,
"altitude": 0.0,
"speed": 0.0,
"bearingDeg": 0.0,
"horizontalAccuracy": 100.0,
"unixTimestampMillis": int(datetime.now(UTC).timestamp() * 1000),
"verticalAccuracy": 100.0,
"bearingAccuracyDeg": 180.0,
"speedAccuracy": 100.0,
"hasFix": coordinates_valid,
"satelliteCount": 0,
"vNED": [0.0, 0.0, 0.0],
}
FORD_MACH_E_GPS_MESSAGES = (
"APIMGPS_Data_Nav_1_FD1",
"APIMGPS_Data_Nav_2_FD1",
"APIMGPS_Data_Nav_3_FD1",
)
CHEVROLET_BOLT_GPS_MESSAGES = ("TCICOnStarGPSPosition",)
CHEVROLET_BOLT_GPS_CARS = (
GM_CAR.CHEVROLET_BOLT_ACC_2022_2023,
GM_CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
GM_CAR.CHEVROLET_BOLT_CC_2022_2023,
GM_CAR.CHEVROLET_BOLT_CC_2018_2021,
GM_CAR.CHEVROLET_BOLT_CC_2017,
)
CAR_GPS_CONFIGS: dict[str, CarGpsConfig] = {
FORD_CAR.FORD_MUSTANG_MACH_E_MK1: CarGpsConfig(
brand="ford",
messages=FORD_MACH_E_GPS_MESSAGES,
decoder=parse_ford_can_gps,
),
**{
car: CarGpsConfig(
brand="gm",
messages=CHEVROLET_BOLT_GPS_MESSAGES,
decoder=parse_chevrolet_bolt_can_gps,
)
for car in CHEVROLET_BOLT_GPS_CARS
},
}
def get_car_gps_config(CP) -> CarGpsConfig | None:
config = CAR_GPS_CONFIGS.get(CP.carFingerprint)
return config if config is not None and config.brand == CP.brand else None
def car_gps_available(CP) -> bool:
return get_car_gps_config(CP) is not None
+15 -126
View File
@@ -7,7 +7,6 @@ from opendbc.car.honda import hondacan
from opendbc.car.honda.values import ( from opendbc.car.honda.values import (
CAR, CAR,
CruiseButtons, CruiseButtons,
CruiseSettings,
HONDA_BOSCH, HONDA_BOSCH,
HONDA_BOSCH_CANFD, HONDA_BOSCH_CANFD,
HONDA_BOSCH_RADARLESS, HONDA_BOSCH_RADARLESS,
@@ -17,7 +16,6 @@ from opendbc.car.honda.values import (
HondaFlags, HondaFlags,
) )
from opendbc.car.interfaces import CarControllerBase from opendbc.car.interfaces import CarControllerBase
from opendbc.car.common.pid import PIDController
from openpilot.common.params import Params from openpilot.common.params import Params
VisualAlert = structs.CarControl.HUDControl.VisualAlert VisualAlert = structs.CarControl.HUDControl.VisualAlert
@@ -213,14 +211,6 @@ class CarController(CarControllerBase):
self.CAN = hondacan.CanBus(CP) self.CAN = hondacan.CanBus(CP)
self.tja_control = CP.carFingerprint in HONDA_BOSCH_TJA_CONTROL self.tja_control = CP.carFingerprint in HONDA_BOSCH_TJA_CONTROL
# MVL CAN-FD ownership state. These do not affect non-CANFD vehicles.
self.radar_disable_counter = 0
self.radar_mux = 0
self.radar_hud_pulse = 0
self.last_acc_enabled = False
self.lkas_button_send_remaining = 0
self.last_lkas_button_frame = 0
self.braking = False self.braking = False
self.brake_steady = 0.0 self.brake_steady = 0.0
self.brake_last = 0.0 self.brake_last = 0.0
@@ -244,10 +234,6 @@ class CarController(CarControllerBase):
self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor
self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor
self.pitch = 0.0 self.pitch = 0.0
self.mvl_accord_mode = CP.carFingerprint == CAR.HONDA_ACCORD_11G
# MVL Bosch low-speed extra-brake integrator. Active only for Accord 11G MVL mode.
self.mvl_brake_pid = PIDController(k_p=0.0, k_i=1.0, pos_limit=0.0, neg_limit=-2.0, rate=50)
self.mvl_brake_pid.reset()
def _modified_civic_standard_active(self) -> bool: def _modified_civic_standard_active(self) -> bool:
return self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH and bool(self.CP.flags & HondaFlags.EPS_MODIFIED) return self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH and bool(self.CP.flags & HondaFlags.EPS_MODIFIED)
@@ -269,7 +255,6 @@ class CarController(CarControllerBase):
hud_v_cruise = hud_control.setSpeed / CS.v_cruise_factor if hud_control.speedVisible else 255 hud_v_cruise = hud_control.setSpeed / CS.v_cruise_factor if hud_control.speedVisible else 255
pcm_cancel_cmd = CC.cruiseControl.cancel pcm_cancel_cmd = CC.cruiseControl.cancel
gas_interceptor_command = 0.0 gas_interceptor_command = 0.0
min_gas = self.params.BOSCH_GAS_LOOKUP_BP[0]
if len(CC.orientationNED) == 3: if len(CC.orientationNED) == 3:
self.pitch = CC.orientationNED[1] self.pitch = CC.orientationNED[1]
hill_brake = math.sin(self.pitch) * ACCELERATION_DUE_TO_GRAVITY hill_brake = math.sin(self.pitch) * ACCELERATION_DUE_TO_GRAVITY
@@ -323,56 +308,11 @@ class CarController(CarControllerBase):
# Send CAN commands # Send CAN commands
can_sends = [] can_sends = []
# Bosch radar ownership. On CAN-FD, leave the stock radar active until the comma relay is open, # tester present - w/ no response (keeps radar disabled)
# then enter extended diagnostics and disable radar RX/TX. This prevents a gap between stock
# ACC_CONTROL disappearing and panda permitting openpilot's replacement stream.
if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and self.CP.openpilotLongitudinalControl: if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and self.CP.openpilotLongitudinalControl:
if self.mvl_accord_mode and CS.stock_acc_alive: if self.frame % 10 == 0:
if CS.canfd_relay_open:
if self.radar_disable_counter % 50 == 0:
can_sends.append((0x18DAB0F1, b'\x02\x10\x03\x00\x00\x00\x00\x00', self.CAN.pt))
elif self.radar_disable_counter % 50 == 5:
can_sends.append((0x18DAB0F1, b'\x03\x28\x83\x03\x00\x00\x00\x00', self.CAN.pt))
self.radar_disable_counter += 1
elif self.frame % 10 == 0:
can_sends.append(make_tester_present_msg(0x18DAB0F1, self.CAN.pt, suppress_response=True)) can_sends.append(make_tester_present_msg(0x18DAB0F1, self.CAN.pt, suppress_response=True))
# After the stock CAN-FD radar is silent, reproduce its low-rate/tick-aligned messages on both
# the PT and camera sides of the open relay. Pack once and mirror identical bytes so counters and
# checksums stay synchronized. v3 deliberately uses an idle lane/object payload first; model-based
# cluster rendering is deferred until the ownership/DTC handover is proven.
mvl_radar_owned = self.mvl_accord_mode and CS.canfd_relay_open and not CS.stock_acc_alive
if mvl_radar_owned and self.CP.openpilotLongitudinalControl:
if CC.enabled and not self.last_acc_enabled:
self.radar_hud_pulse = 30
self.last_acc_enabled = CC.enabled
radar_msgs = []
if CS.hud_tick:
radar_msgs.append(hondacan.create_radar_hud_canfd(self.packer, self.CAN.pt, CC.enabled, self.radar_hud_pulse > 0))
if self.radar_hud_pulse > 0:
self.radar_hud_pulse -= 1
if CS.supp_tick:
radar_msgs.append(hondacan.create_canfd_supplemental(self.packer, self.CAN.pt))
if CS.radar_50hz_tick:
if self.radar_mux >= 58:
self.radar_mux = 1
elif self.radar_mux == 10:
self.radar_mux = 17
elif self.radar_mux == 26:
self.radar_mux = 33
elif self.radar_mux == 42:
self.radar_mux = 49
else:
self.radar_mux += 1
radar_msgs.extend(hondacan.create_canfd_50hz_radar_messages(self.packer, self.CAN.pt, self.radar_mux))
if CS.radar_5hz_tick:
radar_msgs.extend(hondacan.create_canfd_5hz_radar_messages(self.packer, self.CAN.pt, CS.radar_ref_counter))
for addr, dat, _ in radar_msgs:
can_sends.append((addr, dat, self.CAN.pt))
can_sends.append((addr, dat, self.CAN.camera))
# Send steering command. # Send steering command.
can_sends.append(hondacan.create_steering_control(self.packer, self.CAN, apply_torque, CC.latActive, self.tja_control)) can_sends.append(hondacan.create_steering_control(self.packer, self.CAN, apply_torque, CC.latActive, self.tja_control))
@@ -412,37 +352,23 @@ class CarController(CarControllerBase):
ts = self.frame * DT_CTRL ts = self.frame * DT_CTRL
if self.CP.carFingerprint in HONDA_BOSCH: if self.CP.carFingerprint in HONDA_BOSCH:
if self.mvl_accord_mode and (accel < min_gas) and (1e-3 < CS.out.vEgo < 3.0): self.accel = float(np.clip(accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX))
brake_addon = self.mvl_brake_pid.update(error=accel - CS.out.aEgo, speed=CS.out.vEgo) gas_pedal_force = self.accel + hill_brake
target_accel = min(accel, accel + brake_addon)
else:
if self.mvl_accord_mode:
self.mvl_brake_pid.reset()
target_accel = accel
self.accel = float(np.clip(target_accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX))
# MVL uses requested accel (not extra-brake-adjusted accel) to decide propulsion crossover.
gas_pedal_force = (accel if self.mvl_accord_mode else self.accel) + hill_brake
if self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS: if self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS:
gas_pedal_force += wind_brake_mps2 * self.bosch_wind_factor gas_pedal_force += wind_brake_mps2 * self.bosch_wind_factor
if actuators.longControlState == LongCtrlState.pid and not CS.out.gasPressed: if actuators.longControlState == LongCtrlState.pid and not CS.out.gasPressed:
gas_error = (accel if self.mvl_accord_mode else self.accel) - CS.out.aEgo gas_error = self.accel - CS.out.aEgo
if gas_error != 0.0 and gas_pedal_force > min_gas: if gas_error != 0.0 and gas_pedal_force > 0.0:
if self.CP.carFingerprint == CAR.HONDA_INSIGHT: if self.CP.carFingerprint == CAR.HONDA_INSIGHT:
gas_learn_speed = 150.0 gas_learn_speed = 150.0
elif self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR): elif self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR):
gas_learn_speed = 300.0 gas_learn_speed = 300.0
else: else:
gas_learn_speed = 50.0 gas_learn_speed = 50.0
gas_factor_floor = 0.01 if self.mvl_accord_mode else 0.1 self.bosch_gas_factor = float(np.clip(self.bosch_gas_factor + gas_error / gas_learn_speed * gas_pedal_force, 0.1, 3.0))
gas_learn_force = (gas_pedal_force - min_gas) if self.mvl_accord_mode else gas_pedal_force
self.bosch_gas_factor = float(np.clip(
self.bosch_gas_factor + gas_error / gas_learn_speed * gas_learn_force,
gas_factor_floor, 3.0,
))
if gas_error != 0.0 and not CS.out.brakePressed and CS.out.vEgo > 0.0: if gas_error != 0.0 and not CS.out.brakePressed and CS.out.vEgo > 0.0:
wind_learn_speed = 100.0 if self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR) else 1000.0 wind_learn_speed = 100.0 if self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR) else 1000.0
@@ -452,8 +378,7 @@ class CarController(CarControllerBase):
else: else:
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor / wind_adjust, 0.1, 3.0)) self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor / wind_adjust, 0.1, 3.0))
wind_brake_threshold = min_gas if self.mvl_accord_mode else 0.0 if gas_pedal_force <= 0.0:
if gas_pedal_force <= wind_brake_threshold:
self.bosch_wind_factor = max(self.bosch_wind_factor, self.bosch_wind_factor_before_brake) self.bosch_wind_factor = max(self.bosch_wind_factor, self.bosch_wind_factor_before_brake)
else: else:
self.bosch_wind_factor_before_brake = self.bosch_wind_factor self.bosch_wind_factor_before_brake = self.bosch_wind_factor
@@ -465,21 +390,15 @@ class CarController(CarControllerBase):
self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor
self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor
gas_lookup_input = ((gas_pedal_force - min_gas) * self.bosch_gas_factor + min_gas) if self.mvl_accord_mode else \ self.gas = float(np.interp(gas_pedal_force * self.bosch_gas_factor, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V))
gas_pedal_force * self.bosch_gas_factor
self.gas = float(np.interp(gas_lookup_input, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V))
self.gas = min(self.gas, max(60.0, self.bosch_last_gas + 60.0)) self.gas = min(self.gas, max(60.0, self.bosch_last_gas + 60.0))
self.bosch_last_gas = self.gas self.bosch_last_gas = self.gas
stopping = actuators.longControlState == LongCtrlState.stopping stopping = actuators.longControlState == LongCtrlState.stopping
self.stopping_counter = self.stopping_counter + 1 if stopping else 0 self.stopping_counter = self.stopping_counter + 1 if stopping else 0
if not self.mvl_accord_mode or mvl_radar_owned: can_sends.extend(
can_sends.extend( hondacan.create_acc_commands(self.packer, self.CAN, CC.enabled, CC.longActive, self.accel, self.gas, self.stopping_counter, self.CP.carFingerprint)
hondacan.create_acc_commands( )
self.packer, self.CAN, CC.enabled, CC.longActive, self.accel, self.gas, self.stopping_counter, self.CP,
gas_force=gas_pedal_force if self.mvl_accord_mode else None,
)
)
else: else:
apply_brake = np.clip(self.brake_last - wind_brake, 0.0, 1.0) apply_brake = np.clip(self.brake_last - wind_brake, 0.0, 1.0)
apply_brake = int(np.clip(apply_brake * self.params.NIDEC_BRAKE_MAX, 0, self.params.NIDEC_BRAKE_MAX - 1)) apply_brake = int(np.clip(apply_brake * self.params.NIDEC_BRAKE_MAX, 0, self.params.NIDEC_BRAKE_MAX - 1))
@@ -521,16 +440,9 @@ class CarController(CarControllerBase):
idx = (self.frame // 2) % 0x10 idx = (self.frame // 2) % 0x10
can_sends.append(create_gas_interceptor_command(self.packer, gas_interceptor_command, idx)) can_sends.append(create_gas_interceptor_command(self.packer, gas_interceptor_command, idx))
# Send dashboard UI commands. On CAN-FD, ACC_HUD is owned by the radar and must only start # Send dashboard UI commands.
# after the handover, aligned to the radar's 10 Hz HUD tick.
if (mvl_radar_owned and CS.hud_tick and self.CP.openpilotLongitudinalControl):
can_sends.append(
hondacan.create_acc_hud(self.packer, self.CAN.pt, self.CP, CC.enabled, pcm_speed, actuators.accel,
hud_control, hud_v_cruise, CS.is_metric, CS.acc_hud)
)
if self.frame % 10 == 0: if self.frame % 10 == 0:
if self.CP.openpilotLongitudinalControl and not self.mvl_accord_mode: if self.CP.openpilotLongitudinalControl:
# On Nidec, this also controls longitudinal positive acceleration # On Nidec, this also controls longitudinal positive acceleration
can_sends.append( can_sends.append(
hondacan.create_acc_hud(self.packer, self.CAN.pt, self.CP, CC.enabled, pcm_speed, pcm_accel, hud_control, hud_v_cruise, CS.is_metric, CS.acc_hud) hondacan.create_acc_hud(self.packer, self.CAN.pt, self.CP, CC.enabled, pcm_speed, pcm_accel, hud_control, hud_v_cruise, CS.is_metric, CS.acc_hud)
@@ -546,7 +458,7 @@ class CarController(CarControllerBase):
if self.CP.openpilotLongitudinalControl: if self.CP.openpilotLongitudinalControl:
# TODO: combining with create_acc_hud block above will change message order and will need replay logs regenerated # TODO: combining with create_acc_hud block above will change message order and will need replay logs regenerated
if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS - {CAR.HONDA_ACCORD_11G}): if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS):
can_sends.append(hondacan.create_radar_hud(self.packer, self.CAN.pt)) can_sends.append(hondacan.create_radar_hud(self.packer, self.CAN.pt))
if self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH: if self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH:
can_sends.append(hondacan.create_legacy_brake_command(self.packer, self.CAN.pt)) can_sends.append(hondacan.create_legacy_brake_command(self.packer, self.CAN.pt))
@@ -557,29 +469,6 @@ class CarController(CarControllerBase):
else: else:
self.gas = pcm_accel / self.params.NIDEC_GAS_MAX self.gas = pcm_accel / self.params.NIDEC_GAS_MAX
# CAN-FD: while engaged, the camera still needs a valid SCM_BUTTONS stream behind the open relay.
# Take over that stream, echoing the live ambient-light byte. Also send a short LKAS-setting pulse
# when stock LKAS is ready, matching MVL's workaround for the Honda touch-steering-wheel timer.
if (self.mvl_accord_mode and CC.enabled and self.frame % 4 == 0
and not pcm_cancel_cmd and not CC.cruiseControl.resume):
if (self.lkas_button_send_remaining == 0 and CS.lkas_hud["LKAS_READY"]
and self.frame >= self.last_lkas_button_frame + 500):
self.lkas_button_send_remaining = 3
if self.lkas_button_send_remaining > 0:
self.last_lkas_button_frame = self.frame
self.lkas_button_send_remaining -= 1
cruise_setting = CruiseSettings.LKAS
elif CS.cruise_setting == CruiseSettings.LKAS:
cruise_setting = 0
else:
cruise_setting = CS.cruise_setting
can_sends.append(hondacan.spam_buttons_command(
self.packer, self.CAN, CS.cruise_buttons, self.CP.carFingerprint,
cruise_setting=cruise_setting, ambient_light=CS.scm_ambient_light, bus=self.CAN.camera,
))
if self.frame > 0 and self.frame % 6000 == 0: if self.frame > 0 and self.frame % 6000 == 0:
self.param_store.put_float("HondaGasFactorParams", self.bosch_gas_factor) self.param_store.put_float("HondaGasFactorParams", self.bosch_gas_factor)
self.param_store.put_float("HondaWindFactorParams", self.bosch_wind_factor) self.param_store.put_float("HondaWindFactorParams", self.bosch_wind_factor)
+2 -95
View File
@@ -68,33 +68,11 @@ class CarState(CarStateBase):
self.initial_accFault_cleared = False self.initial_accFault_cleared = False
self.initial_accFault_cleared_timer = int(10 / DT_CTRL) self.initial_accFault_cleared_timer = int(10 / DT_CTRL)
# CAN-FD deferred radar handover state. The stock radar remains responsible for ACC_CONTROL
# until the relay is open and the controller has silenced it; radar reference/tick messages are
# used to keep the replacement radar look-alikes on the stock cadence after the handover.
self.radar_ref_counter = 0
self.radar_5hz_tick_counter = 0
self.radar_5hz_tick = False
self.supp_tick_counter = 0
self.supp_tick = False
self.hud_tick_counter = 0
self.hud_tick = False
self.radar_50hz_tick_counter = 0
self.radar_50hz_tick = False
self.scm_ambient_light = 0
self.stock_acc_counter = 0
self.stock_acc_alive = False
self.camera_steer_counter = 0
self.camera_steer_seen = False
self.canfd_frames = 0
self.canfd_relay_open = False
def update(self, can_parsers, starpilot_toggles) -> structs.CarState: def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
cp = can_parsers[Bus.pt] cp = can_parsers[Bus.pt]
cp_cam = can_parsers[Bus.cam] cp_cam = can_parsers[Bus.cam]
if self.CP.enableBsm: if self.CP.enableBsm:
cp_body = can_parsers[Bus.body] cp_body = can_parsers[Bus.body]
if self.CP.carFingerprint == CAR.HONDA_ACCORD_11G:
cp_radar = can_parsers[Bus.radar]
ret = structs.CarState() ret = structs.CarState()
@@ -107,10 +85,6 @@ class CarState(CarStateBase):
prev_cruise_setting = self.cruise_setting prev_cruise_setting = self.cruise_setting
self.cruise_setting = cp.vl["SCM_BUTTONS"]["CRUISE_SETTING"] self.cruise_setting = cp.vl["SCM_BUTTONS"]["CRUISE_SETTING"]
self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"] self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"]
if self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | {CAR.HONDA_ACCORD_11G}):
# The camera consumes this byte in SCM_BUTTONS too (adaptive high beam); preserve it when
# openpilot temporarily takes over SCM_BUTTONS toward the camera.
self.scm_ambient_light = cp.vl["SCM_BUTTONS"]["AMBIENT_LIGHT_MAYBE"]
# used for car hud message # used for car hud message
self.is_metric = self.CP.carFingerprint in (CAR.HONDA_ODYSSEY_TWN,) or not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"] self.is_metric = self.CP.carFingerprint in (CAR.HONDA_ODYSSEY_TWN,) or not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
@@ -142,8 +116,8 @@ class CarState(CarStateBase):
steer_status = self.steer_status_values[cp.vl["STEER_STATUS"]["STEER_STATUS"]] steer_status = self.steer_status_values[cp.vl["STEER_STATUS"]["STEER_STATUS"]]
ret.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TJA_LOW_SPEED_LOCKOUT", ret.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TJA_LOW_SPEED_LOCKOUT",
"TMP_FAULT") "TMP_FAULT")
if self.CP.carFingerprint in (HONDA_BOSCH_ALT_RADAR | {CAR.HONDA_ACCORD_11G}): if self.CP.carFingerprint in HONDA_BOSCH_ALT_RADAR:
# MVL treats CAN-FD low-speed lockout as an expected EPS state too. # TODO: See if this logic works for all other Honda
min_steer_speed = max(CarControllerParams.STEER_GLOBAL_MIN_SPEED, self.CP.minSteerSpeed) min_steer_speed = max(CarControllerParams.STEER_GLOBAL_MIN_SPEED, self.CP.minSteerSpeed)
expected_low_speed_lockout = steer_status == "LOW_SPEED_LOCKOUT" and ret.vEgo < min_steer_speed expected_low_speed_lockout = steer_status == "LOW_SPEED_LOCKOUT" and ret.vEgo < min_steer_speed
ret.steerFaultTemporary = steer_status != "NORMAL" and not expected_low_speed_lockout ret.steerFaultTemporary = steer_status != "NORMAL" and not expected_low_speed_lockout
@@ -275,63 +249,6 @@ class CarState(CarStateBase):
if self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_CANFD): if self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_CANFD):
self.lkas_hud = cp_cam.vl["LKAS_HUD"] self.lkas_hud = cp_cam.vl["LKAS_HUD"]
if self.CP.carFingerprint == CAR.HONDA_ACCORD_11G:
# Phase replacement radar messages from the stock radar's tick references. CarState reads the
# tick in one 100 Hz cycle and CarController transmits on the next, so pulse one frame before
# the expected next stock tick.
self.radar_ref_counter = cp.vl["RADAR_REFERENCE"]["COUNTER"]
ref_tick_vals = cp.vl_all.get("RADAR_REFERENCE", {}).get("COUNTER", [])
if len(ref_tick_vals) > 0:
self.radar_5hz_tick_counter = 0
else:
self.radar_5hz_tick_counter += 1
self.radar_5hz_tick = self.radar_5hz_tick_counter == 11
supp_tick_vals = cp_radar.vl_all.get("RADAR_SUPP_TICK_REFERENCE", {}).get("IGNORE", [])
if len(supp_tick_vals) > 0:
self.supp_tick_counter = 0
else:
self.supp_tick_counter += 1
self.supp_tick = self.supp_tick_counter == 99
hud_tick_vals = cp_radar.vl_all.get("RADAR_HUD_TICK_REFERENCE", {}).get("IGNORE", [])
if len(hud_tick_vals) > 0:
self.hud_tick_counter = 0
else:
self.hud_tick_counter += 1
self.hud_tick = self.hud_tick_counter == 9
tick_50hz_vals = cp_radar.vl_all.get("RADAR_50HZ_TICK_REFERENCE", {}).get("IGNORE", [])
if len(tick_50hz_vals) > 0:
self.radar_50hz_tick_counter = 0
else:
self.radar_50hz_tick_counter += 1
self.radar_50hz_tick = self.radar_50hz_tick_counter == 1
# ACC_CONTROL is normally present every 2 frames. Keep treating the stock radar as alive until
# four consecutive frames have passed without it, preventing overlap between stock and OP ACC.
self.canfd_frames += 1
if len(cp.vl_all.get("ACC_CONTROL", {}).get("COUNTER", [])) > 0:
self.stock_acc_counter = 0
else:
self.stock_acc_counter += 1
self.stock_acc_alive = self.stock_acc_counter < 4
# Before the relay opens, the camera's STEERING_CONTROL is physically visible on PT. Once the
# relay opens it disappears. Fallback to 5 seconds in case the camera frame was never observed.
if len(cp.vl_all.get("STEERING_CONTROL", {}).get("COUNTER", [])) > 0:
self.camera_steer_counter = 0
self.camera_steer_seen = True
else:
self.camera_steer_counter += 1
self.canfd_relay_open = (self.camera_steer_seen and self.camera_steer_counter >= 5) or self.canfd_frames >= 500
else:
self.supp_tick = False
self.hud_tick = False
self.radar_5hz_tick = False
self.radar_50hz_tick = False
if self.CP.enableBsm: if self.CP.enableBsm:
# BSM messages are on B-CAN, requires a panda forwarding B-CAN messages to CAN 0 # BSM messages are on B-CAN, requires a panda forwarding B-CAN messages to CAN 0
# more info here: https://github.com/commaai/openpilot/pull/1867 # more info here: https://github.com/commaai/openpilot/pull/1867
@@ -354,10 +271,6 @@ class CarState(CarStateBase):
def get_can_parsers(self, CP): def get_can_parsers(self, CP):
pt_messages = [("GAS_SENSOR", 0)] if CP.enableGasInterceptorDEPRECATED else [] pt_messages = [("GAS_SENSOR", 0)] if CP.enableGasInterceptorDEPRECATED else []
if CP.carFingerprint == CAR.HONDA_ACCORD_11G:
# Both deliberately go silent during the handover, so skip alive/timeout checks.
pt_messages += [("ACC_CONTROL", float("nan")), ("STEERING_CONTROL", float("nan"))]
pt_parser = CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CanBus(CP).pt) pt_parser = CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CanBus(CP).pt)
if CP.enableGasInterceptorDEPRECATED: if CP.enableGasInterceptorDEPRECATED:
pt_parser.message_states[0x201].ignore_checksum = True pt_parser.message_states[0x201].ignore_checksum = True
@@ -369,11 +282,5 @@ class CarState(CarStateBase):
} }
if CP.enableBsm: if CP.enableBsm:
parsers[Bus.body] = CANParser(DBC[CP.carFingerprint][Bus.body], [], CanBus(CP).radar) parsers[Bus.body] = CANParser(DBC[CP.carFingerprint][Bus.body], [], CanBus(CP).radar)
if CP.carFingerprint == CAR.HONDA_ACCORD_11G:
parsers[Bus.radar] = CANParser(DBC[CP.carFingerprint][Bus.radar], [
("RADAR_SUPP_TICK_REFERENCE", 0),
("RADAR_HUD_TICK_REFERENCE", 0),
("RADAR_50HZ_TICK_REFERENCE", 0),
], CanBus(CP).radar)
return parsers return parsers
@@ -993,7 +993,6 @@ FW_VERSIONS = {
b'36161-T47-A060\x00\x00', b'36161-T47-A060\x00\x00',
b'36161-T47-A070\x00\x00', b'36161-T47-A070\x00\x00',
b'8S102-T20-AA10\x00\x00', b'8S102-T20-AA10\x00\x00',
b'8S102-T20-AA20\x00\x00',
b'8S102-T43-J540\x00\x00', b'8S102-T43-J540\x00\x00',
b'8S102-T47-AA10\x00\x00', b'8S102-T47-AA10\x00\x00',
b'8S102-T47-AA20\x00\x00', b'8S102-T47-AA20\x00\x00',
@@ -1002,7 +1001,6 @@ FW_VERSIONS = {
b'8S102-T56-A070\x00\x00', b'8S102-T56-A070\x00\x00',
b'8S102-T60-AA10\x00\x00', b'8S102-T60-AA10\x00\x00',
b'8S102-T64-A040\x00\x00', b'8S102-T64-A040\x00\x00',
b'8S102-T64-A050\x00\x00',
], ],
(Ecu.vsa, 0x18da28f1, None): [ (Ecu.vsa, 0x18da28f1, None): [
b'57114-T20-AB40\x00\x00', b'57114-T20-AB40\x00\x00',
@@ -1039,8 +1037,6 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x18dab5f1, None): [ (Ecu.fwdCamera, 0x18dab5f1, None): [
b'8S102-30A-A050\x00\x00', b'8S102-30A-A050\x00\x00',
b'8S102-30A-A060\x00\x00', b'8S102-30A-A060\x00\x00',
b'8S102-30A-A070\x00\x00',
b'8S102-30A-A080\x00\x00',
], ],
}, },
CAR.HONDA_CRV_6G: { CAR.HONDA_CRV_6G: {
+11 -112
View File
@@ -2,7 +2,6 @@ from opendbc.car import CanBusBase
from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.honda.values import (HondaFlags, HONDA_BOSCH, HONDA_BOSCH_ALT_RADAR, HONDA_BOSCH_RADARLESS, from opendbc.car.honda.values import (HondaFlags, HONDA_BOSCH, HONDA_BOSCH_ALT_RADAR, HONDA_BOSCH_RADARLESS,
HONDA_BOSCH_CANFD, CarControllerParams) HONDA_BOSCH_CANFD, CarControllerParams)
from opendbc.car.honda.values import CAR
# CAN bus layout with relay # CAN bus layout with relay
# 0 = ACC-CAN - radar side # 0 = ACC-CAN - radar side
@@ -71,16 +70,14 @@ def create_brake_command(packer, CAN, apply_brake, pump_on, pcm_override, pcm_ca
return packer.make_can_msg("BRAKE_COMMAND", CAN.pt, values) return packer.make_can_msg("BRAKE_COMMAND", CAN.pt, values)
def create_acc_commands(packer, CAN, enabled, active, accel, gas, stopping_counter, CP, gas_force=None): def create_acc_commands(packer, CAN, enabled, active, accel, gas, stopping_counter, car_fingerprint):
commands = [] commands = []
min_gas_accel = CarControllerParams.BOSCH_GAS_LOOKUP_BP[0] min_gas_accel = CarControllerParams.BOSCH_GAS_LOOKUP_BP[0]
control_on = 5 if enabled else 0 control_on = 5 if enabled else 0
if gas_force is None: gas_command = gas if active and accel > min_gas_accel else -30000
gas_force = accel
gas_command = gas if active and gas_force > min_gas_accel else -30000
accel_command = accel if active else 0 accel_command = accel if active else 0
braking = 1 if active and gas_force < min_gas_accel else 0 braking = 1 if active and accel < min_gas_accel else 0
standstill = 1 if active and stopping_counter > 0 else 0 standstill = 1 if active and stopping_counter > 0 else 0
standstill_release = 1 if active and stopping_counter == 0 else 0 standstill_release = 1 if active and stopping_counter == 0 else 0
@@ -90,7 +87,7 @@ def create_acc_commands(packer, CAN, enabled, active, accel, gas, stopping_count
'STANDSTILL': standstill, 'STANDSTILL': standstill,
} }
if CP.carFingerprint in HONDA_BOSCH_RADARLESS: if car_fingerprint in HONDA_BOSCH_RADARLESS:
acc_control_values.update({ acc_control_values.update({
"CONTROL_ON": enabled, "CONTROL_ON": enabled,
"IDLESTOP_ALLOW": stopping_counter > 200, # allow idle stop after 4 seconds (50 Hz) "IDLESTOP_ALLOW": stopping_counter > 200, # allow idle stop after 4 seconds (50 Hz)
@@ -150,20 +147,10 @@ def create_acc_hud(packer, bus, CP, enabled, pcm_speed, pcm_accel, hud_control,
'SET_ME_X01_2': 1, 'SET_ME_X01_2': 1,
} }
if CP.carFingerprint == CAR.HONDA_ACCORD_11G:
# Stock CAN-FD radar toggles these together with ACC/lead/braking state. Keeping them low when
# neither lead nor braking is present matches MVL's observed CAN-FD payload shape.
set_me = int(enabled and (bool(acc_hud_values['HUD_LEAD']) or (pcm_accel < 0.2)))
acc_hud_values['SET_ME_X01'] = set_me
acc_hud_values['SET_ME_X01_2'] = set_me
if CP.carFingerprint in HONDA_BOSCH: if CP.carFingerprint in HONDA_BOSCH:
acc_hud_values['ACC_ON'] = int(enabled) acc_hud_values['ACC_ON'] = int(enabled)
# Preserve StarPilot's existing Bosch HUD behavior outside CAN-FD. MVL's CAN-FD acc_hud_values['FCM_OFF'] = 1
# replacement radar expects FCW/CMBS enabled, while legacy Bosch keeps them off. acc_hud_values['FCM_OFF_2'] = 1
canfd = CP.carFingerprint == CAR.HONDA_ACCORD_11G
acc_hud_values['FCM_OFF'] = 0 if canfd else 1
acc_hud_values['FCM_OFF_2'] = 0 if canfd else 1
else: else:
# Shows the distance bars, TODO: stock camera shows updates temporarily while disabled # Shows the distance bars, TODO: stock camera shows updates temporarily while disabled
acc_hud_values['ACC_ON'] = int(enabled) acc_hud_values['ACC_ON'] = int(enabled)
@@ -232,104 +219,16 @@ def create_legacy_brake_command(packer, bus):
return packer.make_can_msg("LEGACY_BRAKE_COMMAND", bus, {}) return packer.make_can_msg("LEGACY_BRAKE_COMMAND", bus, {})
def spam_buttons_command(packer, CAN, button_val, car_fingerprint, cruise_setting=0, ambient_light=None, bus=None): def spam_buttons_command(packer, CAN, button_val, car_fingerprint):
values = { values = {
'CRUISE_BUTTONS': button_val, 'CRUISE_BUTTONS': button_val,
'CRUISE_SETTING': cruise_setting, 'CRUISE_SETTING': 0,
} }
# Existing StarPilot callers should retain their previous payload; only the CAN-FD camera # send buttons to camera on radarless (camera does ACC) cars
# takeover path explicitly echoes the live ambient-light byte. bus = CAN.camera if car_fingerprint in HONDA_BOSCH_RADARLESS else CAN.pt
if ambient_light is not None:
values['AMBIENT_LIGHT_MAYBE'] = ambient_light
if bus is None:
# send buttons to camera on radarless (camera does ACC) cars
bus = CAN.camera if car_fingerprint in HONDA_BOSCH_RADARLESS else CAN.pt
return packer.make_can_msg("SCM_BUTTONS", bus, values) return packer.make_can_msg("SCM_BUTTONS", bus, values)
def create_radar_hud_canfd(packer, bus, acc, acc_pulse=False):
values = {
'CMBS_ENABLED_MAYBE': 1 if (acc and acc_pulse) else 0,
'ACC_ON': acc,
'SET_ME_X01': 0x01,
'SET_ME_X01_2': 0x01,
}
return packer.make_can_msg("RADAR_HUD_CANFD", bus, values)
def create_canfd_supplemental(packer, bus):
values = {
'SET_ME_X01': 0x01,
'SET_ME_X41': 0x41,
}
return packer.make_can_msg("BOSCH_SUPPLEMENTAL_CANFD", bus, values)
RADAR_MUX_BANK_STARTS = (1, 17, 33, 49)
PATH_OFFSET_INVALID = 2047
# These extended IDs use the CAN-FD checksum offset used by the Accord 11G
# replacement-radar stream. Keep the legacy Honda offset for existing high-ID
# messages on other Honda platforms.
HONDA_CANFD_MVL_CHECKSUM_IDS = frozenset((
0x6CD5558, 0x6CD5559, 0xF31AA52, 0xF31AA5C, 0x1A45AA4E,
))
def _lane_path_offsets(radar_mux):
pos = next((radar_mux - start for start in RADAR_MUX_BANK_STARTS if start <= radar_mux <= start + 9), 0)
if pos == 0:
return (0, 0, 0, 0)
if pos == 1:
return (0, 0, PATH_OFFSET_INVALID, PATH_OFFSET_INVALID)
return (PATH_OFFSET_INVALID,) * 4
def create_canfd_50hz_radar_messages(packer, bus, radar_mux):
offsets = _lane_path_offsets(radar_mux)
lane_path_values = {
'MUX': radar_mux,
'PATH_OFFSET_1': offsets[0],
'PATH_OFFSET_2': offsets[1],
'PATH_OFFSET_3': offsets[2],
'PATH_OFFSET_4': offsets[3],
}
hud_objects_values = {
'MUX': radar_mux,
'OBJECT_ID': 0,
'IS_LEAD_CAR': 0,
'CAR_TYPE': -1,
'ROTATION': -128,
'LONG_DIST': 196.9,
'LAT_DIST': 204.7,
}
return [
packer.make_can_msg('LANE_PATH', bus, lane_path_values),
packer.make_can_msg('HUD_OBJECTS', bus, hud_objects_values),
]
def create_canfd_5hz_radar_messages(packer, bus, radar_ref_cntr):
radar_lead_values = {
'CNTR_REF': radar_ref_cntr,
'SET_ME_X01': 0x01,
'TARGET_SPEED_MAYBE': 140,
# v3 initially sends MVL's stock-like idle lane state. Model-derived dash rendering can be added
# separately after the DTC/ownership handover is proven on-car.
'LEFT_LANE': 0,
'RIGHT_LANE': 0,
'LANE_PATH_LENGTH': 6,
}
radar_lead2_values = {
'SET_ME_X88': 136,
'SET_ME_X78': 120,
'LEAD_DISTANCE_MAYBE': 0,
}
return [
packer.make_can_msg('RADAR_LEAD', bus, radar_lead_values),
packer.make_can_msg('RADAR_LEAD2', bus, radar_lead2_values),
]
def honda_checksum(address: int, sig, d: bytearray) -> int: def honda_checksum(address: int, sig, d: bytearray) -> int:
s = 0 s = 0
extended = address > 0x7FF extended = address > 0x7FF
@@ -344,5 +243,5 @@ def honda_checksum(address: int, sig, d: bytearray) -> int:
s += (x & 0xF) + (x >> 4) s += (x & 0xF) + (x >> 4)
s = 8 - s s = 8 - s
if extended: if extended:
s += 10 if address in HONDA_CANFD_MVL_CHECKSUM_IDS else 3 s += 3
return s & 0xF return s & 0xF
+5 -29
View File
@@ -1,11 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import numpy as np import numpy as np
from openpilot.common.params import Params, UnknownKeyName
from opendbc.car import get_safety_config, structs, uds from opendbc.car import get_safety_config, structs, uds
from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.disable_ecu import disable_ecu from opendbc.car.disable_ecu import disable_ecu
from opendbc.car.honda.hondacan import CanBus from opendbc.car.honda.hondacan import CanBus
from opendbc.car.honda.values import CarControllerParams, HondaFlags, CAR, HONDA_BOSCH, HONDA_BOSCH_A, HONDA_BOSCH_A_RADAR_VERIFIED, HONDA_BOSCH_CANFD, \ from opendbc.car.honda.values import CarControllerParams, HondaFlags, CAR, HONDA_BOSCH, HONDA_BOSCH_CANFD, \
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, HondaSafetyFlags HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, HondaSafetyFlags
from opendbc.car.honda.carcontroller import CarController from opendbc.car.honda.carcontroller import CarController
from opendbc.car.honda.carstate import CarState from opendbc.car.honda.carstate import CarState
@@ -45,17 +44,7 @@ class CarInterface(CarInterfaceBase):
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput)) cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
ret.safetyConfigs = cfgs ret.safetyConfigs = cfgs
# HONDA_BOSCH_A describes the physical harness family. Radar remains unavailable until the ret.radarUnavailable = True
# exact platform is added to HONDA_BOSCH_A_RADAR_VERIFIED after real-capture validation.
try:
# The explicit default keeps the verified platform usable on installs that have not yet
# persisted the internal kill-switch parameter; the verified-platform set remains mandatory.
bosch_a_radar_tryout = not docs and Params().get_bool("HondaBoschARadar", default=True)
except UnknownKeyName:
bosch_a_radar_tryout = False
ret.radarUnavailable = not (candidate in HONDA_BOSCH_A and
candidate in HONDA_BOSCH_A_RADAR_VERIFIED and
bosch_a_radar_tryout)
# Disable the radar and let openpilot control longitudinal # Disable the radar and let openpilot control longitudinal
# WARNING: THIS DISABLES AEB! # WARNING: THIS DISABLES AEB!
# If Bosch radarless, this blocks ACC messages from the camera # If Bosch radarless, this blocks ACC messages from the camera
@@ -154,13 +143,9 @@ class CarInterface(CarInterfaceBase):
CarControllerParams.BOSCH_GAS_LOOKUP_BP = [-0.2, 2.0] CarControllerParams.BOSCH_GAS_LOOKUP_BP = [-0.2, 2.0]
elif candidate == CAR.HONDA_ACCORD_11G: elif candidate == CAR.HONDA_ACCORD_11G:
# MVL Boston sp-honda-dev-202608 tuning (48211d6a63). ret.steerActuatorDelay = 0.22
ret.longitudinalActuatorDelay = 0.05 ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 5200], [0, 2560, 12747]]
ret.steerActuatorDelay = 0.3 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 12789], [0, 12789]]
ret.lateralTuning.pid.kf = 0.000035
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.115], [0.052]]
CarControllerParams.BOSCH_GAS_LOOKUP_BP = [0.0, 2.0]
elif candidate == CAR.ACURA_ILX: elif candidate == CAR.ACURA_ILX:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] # TODO: determine if there is a dead zone at the top end
@@ -329,8 +314,6 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.RADARLESS.value ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.RADARLESS.value
if candidate in HONDA_BOSCH_CANFD: if candidate in HONDA_BOSCH_CANFD:
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.BOSCH_CANFD.value ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.BOSCH_CANFD.value
if candidate == CAR.HONDA_ACCORD_11G:
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.BOSCH_CANFD_MVL.value
# min speed to enable ACC. if car can do stop and go, then set enabling speed # min speed to enable ACC. if car can do stop and go, then set enabling speed
# to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not # to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not
@@ -362,13 +345,6 @@ class CarInterface(CarInterfaceBase):
@staticmethod @staticmethod
def init(CP, can_recv, can_send, communication_control=None): def init(CP, can_recv, can_send, communication_control=None):
if CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and CP.openpilotLongitudinalControl: if CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and CP.openpilotLongitudinalControl:
# CAN-FD radar ownership is handed over only after the comma relay is confirmed open.
# Disabling the radar here can create a gap before panda enters the Honda safety mode and
# replacement ACC_CONTROL is permitted, which can latch CRUISE_FAULT/DTCs in the brake module.
# deinit() still passes an explicit enable request and therefore falls through to disable_ecu.
if CP.carFingerprint == CAR.HONDA_ACCORD_11G and communication_control is None:
return
# 0x80 silences response # 0x80 silences response
if communication_control is None: if communication_control is None:
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.DISABLE_RX_DISABLE_TX, communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.DISABLE_RX_DISABLE_TX,
@@ -1,13 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import math
from collections import deque
from dataclasses import dataclass, field
from opendbc.can import CANParser from opendbc.can import CANParser
from opendbc.car import Bus, structs from opendbc.car import Bus, structs
from opendbc.car.honda.hondacan import CanBus
from opendbc.car.honda.values import DBC
from opendbc.car.interfaces import RadarInterfaceBase from opendbc.car.interfaces import RadarInterfaceBase
from opendbc.car.honda.values import DBC
def _create_nidec_can_parser(car_fingerprint): def _create_nidec_can_parser(car_fingerprint):
@@ -16,615 +11,39 @@ def _create_nidec_can_parser(car_fingerprint):
return CANParser(DBC[car_fingerprint][Bus.radar], messages, 1) return CANParser(DBC[car_fingerprint][Bus.radar], messages, 1)
# ============================================================================
# Honda Bosch-A 16-slot object bank
# ============================================================================
# 16 CAN-visible object slots. Each slot has 4 main frames (f0..f3, one CAN ID each -- NOT sub-frames
# muxed onto a shared ID) plus one synchronized auxiliary 5th frame. This supersedes any prior model of
# 0x280/0x284/0x288/0x28C as pieces of one object, or of 0x2C8/0x2C9 as a separate "coarse" list: it is
# ONE 16-slot bank with one auxiliary frame per slot. See honda_bosch_a_radar.dbc for the bit geometry.
BOSCH_A_DBC_NAME = 'honda_bosch_a_radar'
BOSCH_A_NUM_SLOTS = 16
def _bosch_a_main_base(slot: int) -> int:
return 0x280 + 4 * slot if slot < 4 else 0x2D0 + 4 * (slot - 4)
def _bosch_a_aux_id(slot: int) -> int:
return 0x2C8 + slot if slot < 8 else 0x290 + (slot - 8)
BOSCH_A_MAIN_IDS = [[_bosch_a_main_base(s) + i for i in range(4)] for s in range(BOSCH_A_NUM_SLOTS)]
BOSCH_A_AUX_IDS = [_bosch_a_aux_id(s) for s in range(BOSCH_A_NUM_SLOTS)]
BOSCH_A_ALL_IDS = [addr for ids in BOSCH_A_MAIN_IDS for addr in ids] + BOSCH_A_AUX_IDS
# Publish RadarPoints when the last MAIN object frame arrives. Passive captures prove that slot 15's
# companion frame, 0x297, follows 0x2FF and is the final observed object-family frame in a full sweep:
#
# ... 0x2FC, 0x2FD, 0x2FE, 0x2FF, 0x297
#
# Keep 0x2FF as the RadarPoint trigger while the companion data remains optional/debug-only. Making
# 0x297 the sole trigger would allow one dropped auxiliary frame to suppress an otherwise-valid point
# update, contrary to the parser's "aux never gates validity" contract.
BOSCH_A_TRIGGER_MSG = BOSCH_A_MAIN_IDS[BOSCH_A_NUM_SLOTS - 1][3]
BOSCH_A_SWEEP_END_MSG = BOSCH_A_AUX_IDS[BOSCH_A_NUM_SLOTS - 1] # 0x297
# Observed coherent Bosch-A sweep cadence is ~14.5-16 Hz in the available captures.
BOSCH_A_FREQ_HZ = 15
# Range: f0 raw_range (12-bit, B2:B3 high nibble) -> meters. Firmware q16 = 8*raw_range; physical
# calibration keeps slope/offset as named, replay-refinable constants (do not add a second radar/camera
# longitudinal offset on top of this).
BOSCH_A_RANGE_SCALE_M = 0.05712
BOSCH_A_RANGE_OFFSET_M = -3.0
# Azimuth: f0 raw_angle (11-bit, B4:B5 high 3 bits), offset-binary about 1024.
#
# The f3 angular-edge pair independently closes the exact center-angle scale:
# azimuth_rad = (raw_angle - 1024) / 2048
#
# This supersedes the older empirical 0.032 deg/count fit.
BOSCH_A_AZIMUTH_SCALE_RAD = 1.0 / 2048.0
BOSCH_A_AZIMUTH_CENTER = 1024
# Invalid sentinels (section 3/4/5/6 of the spec).
BOSCH_A_STATUS_INVALID = 0xF
BOSCH_A_RANGE_RAW_INVALID = 0xFFF
BOSCH_A_ANGLE_RAW_INVALID = 0x7FF
BOSCH_A_LIFE_INVALID = 0xFFF
BOSCH_A_TRACK_ID_MIN = 1
BOSCH_A_TRACK_ID_MAX = 0x3F
# AUX logical 0x00CA has an explicit 0x3FF invalid sentinel. Firmware proves the normalization below;
# captures strongly support interpreting the active value as previous/current range ratio.
BOSCH_A_RANGE_RATIO_INVALID = 0x3FF
BOSCH_A_LOGICAL_00CA_INVALID = BOSCH_A_RANGE_RATIO_INVALID # compatibility/debug alias
BOSCH_A_RANGE_RATIO_SCALE = 0.001
BOSCH_A_RANGE_RATIO_OFFSET = 0.5
# The synchronized AUX frame contains an 11-bit offset-binary velocity-like field and a 10-bit
# companion quality/uncertainty field. The byte locations are now decoded in the DBC. The exact
# Bosch descriptor name is still being verified, so keep the conversion constants isolated here.
# Capture validation shows active values in [0, 1728], with 0x7FE used as the inactive sentinel.
BOSCH_A_DIRECT_VREL_INVALID = 0x7FE
BOSCH_A_DIRECT_VREL_MIN_RAW = 0
BOSCH_A_DIRECT_VREL_MAX_RAW = 1728
BOSCH_A_DIRECT_VREL_CENTER_RAW = 864
BOSCH_A_DIRECT_VREL_SCALE_MPS = 1.0 / 64.0
# Empirical raw-quality policy. U11 error against an independent range-derivative reference rises
# with u10 in a graded way, not a cliff: replay evidence bins it roughly as 0-255 clean, 256-511 only
# mildly degraded, 512-767 clearly degraded, 768+ worst. 511 is set at that mild/clear boundary so
# U11 is still trusted directly through the mildly-degraded band; only u10 above this triggers the
# high-u10 coast path below. This is deliberately not presented as a Bosch physical unit or
# descriptor constant; it keeps saturated/high-uncertainty AUX values from becoming authoritative
# velocity measurements.
BOSCH_A_DIRECT_VREL_MAX_UNCERTAINTY_RAW = 511
# Measurement-authority policy. These are replay-derived safety/tuning gates, not recovered Bosch
# constants. Range innovation is measured from the previous accepted observation so a reset cannot
# become the baseline for following sweeps.
BOSCH_A_RANGE_SIGMA_DEGRADED_RAW = 4
BOSCH_A_RANGE_INNOVATION_MAX_M = 2.0
BOSCH_A_RANGE_INNOVATION_HARD_MAX_M = 5.0
BOSCH_A_FALLBACK_RANGE_RATE_MAX_MPS = 50.0
BOSCH_A_USE_TAN_LATERAL_PROJECTION = True
# Accepted-range history is retained for continuity and the adjacent two-point fallback. Rejected
# range resets never enter it, and it is not used for a multi-sample OLS velocity fit.
BOSCH_A_VREL_MAX_SAMPLES = 8
# Staleness gate -- TUNING constant, reused plumbing pattern (not a firmware fact). At the observed
# ~15 Hz cadence, 0.20 s is approximately three missed sweeps.
BOSCH_A_STALE_S = 0.20
@dataclass
class _BoschASlotState:
last_seen_nanos: int | None = None
# Firmware logical-ID companion data -- telemetry/debug only for now, never a RadarPoint validity
# gate. 0x00C9 has a firmware transform but no proven physical meaning; 0x00CA has an explicit
# invalid sentinel and its physical meaning remains unresolved.
logical_00c9_raw: float = float('nan')
logical_00ca_raw: float = float('nan')
direct_vrel_raw: int | None = None
direct_vrel_uncertainty_raw: int | None = None
def reset(self):
self.last_seen_nanos = None
self.logical_00c9_raw = float('nan')
self.logical_00ca_raw = float('nan')
self.direct_vrel_raw = None
self.direct_vrel_uncertainty_raw = None
@dataclass
class _BoschATrackState:
"""Persistent state for one Bosch CAN object identity, independent of wire slot."""
track_id: int
prev_frame_idx: int | None = None
prev_life: int | None = None
last_seen_nanos: int | None = None
wire_slot: int | None = None
samples: deque = field(default_factory=lambda: deque(maxlen=BOSCH_A_VREL_MAX_SAMPLES))
last_trusted_vrel: float | None = None
last_trusted_vrel_nanos: int | None = None
def _bosch_a_direct_vrel(raw_value: int | float | None,
uncertainty_raw: int | float | None = None) -> float | None:
"""Decode the capture-validated AUX relative-velocity candidate.
None means that AUX was absent/invalid and the caller should use the existing fallback policy. The [0, 1728]
active domain is deliberately enforced here because values above the observed +13.5 m/s rail have
not appeared on active objects; 0x7FE is the observed inactive sentinel.
"""
if raw_value is None:
return None
raw = int(raw_value)
if raw == BOSCH_A_DIRECT_VREL_INVALID:
return None
if not BOSCH_A_DIRECT_VREL_MIN_RAW <= raw <= BOSCH_A_DIRECT_VREL_MAX_RAW:
return None
# u10 is retained as a raw quality indicator because its physical units remain unresolved. The
# conservative threshold is evidence-backed tuning, not a recovered firmware validity rule.
if uncertainty_raw is not None and int(uncertainty_raw) > BOSCH_A_DIRECT_VREL_MAX_UNCERTAINTY_RAW:
return None
return (raw - BOSCH_A_DIRECT_VREL_CENTER_RAW) * BOSCH_A_DIRECT_VREL_SCALE_MPS
def _bosch_a_range_ratio(raw_value: int | float | None) -> float | None:
if raw_value is None:
return None
raw = int(raw_value)
if raw == BOSCH_A_RANGE_RATIO_INVALID or not 0 <= raw < BOSCH_A_RANGE_RATIO_INVALID:
return None
return BOSCH_A_RANGE_RATIO_OFFSET + BOSCH_A_RANGE_RATIO_SCALE * raw
def _bosch_a_range_ratio_vrel(raw_value: int | float | None, d_rel: float, dt: float) -> float | None:
"""Return the range rate implied by the empirical previous/current range ratio."""
ratio = _bosch_a_range_ratio(raw_value)
if ratio is None or dt <= 0.0 or not math.isfinite(d_rel):
return None
return d_rel * (1.0 - ratio) / dt
def _bosch_a_measurement_degraded(range_sigma_raw: int, existence_raw: int,
direct_vrel_uncertainty_raw: int | None) -> bool:
range_quality_bad = range_sigma_raw >= BOSCH_A_RANGE_SIGMA_DEGRADED_RAW or existence_raw in (0, 0x7F)
velocity_quality_bad = (direct_vrel_uncertainty_raw is not None and
direct_vrel_uncertainty_raw > BOSCH_A_DIRECT_VREL_MAX_UNCERTAINTY_RAW)
return range_quality_bad or velocity_quality_bad
def _create_bosch_a_can_parser(CP):
messages = [(addr, BOSCH_A_FREQ_HZ) for addr in BOSCH_A_ALL_IDS]
# Bus.radar selects the Bosch-A DBC; the object/fusion feed itself is
# physically on the camera-side ACC-CAN.
return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, CanBus(CP).camera)
class RadarInterface(RadarInterfaceBase): class RadarInterface(RadarInterfaceBase):
def __init__(self, CP): def __init__(self, CP):
super().__init__(CP) super().__init__(CP)
self.track_id = 0
self.radar_fault = False
self.radar_wrong_config = False
self.radar_off_can = CP.radarUnavailable self.radar_off_can = CP.radarUnavailable
self.bosch_a_radar = (not self.radar_off_can and Bus.radar in DBC[CP.carFingerprint] and
DBC[CP.carFingerprint][Bus.radar] == BOSCH_A_DBC_NAME)
# Nidec
if self.radar_off_can: if self.radar_off_can:
self.rcp = None self.rcp = None
self.trigger_msg = 0x445
elif self.bosch_a_radar:
self.rcp = _create_bosch_a_can_parser(CP)
self.trigger_msg = BOSCH_A_TRIGGER_MSG
self._slots = [_BoschASlotState() for _ in range(BOSCH_A_NUM_SLOTS)]
self._tracks: dict[int, _BoschATrackState] = {}
self._slot_track_ids: list[int | None] = [None] * BOSCH_A_NUM_SLOTS
self._last_trigger_nanos = -1
else: else:
# Nidec
self.rcp = _create_nidec_can_parser(CP.carFingerprint) self.rcp = _create_nidec_can_parser(CP.carFingerprint)
self.trigger_msg = 0x445 self.trigger_msg = 0x445
self.track_id = 0
self.radar_fault = False
self.radar_wrong_config = False
self.updated_messages = set() self.updated_messages = set()
def update(self, can_strings): def update(self, can_strings):
if self.radar_off_can or self.rcp is None: # in Bosch radar and we are only steering for now, so sleep 0.05s to keep
# radard at 20Hz and return no points
if self.radar_off_can:
return super().update(None) return super().update(None)
vls = self.rcp.update(can_strings) vls = self.rcp.update(can_strings)
self.updated_messages.update(vls) self.updated_messages.update(vls)
if self.trigger_msg not in self.updated_messages: if self.trigger_msg not in self.updated_messages:
if self.bosch_a_radar and self._last_trigger_nanos >= 0:
now = self.rcp._last_update_nanos
if (now - self._last_trigger_nanos) * 1e-9 > BOSCH_A_STALE_S:
return self._bosch_a_stale_radardata()
return None return None
rr = self._update(self.updated_messages) rr = self._update(self.updated_messages)
self.updated_messages.clear() self.updated_messages.clear()
return rr return rr
def _bosch_a_stale_radardata(self):
# Whole-bus silence: clear every live point/history and emit an EMPTY RadarData (not None) so
# radard drops any lead within a cycle instead of freezing a phantom. The next observation starts
# a fresh incarnation for its CAN identity.
self.pts.clear()
self._tracks.clear()
self._slot_track_ids = [None] * BOSCH_A_NUM_SLOTS
for slot_state in self._slots:
slot_state.reset()
self._last_trigger_nanos = -1
stale = structs.RadarData()
if not self.rcp.can_valid:
stale.errors.canError = True
stale.errors.radarUnavailableTemporary = True
return stale
def _bosch_a_retire_track(self, track_id: int):
self._tracks.pop(track_id, None)
self.pts.pop(track_id, None)
for slot, slot_track_id in enumerate(self._slot_track_ids):
if slot_track_id == track_id:
self._slot_track_ids[slot] = None
def _bosch_a_retire_stale_tracks(self, now: int):
for track_id, track in list(self._tracks.items()):
if track.last_seen_nanos is not None and (now - track.last_seen_nanos) * 1e-9 > BOSCH_A_STALE_S:
self._bosch_a_retire_track(track_id)
def _update(self, updated_messages): def _update(self, updated_messages):
if self.bosch_a_radar:
return self._update_bosch_a(updated_messages)
return self._update_nidec(updated_messages)
def _update_bosch_a(self, updated_messages):
ret = structs.RadarData()
if not self.rcp.can_valid:
ret.errors.canError = True
now = self.rcp._last_update_nanos
self._last_trigger_nanos = now
self._bosch_a_retire_stale_tracks(now)
observations = []
for slot in range(BOSCH_A_NUM_SLOTS):
f0, f1, f2, f3 = BOSCH_A_MAIN_IDS[slot]
aux = BOSCH_A_AUX_IDS[slot]
st = self._slots[slot]
if not (f0 in updated_messages and f1 in updated_messages and
f2 in updated_messages and f3 in updated_messages):
# Incomplete main-frame set: a missing CAN frame must not be treated as a lifecycle mismatch or
# death/replacement. Logical tracks are retired independently by their global staleness gate.
continue
v0 = self.rcp.vl[f0]
v1 = self.rcp.vl[f1]
v2 = self.rcp.vl[f2]
v3 = self.rcp.vl[f3]
idx0 = int(v0['FRAME_IDX'])
if not (idx0 == int(v1['FRAME_IDX']) == int(v2['FRAME_IDX']) == int(v3['FRAME_IDX'])):
# The four main frames don't share a common cycle index -- not a coherent observation this
# window. Only combine main-frame data from a coherent common frame index (section 2).
continue
status = int(v0['STATUS'])
range_raw = int(v0['RANGE_RAW'])
angle_raw = int(v0['AZIMUTH_RAW'])
range_sigma_raw = int(v0['RANGE_SIGMA_RAW'])
existence_raw = int(v1['OBJECT_EXISTENCE_PROBABILITY_RAW'])
life = int(v2['LIFECYCLE_RAW'])
track_id = int(v3['TRACK_ID'])
track_id_valid = BOSCH_A_TRACK_ID_MIN <= track_id <= BOSCH_A_TRACK_ID_MAX
st.last_seen_nanos = now
direct_vrel_raw = None
direct_vrel_uncertainty_raw = None
range_ratio_raw = None
# Attach synchronized companion data only when its cycle matches. Missing AUX never invalidates
# an otherwise coherent F0-F3 object; it only removes independent motion/quality evidence.
if aux in updated_messages:
av = self.rcp.vl[aux]
if int(av['FRAME_IDX']) == idx0:
direct_vrel_raw = int(av['REL_VELOCITY_RAW'])
direct_vrel_uncertainty_raw = int(av['REL_VELOCITY_UNCERTAINTY_RAW'])
range_ratio_raw = int(av['RANGE_RATIO_RAW'])
logical_00c9_raw = av['FW_LID_00C9_RAW']
logical_00ca_raw = av['FW_LID_00CA_RAW']
st.logical_00c9_raw = logical_00c9_raw
st.logical_00ca_raw = (
logical_00ca_raw if logical_00ca_raw != BOSCH_A_LOGICAL_00CA_INVALID else float('nan')
)
st.direct_vrel_raw = direct_vrel_raw
st.direct_vrel_uncertainty_raw = direct_vrel_uncertainty_raw
object_valid = (status != BOSCH_A_STATUS_INVALID and range_raw != BOSCH_A_RANGE_RAW_INVALID and
angle_raw != BOSCH_A_ANGLE_RAW_INVALID and life != BOSCH_A_LIFE_INVALID)
observations.append({
'slot': slot,
'frame_idx': idx0,
'life': life,
'track_id': track_id,
'track_id_valid': track_id_valid,
'object_valid': object_valid,
'range_sigma_raw': range_sigma_raw,
'existence_raw': existence_raw,
'direct_vrel_raw': direct_vrel_raw,
'direct_vrel_uncertainty_raw': direct_vrel_uncertainty_raw,
'range_ratio_raw': range_ratio_raw,
})
# First collapse duplicate wire observations of one CAN identity. The dictionary is also the
# output uniqueness boundary: one valid Bosch identity can never create two RadarPoints.
valid_by_id = {}
for observation in observations:
if not (observation['object_valid'] and observation['track_id_valid']):
# An invalid observation ends publication for the object currently occupying this wire slot,
# but it does not immediately destroy the persistent state. The object may be multiplexed to
# another slot or may return before the per-identity stale deadline; a later lifecycle break
# or staleness expiry will clear its derivative history.
ids_to_hide = {self._slot_track_ids[observation['slot']]}
if observation['track_id_valid']:
ids_to_hide.add(observation['track_id'])
for invalid_id in ids_to_hide - {None}:
self.pts.pop(invalid_id, None)
continue
track_id = observation['track_id']
current = valid_by_id.get(track_id)
if current is None:
valid_by_id[track_id] = observation
continue
# Prefer the wire slot currently associated with the persistent state. If neither candidate is
# preferred, retain the lower slot for deterministic handling of a malformed duplicate frame.
track = self._tracks.get(track_id)
current_score = (0 if track is not None and track.wire_slot == current['slot'] else 1, current['slot'])
candidate_score = (0 if track is not None and track.wire_slot == observation['slot'] else 1,
observation['slot'])
if candidate_score < current_score:
valid_by_id[track_id] = observation
valid_ids = set(valid_by_id)
for track_id, observation in sorted(valid_by_id.items(), key=lambda item: item[1]['slot']):
slot = observation['slot']
idx0 = observation['frame_idx']
life = observation['life']
# A wire-slot replacement ends publication for the old occupant, but not its persistent
# identity/history. If the old ID is still valid in another slot this sweep, keep its point;
# otherwise hide it until that ID returns or reaches its own stale deadline.
old_id = self._slot_track_ids[slot]
if old_id is not None and old_id != track_id and old_id not in valid_ids:
self.pts.pop(old_id, None)
track = self._tracks.get(track_id)
if track is None:
track = _BoschATrackState(track_id=track_id)
self._tracks[track_id] = track
same_incarnation = False
if track.prev_frame_idx is not None and track.prev_life is not None:
frame_delta = (idx0 - track.prev_frame_idx) & 0xF
life_delta = (life - track.prev_life) & 0xFFF
same_incarnation = life_delta == 2 * frame_delta
if not same_incarnation:
# The CAN identity remains the externally-visible key, but a lifecycle discontinuity starts a
# new incarnation and must not inherit the previous object's range-rate history.
track.samples.clear()
track.last_trusted_vrel = None
track.last_trusted_vrel_nanos = None
self.pts.pop(track_id, None)
v0 = self.rcp.vl[BOSCH_A_MAIN_IDS[slot][0]]
range_raw = int(v0['RANGE_RAW'])
angle_raw = int(v0['AZIMUTH_RAW'])
dRel = BOSCH_A_RANGE_SCALE_M * range_raw + BOSCH_A_RANGE_OFFSET_M
azimuth_rad = BOSCH_A_AZIMUTH_SCALE_RAD * (angle_raw - BOSCH_A_AZIMUTH_CENTER)
# The firmware's internal geometry path uses tan(angle) for a forward-axis distance. The
# Bosch object range is consumed as that forward-axis quantity here, so use the same projection
# rather than treating it as radial/slant range. Keep the switch explicit while the final
# output bridge remains under static review.
#
# Sign: AZIMUTH_RAW > center (positive azimuth_rad) is a LEFT-of-center detection in car frame's
# y axis (left is positive), matching the Nidec RadarPoint.yRel contract. Confirmed against real
# captures 2026-08-22: a stationary cluster of queued vehicles visible on the left in the road
# camera was rendering on the right in both the Qt and raylib radar-track overlays with the
# previously-flipped sign.
lateral_projection = math.tan if BOSCH_A_USE_TAN_LATERAL_PROJECTION else math.sin
yRel = dRel * lateral_projection(azimuth_rad)
now_s = now * 1e-9
direct_vrel_raw = observation['direct_vrel_raw']
direct_vrel_uncertainty_raw = observation['direct_vrel_uncertainty_raw']
direct_vrel = _bosch_a_direct_vrel(direct_vrel_raw, direct_vrel_uncertainty_raw)
live_direct_vrel = _bosch_a_direct_vrel(direct_vrel_raw)
range_ratio_raw = observation['range_ratio_raw']
# A live U11 rejected solely by the conservative U10 qualification threshold is neither an
# unavailable velocity nor permission to synthesize a one-sweep range derivative. It is also
# NOT permission to skip range-innovation checking below: u10 correlates with range_sigma in
# replay data, so a high-u10 sweep is exactly the condition where a bad/discontinuous range
# (slot migration, reset) is most likely, not less likely. Range acceptance is therefore
# decided on the same terms as every other sweep first; only once the range clears that gate
# does a high-u10 U11 fall back to coasting instead of publishing a synthesized derivative.
high_u10_live_vrel = (direct_vrel is None and live_direct_vrel is not None and
direct_vrel_uncertainty_raw is not None and
direct_vrel_uncertainty_raw > BOSCH_A_DIRECT_VREL_MAX_UNCERTAINTY_RAW)
# Validate against the previous accepted range. Qualified U11 and the range-ratio field are
# independent corroboration paths; high-U10 U11 is deliberately excluded from this decision.
previous_sample = track.samples[-1] if track.samples else None
fallback_vrel = 0.0
ratio_vrel = None
range_rejected = False
degraded = _bosch_a_measurement_degraded(
observation['range_sigma_raw'], observation['existence_raw'], direct_vrel_uncertainty_raw,
)
if previous_sample is not None:
previous_time, previous_range = previous_sample
dt = now_s - previous_time
if dt <= 0.0:
range_rejected = True
else:
fallback_vrel = (dRel - previous_range) / dt
ratio = _bosch_a_range_ratio(range_ratio_raw)
ratio_vrel = _bosch_a_range_ratio_vrel(range_ratio_raw, dRel, dt)
residuals_m = []
if direct_vrel is not None:
residuals_m.append(abs(dRel - (previous_range + direct_vrel * dt)))
if ratio is not None:
residuals_m.append(abs(previous_range - dRel * ratio))
if residuals_m:
innovation_m = min(residuals_m)
range_rejected = (
innovation_m > BOSCH_A_RANGE_INNOVATION_HARD_MAX_M or
(degraded and innovation_m > BOSCH_A_RANGE_INNOVATION_MAX_M)
)
else:
range_rejected = abs(fallback_vrel) > BOSCH_A_FALLBACK_RANGE_RATE_MAX_MPS
if range_rejected:
# Keep the last accepted point briefly as an unmeasured coast. The rejected geometry is not
# published and never becomes the baseline for a later derivative.
accepted_fresh = previous_sample is not None and now_s - previous_sample[0] <= BOSCH_A_STALE_S
point = self.pts.get(track_id)
if accepted_fresh and point is not None:
point.measured = False
else:
self.pts.pop(track_id, None)
track.prev_frame_idx = idx0
track.prev_life = life
track.last_seen_nanos = now
track.wire_slot = slot
for old_slot, old_id in enumerate(self._slot_track_ids):
if old_slot != slot and old_id == track_id:
self._slot_track_ids[old_slot] = None
self._slot_track_ids[slot] = track_id
continue
if high_u10_live_vrel:
# The range cleared innovation checking above, so geometry here is trustworthy; only vRel is
# in question. Preserve current geometry but coast only a recent authoritative motion
# estimate without a KF update, rather than publishing a one-sweep-derivative synthesis.
trusted_fresh = (track.last_trusted_vrel is not None and track.last_trusted_vrel_nanos is not None and
(now - track.last_trusted_vrel_nanos) * 1e-9 <= BOSCH_A_STALE_S)
if trusted_fresh:
point = self.pts.get(track_id)
if point is not None:
point.dRel = dRel
point.yRel = yRel
point.vRel = track.last_trusted_vrel
point.measured = False
else:
track.last_trusted_vrel = None
track.last_trusted_vrel_nanos = None
self.pts.pop(track_id, None)
# Do not let a coast-only range observation become a future derivative baseline.
track.prev_frame_idx = idx0
track.prev_life = life
track.last_seen_nanos = now
track.wire_slot = slot
for old_slot, old_id in enumerate(self._slot_track_ids):
if old_slot != slot and old_id == track_id:
self._slot_track_ids[old_slot] = None
self._slot_track_ids[slot] = track_id
continue
# Native U11 is unavailable here (sentinel/out-of-range -- the high-u10-but-live case above
# already returned before this point) and the range-ratio field is unusable or degraded too.
# The remaining option is the raw one-sweep (dRel-previous_range)/dt derivative, which is
# structurally the same hazard the high-u10 case guards against: a synthesized rate becoming an
# authoritative measurement. Coast a recent trusted velocity instead, on the same terms as above,
# rather than publish it.
# A true birth observation (no previous accepted range yet) can never mature into a published
# point this cycle regardless of vRel source -- `matured` below requires a second sample -- so
# only intercept once a fallback derivative would actually have something to poison.
u11_and_ratio_unavailable = (direct_vrel is None and (ratio_vrel is None or degraded) and
previous_sample is not None)
if u11_and_ratio_unavailable:
trusted_fresh = (track.last_trusted_vrel is not None and track.last_trusted_vrel_nanos is not None and
(now - track.last_trusted_vrel_nanos) * 1e-9 <= BOSCH_A_STALE_S)
if trusted_fresh:
point = self.pts.get(track_id)
if point is not None:
point.dRel = dRel
point.yRel = yRel
point.vRel = track.last_trusted_vrel
point.measured = False
else:
track.last_trusted_vrel = None
track.last_trusted_vrel_nanos = None
self.pts.pop(track_id, None)
# Do not let a coast-only range observation become a future derivative baseline.
track.prev_frame_idx = idx0
track.prev_life = life
track.last_seen_nanos = now
track.wire_slot = slot
for old_slot, old_id in enumerate(self._slot_track_ids):
if old_slot != slot and old_id == track_id:
self._slot_track_ids[old_slot] = None
self._slot_track_ids[slot] = track_id
continue
track.samples.append((now_s, dRel))
sample_count = len(track.samples)
# Prefer qualified native U11; otherwise the range-ratio field. The raw one-sweep derivative is
# never published as a measurement -- see the coast/drop branch above, which intercepts before
# this point whenever neither native U11 nor the ratio field is usable.
if direct_vrel is not None:
vRel = direct_vrel
else:
vRel = ratio_vrel
trustworthy_vrel = True
# A birth observation has no range-rate yet. Keep it as history, but do not publish a RadarPoint
# until a second coherent observation of the same CAN identity supplies a finite derivative.
matured = sample_count >= 2 and math.isfinite(vRel)
if trustworthy_vrel:
track.last_trusted_vrel = vRel
track.last_trusted_vrel_nanos = now
if matured and track_id not in self.pts:
self.pts[track_id] = structs.RadarData.RadarPoint()
self.pts[track_id].trackId = track_id
self.pts[track_id].aRel = float('nan')
self.pts[track_id].yvRel = float('nan')
if matured:
self.pts[track_id].dRel = dRel
self.pts[track_id].yRel = yRel
self.pts[track_id].vRel = vRel
self.pts[track_id].measured = True
else:
self.pts.pop(track_id, None)
track.prev_frame_idx = idx0
track.prev_life = life
track.last_seen_nanos = now
track.wire_slot = slot
for old_slot, old_id in enumerate(self._slot_track_ids):
if old_slot != slot and old_id == track_id:
self._slot_track_ids[old_slot] = None
self._slot_track_ids[slot] = track_id
ret.points = [self.pts[track_id] for track_id in sorted(self.pts)]
return ret
def _update_nidec(self, updated_messages):
ret = structs.RadarData() ret = structs.RadarData()
for ii in sorted(updated_messages): for ii in sorted(updated_messages):
File diff suppressed because it is too large Load Diff
@@ -2,7 +2,7 @@ import re
from types import SimpleNamespace from types import SimpleNamespace
import pytest import pytest
from opendbc.car import Bus, structs from opendbc.car import structs
from opendbc.car.structs import CarParams from opendbc.car.structs import CarParams
from opendbc.car import gen_empty_fingerprint from opendbc.car import gen_empty_fingerprint
from opendbc.car.honda.interface import CarInterface from opendbc.car.honda.interface import CarInterface
@@ -196,16 +196,6 @@ class TestHondaFingerprint:
assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_CANFD assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_CANFD
assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_LONG assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_LONG
def test_mvl_handover_is_scoped_to_accord_11g(self):
toggles = get_test_toggles()
accord_cp = CarInterface.get_params(CAR.HONDA_ACCORD_11G, gen_empty_fingerprint(), [], True, False, False, toggles)
crv_cp = CarInterface.get_params(CAR.HONDA_CRV_6G, gen_empty_fingerprint(), [], True, False, False, toggles)
assert Bus.radar in DBC[accord_cp.carFingerprint]
assert Bus.radar not in DBC[crv_cp.carFingerprint]
assert accord_cp.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_CANFD_MVL
assert not crv_cp.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_CANFD_MVL
def test_nidec_pedal_detection_enables_interceptor_path(self): def test_nidec_pedal_detection_enables_interceptor_path(self):
toggles = get_test_toggles() toggles = get_test_toggles()
fingerprint = gen_empty_fingerprint() fingerprint = gen_empty_fingerprint()
+12 -78
View File
@@ -57,9 +57,6 @@ class HondaSafetyFlags(IntFlag):
RADARLESS = 8 RADARLESS = 8
BOSCH_CANFD = 16 BOSCH_CANFD = 16
GAS_INTERCEPTOR = 32 GAS_INTERCEPTOR = 32
# Accord 11G MVL radar/camera handover messages. Keep the generic CAN-FD
# safety profile unchanged for other Honda CAN-FD platforms (for example CR-V 6G).
BOSCH_CANFD_MVL = 64
class HondaFlags(IntFlag): class HondaFlags(IntFlag):
@@ -120,17 +117,11 @@ class HondaCarDocs(CarDocs):
self.car_parts = CarParts.common([harness]) self.car_parts = CarParts.common([harness])
if CP.alphaLongitudinalAvailable:
self.footnotes.append(Footnote.EXP_LONG)
class Footnote(Enum): class Footnote(Enum):
CIVIC_DIESEL = CarFootnote( CIVIC_DIESEL = CarFootnote(
"2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.", "2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.",
Column.FSR_STEERING) Column.FSR_STEERING)
EXP_LONG = CarFootnote(
"Enabling longitudinal control (alpha) will disable all CMBS functionality, including AEB and FCW.",
Column.LONGITUDINAL)
@dataclass @dataclass
@@ -171,12 +162,7 @@ class CAR(Platforms):
HondaCarDocs("Honda N-Box 2018", "All", min_steer_speed=5.), HondaCarDocs("Honda N-Box 2018", "All", min_steer_speed=5.),
], ],
CarSpecs(mass=890., wheelbase=2.520, steerRatio=18.64), CarSpecs(mass=890., wheelbase=2.520, steerRatio=18.64),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode). {Bus.pt: 'acura_rdx_2020_can_generated'},
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'acura_rdx_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
) )
HONDA_ACCORD = HondaBoschPlatformConfig( HONDA_ACCORD = HondaBoschPlatformConfig(
[ [
@@ -186,21 +172,15 @@ class CAR(Platforms):
], ],
# steerRatio: 11.82 is spec end-to-end # steerRatio: 11.82 is spec end-to-end
CarSpecs(mass=3279 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.33, centerToFrontRatio=0.39, tireStiffnessFactor=0.8467), CarSpecs(mass=3279 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.33, centerToFrontRatio=0.39, tireStiffnessFactor=0.8467),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode). {Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
flags=HondaFlags.ALLOW_MANUAL_TRANS, flags=HondaFlags.ALLOW_MANUAL_TRANS,
) )
HONDA_ACCORD_11G = HondaBoschCANFDPlatformConfig( HONDA_ACCORD_11G = HondaBoschCANFDPlatformConfig(
[ [
HondaCarDocs("Honda Accord 2023-25", "All"), HondaCarDocs("Honda Accord 2023-25", "All"),
HondaCarDocs("Honda Accord Hybrid 2023-25", "All"), HondaCarDocs("Honda Accord Hybrid 2023-25", "All"),
], ],
CarSpecs(mass=3477 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.7, centerToFrontRatio=0.39), CarSpecs(mass=3477 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.0, centerToFrontRatio=0.39),
{Bus.pt: 'honda_common_canfd_generated', Bus.radar: 'honda_common_canfd_generated'},
) )
HONDA_CIVIC_BOSCH = HondaBoschPlatformConfig( HONDA_CIVIC_BOSCH = HondaBoschPlatformConfig(
[ [
@@ -210,22 +190,12 @@ class CAR(Platforms):
HondaCarDocs("Honda Civic Hatchback 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS), HondaCarDocs("Honda Civic Hatchback 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS),
], ],
CarSpecs(mass=1326, wheelbase=2.7, steerRatio=15.38, centerToFrontRatio=0.4), # steerRatio: 10.93 is end-to-end spec CarSpecs(mass=1326, wheelbase=2.7, steerRatio=15.38, centerToFrontRatio=0.4), # steerRatio: 10.93 is end-to-end spec
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode). {Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
) )
HONDA_CIVIC_BOSCH_DIESEL = HondaBoschPlatformConfig( HONDA_CIVIC_BOSCH_DIESEL = HondaBoschPlatformConfig(
[], # don't show in docs [], # don't show in docs
HONDA_CIVIC_BOSCH.specs, HONDA_CIVIC_BOSCH.specs,
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode). {Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
) )
HONDA_CIVIC_2022 = HondaBoschPlatformConfig( HONDA_CIVIC_2022 = HondaBoschPlatformConfig(
[ [
@@ -244,12 +214,7 @@ class CAR(Platforms):
[HondaCarDocs("Honda CR-V 2017-22", min_steer_speed=15. * CV.MPH_TO_MS)], [HondaCarDocs("Honda CR-V 2017-22", min_steer_speed=15. * CV.MPH_TO_MS)],
# steerRatio: 12.3 is spec end-to-end # steerRatio: 12.3 is spec end-to-end
CarSpecs(mass=3410 * CV.LB_TO_KG, wheelbase=2.66, steerRatio=16.0, centerToFrontRatio=0.41, tireStiffnessFactor=0.677), CarSpecs(mass=3410 * CV.LB_TO_KG, wheelbase=2.66, steerRatio=16.0, centerToFrontRatio=0.41, tireStiffnessFactor=0.677),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode). {Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.body: 'honda_crv_ex_2017_body_generated'},
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.body: 'honda_crv_ex_2017_body_generated', Bus.radar: 'honda_bosch_a_radar'},
flags=HondaFlags.BOSCH_ALT_BRAKE, flags=HondaFlags.BOSCH_ALT_BRAKE,
) )
HONDA_CRV_6G = HondaBoschCANFDPlatformConfig( HONDA_CRV_6G = HondaBoschCANFDPlatformConfig(
@@ -263,12 +228,7 @@ class CAR(Platforms):
[HondaCarDocs("Honda CR-V Hybrid 2017-22", min_steer_speed=12. * CV.MPH_TO_MS)], [HondaCarDocs("Honda CR-V Hybrid 2017-22", min_steer_speed=12. * CV.MPH_TO_MS)],
# mass: mean of 4 models in kg, steerRatio: 12.3 is spec end-to-end # mass: mean of 4 models in kg, steerRatio: 12.3 is spec end-to-end
CarSpecs(mass=1667, wheelbase=2.66, steerRatio=16, centerToFrontRatio=0.41, tireStiffnessFactor=0.677), CarSpecs(mass=1667, wheelbase=2.66, steerRatio=16, centerToFrontRatio=0.41, tireStiffnessFactor=0.677),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode). {Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
) )
HONDA_HRV_3G = HondaBoschPlatformConfig( HONDA_HRV_3G = HondaBoschPlatformConfig(
[HondaCarDocs("Honda HR-V 2023-25", "All")], [HondaCarDocs("Honda HR-V 2023-25", "All")],
@@ -285,12 +245,7 @@ class CAR(Platforms):
ACURA_RDX_3G = HondaBoschPlatformConfig( ACURA_RDX_3G = HondaBoschPlatformConfig(
[HondaCarDocs("Acura RDX 2019-21", "All", min_steer_speed=3. * CV.MPH_TO_MS)], [HondaCarDocs("Acura RDX 2019-21", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
CarSpecs(mass=4068 * CV.LB_TO_KG, wheelbase=2.75, steerRatio=11.95, centerToFrontRatio=0.41, tireStiffnessFactor=0.677), # as spec CarSpecs(mass=4068 * CV.LB_TO_KG, wheelbase=2.75, steerRatio=11.95, centerToFrontRatio=0.41, tireStiffnessFactor=0.677), # as spec
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode). {Bus.pt: 'acura_rdx_2020_can_generated'},
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'acura_rdx_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
flags=HondaFlags.BOSCH_ALT_BRAKE, flags=HondaFlags.BOSCH_ALT_BRAKE,
) )
ACURA_RDX_3G_MMR = HondaBoschPlatformConfig( ACURA_RDX_3G_MMR = HondaBoschPlatformConfig(
@@ -302,32 +257,17 @@ class CAR(Platforms):
HONDA_INSIGHT = HondaBoschPlatformConfig( HONDA_INSIGHT = HondaBoschPlatformConfig(
[HondaCarDocs("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS)], [HondaCarDocs("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
CarSpecs(mass=2987 * CV.LB_TO_KG, wheelbase=2.7, steerRatio=15.0, centerToFrontRatio=0.39, tireStiffnessFactor=0.82), # as spec CarSpecs(mass=2987 * CV.LB_TO_KG, wheelbase=2.7, steerRatio=15.0, centerToFrontRatio=0.39, tireStiffnessFactor=0.82), # as spec
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode). {Bus.pt: 'honda_insight_ex_2019_can_generated'},
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_insight_ex_2019_can_generated', Bus.radar: 'honda_bosch_a_radar'},
) )
HONDA_E = HondaBoschPlatformConfig( HONDA_E = HondaBoschPlatformConfig(
[HondaCarDocs("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS)], [HondaCarDocs("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
CarSpecs(mass=3338.8 * CV.LB_TO_KG, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82), CarSpecs(mass=3338.8 * CV.LB_TO_KG, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode). {Bus.pt: 'acura_rdx_2020_can_generated'},
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'acura_rdx_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
) )
HONDA_E_ADVANCE = HondaBoschPlatformConfig( HONDA_E_ADVANCE = HondaBoschPlatformConfig(
[], # don't show in docs, base trim already in docs [], # don't show in docs, base trim already in docs
CarSpecs(mass=1527, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82), CarSpecs(mass=1527, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode). {Bus.pt: 'honda_e_advance_2020_can_generated'},
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_e_advance_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
) )
HONDA_PILOT_4G = HondaBoschCANFDPlatformConfig( HONDA_PILOT_4G = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Honda Pilot 2023-25", "All")], [HondaCarDocs("Honda Pilot 2023-25", "All")],
@@ -528,12 +468,6 @@ HONDA_BOSCH = CAR.with_flags(HondaFlags.BOSCH)
HONDA_BOSCH_RADARLESS = CAR.with_flags(HondaFlags.BOSCH_RADARLESS) HONDA_BOSCH_RADARLESS = CAR.with_flags(HondaFlags.BOSCH_RADARLESS)
HONDA_BOSCH_CANFD = CAR.with_flags(HondaFlags.BOSCH_CANFD) HONDA_BOSCH_CANFD = CAR.with_flags(HondaFlags.BOSCH_CANFD)
HONDA_BOSCH_ALT_RADAR = CAR.with_flags(HondaFlags.BOSCH_ALT_RADAR) HONDA_BOSCH_ALT_RADAR = CAR.with_flags(HondaFlags.BOSCH_ALT_RADAR)
# Plain bosch_a harness: not CANFD, not radarless, not alt-radar. These platforms have a firmware-correct
# RadarInterface (16-slot Bosch-A object bank, RX-only, see radar_interface.py) available behind
# HondaBoschARadar. This describes hardware compatibility only; it is deliberately separate from the
# verified set below so a newly supported model cannot start using unvalidated radar data by accident.
HONDA_BOSCH_A = HONDA_BOSCH - HONDA_BOSCH_RADARLESS - HONDA_BOSCH_CANFD - HONDA_BOSCH_ALT_RADAR
HONDA_BOSCH_A_RADAR_VERIFIED = frozenset({CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CRV_5G})
HONDA_BOSCH_TJA_CONTROL = CAR.with_flags(HondaFlags.BOSCH_TJA_CONTROL) HONDA_BOSCH_TJA_CONTROL = CAR.with_flags(HondaFlags.BOSCH_TJA_CONTROL)
HONDA_CAMERA_MESSAGE_CARS = { HONDA_CAMERA_MESSAGE_CARS = {
CAR.HONDA_ACCORD, CAR.HONDA_ACCORD,
+44 -145
View File
@@ -9,12 +9,10 @@ from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.hyundai import hyundaicanfd, hyundaican from opendbc.car.hyundai import hyundaicanfd, hyundaican
from opendbc.car.hyundai.hyundaicanfd import CanBus from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR, CANFD_ANGLE_LONGITUDINAL_CAR, \ from opendbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR, CANFD_ANGLE_LONGITUDINAL_CAR, \
CANFD_RADAR_LIVE_LONGITUDINAL_CAR, CANFD_ALT_BUTTONS_RESUME_CAR, kia_ev6_gt_line_longitudinal_tuning, \ CANFD_RADAR_LIVE_LONGITUDINAL_CAR, kia_ev6_gt_line_longitudinal_tuning
KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID
from opendbc.car.interfaces import CarControllerBase from opendbc.car.interfaces import CarControllerBase
from opendbc.car.vehicle_model import VehicleModel from opendbc.car.vehicle_model import VehicleModel
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.starpilot.common.testing_grounds import testing_ground
VisualAlert = structs.CarControl.HUDControl.VisualAlert VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState LongCtrlState = structs.CarControl.Actuators.LongControlState
@@ -34,7 +32,6 @@ HYUNDAI_CANFD_SCC_DECEL_STEP = 12.5 / 50.0
IONIQ_6_RESPONSE_MULTIPLIER = 1.2 IONIQ_6_RESPONSE_MULTIPLIER = 1.2
IONIQ_6_CANFD_SCC_ACCEL_STEP = (6.0 / 50.0) * IONIQ_6_RESPONSE_MULTIPLIER IONIQ_6_CANFD_SCC_ACCEL_STEP = (6.0 / 50.0) * IONIQ_6_RESPONSE_MULTIPLIER
IONIQ_6_CANFD_SCC_DECEL_STEP = (15.0 / 50.0) * IONIQ_6_RESPONSE_MULTIPLIER IONIQ_6_CANFD_SCC_DECEL_STEP = (15.0 / 50.0) * IONIQ_6_RESPONSE_MULTIPLIER
EV9_CANFD_SCC_DECEL_STEP = 10.0 / 50.0
GENESIS_G90_STOP_HOLD_SPEED_BP = [0.0, 0.03, 0.08, 0.16, 0.3, 0.5, 0.8, 1.2, 2.0, 3.0] GENESIS_G90_STOP_HOLD_SPEED_BP = [0.0, 0.03, 0.08, 0.16, 0.3, 0.5, 0.8, 1.2, 2.0, 3.0]
GENESIS_G90_STOP_HOLD_ACCEL_V = [-0.10, -0.10, -0.12, -0.18, -0.30, -0.50, -0.75, -1.00, -1.40, -1.80] GENESIS_G90_STOP_HOLD_ACCEL_V = [-0.10, -0.10, -0.12, -0.18, -0.30, -0.50, -0.75, -1.00, -1.40, -1.80]
GENESIS_G90_STOP_HOLD_RELAX_SPEED_BP = [0.0, 0.08, 0.16, 0.3, 0.5, 0.8, 1.2, 2.0, 3.0] GENESIS_G90_STOP_HOLD_RELAX_SPEED_BP = [0.0, 0.08, 0.16, 0.3, 0.5, 0.8, 1.2, 2.0, 3.0]
@@ -45,7 +42,6 @@ GENESIS_G90_RELEASE_DECEL_STEP_V = [0.16, 0.18, 0.18]
GENESIS_G90_RELEASE_MAX_SPEED = 0.8 GENESIS_G90_RELEASE_MAX_SPEED = 0.8
IONIQ_6_LONG_MIN_JERK = 0.5 * IONIQ_6_RESPONSE_MULTIPLIER IONIQ_6_LONG_MIN_JERK = 0.5 * IONIQ_6_RESPONSE_MULTIPLIER
IONIQ_6_LONG_JERK_LIMIT = 4.8 * IONIQ_6_RESPONSE_MULTIPLIER IONIQ_6_LONG_JERK_LIMIT = 4.8 * IONIQ_6_RESPONSE_MULTIPLIER
EV9_LONG_DECEL_JERK = 2.0
IONIQ_6_LONG_LOOKAHEAD_JERK_BP = [2.0, 5.0, 20.0] IONIQ_6_LONG_LOOKAHEAD_JERK_BP = [2.0, 5.0, 20.0]
IONIQ_6_LONG_LOOKAHEAD_JERK_V = [0.3 / IONIQ_6_RESPONSE_MULTIPLIER, IONIQ_6_LONG_LOOKAHEAD_JERK_V = [0.3 / IONIQ_6_RESPONSE_MULTIPLIER,
0.45 / IONIQ_6_RESPONSE_MULTIPLIER, 0.45 / IONIQ_6_RESPONSE_MULTIPLIER,
@@ -80,22 +76,12 @@ BLINDSPOT_WARNING_SOUND_SAMPLES = 36
def egmp_dynamic_longitudinal_tuning(CP) -> bool: def egmp_dynamic_longitudinal_tuning(CP) -> bool:
return CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE) or \ return CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9) or \
kia_ev6_gt_line_longitudinal_tuning( kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, getattr(CP, "carVin", ""))
CP.carFingerprint, getattr(CP, "carVin", ""),
testing_ground.use(KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID),
)
def get_canfd_scc_decel_step(CP) -> float:
return EV9_CANFD_SCC_DECEL_STEP if CP.carFingerprint == CAR.KIA_EV9 else IONIQ_6_CANFD_SCC_DECEL_STEP
def should_reset_ev6_gt_line_longitudinal_tuning(CP, long_control_state: LongCtrlState) -> bool: def should_reset_ev6_gt_line_longitudinal_tuning(CP, long_control_state: LongCtrlState) -> bool:
return kia_ev6_gt_line_longitudinal_tuning( return kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, getattr(CP, "carVin", "")) and \
CP.carFingerprint, getattr(CP, "carVin", ""),
testing_ground.use(KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID),
) and \
long_control_state == LongCtrlState.off long_control_state == LongCtrlState.off
@@ -166,15 +152,6 @@ def should_track_stop_accel_directly(stopping: bool, v_ego: float,
return bool(stopping and v_ego > EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED and accel_cmd < actual_accel) return bool(stopping and v_ego > EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED and accel_cmd < actual_accel)
def should_track_stop_accel_directly_for_car(car_fingerprint, stopping: bool, v_ego: float,
accel_cmd: float, actual_accel: float) -> bool:
# EV9 uses the low-speed stop cap to avoid a harsh lead re-brake handoff.
# Keep direct tracking for the other CCNC angle-steering platform.
return car_fingerprint != CAR.KIA_EV9 and should_track_stop_accel_directly(
stopping, v_ego, accel_cmd, actual_accel,
)
def should_use_ev6_gt_line_stop_direct_tracking(ev6_gt_line: bool, stopping: bool, v_ego: float, def should_use_ev6_gt_line_stop_direct_tracking(ev6_gt_line: bool, stopping: bool, v_ego: float,
accel_cmd: float, actual_accel: float) -> bool: accel_cmd: float, actual_accel: float) -> bool:
return bool(ev6_gt_line and stopping and v_ego > EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED and accel_cmd < actual_accel) return bool(ev6_gt_line and stopping and v_ego > EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED and accel_cmd < actual_accel)
@@ -256,8 +233,7 @@ def reset_egmp_longitudinal_tuning(state: Ioniq6LongitudinalTuningState) -> Ioni
def update_ioniq_6_longitudinal_tuning(state: Ioniq6LongitudinalTuningState, accel_cmd: float, v_ego: float, a_ego: float, def update_ioniq_6_longitudinal_tuning(state: Ioniq6LongitudinalTuningState, accel_cmd: float, v_ego: float, a_ego: float,
long_control_state: LongCtrlState, long_active: bool, long_control_state: LongCtrlState, long_active: bool,
ev6_gt_line: bool = False, low_speed_stop_brake_cap: bool = False, ev6_gt_line: bool = False, low_speed_stop_brake_cap: bool = False) -> Ioniq6LongitudinalTuningState:
ev9: bool = False) -> Ioniq6LongitudinalTuningState:
starting = long_control_state == LongCtrlState.starting starting = long_control_state == LongCtrlState.starting
stopping = long_control_state == LongCtrlState.stopping stopping = long_control_state == LongCtrlState.stopping
restart_from_stop = state.long_control_state_last in (LongCtrlState.stopping, LongCtrlState.starting) and \ restart_from_stop = state.long_control_state_last in (LongCtrlState.stopping, LongCtrlState.starting) and \
@@ -297,8 +273,6 @@ def update_ioniq_6_longitudinal_tuning(state: Ioniq6LongitudinalTuningState, acc
dynamic_lower_jerk = _calculate_ioniq_6_dynamic_lower_jerk(dynamic_accel_error) dynamic_lower_jerk = _calculate_ioniq_6_dynamic_lower_jerk(dynamic_accel_error)
state.jerk_upper = desired_jerk_upper state.jerk_upper = desired_jerk_upper
state.jerk_lower = min(dynamic_lower_jerk, lower_speed_limit) state.jerk_lower = min(dynamic_lower_jerk, lower_speed_limit)
if ev9:
state.jerk_lower = min(state.jerk_lower, EV9_LONG_DECEL_JERK)
if state.stopping: if state.stopping:
stop_brake_cap_max_speed = EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED if ev6_gt_line or low_speed_stop_brake_cap else \ stop_brake_cap_max_speed = EV6_GT_LINE_STOP_BRAKE_CAP_MAX_SPEED if ev6_gt_line or low_speed_stop_brake_cap else \
@@ -416,27 +390,6 @@ def process_hud_alert(enabled, fingerprint, hud_control):
return sys_warning, sys_state, left_lane_warning, right_lane_warning return sys_warning, sys_state, left_lane_warning, right_lane_warning
def preserve_stock_canfd_lfa_status(car_fingerprint) -> bool:
return car_fingerprint not in (CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN)
def preserve_stock_canfd_lkas_status(car_fingerprint) -> bool:
return car_fingerprint not in (CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN)
def suppress_redundant_gv70_brake_cancel(CP, brake_pressed: bool, lat_active: bool) -> bool:
return bool(
CP.carFingerprint == CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN and
not CP.openpilotLongitudinalControl and brake_pressed and lat_active
)
def clear_ioniq_6_torque_when_request_inactive(CP, apply_torque: int, apply_steer_req: bool) -> int:
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and not apply_steer_req:
return 0
return apply_torque
class CarController(CarControllerBase): class CarController(CarControllerBase):
def __init__(self, dbc_names, CP): def __init__(self, dbc_names, CP):
super().__init__(dbc_names, CP) super().__init__(dbc_names, CP)
@@ -458,11 +411,11 @@ class CarController(CarControllerBase):
self.ecu_disable_failed = False self.ecu_disable_failed = False
self._ecu_disable_checked = False self._ecu_disable_checked = False
self._params = Params() self._params = Params()
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR: if CP.carFingerprint == CAR.KIA_EV9:
self._ev9_long_tuning = EV9LongitudinalTuningState() self._ev9_long_tuning = EV9LongitudinalTuningState()
self._left_blindspot_warning = BlindspotWarningState() self._left_blindspot_warning = BlindspotWarningState()
self._right_blindspot_warning = BlindspotWarningState() self._right_blindspot_warning = BlindspotWarningState()
self.long_active_ecu = self.CP.openpilotLongitudinalControl and not (self.CP.flags & HyundaiFlags.NON_SCC) self.long_active_ecu = self.CP.openpilotLongitudinalControl
self._ioniq_6_lane_change_ui_side = None self._ioniq_6_lane_change_ui_side = None
self._ioniq_6_lane_change_ui_frames = 0 self._ioniq_6_lane_change_ui_frames = 0
self._ioniq_6_long_tuning = Ioniq6LongitudinalTuningState() self._ioniq_6_long_tuning = Ioniq6LongitudinalTuningState()
@@ -470,7 +423,6 @@ class CarController(CarControllerBase):
self._dash_lat_disengage_blink_frame = 0 self._dash_lat_disengage_blink_frame = 0
self._dash_lat_disengage_init = False self._dash_lat_disengage_init = False
self._dash_prev_lat_active = False self._dash_prev_lat_active = False
self._ray_lkas11_active = False
def _update_dash_icon_state(self, CC): def _update_dash_icon_state(self, CC):
if CC.latActive: if CC.latActive:
@@ -563,8 +515,6 @@ class CarController(CarControllerBase):
drive_gear = CS.out.gearShifter == structs.CarState.GearShifter.drive drive_gear = CS.out.gearShifter == structs.CarState.GearShifter.drive
angle_lat_active = direct_angle_request_allowed(CS.out.vEgoRaw, measured_steering_angle, self.apply_angle_last, angle_lat_active = direct_angle_request_allowed(CS.out.vEgoRaw, measured_steering_angle, self.apply_angle_last,
drive_gear, self.BASELINE_VM, self.params) and not CS.angle_steering_fault drive_gear, self.BASELINE_VM, self.params) and not CS.angle_steering_fault
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_5_PE and CS.out.standstill:
angle_lat_active = False
self.direct_angle_request_allowed = angle_lat_active self.direct_angle_request_allowed = angle_lat_active
apply_angle = measured_steering_angle apply_angle = measured_steering_angle
@@ -620,8 +570,6 @@ class CarController(CarControllerBase):
if not CC.latActive: if not CC.latActive:
apply_torque = 0 apply_torque = 0
apply_torque = clear_ioniq_6_torque_when_request_inactive(self.CP, apply_torque, apply_steer_req)
# Hold torque with induced temporary fault when cutting the actuation bit # Hold torque with induced temporary fault when cutting the actuation bit
# FIXME: we don't use this with CAN FD? # FIXME: we don't use this with CAN FD?
torque_fault = CC.latActive and not apply_steer_req torque_fault = CC.latActive and not apply_steer_req
@@ -644,16 +592,13 @@ class CarController(CarControllerBase):
# When ECU disable was skipped (car started in READY mode), don't send any # When ECU disable was skipped (car started in READY mode), don't send any
# longitudinal messages - stock ECU is still active and these would conflict # longitudinal messages - stock ECU is still active and these would conflict
self.long_active_ecu = self.CP.openpilotLongitudinalControl and not (self.CP.flags & HyundaiFlags.NON_SCC) and not self.ecu_disable_failed self.long_active_ecu = self.CP.openpilotLongitudinalControl and not self.ecu_disable_failed
use_egmp_dynamic_long_tuning = egmp_dynamic_longitudinal_tuning(self.CP) and self.long_active_ecu and \ use_egmp_dynamic_long_tuning = egmp_dynamic_longitudinal_tuning(self.CP) and self.long_active_ecu and \
actuators.longControlState in (LongCtrlState.starting, LongCtrlState.pid, LongCtrlState.stopping) actuators.longControlState in (LongCtrlState.starting, LongCtrlState.pid, LongCtrlState.stopping)
is_ev6_gt_line = kia_ev6_gt_line_longitudinal_tuning( is_ev6_gt_line = kia_ev6_gt_line_longitudinal_tuning(self.CP.carFingerprint, getattr(self.CP, "carVin", ""))
self.CP.carFingerprint, getattr(self.CP, "carVin", ""), is_ev9 = self.CP.carFingerprint == CAR.KIA_EV9
testing_ground.use(KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID), if is_ev9 and (self._ev9_long_tuning.stop_request or not CC.enabled or CC.cruiseControl.override):
)
is_ccnc_angle_long = self.CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR
if is_ccnc_angle_long and (self._ev9_long_tuning.stop_request or not CC.enabled or CC.cruiseControl.override):
self._ioniq_6_long_tuning = reset_egmp_longitudinal_tuning(self._ioniq_6_long_tuning) self._ioniq_6_long_tuning = reset_egmp_longitudinal_tuning(self._ioniq_6_long_tuning)
if should_reset_ev6_gt_line_longitudinal_tuning(self.CP, actuators.longControlState): if should_reset_ev6_gt_line_longitudinal_tuning(self.CP, actuators.longControlState):
self._ioniq_6_long_tuning = reset_ev6_gt_line_longitudinal_tuning(self._ioniq_6_long_tuning, self.CP, self._ioniq_6_long_tuning = reset_ev6_gt_line_longitudinal_tuning(self._ioniq_6_long_tuning, self.CP,
@@ -663,30 +608,25 @@ class CarController(CarControllerBase):
CS.out.vEgo, CS.out.aEgo, CS.out.vEgo, CS.out.aEgo,
actuators.longControlState, self.long_active_ecu, actuators.longControlState, self.long_active_ecu,
ev6_gt_line=is_ev6_gt_line, ev6_gt_line=is_ev6_gt_line,
low_speed_stop_brake_cap=is_ccnc_angle_long, low_speed_stop_brake_cap=is_ev9)
ev9=self.CP.carFingerprint == CAR.KIA_EV9)
use_egmp_smoothed_accel = use_egmp_dynamic_long_tuning and ( use_egmp_smoothed_accel = use_egmp_dynamic_long_tuning and (
accel_cmd >= self._ioniq_6_long_tuning.actual_accel or accel_cmd >= self._ioniq_6_long_tuning.actual_accel or
self._ioniq_6_long_tuning.launch_active or self._ioniq_6_long_tuning.launch_active or
self._ioniq_6_long_tuning.stopping or self._ioniq_6_long_tuning.stopping
self.CP.carFingerprint == CAR.KIA_EV9
) )
if should_use_ev6_gt_line_stop_direct_tracking(is_ev6_gt_line, self._ioniq_6_long_tuning.stopping, if should_use_ev6_gt_line_stop_direct_tracking(is_ev6_gt_line, self._ioniq_6_long_tuning.stopping,
CS.out.vEgo, accel_cmd, self._ioniq_6_long_tuning.actual_accel): CS.out.vEgo, accel_cmd, self._ioniq_6_long_tuning.actual_accel):
use_egmp_smoothed_accel = False use_egmp_smoothed_accel = False
if is_ccnc_angle_long and should_track_stop_accel_directly_for_car( if is_ev9 and should_track_stop_accel_directly(self._ioniq_6_long_tuning.stopping, CS.out.vEgo,
self.CP.carFingerprint, self._ioniq_6_long_tuning.stopping, CS.out.vEgo, accel_cmd, self._ioniq_6_long_tuning.actual_accel):
accel_cmd, self._ioniq_6_long_tuning.actual_accel,
):
use_egmp_smoothed_accel = False use_egmp_smoothed_accel = False
if use_egmp_dynamic_long_tuning: if use_egmp_dynamic_long_tuning:
if use_egmp_smoothed_accel: if use_egmp_smoothed_accel:
accel = self._ioniq_6_long_tuning.actual_accel accel = self._ioniq_6_long_tuning.actual_accel
stopping = self._ioniq_6_long_tuning.stopping stopping = self._ioniq_6_long_tuning.stopping
else: else:
decel_step = get_canfd_scc_decel_step(self.CP)
accel = float(np.clip(accel_cmd, accel = float(np.clip(accel_cmd,
self.accel_last - decel_step, self.accel_last - IONIQ_6_CANFD_SCC_DECEL_STEP,
self.accel_last + IONIQ_6_CANFD_SCC_ACCEL_STEP)) self.accel_last + IONIQ_6_CANFD_SCC_ACCEL_STEP))
self._ioniq_6_long_tuning.desired_accel = accel_cmd self._ioniq_6_long_tuning.desired_accel = accel_cmd
self._ioniq_6_long_tuning.actual_accel = accel self._ioniq_6_long_tuning.actual_accel = accel
@@ -723,7 +663,7 @@ class CarController(CarControllerBase):
stopping, hud_control, CS, CC, starpilot_toggles, lka_icon, lfa_icon)) stopping, hud_control, CS, CC, starpilot_toggles, lka_icon, lfa_icon))
else: else:
can_sends.extend(self.create_can_msgs(apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel, can_sends.extend(self.create_can_msgs(apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel,
stopping, hud_control, actuators, CS, CC, lka_icon, lfa_icon)) stopping, hud_control, actuators, CS, CC, lfa_icon))
new_actuators = actuators.as_builder() new_actuators = actuators.as_builder()
if self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING: if self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
@@ -738,28 +678,18 @@ class CarController(CarControllerBase):
self.frame += 1 self.frame += 1
return new_actuators, can_sends return new_actuators, can_sends
def create_can_msgs(self, apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel, stopping, hud_control, actuators, CS, CC, lka_icon, lfa_icon): def create_can_msgs(self, apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel, stopping, hud_control, actuators, CS, CC, lfa_icon):
can_sends = [] can_sends = []
can_canfd_blended = bool(self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED) can_canfd_blended = bool(self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED)
blended_hda2 = can_canfd_blended and bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING)
# HUD messages # HUD messages
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint, sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
hud_control) hud_control)
if blended_hda2: if can_canfd_blended and self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
can_sends.extend(hyundaicanfd.create_steering_messages( can_sends.extend(hyundaicanfd.create_steering_messages(
self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque, 0.0, self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque, 0.0,
)) ))
if self.long_active_ecu:
can_sends.extend(hyundaican.create_lkas11_can_canfd_blended(
self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
left_lane_warning, right_lane_warning, CS.msg_364,
include_alerts=False,
counter_mod=0xF,
))
if self.frame % 5 == 0: if self.frame % 5 == 0:
can_sends.append(hyundaicanfd.create_suppress_lfa( can_sends.append(hyundaicanfd.create_suppress_lfa(
self.packer, self.CAN, CS.lfa_block_msg, False, self.packer, self.CAN, CS.lfa_block_msg, False,
@@ -770,13 +700,10 @@ class CarController(CarControllerBase):
hud_control.leftLaneVisible, hud_control.rightLaneVisible, hud_control.leftLaneVisible, hud_control.rightLaneVisible,
left_lane_warning, right_lane_warning, CS.msg_364)) left_lane_warning, right_lane_warning, CS.msg_364))
else: else:
if self.CP.carFingerprint != CAR.KIA_RAY_EV or self._ray_lkas11_active: can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.CP, apply_torque, apply_steer_req, torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled, hud_control.leftLaneVisible, hud_control.rightLaneVisible,
hud_control.leftLaneVisible, hud_control.rightLaneVisible, left_lane_warning, right_lane_warning))
left_lane_warning, right_lane_warning, lka_icon))
if self.CP.carFingerprint == CAR.KIA_RAY_EV:
self._ray_lkas11_active = True
# Button messages # Button messages
if not self.long_active_ecu: if not self.long_active_ecu:
@@ -793,23 +720,13 @@ class CarController(CarControllerBase):
can_sends.extend(self._create_can_redneck_button_messages(CS)) can_sends.extend(self._create_can_redneck_button_messages(CS))
if self.long_active_ecu and can_canfd_blended: if self.long_active_ecu and can_canfd_blended:
if blended_hda2: can_sends.extend(hyundaican.create_radar_aux_messages(self.packer, self.CAN, self.frame))
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame, blended_hda2=True))
can_sends.extend(hyundaican.create_radar_aux_messages(self.packer, self.CAN, self.frame, hda2=blended_hda2))
if self.frame % 2 == 0 and self.long_active_ecu: if self.frame % 2 == 0 and self.long_active_ecu:
# TODO: unclear if this is needed # TODO: unclear if this is needed
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0 jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
main_cruise_enabled = getattr(CS, "main_cruise_on", False) if getattr(CS, "main_cruise_tracking", False) else True if can_canfd_blended:
if blended_hda2:
stopping = stopping and CS.out.vEgoRaw < 0.1
can_sends.extend(hyundaican.create_acc_commands_can_canfd_blended_hda2(
self.packer, CC.enabled, accel, self.accel_last, jerk, int(self.frame / 2), hud_control,
set_speed_in_units, stopping, CC.cruiseControl.override, use_fca, self.CP,
))
self.accel_last = accel
elif can_canfd_blended:
can_sends.extend(hyundaican.create_acc_commands_can_canfd_blended(self.packer, CC.enabled, accel, jerk, can_sends.extend(hyundaican.create_acc_commands_can_canfd_blended(self.packer, CC.enabled, accel, jerk,
int(self.frame / 2), hud_control, int(self.frame / 2), hud_control,
set_speed_in_units, stopping, set_speed_in_units, stopping,
@@ -817,11 +734,10 @@ class CarController(CarControllerBase):
else: else:
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2), can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
hud_control, set_speed_in_units, stopping, hud_control, set_speed_in_units, stopping,
CC.cruiseControl.override, use_fca, self.CP, CC.cruiseControl.override, use_fca, self.CP))
main_cruise_enabled))
# 20 Hz LFA MFA message # 20 Hz LFA MFA message
if self.frame % 5 == 0 and (self.CP.flags & HyundaiFlags.SEND_LFA.value or (self.long_active_ecu and blended_hda2)): if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled, self.frame, self.CP, lfa_icon)) can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled, self.frame, self.CP, lfa_icon))
# 5 Hz ACC options # 5 Hz ACC options
@@ -850,12 +766,7 @@ class CarController(CarControllerBase):
) )
# steering control # steering control
# The first-generation Electrified GV70 expects the synthesized LKAS status preserve_stock_lkas = bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING) and not self.long_active_ecu
# payload. Forwarding its stock status bits leaves lane-safety state asserted
# while StarPilot is suppressing the stock LFA path.
preserve_stock_lkas = bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING) and \
not self.long_active_ecu and self.CP.carFingerprint != CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN and \
preserve_stock_canfd_lkas_status(self.CP.carFingerprint)
angle_lkas_alt = bool(self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and angle_lkas_alt = bool(self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and
self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT) self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT)
ccnc_angle_long = self.CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and \ ccnc_angle_long = self.CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and \
@@ -874,11 +785,10 @@ class CarController(CarControllerBase):
forward_stock_lkas = angle_lkas_alt and ( forward_stock_lkas = angle_lkas_alt and (
angle_lkas_alt_standstill_handoff or not (drive_gear and (CC.latActive or CC.enabled)) angle_lkas_alt_standstill_handoff or not (drive_gear and (CC.latActive or CC.enabled))
) )
preserve_stock_lfa_status = preserve_stock_canfd_lfa_status(self.CP.carFingerprint)
if not forward_stock_lkas and not ccnc_angle_long: if not forward_stock_lkas and not ccnc_angle_long:
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled,
steering_msg_active, apply_torque, apply_angle, steering_msg_active, apply_torque, apply_angle,
CS.stock_lfa_msg if preserve_stock_lfa_status else None, CS.stock_lfa_msg,
CS.stock_lkas_msg if preserve_stock_lkas else None, CS.stock_lkas_msg if preserve_stock_lkas else None,
lka_icon=lka_icon)) lka_icon=lka_icon))
direct_steering_active = ccnc_angle_long and drive_gear and CC.latActive and self.direct_angle_request_allowed and not CS.angle_steering_fault direct_steering_active = ccnc_angle_long and drive_gear and CC.latActive and self.direct_angle_request_allowed and not CS.angle_steering_fault
@@ -910,8 +820,7 @@ class CarController(CarControllerBase):
CC.leftBlinker, CC.rightBlinker, CS.msg_161, CS.msg_162, CS.msg_1b5, CC.leftBlinker, CC.rightBlinker, CS.msg_161, CS.msg_162, CS.msg_1b5,
CS.is_metric, CS.out, CS.out.cruiseState.available, lfa_icon)) CS.is_metric, CS.out, CS.out.cruiseState.available, lfa_icon))
else: else:
cluster_base_values = CS.stock_lfahda_cluster_msg if preserve_stock_lfa_status else None can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled, CS.stock_lfahda_cluster_msg,
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled, cluster_base_values,
lfa_icon=lfa_icon)) lfa_icon=lfa_icon))
# blinkers # blinkers
@@ -996,19 +905,16 @@ class CarController(CarControllerBase):
CC.leftBlinker, CC.leftBlinker,
CC.rightBlinker)) CC.rightBlinker))
if self.frame % 2 == 0: if self.frame % 2 == 0:
if self.CP.carFingerprint == CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN: lead_visible, lead_distance, lead_rel_speed = self._get_canfd_scc_lead_state(CC, CS, now_nanos)
acc_kwargs = {} acc_kwargs = {
else: "main_mode_acc": int(CS.out.cruiseState.available),
lead_visible, lead_distance, lead_rel_speed = self._get_canfd_scc_lead_state(CC, CS, now_nanos) "direct_accel": True,
acc_kwargs = { "jerk_lower": 5.0,
"main_mode_acc": int(CS.out.cruiseState.available), "jerk_upper": 3.0 if CC.actuators.longControlState == LongCtrlState.pid else 1.0,
"direct_accel": True, "lead_distance": lead_distance,
"jerk_lower": 5.0, "lead_rel_speed": lead_rel_speed,
"jerk_upper": 3.0 if CC.actuators.longControlState == LongCtrlState.pid else 1.0, "lead_visible": lead_visible,
"lead_distance": lead_distance, }
"lead_rel_speed": lead_rel_speed,
"lead_visible": lead_visible,
}
if use_egmp_dynamic_long_tuning: if use_egmp_dynamic_long_tuning:
if use_egmp_smoothed_accel: if use_egmp_smoothed_accel:
acc_kwargs["jerk_lower"] = self._ioniq_6_long_tuning.jerk_lower acc_kwargs["jerk_lower"] = self._ioniq_6_long_tuning.jerk_lower
@@ -1040,10 +946,7 @@ class CarController(CarControllerBase):
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25: if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
# cruise cancel - suppress when stock ACC is the fallback (ECU disable failed), # cruise cancel - suppress when stock ACC is the fallback (ECU disable failed),
# so openpilot doesn't fight/cancel the user's stock cruise # so openpilot doesn't fight/cancel the user's stock cruise
suppress_brake_cancel = suppress_redundant_gv70_brake_cancel( if CC.cruiseControl.cancel and not self.ecu_disable_failed:
self.CP, CS.out.brakePressed, CC.latActive,
)
if CC.cruiseControl.cancel and not self.ecu_disable_failed and not suppress_brake_cancel:
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS: if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info)) can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
self.last_button_frame = self.frame self.last_button_frame = self.frame
@@ -1054,13 +957,9 @@ class CarController(CarControllerBase):
# cruise standstill resume # cruise standstill resume
elif CC.cruiseControl.resume: elif CC.cruiseControl.resume:
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS and self.CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR: if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
for _ in range(20): # TODO: resume for alt button cars
can_sends.append(hyundaicanfd.create_buttons( pass
self.packer, self.CP, self.CAN, (CS.buttons_counter + 1) % 0x100,
Buttons.RES_ACCEL, base_values=CS.cruise_buttons_msg,
))
self.last_button_frame = self.frame
else: else:
for _ in range(20): for _ in range(20):
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.RES_ACCEL)) can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.RES_ACCEL))
+33 -85
View File
@@ -9,7 +9,6 @@ from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.hyundai.hyundaicanfd import CanBus from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import HyundaiFlags, HyundaiStarPilotFlags, HyundaiStarPilotSafetyFlags, CAR, DBC, Buttons, CarControllerParams, \ from opendbc.car.hyundai.values import HyundaiFlags, HyundaiStarPilotFlags, HyundaiStarPilotSafetyFlags, CAR, DBC, Buttons, CarControllerParams, \
CANFD_ANGLE_LONGITUDINAL_CAR, CANFD_CORNER_RADAR_BSM_CAR, \ CANFD_ANGLE_LONGITUDINAL_CAR, CANFD_CORNER_RADAR_BSM_CAR, \
CANFD_ALT_BUTTONS_RESUME_CAR, \
hyundai_cancel_button_enables_cruise, ALT_BUS_LDA_BUTTON_CARS, ALT_BUS_LDA_BUTTON_SWL_STAT_CARS hyundai_cancel_button_enables_cruise, ALT_BUS_LDA_BUTTON_CARS, ALT_BUS_LDA_BUTTON_SWL_STAT_CARS
from opendbc.car.interfaces import CarStateBase from opendbc.car.interfaces import CarStateBase
@@ -29,11 +28,6 @@ IONIQ_6_BLINDSPOT_LEFT_MASK = 0x10
CANFD_CAMERA_LEAD_MIN_DISTANCE = 0.1 CANFD_CAMERA_LEAD_MIN_DISTANCE = 0.1
ALT_BUS_LDA_BUTTON_BURST_DEBOUNCE_NS = int(1.3e9) ALT_BUS_LDA_BUTTON_BURST_DEBOUNCE_NS = int(1.3e9)
CLASSIC_MEDIA_BUTTON_CARS = frozenset({
CAR.HYUNDAI_ELANTRA_2024,
CAR.HYUNDAI_ELANTRA_HEV_2024,
})
def get_non_scc_cruise_signals(CP) -> tuple[str, str, str, str, str, str]: def get_non_scc_cruise_signals(CP) -> tuple[str, str, str, str, str, str]:
if CP.flags & HyundaiFlags.EV: if CP.flags & HyundaiFlags.EV:
@@ -55,15 +49,6 @@ def calculate_canfd_speed_limit(CP, FPCP, cp, cp_cam, speed_factor):
return 0.0 return 0.0
def get_canfd_cruise_available(CP, cp, scc_available: bool) -> bool:
# The EV9 fallback keeps stock ACC active when ECU disable is skipped. Its
# SCC status remains inactive in that mode, while TCS still reports whether
# ACC is fault-free and available.
if CP.carFingerprint == CAR.KIA_EV9 and not CP.openpilotLongitudinalControl:
return cp.vl["TCS"]["ACCEnable"] == 0
return scc_available
def decode_ioniq_6_blindspot_radar_state(state: int) -> tuple[bool, bool]: def decode_ioniq_6_blindspot_radar_state(state: int) -> tuple[bool, bool]:
state_int = int(state) state_int = int(state)
return bool(state_int & IONIQ_6_BLINDSPOT_LEFT_MASK), bool(state_int & IONIQ_6_BLINDSPOT_RIGHT_MASK) return bool(state_int & IONIQ_6_BLINDSPOT_LEFT_MASK), bool(state_int & IONIQ_6_BLINDSPOT_RIGHT_MASK)
@@ -132,8 +117,6 @@ class CarState(CarStateBase):
"CRUISE_BUTTONS" "CRUISE_BUTTONS"
self.is_metric = False self.is_metric = False
self.buttons_counter = 0 self.buttons_counter = 0
self.main_cruise_on = False
self.main_cruise_tracking = bool(getattr(FPCP, "flags", 0) & HyundaiStarPilotFlags.MAIN_CRUISE_STATE_TRACKING)
self.cruise_info = {} self.cruise_info = {}
self.msg_161 = {} self.msg_161 = {}
@@ -155,7 +138,7 @@ class CarState(CarStateBase):
self.blindspots_front_corner_1_ts = 0 self.blindspots_front_corner_1_ts = 0
self.left_blindspot_from_radar = False self.left_blindspot_from_radar = False
self.right_blindspot_from_radar = False self.right_blindspot_from_radar = False
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR: if CP.carFingerprint == CAR.KIA_EV9:
self.hba_icon = 0 self.hba_icon = 0
self.main_cruise_on = False self.main_cruise_on = False
self.angle_steering_angle = 0.0 self.angle_steering_angle = 0.0
@@ -173,10 +156,8 @@ class CarState(CarStateBase):
# Main button also can trigger an engagement on these cars # Main button also can trigger an engagement on these cars
return any(btn in ENABLE_BUTTONS for btn in self.cruise_buttons) or any(self.main_buttons) return any(btn in ENABLE_BUTTONS for btn in self.cruise_buttons) or any(self.main_buttons)
def update_main_cruise(self, ret: structs.CarState, def update_main_cruise(self, ret: structs.CarState) -> bool:
button_events: list[structs.CarState.ButtonEvent] | None = None) -> bool: if any(be.type == ButtonType.mainCruise and be.pressed for be in ret.buttonEvents):
button_events = ret.buttonEvents if button_events is None else button_events
if any(be.type == ButtonType.mainCruise and be.pressed for be in button_events):
self.main_cruise_on = not self.main_cruise_on self.main_cruise_on = not self.main_cruise_on
return bool(ret.cruiseState.available and self.main_cruise_on) return bool(ret.cruiseState.available and self.main_cruise_on)
@@ -242,23 +223,15 @@ class CarState(CarStateBase):
return button_events return button_events
def create_lkas_button_events(self, cp: CANParser, prev_lda_button: int) -> list[structs.CarState.ButtonEvent]: def create_lkas_button_events(self, cp: CANParser, prev_lda_button: int) -> list[structs.CarState.ButtonEvent]:
if self.CP.carFingerprint == CAR.HYUNDAI_SONATA: if self.CP.carFingerprint == CAR.HYUNDAI_SONATA_HYBRID:
self.lda_button = int(cp.vl["BCM_PO_11"]["LDA_BTN"]) if cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0 else 0
elif self.CP.carFingerprint == CAR.HYUNDAI_SONATA_HYBRID:
self.lda_button = self.get_sonata_hybrid_lkas_button_state(cp) self.lda_button = self.get_sonata_hybrid_lkas_button_state(cp)
elif self.CP.carFingerprint == CAR.HYUNDAI_ELANTRA_HEV_2024: # Some classic HKG platforms publish the LKAS button on the cluster bus instead of BCM_PO_11.
lda_samples = [ elif cp.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0:
*cp.vl_all["CLU13"]["CF_Clu_LdwsLkasSW"], self.lda_button = int(cp.vl["CLU13"]["CF_Clu_LdwsLkasSW"])
*cp.vl_all["BCM_PO_11"]["LDA_BTN"], elif cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0:
] self.lda_button = int(cp.vl["BCM_PO_11"]["LDA_BTN"])
if lda_samples:
self.lda_button = int(any(lda_samples))
else: else:
source_states = ( self.lda_button = 0
int(cp.vl["CLU13"]["CF_Clu_LdwsLkasSW"]) if cp.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0 else 0,
int(cp.vl["BCM_PO_11"]["LDA_BTN"]) if cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0 else 0,
)
self.lda_button = int(any(source_states))
return create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas}) return create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas})
@@ -336,19 +309,14 @@ class CarState(CarStateBase):
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5) ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0 ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
prev_cruise_buttons = self.cruise_buttons[-1]
prev_main_buttons = self.main_buttons[-1]
prev_lda_button = self.lda_button
main_button_events = []
if self.main_cruise_tracking:
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
main_button_events = create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise})
# cruise state # cruise state
no_scc = bool(self.CP.flags & HyundaiFlags.NON_SCC) no_scc = bool(self.CP.flags & HyundaiFlags.NON_SCC)
if self.CP.carFingerprint == CAR.KIA_RAY_EV: if self.CP.openpilotLongitudinalControl:
pass # These are not used for engage/disengage since openpilot keeps track of state using the buttons
ret.cruiseState.available = cp.vl["TCS13"]["ACCEnable"] == 0
ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
ret.cruiseState.standstill = False
ret.cruiseState.nonAdaptive = False
elif no_scc: elif no_scc:
cruise_available_msg, cruise_available_sig, cruise_enabled_msg, cruise_enabled_sig, cruise_speed_msg, cruise_speed_sig = get_non_scc_cruise_signals(self.CP) cruise_available_msg, cruise_available_sig, cruise_enabled_msg, cruise_enabled_sig, cruise_speed_msg, cruise_speed_sig = get_non_scc_cruise_signals(self.CP)
ret.cruiseState.available = cp.vl[cruise_available_msg][cruise_available_sig] != 0 ret.cruiseState.available = cp.vl[cruise_available_msg][cruise_available_sig] != 0
@@ -356,12 +324,6 @@ class CarState(CarStateBase):
ret.cruiseState.standstill = False ret.cruiseState.standstill = False
ret.cruiseState.nonAdaptive = False ret.cruiseState.nonAdaptive = False
ret.cruiseState.speed = cp.vl[cruise_speed_msg][cruise_speed_sig] * speed_conv ret.cruiseState.speed = cp.vl[cruise_speed_msg][cruise_speed_sig] * speed_conv
elif self.CP.openpilotLongitudinalControl:
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
ret.cruiseState.available = cp.vl["TCS13"]["ACCEnable"] == 0
ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
ret.cruiseState.standstill = False
ret.cruiseState.nonAdaptive = False
else: else:
scc_msg = "SCC12" if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED else "SCC11" scc_msg = "SCC12" if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED else "SCC11"
ret.cruiseState.available = cp_cruise.vl[scc_msg]["MainMode_ACC"] == 1 ret.cruiseState.available = cp_cruise.vl[scc_msg]["MainMode_ACC"] == 1
@@ -370,9 +332,6 @@ class CarState(CarStateBase):
ret.cruiseState.nonAdaptive = cp_cruise.vl[scc_msg]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash ret.cruiseState.nonAdaptive = cp_cruise.vl[scc_msg]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash
ret.cruiseState.speed = cp_cruise.vl[scc_msg]["VSetDis"] * speed_conv ret.cruiseState.speed = cp_cruise.vl[scc_msg]["VSetDis"] * speed_conv
if self.CP.openpilotLongitudinalControl and self.main_cruise_tracking:
ret.cruiseState.available = self.update_main_cruise(ret, main_button_events)
if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED: if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED:
if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING: if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
self.lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x2a4"]) self.lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x2a4"])
@@ -442,18 +401,19 @@ class CarState(CarStateBase):
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"]) self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
self.clu11 = copy.copy(cp.vl["CLU11"]) self.clu11 = copy.copy(cp.vl["CLU11"])
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
if not self.main_cruise_tracking: prev_cruise_buttons = self.cruise_buttons[-1]
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"]) prev_main_buttons = self.main_buttons[-1]
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"]) prev_lda_button = self.lda_button
main_button_events = create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise})
lkas_button_events = [] lkas_button_events = []
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
if self.CP.carFingerprint in ALT_BUS_LDA_BUTTON_CARS and cp_alt is not None and self.get_alt_bus_lda_button_raw_state(cp_alt)[1] > 0: if self.CP.carFingerprint in ALT_BUS_LDA_BUTTON_CARS and cp_alt is not None and self.get_alt_bus_lda_button_raw_state(cp_alt)[1] > 0:
lkas_button_events = self.create_alt_bus_lda_button_events(cp_alt) lkas_button_events = self.create_alt_bus_lda_button_events(cp_alt)
else: else:
lkas_button_events = self.create_lkas_button_events(cp, prev_lda_button) lkas_button_events = self.create_lkas_button_events(cp, prev_lda_button)
ret.buttonEvents = [*self.create_cruise_button_events(self.cruise_buttons[-1], prev_cruise_buttons), ret.buttonEvents = [*self.create_cruise_button_events(self.cruise_buttons[-1], prev_cruise_buttons),
*main_button_events, *create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}),
*lkas_button_events] *lkas_button_events]
ret.blockPcmEnable = not self.recent_button_interaction() ret.blockPcmEnable = not self.recent_button_interaction()
@@ -466,9 +426,6 @@ class CarState(CarStateBase):
ret.lowSpeedAlert = self.low_speed_alert ret.lowSpeedAlert = self.low_speed_alert
fp_ret = custom.StarPilotCarState.new_message() fp_ret = custom.StarPilotCarState.new_message()
if self.CP.carFingerprint in CLASSIC_MEDIA_BUTTON_CARS:
fp_ret.modePressed = bool(cp.vl["GW_SWRC_PE"]["C_ModeSW"])
fp_ret.customPressed = bool(cp.vl["GW_SWRC_PE"]["C_MTSSW"])
return ret, fp_ret return ret, fp_ret
@@ -561,8 +518,7 @@ class CarState(CarStateBase):
ret.cruiseState.standstill = False ret.cruiseState.standstill = False
else: else:
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
ret.cruiseState.available = get_canfd_cruise_available( ret.cruiseState.available = cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1
self.CP, cp, cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1)
ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2) ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1 ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
@@ -582,9 +538,7 @@ class CarState(CarStateBase):
self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"]) self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
self.lda_button = cp.vl[self.cruise_btns_msg_canfd]["LDA_BTN"] self.lda_button = cp.vl[self.cruise_btns_msg_canfd]["LDA_BTN"]
self.left_paddle = 0 self.left_paddle = 0
if self.CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR: if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
self.cruise_buttons_msg = copy.copy(cp.vl[self.cruise_btns_msg_canfd])
elif self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
self.cruise_buttons_msg = copy.copy(cp.vl["CRUISE_BUTTONS"]) self.cruise_buttons_msg = copy.copy(cp.vl["CRUISE_BUTTONS"])
self.left_paddle = cp.vl["CRUISE_BUTTONS"]["LEFT_PADDLE"] self.left_paddle = cp.vl["CRUISE_BUTTONS"]["LEFT_PADDLE"]
self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"] self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
@@ -617,7 +571,7 @@ class CarState(CarStateBase):
*create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}), *create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}),
*create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas}), *create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas}),
*create_button_events(self.left_paddle, prev_left_paddle, {1: ButtonType.altButton2})] *create_button_events(self.left_paddle, prev_left_paddle, {1: ButtonType.altButton2})]
if self.CP.openpilotLongitudinalControl and (self.CP.carFingerprint == CAR.KIA_EV9 or self.main_cruise_tracking): if self.CP.openpilotLongitudinalControl and self.CP.carFingerprint == CAR.KIA_EV9:
ret.cruiseState.available = self.update_main_cruise(ret) ret.cruiseState.available = self.update_main_cruise(ret)
ret.blockPcmEnable = not self.recent_button_interaction() ret.blockPcmEnable = not self.recent_button_interaction()
@@ -644,18 +598,14 @@ class CarState(CarStateBase):
def get_can_parsers_canfd(self, CP): def get_can_parsers_canfd(self, CP):
msgs = [] msgs = []
cam_msgs = [] cam_msgs = []
if CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR: if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
msgs.append(("CRUISE_BUTTONS_ALT", 50)) # TODO: this can be removed once we add dynamic support to vl_all
elif not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
# The EV9 can stop publishing this during the non-ECU-disabled startup
# state. Keep decoding it when present without making CAN invalid.
msgs += [ msgs += [
("CRUISE_BUTTONS", 0 if CP.carFingerprint == CAR.KIA_EV9 else 1) # this message is 50Hz but the ECU frequently stops transmitting for ~0.5s
("CRUISE_BUTTONS", 1)
] ]
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING: if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
# EV9 camera status can disappear for an extended period when the msgs.append(("FR_CMR_02_100ms", 10))
# documented ECU startup sequence is skipped.
msgs.append(("FR_CMR_02_100ms", 0 if CP.carFingerprint == CAR.KIA_EV9 else 10))
msgs.append(("FR_CMR_03_50ms", 0)) msgs.append(("FR_CMR_03_50ms", 0))
cam_msgs.append(("LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS", 0)) cam_msgs.append(("LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS", 0))
else: else:
@@ -671,7 +621,8 @@ class CarState(CarStateBase):
("LFAHDA_CLUSTER", 0), # optional: carries cluster icon state on some variants ("LFAHDA_CLUSTER", 0), # optional: carries cluster icon state on some variants
("BLINKER_STALKS", 0), # optional: some trims publish live stalk/light state on ECAN during turn camera events ("BLINKER_STALKS", 0), # optional: some trims publish live stalk/light state on ECAN during turn camera events
] ]
if CP.enableBsm: if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and CP.enableBsm:
# Keep the suppressed ADAS BSM output optional.
msgs.append(("BLINDSPOTS_REAR_CORNERS", 0)) msgs.append(("BLINDSPOTS_REAR_CORNERS", 0))
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR: if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR:
msgs.append(("BLINDSPOTS_FRONT_CORNER_2", 0)) msgs.append(("BLINDSPOTS_FRONT_CORNER_2", 0))
@@ -703,7 +654,7 @@ class CarState(CarStateBase):
("CGW2", 5), ("CGW2", 5),
("WHL_SPD11", 50), ("WHL_SPD11", 50),
("SAS11", 100), ("SAS11", 100),
("SCC12", 0 if CP.openpilotLongitudinalControl and CP.flags & HyundaiFlags.CANFD_LKA_STEERING else 50), ("SCC12", 50),
("EMS12", 100), ("EMS12", 100),
("EMS16", 100), ("EMS16", 100),
("LVR12", 100), ("LVR12", 100),
@@ -722,9 +673,6 @@ class CarState(CarStateBase):
("BCM_PO_11", 0), ("BCM_PO_11", 0),
("CLU13", 0), ("CLU13", 0),
] ]
if CP.carFingerprint in CLASSIC_MEDIA_BUTTON_CARS:
# Steering-wheel media switches are event-driven on the refresh Elantra.
msgs.append(("GW_SWRC_PE", 0))
if CP.flags & HyundaiFlags.NON_SCC and not (CP.flags & HyundaiFlags.NON_SCC_NO_FCA): if CP.flags & HyundaiFlags.NON_SCC and not (CP.flags & HyundaiFlags.NON_SCC_NO_FCA):
msgs.append(("FCA11", 0)) # Non-SCC trims can stop publishing FCA11; don't let it poison canValid msgs.append(("FCA11", 0)) # Non-SCC trims can stop publishing FCA11; don't let it poison canValid
@@ -1402,14 +1402,6 @@ FW_VERSIONS = {
b'\xf1\x00JK__ RDR ----- 1.00 1.01 99110-DS500 ', b'\xf1\x00JK__ RDR ----- 1.00 1.01 99110-DS500 ',
], ],
}, },
CAR.GENESIS_GV70_2026: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JK MFC AT USA LHD 1.00 1.11 99211-IY600 241125',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00JK__ RDR ----- 1.00 1.01 99110-AR600 ',
],
},
CAR.GENESIS_GV80_2025: { CAR.GENESIS_GV80_2025: {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00JX__ RDR ----- 1.00 1.03 99110-T6500 ', b'\xf1\x00JX__ RDR ----- 1.00 1.03 99110-T6500 ',
@@ -1696,9 +1688,4 @@ FW_VERSIONS = {
b'\xf1\x00BC3 LKA AT EUR LHD 1.00 1.01 99211-Q0100 261', b'\xf1\x00BC3 LKA AT EUR LHD 1.00 1.01 99211-Q0100 261',
], ],
}, },
CAR.KIA_RAY_EV: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00TAM MFC AT KOR LHD 1.00 1.02 99211-E2000 230901',
],
},
} }
+18 -84
View File
@@ -8,7 +8,7 @@ hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf)
def create_lkas11(packer, frame, CP, apply_torque, steer_req, def create_lkas11(packer, frame, CP, apply_torque, steer_req,
torque_fault, lkas11, sys_warning, sys_state, enabled, torque_fault, lkas11, sys_warning, sys_state, enabled,
left_lane, right_lane, left_lane, right_lane,
left_lane_depart, right_lane_depart, lka_icon): left_lane_depart, right_lane_depart):
values = {s: lkas11[s] for s in [ values = {s: lkas11[s] for s in [
"CF_Lkas_LdwsActivemode", "CF_Lkas_LdwsActivemode",
"CF_Lkas_LdwsSysState", "CF_Lkas_LdwsSysState",
@@ -40,7 +40,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
CAR.HYUNDAI_ELANTRA_HEV_2021, CAR.HYUNDAI_SONATA_HYBRID, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_KONA_HEV, CAR.HYUNDAI_KONA_EV_2022, CAR.HYUNDAI_ELANTRA_HEV_2021, CAR.HYUNDAI_SONATA_HYBRID, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_KONA_HEV, CAR.HYUNDAI_KONA_EV_2022,
CAR.HYUNDAI_SANTA_FE_2022, CAR.KIA_K5_2021, CAR.HYUNDAI_IONIQ_HEV_2022, CAR.HYUNDAI_SANTA_FE_HEV_2022, CAR.HYUNDAI_SANTA_FE_2022, CAR.KIA_K5_2021, CAR.HYUNDAI_IONIQ_HEV_2022, CAR.HYUNDAI_SANTA_FE_HEV_2022,
CAR.HYUNDAI_SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED, CAR.KIA_XCEED_PHEV, CAR.HYUNDAI_SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED, CAR.KIA_XCEED_PHEV,
CAR.HYUNDAI_AZERA_6TH_GEN, CAR.HYUNDAI_AZERA_HEV_6TH_GEN, CAR.HYUNDAI_CUSTIN_1ST_GEN, CAR.HYUNDAI_KONA_2022, CAR.KIA_RAY_EV, CAR.HYUNDAI_AZERA_6TH_GEN, CAR.HYUNDAI_AZERA_HEV_6TH_GEN, CAR.HYUNDAI_CUSTIN_1ST_GEN, CAR.HYUNDAI_KONA_2022,
CAR.HYUNDAI_ELANTRA_2024, CAR.HYUNDAI_ELANTRA_HEV_2024): CAR.HYUNDAI_ELANTRA_2024, CAR.HYUNDAI_ELANTRA_HEV_2024):
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1) values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
values["CF_Lkas_LdwsOpt_USM"] = 2 values["CF_Lkas_LdwsOpt_USM"] = 2
@@ -51,7 +51,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
# FcwOpt_USM 2 = Green car + lanes # FcwOpt_USM 2 = Green car + lanes
# FcwOpt_USM 1 = White car + lanes # FcwOpt_USM 1 = White car + lanes
# FcwOpt_USM 0 = No car + lanes # FcwOpt_USM 0 = No car + lanes
values["CF_Lkas_FcwOpt_USM"] = lka_icon if CP.carFingerprint == CAR.GENESIS_G70_2020 else 2 if enabled else 1 values["CF_Lkas_FcwOpt_USM"] = 2 if enabled else 1
# SysWarning 4 = keep hands on wheel # SysWarning 4 = keep hands on wheel
# SysWarning 5 = keep hands on wheel (red) # SysWarning 5 = keep hands on wheel (red)
@@ -60,7 +60,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0 values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
# Likely cars lacking the ability to show individual lane lines in the dash # Likely cars lacking the ability to show individual lane lines in the dash
elif CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.HYUNDAI_KONA_NON_SCC): elif CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL):
# SysWarning 4 = keep hands on wheel + beep # SysWarning 4 = keep hands on wheel + beep
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0 values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
@@ -68,7 +68,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
# SysState 1-2 = white car + lanes # SysState 1-2 = white car + lanes
# SysState 3 = green car + lanes, green steering wheel # SysState 3 = green car + lanes, green steering wheel
# SysState 4 = green car + lanes # SysState 4 = green car + lanes
values["CF_Lkas_LdwsSysState"] = lka_icon if CP.carFingerprint == CAR.HYUNDAI_KONA_NON_SCC else 3 if enabled else 1 values["CF_Lkas_LdwsSysState"] = 3 if enabled else 1
values["CF_Lkas_LdwsOpt_USM"] = 2 # non-2 changes above SysState definition values["CF_Lkas_LdwsOpt_USM"] = 2 # non-2 changes above SysState definition
# these have no effect # these have no effect
@@ -80,10 +80,6 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
# Genesis and Optima fault when forwarding while engaged # Genesis and Optima fault when forwarding while engaged
values["CF_Lkas_LdwsActivemode"] = 2 values["CF_Lkas_LdwsActivemode"] = 2
if CP.carFingerprint == CAR.KIA_RAY_EV:
values["CF_Lkas_LdwsOpt_USM"] = 0
values["CF_Lkas_Chksum"] = 0
dat = packer.make_can_msg("LKAS11", 0, values)[1] dat = packer.make_can_msg("LKAS11", 0, values)[1]
if CP.flags & HyundaiFlags.CHECKSUM_CRC8: if CP.flags & HyundaiFlags.CHECKSUM_CRC8:
@@ -110,8 +106,7 @@ def create_checksum_can_canfd_blended(packer, bus, addr, values):
def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req, def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req,
torque_fault, lkas11, sys_warning, sys_state, enabled, torque_fault, lkas11, sys_warning, sys_state, enabled,
left_lane, right_lane, left_lane, right_lane,
left_lane_depart, right_lane_depart, msg_364, left_lane_depart, right_lane_depart, msg_364):
include_alerts=True, counter_mod=0x10):
bus = CanBus(CP).ECAN bus = CanBus(CP).ECAN
values = { values = {
"CF_Lkas_LdwsActivemode": int(left_lane) + (int(right_lane) << 1), "CF_Lkas_LdwsActivemode": int(left_lane) + (int(right_lane) << 1),
@@ -121,7 +116,7 @@ def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req,
"CR_Lkas_StrToqReq": apply_steer, "CR_Lkas_StrToqReq": apply_steer,
"CF_Lkas_ActToi": steer_req, "CF_Lkas_ActToi": steer_req,
"CF_Lkas_ToiFlt": torque_fault, "CF_Lkas_ToiFlt": torque_fault,
"CF_Lkas_MsgCount": frame % counter_mod, "CF_Lkas_MsgCount": frame % 0x10,
"NEW_SIGNAL_1": 0, "NEW_SIGNAL_1": 0,
"NEW_SIGNAL_5": 100, "NEW_SIGNAL_5": 100,
} }
@@ -135,13 +130,13 @@ def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req,
alerts_364.setdefault("BYTE5", 0) alerts_364.setdefault("BYTE5", 0)
alerts_364.setdefault("BYTE6", 0) alerts_364.setdefault("BYTE6", 0)
alerts_364.setdefault("BYTE7", 0) alerts_364.setdefault("BYTE7", 0)
alerts_364["COUNTER"] = frame % counter_mod alerts_364["COUNTER"] = frame % 0x10
alerts_364["CHECKSUM"] = create_checksum_can_canfd_blended(packer, bus, "ALERTS_364", alerts_364) alerts_364["CHECKSUM"] = create_checksum_can_canfd_blended(packer, bus, "ALERTS_364", alerts_364)
ret = [packer.make_can_msg("LKAS11", bus, values)] return [
if include_alerts: packer.make_can_msg("LKAS11", bus, values),
ret.append(packer.make_can_msg("ALERTS_364", bus, alerts_364)) packer.make_can_msg("ALERTS_364", bus, alerts_364),
return ret ]
def create_clu11(packer, frame, clu11, button, CP): def create_clu11(packer, frame, clu11, button, CP):
@@ -238,62 +233,11 @@ def create_acc_commands_can_canfd_blended(packer, enabled, accel, upper_jerk, id
return commands return commands
def create_acc_commands_can_canfd_blended_hda2(packer, enabled, accel, accel_last, upper_jerk, idx, def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP):
hud_control, set_speed, stopping, long_override, use_fca, CP):
commands = []
bus = CanBus(CP).ECAN
jerk = 5.0
if not enabled or long_override:
accel_raw, accel_value = 0.0, 0.0
else:
accel_raw = accel
accel_value = max(accel_last - jerk / 50.0, min(accel, accel_last + jerk / 50.0))
message_values = [
("SCC11", {
"aReqRaw": accel_raw,
"aReqValue": accel_value,
"JerkUpperLimit": upper_jerk,
"JerkLowerLimit": jerk if enabled else 1.0,
}),
("SCC12", {
"MainMode_ACC": 1,
"ACCMode_Inactive": 0 if enabled else 1,
"TauGapSet": hud_control.leadDistanceBars,
"VSetDis": set_speed,
"ACC_ObjDist": 1,
"ACCMode": 2 if enabled and long_override else 1 if enabled else 0,
"StopReq": 1 if stopping else 0,
}),
("SCC14", {
"ACC_ObjRelSpd": 0,
"ObjValid": 0,
"ObjStatus": 2 if hud_control.leadVisible and enabled else 1 if hud_control.leadVisible else 0,
}),
]
if use_fca and not (CP.flags & HyundaiFlags.CAMERA_SCC):
# These values reproduce the stock status bytes without requesting AEB/FCA actuation.
message_values.append(("FCA11", {
"cr_vsm_deccmd": 255,
"cf_vsm_deccmdact": 0,
}))
for name, values in message_values:
values["COUNTER"] = idx % 0xF
values["CHECKSUM"] = create_checksum_can_canfd_blended(packer, bus, name, values)
commands.append(packer.make_can_msg(name, bus, values))
return commands
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP,
main_cruise_enabled=True):
commands = [] commands = []
scc11_values = { scc11_values = {
"MainMode_ACC": int(bool(main_cruise_enabled)), "MainMode_ACC": 1,
"TauGapSet": hud_control.leadDistanceBars, "TauGapSet": hud_control.leadDistanceBars,
"VSetDis": set_speed if enabled else 0, "VSetDis": set_speed if enabled else 0,
"AliveCounterACC": idx % 0x10, "AliveCounterACC": idx % 0x10,
@@ -380,27 +324,17 @@ def create_frt_radar_opt(packer):
return packer.make_can_msg("FRT_RADAR11", 0, frt_radar11_values) return packer.make_can_msg("FRT_RADAR11", 0, frt_radar11_values)
def create_radar_aux_messages(packer, CAN, frame, hda2=False): def create_radar_aux_messages(packer, CAN, frame):
commands = [] commands = []
message_specs = ( for addr, freq, values in (
("RADAR_0x363", 2, {"FCA_ESA": 1}),
("RADAR_0x398", 5, {"BYTE4": 0x80, "BYTE5": 0x5D}),
("RADAR_0x399", 5, {"BYTE2": 0x02}),
("RADAR_0x39a", 5, {"BYTE7": 0xFF}),
("RADAR_0x39b", 5, {}),
("RADAR_0x39c", 5, {"BYTE5": 0xE0, "BYTE6": 0x79}),
("RADAR_0x43a", 20, {"BYTE2": 0x07}),
) if hda2 else (
("RADAR_0x363", 2, {"FCA_ESA": 1}), ("RADAR_0x363", 2, {"FCA_ESA": 1}),
("RADAR_0x398", 5, {"BYTE4": 0x80, "BYTE5": 0x10}), ("RADAR_0x398", 5, {"BYTE4": 0x80, "BYTE5": 0x10}),
) ):
for addr, freq, values in message_specs:
if frame % freq != 0: if frame % freq != 0:
continue continue
msg_values = values | {"COUNTER": frame % (0xF if hda2 else 0x10)} msg_values = values | {"COUNTER": frame % 0x10}
msg_values["CHECKSUM"] = create_checksum_can_canfd_blended(packer, CAN.ECAN, addr, msg_values) msg_values["CHECKSUM"] = create_checksum_can_canfd_blended(packer, CAN.ECAN, addr, msg_values)
commands.append(packer.make_can_msg(addr, CAN.ECAN, msg_values)) commands.append(packer.make_can_msg(addr, CAN.ECAN, msg_values))
@@ -3,7 +3,7 @@ import numpy as np
from opendbc.car import CanBusBase, CanData from opendbc.car import CanBusBase, CanData
from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.crc import CRC16_XMODEM from opendbc.car.crc import CRC16_XMODEM
from opendbc.car.hyundai.values import HyundaiFlags, CAR, CANFD_ALT_BUTTONS_RESUME_CAR from opendbc.car.hyundai.values import HyundaiFlags, CAR
def _set_value(msg: bytearray, sig, ival: int) -> None: def _set_value(msg: bytearray, sig, ival: int) -> None:
@@ -63,61 +63,6 @@ def _update_checksum(packer, address: int, dat: bytearray) -> None:
_set_value(dat, sig_checksum, checksum) _set_value(dat, sig_checksum, checksum)
def _set_little_endian_bits(dat: bytearray, lsb: int, size: int, value: int) -> None:
"""Write the legacy HDA-II field layout without changing the generated DBC aliases."""
value &= (1 << size) - 1
bit = lsb
remaining = size
while remaining:
byte = bit // 8
shift = bit % 8
chunk_size = min(remaining, 8 - shift)
mask = ((1 << chunk_size) - 1) << shift
dat[byte] = (dat[byte] & ~mask) | ((value & ((1 << chunk_size) - 1)) << shift)
value >>= chunk_size
bit += chunk_size
remaining -= chunk_size
def _create_gv70_lka_status_msg(packer, CAN, message_name: str, bus: int, enabled: bool,
lat_active: bool, apply_torque: int):
values = {
"LKA_MODE": 2,
"LKA_ICON": 2 if enabled else 1,
"TORQUE_REQUEST": apply_torque,
"STEER_REQ": 1 if lat_active else 0,
"LKA_ASSIST": 0,
"STEER_MODE": 0,
"DAMP_FACTOR": 100,
}
address, raw, _ = packer.make_can_msg(message_name, bus, values)
dat = bytearray(raw)
legacy_fields = (
(24, 3, 2),
(27, 3, 0),
(30, 2, 0),
(32, 2, 0),
(34, 2, 0),
(36, 2, 0),
(38, 3, 2 if enabled else 1),
(52, 2, 1 if lat_active else 0),
(54, 2, 0),
(56, 1, 0),
(60, 4, 0),
(80, 2, 0),
)
for lsb, size, value in legacy_fields:
_set_little_endian_bits(dat, lsb, size, value)
_set_little_endian_bits(dat, 64 if message_name == "LKAS" else 104, 8, 100)
if message_name == "LKAS":
_set_little_endian_bits(dat, 84, 3, 0)
_update_checksum(packer, address, dat)
return address, bytes(dat), bus
def _create_angle_lfa_msg(packer, CAN, values, apply_angle: float, lat_active: bool, torque_reduction_gain: float): def _create_angle_lfa_msg(packer, CAN, values, apply_angle: float, lat_active: bool, torque_reduction_gain: float):
address = packer.dbc.name_to_msg["LFA"].address address = packer.dbc.name_to_msg["LFA"].address
dat = packer.pack(address, values) dat = packer.pack(address, values)
@@ -155,14 +100,6 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
lfa_base_values=None, lkas_base_values=None, lka_icon=None): lfa_base_values=None, lkas_base_values=None, lka_icon=None):
if lka_icon is None: if lka_icon is None:
lka_icon = 2 if enabled else 1 lka_icon = 2 if enabled else 1
if CP.carFingerprint == CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN and CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
ret = []
if CP.openpilotLongitudinalControl:
ret.append(_create_gv70_lka_status_msg(packer, CAN, "LFA", CAN.ECAN, enabled, lat_active, apply_torque))
ret.append(_create_gv70_lka_status_msg(packer, CAN, "LKAS", CAN.ACAN, enabled, lat_active, apply_torque))
return ret
angle_lkas_alt = CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT angle_lkas_alt = CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT
control_values = { control_values = {
@@ -180,8 +117,6 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
else: else:
lkas_values = copy.copy(control_values) lkas_values = copy.copy(control_values)
lkas_values["LKA_AVAILABLE"] = 0 lkas_values["LKA_AVAILABLE"] = 0
if CP.carFingerprint in (CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN):
lkas_values["DAMP_FACTOR"] = 100
if lfa_base_values: if lfa_base_values:
# Preserve stock UI/status fields and only override the actuation-relevant signals. # Preserve stock UI/status fields and only override the actuation-relevant signals.
@@ -255,7 +190,7 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
ret = [] ret = []
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING: if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS" lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS"
if CP.openpilotLongitudinalControl and not CP.flags & HyundaiFlags.CAN_CANFD_BLENDED: if CP.openpilotLongitudinalControl:
ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values)) ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values))
ret.append(packer.make_can_msg(lkas_msg, CAN.ACAN, lkas_values)) ret.append(packer.make_can_msg(lkas_msg, CAN.ACAN, lkas_values))
else: else:
@@ -306,27 +241,16 @@ def create_suppress_lfa(packer, CAN, lfa_block_msg, lka_steering_alt):
def create_buttons(packer, CP, CAN, cnt, btn=0, base_values=None, left_paddle=False, right_paddle=False): def create_buttons(packer, CP, CAN, cnt, btn=0, base_values=None, left_paddle=False, right_paddle=False):
values = {k: v for k, v in base_values.items() if k not in ("CHECKSUM", "_CHECKSUM", "COUNTER")} if base_values else {} values = {k: v for k, v in base_values.items() if k not in ("_CHECKSUM", "COUNTER")} if base_values else {}
values.update({ values.update({
"COUNTER": cnt, "COUNTER": cnt,
"SET_ME_1": 1, "SET_ME_1": 1,
"CRUISE_BUTTONS": btn, "CRUISE_BUTTONS": btn,
"LEFT_PADDLE": int(left_paddle),
"RIGHT_PADDLE": int(right_paddle),
}) })
if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS and CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR):
values.update({
"LEFT_PADDLE": int(left_paddle),
"RIGHT_PADDLE": int(right_paddle),
})
bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_LKA_STEERING else CAN.CAM bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_LKA_STEERING else CAN.CAM
if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS and CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR:
address, dat, bus = packer.make_can_msg("CRUISE_BUTTONS_ALT", bus, values)
dat = bytearray(dat)
checksum = hkg_can_fd_checksum(address, None, dat)
dat[0] = checksum & 0xFF
dat[1] = (checksum >> 8) & 0xFF
return address, bytes(dat), bus
return packer.make_can_msg("CRUISE_BUTTONS", bus, values) return packer.make_can_msg("CRUISE_BUTTONS", bus, values)
@@ -826,7 +750,7 @@ def create_fca_warning_light(packer, CAN, frame):
return ret return ret
def create_adrv_messages(packer, CAN, frame, blended_hda2=False): def create_adrv_messages(packer, CAN, frame):
# messages needed to car happy after disabling # messages needed to car happy after disabling
# the ADAS Driving ECU to do longitudinal control # the ADAS Driving ECU to do longitudinal control
@@ -836,9 +760,6 @@ def create_adrv_messages(packer, CAN, frame, blended_hda2=False):
} }
ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values)) ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
if blended_hda2:
return ret
ret.extend(create_fca_warning_light(packer, CAN, frame)) ret.extend(create_fca_warning_light(packer, CAN, frame))
if frame % 5 == 0: if frame % 5 == 0:
@@ -922,7 +843,6 @@ def hkg_can_fd_checksum(address: int, sig, d: bytearray) -> int:
# brake, and accelerator bits are updated for the radar heartbeat. # brake, and accelerator bits are updated for the radar heartbeat.
_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000020000fcff000000000020000055ff000068000000") _ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000020000fcff000000000020000055ff000068000000")
_KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("00000000ff006f00e80400001201030055ffff0000000000") _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("00000000ff006f00e80400001201030055ffff0000000000")
_HYUNDAI_IONIQ_5_PE_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000000000000000000000ff1fffff55ffff00a8000000")
# Neutral bodies verified across stock and successful suppression routes. Only # Neutral bodies verified across stock and successful suppression routes. Only
# rolling integrity fields and the decoded state above are changed at runtime. # rolling integrity fields and the decoded state above are changed at runtime.
_CCNC_ADRV_TEMPLATES = { _CCNC_ADRV_TEMPLATES = {
@@ -939,19 +859,6 @@ _CCNC_ADRV_TEMPLATES = {
0x1E0: bytes.fromhex("00000002000000000000000000000000"), 0x1E0: bytes.fromhex("00000002000000000000000000000000"),
0x38C: bytes.fromhex("000000f71f000000000000000000000000000000000000000000000000000000"), 0x38C: bytes.fromhex("000000f71f000000000000000000000000000000000000000000000000000000"),
}, },
CAR.HYUNDAI_IONIQ_5_PE: {
0x160: bytes.fromhex("0000000000000000fffc0100a8001000"),
0x1DA: bytes.fromhex("0000002200010000000000000000000000000000000000000000000000000000"),
0x1EA: bytes.fromhex("000000080000000000000000000000ff000000000000000000000000000f0f00"),
0x200: bytes.fromhex("00000014401b0000"),
0x345: bytes.fromhex("0000001500560000"),
0x161: bytes.fromhex("0000000000000000c0fff0c003000040000000000000000000ff000000000000"),
0x162: bytes.fromhex("0000002700000000c0ff00000000000000000000000000000000000000000000"),
0x1BA: bytes.fromhex("00000000000000880200000000000000000100000000000f"),
0x1E5: bytes.fromhex("00000000000000000000220200000080"),
0x1E0: bytes.fromhex("00000002000000000000000000000000"),
0x38C: bytes.fromhex("000000f79f000000000000000000000000000000000000000000000000000000"),
},
} }
_CCNC_ADRV_PERIODS = { _CCNC_ADRV_PERIODS = {
CAR.KIA_EV9: { CAR.KIA_EV9: {
@@ -963,26 +870,12 @@ _CCNC_ADRV_PERIODS = {
0x1E0: 5, 0x1E0: 5,
0x38C: 20, 0x38C: 20,
}, },
CAR.HYUNDAI_IONIQ_5_PE: {
0x160: 2,
0x1DA: 100,
0x1EA: 5,
0x200: 5,
0x345: 20,
0x1E0: 5,
0x38C: 20,
},
} }
def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool, def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool,
car_fingerprint=None) -> CanData: car_fingerprint=None) -> CanData:
if car_fingerprint == CAR.KIA_EV9: template = _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE if car_fingerprint == CAR.KIA_EV9 else _ACCEL_BRAKE_ALT_TEMPLATE
template = _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE
elif car_fingerprint == CAR.HYUNDAI_IONIQ_5_PE:
template = _HYUNDAI_IONIQ_5_PE_ACCEL_BRAKE_ALT_TEMPLATE
else:
template = _ACCEL_BRAKE_ALT_TEMPLATE
d = bytearray(template) d = bytearray(template)
d[2] = counter & 0xFF # COUNTER (bit 16, 8-bit) d[2] = counter & 0xFF # COUNTER (bit 16, 8-bit)
d[4] = (d[4] & ~0x01) | (0x01 if brake_pressed else 0x00) # BRAKE_PRESSED (bit 32) d[4] = (d[4] & ~0x01) | (0x01 if brake_pressed else 0x00) # BRAKE_PRESSED (bit 32)
+29 -79
View File
@@ -9,18 +9,15 @@ from opendbc.car.hyundai.values import HyundaiFlags, CAR, CarControllerParams, \
RADAR_LIVE_LONGITUDINAL_CAR, \ RADAR_LIVE_LONGITUDINAL_CAR, \
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, \ UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, \
LEGACY_LONGITUDINAL_CAR, \ LEGACY_LONGITUDINAL_CAR, \
CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR, \
HyundaiStarPilotSafetyFlags, \ HyundaiStarPilotSafetyFlags, \
hyundai_cancel_button_enables_cruise, \ hyundai_cancel_button_enables_cruise, \
kia_ev6_gt_line_longitudinal_tuning, \ kia_ev6_gt_line_longitudinal_tuning
KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID
from opendbc.car.hyundai.radar_interface import get_radar_track_config, radar_tracks_available from opendbc.car.hyundai.radar_interface import get_radar_track_config, radar_tracks_available
from opendbc.car.interfaces import CarInterfaceBase, ACCEL_MIN from opendbc.car.interfaces import CarInterfaceBase, ACCEL_MIN
from opendbc.car.disable_ecu import disable_ecu, ecu_log from opendbc.car.disable_ecu import disable_ecu, ecu_log
from opendbc.car.hyundai.carcontroller import CarController from opendbc.car.hyundai.carcontroller import CarController
from opendbc.car.hyundai.carstate import CarState from opendbc.car.hyundai.carstate import CarState
from opendbc.car.hyundai.radar_interface import RadarInterface from opendbc.car.hyundai.radar_interface import RadarInterface
from openpilot.starpilot.common.testing_grounds import testing_ground
ButtonType = structs.CarState.ButtonEvent.Type ButtonType = structs.CarState.ButtonEvent.Type
Ecu = structs.CarParams.Ecu Ecu = structs.CarParams.Ecu
@@ -31,7 +28,7 @@ ENABLE_BUTTONS = (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.can
# Track when ECU disable happened - used to permanently suppress CAN errors from disabled ECU # Track when ECU disable happened - used to permanently suppress CAN errors from disabled ECU
ECU_DISABLE_TIMESTAMP = 0.0 ECU_DISABLE_TIMESTAMP = 0.0
KONA_NON_SCC_FCA_RADAR_ADDR = 0x602 KONA_NON_SCC_FCA_RADAR_ADDR = 0x602
KIA_EV9_ACCEL_MAX = 2.2 KIA_EV9_ACCEL_MAX = 2.5
def apply_platform_longitudinal_params(ret: structs.CarParams) -> None: def apply_platform_longitudinal_params(ret: structs.CarParams) -> None:
@@ -65,25 +62,6 @@ def apply_ecu_disable_failure_fallback(CP: structs.CarParams, params) -> None:
CP.pcmCruise = True CP.pcmCruise = True
def egmp_in_ready_state(can_recv, bus: int, timeout_s: float = 0.5) -> bool:
accelerator_addr = 0x35
ready_bit_mask = 0x40
deadline = time.monotonic() + timeout_s
while time.monotonic() < deadline:
try:
can_packets = can_recv(wait_for_one=True)
except Exception:
break
for packet in can_packets:
for msg in packet:
if msg.address == accelerator_addr and msg.src == bus and len(msg.dat) > 3 and msg.dat[3] & ready_bit_mask:
return True
return False
def detect_kona_non_scc_radar_fca(candidate, fingerprint, car_fw) -> bool: def detect_kona_non_scc_radar_fca(candidate, fingerprint, car_fw) -> bool:
if candidate != CAR.HYUNDAI_KONA_NON_SCC: if candidate != CAR.HYUNDAI_KONA_NON_SCC:
return False return False
@@ -108,8 +86,7 @@ class CarInterface(CarInterfaceBase):
@staticmethod @staticmethod
def apply_post_fingerprint_params(CP: structs.CarParams, candidate, fingerprint, car_fw) -> None: def apply_post_fingerprint_params(CP: structs.CarParams, candidate, fingerprint, car_fw) -> None:
gt_line_testing_ground = testing_ground.use(KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID) if kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin):
if kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin, gt_line_testing_ground):
apply_kia_ev6_gt_line_longitudinal_params(CP) apply_kia_ev6_gt_line_longitudinal_params(CP)
@staticmethod @staticmethod
@@ -152,8 +129,7 @@ class CarInterface(CarInterfaceBase):
ret.flags |= HyundaiFlags.CANFD_LKA_STEERING_ALT.value ret.flags |= HyundaiFlags.CANFD_LKA_STEERING_ALT.value
# This HDA II Carnival uses the alternate 0x1AA cruise-button frame even # This HDA II Carnival uses the alternate 0x1AA cruise-button frame even
# though other LKA-steering platforms use 0x1CF. # though other LKA-steering platforms use 0x1CF.
if candidate in (CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN) and \ if candidate == CAR.KIA_CARNIVAL_2025 and 0x1aa in fingerprint[CAN.ECAN] and 0x1cf not in fingerprint[CAN.ECAN]:
0x1aa in fingerprint[CAN.ECAN] and 0x1cf not in fingerprint[CAN.ECAN]:
ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
else: else:
# no LKA steering # no LKA steering
@@ -195,16 +171,13 @@ class CarInterface(CarInterfaceBase):
# panda safety or the carcontroller; the MDPS tolerating held torque at 0 speed # panda safety or the carcontroller; the MDPS tolerating held torque at 0 speed
# is being validated on-road. # is being validated on-road.
ret.steerAtStandstill = True ret.steerAtStandstill = True
if candidate == CAR.HYUNDAI_IONIQ_5_PE:
ret.steerAtStandstill = True
if ret.flags & HyundaiFlags.CCNC and not ret.flags & HyundaiFlags.CANFD_LKA_STEERING: if ret.flags & HyundaiFlags.CCNC and not ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CCNC.value ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CCNC.value
else: else:
# Shared configuration for non CAN-FD cars # Shared configuration for non CAN-FD cars
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR or candidate in LEGACY_LONGITUDINAL_CAR ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR or candidate in LEGACY_LONGITUDINAL_CAR
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED and ret.flags & HyundaiFlags.CANFD_LKA_STEERING and \ if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED and ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
candidate not in CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR:
ret.alphaLongitudinalAvailable = False ret.alphaLongitudinalAvailable = False
ret.enableBsm = 0x58b in fingerprint[CAN.ECAN] ret.enableBsm = 0x58b in fingerprint[CAN.ECAN]
@@ -230,7 +203,7 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_REFRESH_MSGS.value ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_REFRESH_MSGS.value
# These cars expose an LKAS/LFA steering-wheel button that StarPilot can customize. # These cars expose an LKAS/LFA steering-wheel button that StarPilot can customize.
if 0x391 in fingerprint[0] or 0x50C in fingerprint[0] or ret.flags & HyundaiFlags.CAN_CANFD_BLENDED: if 0x391 in fingerprint[0] or ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED: if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_CANFD_BLENDED.value ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_CANFD_BLENDED.value
@@ -239,11 +212,6 @@ class CarInterface(CarInterfaceBase):
if hyundai_cancel_button_enables_cruise(candidate): if hyundai_cancel_button_enables_cruise(candidate):
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANCEL_BTN_ENABLE.value ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANCEL_BTN_ENABLE.value
if 0x2AA in fingerprint[0]:
ret.minSteerSpeed = 0.0
ret.flags &= ~HyundaiFlags.MIN_STEER_32_MPH.value
ret.steerAtStandstill = True
# Common lateral control setup # Common lateral control setup
ret.centerToFront = ret.wheelbase * 0.4 ret.centerToFront = ret.wheelbase * 0.4
@@ -312,17 +280,6 @@ class CarInterface(CarInterfaceBase):
if candidate == CAR.HYUNDAI_IONIQ_6: if candidate == CAR.HYUNDAI_IONIQ_6:
ret.longitudinalActuatorDelay = 0.6 ret.longitudinalActuatorDelay = 0.6
if candidate == CAR.HYUNDAI_SANTA_FE_2022:
ret.longitudinalActuatorDelay = 0.4
ret.longitudinalTuning.kpBP = [0.0, 8.0, 20.0, 35.0]
ret.longitudinalTuning.kpV = [0.20, 0.17, 0.12, 0.08]
ret.longitudinalTuning.kiBP = [0.0, 8.0, 20.0, 35.0]
ret.longitudinalTuning.kiV = [0.02, 0.03, 0.05, 0.07]
if candidate == CAR.HYUNDAI_IONIQ_5_PE:
ret.longitudinalActuatorDelay = 0.35
ret.vEgoStarting = 0.4
if candidate == CAR.KIA_EV9 and ret.openpilotLongitudinalControl: if candidate == CAR.KIA_EV9 and ret.openpilotLongitudinalControl:
apply_kia_ev9_longitudinal_params(ret) apply_kia_ev9_longitudinal_params(ret)
@@ -359,42 +316,35 @@ class CarInterface(CarInterfaceBase):
ecu_log(f"=== init() called: opLong={CP.openpilotLongitudinalControl}, flags=0x{CP.flags:x}, safetyParam={CP.safetyConfigs[-1].safetyParam} ===") ecu_log(f"=== init() called: opLong={CP.openpilotLongitudinalControl}, flags=0x{CP.flags:x}, safetyParam={CP.safetyConfigs[-1].safetyParam} ===")
if CP.openpilotLongitudinalControl and not (CP.flags & (HyundaiFlags.NON_SCC | HyundaiFlags.CANFD_CAMERA_SCC | HyundaiFlags.CAMERA_SCC)): if CP.openpilotLongitudinalControl and not (CP.flags & (HyundaiFlags.CANFD_CAMERA_SCC | HyundaiFlags.CAMERA_SCC)):
addr, bus = 0x7d0, CanBus(CP).ECAN if CP.flags & (HyundaiFlags.CANFD | HyundaiFlags.CAN_CANFD_BLENDED) else 0 addr, bus = 0x7d0, CanBus(CP).ECAN if CP.flags & (HyundaiFlags.CANFD | HyundaiFlags.CAN_CANFD_BLENDED) else 0
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value: if CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value:
addr, bus = 0x730, CanBus(CP).ECAN addr, bus = 0x730, CanBus(CP).ECAN
skip_disable_ecu = False # Try ECU disable. If it succeeds (IGN-ON mode), enable longitudinal.
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and egmp_in_ready_state(can_recv, bus): # If it fails (READY mode returns NRC 0x22, or timeout), strip LONG safety flag
apply_ecu_disable_failure_fallback(CP, params) # so panda forwards stock SCC messages normally (lateral-only mode).
ecu_log(f"=== ECU DISABLE SKIPPED - READY detected, safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===") ecu_log(f"=== ECU DISABLE attempt: addr=0x{addr:x}, bus={bus} ===")
skip_disable_ecu = True ecu_disabled = disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control,
reset=bool(CP.flags & HyundaiFlags.CAN_CANFD_BLENDED))
if not skip_disable_ecu: if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
# Try ECU disable. If it succeeds (IGN-ON mode), enable longitudinal. # Ioniq 6: track success/failure to auto-switch between openpilot long and stock ACC
# If it fails (READY mode returns NRC 0x22, or timeout), strip LONG safety flag if ecu_disabled:
# so panda forwards stock SCC messages normally (lateral-only mode). ECU_DISABLE_TIMESTAMP = time.monotonic()
ecu_log(f"=== ECU DISABLE attempt: addr=0x{addr:x}, bus={bus} ===") params.put_bool("EcuDisableFailed", False)
ecu_disabled = disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control, params.put_bool("ExperimentalMode", True)
reset=bool(CP.flags & HyundaiFlags.CAN_CANFD_BLENDED)) ecu_log("=== ECU DISABLE SUCCESS - Longitudinal + Experimental ENABLED ===")
if CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_IONIQ_5_PE):
# Track success/failure to auto-switch between openpilot long and stock ACC
if ecu_disabled:
ECU_DISABLE_TIMESTAMP = time.monotonic()
params.put_bool("EcuDisableFailed", False)
params.put_bool("ExperimentalMode", True)
ecu_log("=== ECU DISABLE SUCCESS - Longitudinal + Experimental ENABLED ===")
else:
apply_ecu_disable_failure_fallback(CP, params)
ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
else: else:
if ecu_disabled: apply_ecu_disable_failure_fallback(CP, params)
params.put_bool("EcuDisableFailed", False) ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
ecu_log("=== ECU DISABLE SUCCESS ===") else:
else: if ecu_disabled:
apply_ecu_disable_failure_fallback(CP, params) params.put_bool("EcuDisableFailed", False)
ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===") ecu_log("=== ECU DISABLE SUCCESS ===")
else:
apply_ecu_disable_failure_fallback(CP, params)
ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
# for blinkers # for blinkers
if CP.flags & HyundaiFlags.ENABLE_BLINKERS: if CP.flags & HyundaiFlags.ENABLE_BLINKERS:
File diff suppressed because it is too large Load Diff
+26 -46
View File
@@ -45,12 +45,8 @@ class CarControllerParams:
self.STEER_DRIVER_MULTIPLIER = 2 self.STEER_DRIVER_MULTIPLIER = 2
self.STEER_THRESHOLD = 100 self.STEER_THRESHOLD = 100
if vEgoRaw < 15.0: # below ~34 mph - more aggressive for tight turns if vEgoRaw < 15.0: # below ~34 mph - more aggressive for tight turns
if CP.carFingerprint == CAR.KIA_CARNIVAL_HEV_4TH_GEN: self.STEER_DELTA_UP = 10
self.STEER_DELTA_UP = 2 self.STEER_DELTA_DOWN = 8
self.STEER_DELTA_DOWN = 3
else:
self.STEER_DELTA_UP = 10
self.STEER_DELTA_DOWN = 8
else: else:
self.STEER_DELTA_UP = 2 self.STEER_DELTA_UP = 2
self.STEER_DELTA_DOWN = 3 self.STEER_DELTA_DOWN = 3
@@ -115,7 +111,6 @@ class HyundaiSafetyFlags(IntFlag):
class HyundaiStarPilotSafetyFlags(IntFlag): class HyundaiStarPilotSafetyFlags(IntFlag):
AOL_MAIN_LKAS_ON_ENGAGE = 128
AOL_MAIN_LKAS_SYNC = 32 AOL_MAIN_LKAS_SYNC = 32
HAS_LDA_BUTTON = 1024 HAS_LDA_BUTTON = 1024
AOL_LKAS_ON_ENGAGE = 2048 AOL_LKAS_ON_ENGAGE = 2048
@@ -123,7 +118,6 @@ class HyundaiStarPilotSafetyFlags(IntFlag):
class HyundaiStarPilotFlags(IntFlag): class HyundaiStarPilotFlags(IntFlag):
SPEED_LIMIT_AVAILABLE = 1 SPEED_LIMIT_AVAILABLE = 1
MAIN_CRUISE_STATE_TRACKING = 2 ** 2
class HyundaiFlags(IntFlag): class HyundaiFlags(IntFlag):
@@ -486,7 +480,7 @@ class CAR(Platforms):
[ [
HyundaiCarDocs("Hyundai Palisade (without HDA II) 2023-25", "Highway Driving Assist", HyundaiCarDocs("Hyundai Palisade (without HDA II) 2023-25", "Highway Driving Assist",
car_parts=CarParts.common([CarHarness.hyundai_a])), car_parts=CarParts.common([CarHarness.hyundai_a])),
HyundaiCarDocs("Hyundai Palisade (with HDA II) 2023-25", "Highway Driving Assist II", HyundaiCarDocs("Hyundai Palisade (with HDA II) 2023-24", "Highway Driving Assist II",
car_parts=CarParts.common([CarHarness.hyundai_r])), car_parts=CarParts.common([CarHarness.hyundai_r])),
HyundaiCarDocs("Kia Telluride (without HDA II) 2023-25", "Highway Driving Assist", HyundaiCarDocs("Kia Telluride (without HDA II) 2023-25", "Highway Driving Assist",
car_parts=CarParts.common([CarHarness.hyundai_l])), car_parts=CarParts.common([CarHarness.hyundai_l])),
@@ -527,8 +521,8 @@ class CAR(Platforms):
car_parts=CarParts.common([CarHarness.hyundai_q])) car_parts=CarParts.common([CarHarness.hyundai_q]))
], ],
HYUNDAI_IONIQ_5.specs, HYUNDAI_IONIQ_5.specs,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING | HyundaiFlags.CCNC, flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC, radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
) )
HYUNDAI_IONIQ_5_N = HyundaiCanFDPlatformConfig( HYUNDAI_IONIQ_5_N = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Ioniq 5 N (with HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_s]))], [HyundaiCarDocs("Hyundai Ioniq 5 N (with HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_s]))],
@@ -877,16 +871,6 @@ class CAR(Platforms):
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING, flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC, radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
) )
GENESIS_GV70_2026 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Genesis GV70 (3.5T Sport Prestige Trim, with HDA II & LFA2) 2026",
"Highway Driving Assist II & Lane Follow Assist 2",
car_parts=CarParts.common([CarHarness.hyundai_m])),
],
GENESIS_GV70_1ST_GEN.specs,
flags=HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
)
GENESIS_G80 = HyundaiPlatformConfig( GENESIS_G80 = HyundaiPlatformConfig(
[HyundaiCarDocs("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))], [HyundaiCarDocs("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))],
CarSpecs(mass=2060, wheelbase=3.01, steerRatio=16.5), CarSpecs(mass=2060, wheelbase=3.01, steerRatio=16.5),
@@ -945,11 +929,6 @@ class CAR(Platforms):
HYUNDAI_KONA_EV.specs, HYUNDAI_KONA_EV.specs,
flags=HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS, flags=HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS,
) )
KIA_RAY_EV = HyundaiNonSccPlatformConfig(
[HyundaiNonSccCarDocs("Kia Ray EV 2025", car_parts=CarParts.common([CarHarness.hyundai_h]))],
CarSpecs(mass=1295, wheelbase=2.52, steerRatio=14.5),
flags=HyundaiFlags.EV | HyundaiFlags.CHECKSUM_CRC8,
)
KIA_CEED_PHEV_2022_NON_SCC = HyundaiNonSccPlatformConfig( KIA_CEED_PHEV_2022_NON_SCC = HyundaiNonSccPlatformConfig(
[HyundaiNonSccCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_i]))], [HyundaiNonSccCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_i]))],
CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5), CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
@@ -988,27 +967,32 @@ CANCEL_BUTTON_ENABLE_CARS = frozenset({
CAR.HYUNDAI_PALISADE_2023, CAR.HYUNDAI_PALISADE_2023,
}) })
CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR = frozenset({
CAR.HYUNDAI_PALISADE_2023,
})
KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES = frozenset({ KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES = frozenset({
"C4DLC", "C4DLC",
}) })
KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID = "5"
ALT_BUS_LDA_BUTTON_CARS = frozenset() # These classic HKG platforms publish the LKAS button on CLU13 over the alt bus.
ALT_BUS_LDA_BUTTON_SWL_STAT_CARS = frozenset() # Keep G90 excluded until its alt-bus path is route-proven without the recent
# engage/disengage regression.
ALT_BUS_LDA_BUTTON_CARS = frozenset({
CAR.HYUNDAI_SONATA,
})
# On these Sonata layouts the alt-bus LKAS button pulses through the CLU13
# steering-wheel-status field instead of the dedicated LKAS bit.
ALT_BUS_LDA_BUTTON_SWL_STAT_CARS = frozenset({
CAR.HYUNDAI_SONATA,
})
def hyundai_cancel_button_enables_cruise(car_fingerprint) -> bool: def hyundai_cancel_button_enables_cruise(car_fingerprint) -> bool:
return car_fingerprint in CANCEL_BUTTON_ENABLE_CARS return car_fingerprint in CANCEL_BUTTON_ENABLE_CARS
def kia_ev6_gt_line_longitudinal_tuning(car_fingerprint, vin: str, testing_ground_active: bool = False) -> bool: def kia_ev6_gt_line_longitudinal_tuning(car_fingerprint, vin: str) -> bool:
vin_match = isinstance(vin, str) and len(vin) == 17 and vin[3:8] in KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES return car_fingerprint == CAR.KIA_EV6 and isinstance(vin, str) and \
return car_fingerprint == CAR.KIA_EV6 and (vin_match or testing_ground_active) len(vin) == 17 and vin[3:8] in KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES
def get_platform_codes(fw_versions: list[bytes]) -> set[tuple[bytes, bytes | None]]: def get_platform_codes(fw_versions: list[bytes]) -> set[tuple[bytes, bytes | None]]:
@@ -1100,7 +1084,7 @@ PART_NUMBER_FW_PATTERN = re.compile(b'(?<=[0-9][.,][0-9]{2} )([0-9]{5}[-/]?[A-Z]
# We've seen both ICE and hybrid for these platforms, and they have hybrid descriptors (e.g. MQ4 vs MQ4H) # We've seen both ICE and hybrid for these platforms, and they have hybrid descriptors (e.g. MQ4 vs MQ4H)
CANFD_FUZZY_WHITELIST = {CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KIA_K8_HEV_1ST_GEN, CANFD_FUZZY_WHITELIST = {CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KIA_K8_HEV_1ST_GEN,
CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN, CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN,
CAR.KIA_SORENTO_HEV_4TH_GEN_LFA2, CAR.GENESIS_GV70_2026} CAR.KIA_SORENTO_HEV_4TH_GEN_LFA2}
# List of ECUs expected to have platform codes, camera and radar should exist on all cars # List of ECUs expected to have platform codes, camera and radar should exist on all cars
# TODO: use abs, it has the platform code and part number on many platforms # TODO: use abs, it has the platform code and part number on many platforms
@@ -1199,14 +1183,13 @@ CANFD_RADAR_SCC_CAR = CAR.with_flags(HyundaiFlags.RADAR_SCC) # TODO: merge with
# CAN-FD cars with ADAS ECUs that work with the communication-control path. # CAN-FD cars with ADAS ECUs that work with the communication-control path.
CANFD_SECURITYACCESS_CAR = { CANFD_SECURITYACCESS_CAR = {
CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_5_PE, CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_KONA_EV_2ND_GEN, CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_KONA_EV_2ND_GEN, CAR.KIA_EV9,
} }
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) - CANFD_SECURITYACCESS_CAR # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) - CANFD_SECURITYACCESS_CAR # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
CANFD_ANGLE_LONGITUDINAL_CAR = {CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE} CANFD_ANGLE_LONGITUDINAL_CAR = {CAR.KIA_EV9}
CANFD_ALT_BUTTONS_RESUME_CAR = {CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN} CANFD_CORNER_RADAR_BSM_CAR = {CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9}
CANFD_CORNER_RADAR_BSM_CAR = {CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_IONIQ_5_PE, CAR.KIA_EV9}
CANFD_RADAR_LIVE_LONGITUDINAL_CAR = { CANFD_RADAR_LIVE_LONGITUDINAL_CAR = {
CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_5_PE, CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV6, CAR.KIA_EV9, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV6, CAR.KIA_EV9, CAR.GENESIS_GV60_EV_1ST_GEN,
} }
RADAR_LIVE_LONGITUDINAL_CAR = CANFD_RADAR_LIVE_LONGITUDINAL_CAR | { RADAR_LIVE_LONGITUDINAL_CAR = CANFD_RADAR_LIVE_LONGITUDINAL_CAR | {
CAR.HYUNDAI_IONIQ, CAR.HYUNDAI_IONIQ,
@@ -1234,9 +1217,6 @@ NON_SCC_CAR = CAR.with_flags(HyundaiFlags.NON_SCC)
# HyundaiFlags.CANFD_RADAR_SCC | HyundaiFlags.CANFD_NO_RADAR_DISABLE | ) # HyundaiFlags.CANFD_RADAR_SCC | HyundaiFlags.CANFD_NO_RADAR_DISABLE | )
UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.LEGACY) | CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL) UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.LEGACY) | CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL)
LEGACY_LONGITUDINAL_CAR = { LEGACY_LONGITUDINAL_CAR = {CAR.KIA_XCEED_PHEV}
CAR.GENESIS_G80,
CAR.KIA_XCEED_PHEV,
}
DBC = CAR.create_dbc_map() DBC = CAR.create_dbc_map()
+7 -25
View File
@@ -187,18 +187,12 @@ class CarInterfaceBase(ABC):
ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase)
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, ret.tireStiffnessFactor) ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, ret.tireStiffnessFactor)
force_torque_controller = bool(getattr(starpilot_toggles, "force_torque_controller", False)) toggles_to_check = ("force_torque_controller", "nnff", "nnff_lite")
toggles_to_check = ("nnff", "nnff_lite")
modified_civic_force_torque = ( modified_civic_force_torque = (
candidate == HONDA.HONDA_CIVIC_BOSCH and candidate == HONDA.HONDA_CIVIC_BOSCH and
bool(ret.flags & HondaFlags.EPS_MODIFIED) bool(ret.flags & HondaFlags.EPS_MODIFIED)
) )
# ForceTorqueController converts PID-based paths to torque control. It must
# not reinitialize cars that already selected torque control: those paths
# may have vehicle-specific torque tuning applied in their interface.
force_torque_conversion = force_torque_controller and ret.lateralTuning.which() != "torque"
if ret.steerControlType != structs.CarParams.SteerControlType.angle and ( if ret.steerControlType != structs.CarParams.SteerControlType.angle and (
force_torque_conversion or
any(getattr(starpilot_toggles, toggle, False) for toggle in toggles_to_check) or any(getattr(starpilot_toggles, toggle, False) for toggle in toggles_to_check) or
modified_civic_force_torque modified_civic_force_torque
): ):
@@ -241,14 +235,11 @@ class CarInterfaceBase(ABC):
fp_ret.flags |= HyundaiStarPilotFlags.SPEED_LIMIT_AVAILABLE.value fp_ret.flags |= HyundaiStarPilotFlags.SPEED_LIMIT_AVAILABLE.value
fp_ret.redneckCruiseAvailable = bool(CP.flags & HyundaiFlags.NON_SCC) and not bool(CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS) fp_ret.redneckCruiseAvailable = bool(CP.flags & HyundaiFlags.NON_SCC) and not bool(CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS)
if fp_ret.redneckCruiseAvailable and params.get_bool("RedneckCruise"): if fp_ret.redneckCruiseAvailable and params.get_bool("RedneckCruise") and \
not CP.openpilotLongitudinalControl:
fp_ret.pcmCruiseSpeed = False fp_ret.pcmCruiseSpeed = False
CP.openpilotLongitudinalControl = True
if candidate == HYUNDAI.HYUNDAI_ELANTRA_HEV_2024 and CP.openpilotLongitudinalControl: hyundai_has_lda_button = (
fp_ret.flags |= HyundaiStarPilotFlags.MAIN_CRUISE_STATE_TRACKING.value
hyundai_has_lda_button = not (CP.flags & HyundaiFlags.CANFD) and (
0x391 in fingerprint[0] or 0x391 in fingerprint[0] or
0x50C in fingerprint[0] or 0x50C in fingerprint[0] or
candidate in ALT_BUS_LDA_BUTTON_CARS or candidate in ALT_BUS_LDA_BUTTON_CARS or
@@ -260,22 +251,13 @@ class CarInterfaceBase(ABC):
if getattr(starpilot_toggles, "always_on_lateral_lkas", False): if getattr(starpilot_toggles, "always_on_lateral_lkas", False):
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
if candidate in (HYUNDAI.HYUNDAI_ELANTRA_HEV_2024, HYUNDAI.HYUNDAI_SONATA_HYBRID) and \ # LKASButtonControl == 9 means BUTTON_FUNCTIONS["AOL_TOGGLE"] in starpilot_variables.
getattr(starpilot_toggles, "always_on_lateral_main", False): if params.get_bool("AlwaysOnLateral") and params.get_int("LKASButtonControl") == 9:
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_MAIN_LKAS_ON_ENGAGE.value
if candidate == HYUNDAI.HYUNDAI_SONATA_HYBRID:
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
# The refresh Elantra's safety mapping comes from the resolved Galaxy
# toggle above, not from this legacy persisted-parameter fallback.
if candidate != HYUNDAI.HYUNDAI_ELANTRA_HEV_2024 and \
params.get_bool("AlwaysOnLateral") and params.get_int("LKASButtonControl") == 9:
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
if candidate == HYUNDAI.HYUNDAI_SONATA_HYBRID and getattr(starpilot_toggles, "always_on_lateral_lkas", False) and \ if candidate == HYUNDAI.HYUNDAI_SONATA_HYBRID and getattr(starpilot_toggles, "always_on_lateral_lkas", False) and \
getattr(starpilot_toggles, "main_cruise_aol_toggle", False): getattr(starpilot_toggles, "main_cruise_aol_toggle", False):
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_MAIN_LKAS_SYNC.value fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_MAIN_LKAS_SYNC.value
elif platform in TOYOTA: elif platform in TOYOTA:
fp_ret.canUsePedal = not CP.autoResumeSng fp_ret.canUsePedal = not CP.autoResumeSng
fp_ret.canUseSDSU = candidate not in UNSUPPORTED_DSU_CAR and candidate not in TSS2_CAR fp_ret.canUseSDSU = candidate not in UNSUPPORTED_DSU_CAR and candidate not in TSS2_CAR
@@ -286,7 +268,7 @@ class CarInterfaceBase(ABC):
if 0x2FF in fingerprint[0] or (0x2AA in fingerprint[0] and candidate in NO_DSU_CAR): if 0x2FF in fingerprint[0] or (0x2AA in fingerprint[0] and candidate in NO_DSU_CAR):
fp_ret.flags |= ToyotaStarPilotFlags.SMART_DSU.value fp_ret.flags |= ToyotaStarPilotFlags.SMART_DSU.value
if candidate in (TOYOTA.TOYOTA_PRIUS, TOYOTA.TOYOTA_PRIUS_RETROFIT): if candidate == TOYOTA.TOYOTA_PRIUS:
if 0x23 in fingerprint[0]: if 0x23 in fingerprint[0]:
fp_ret.flags |= ToyotaStarPilotFlags.ZSS.value fp_ret.flags |= ToyotaStarPilotFlags.ZSS.value
+1 -30
View File
@@ -1,7 +1,7 @@
import math import math
import numpy as np import numpy as np
from dataclasses import dataclass from dataclasses import dataclass
from opendbc.car import ACCELERATION_DUE_TO_GRAVITY, structs, rate_limit, DT_CTRL from opendbc.car import structs, rate_limit, DT_CTRL
from opendbc.car.vehicle_model import VehicleModel from opendbc.car.vehicle_model import VehicleModel
FRICTION_THRESHOLD = 0.3 FRICTION_THRESHOLD = 0.3
@@ -10,12 +10,6 @@ FRICTION_THRESHOLD = 0.3
ISO_LATERAL_ACCEL = 3.0 # m/s^2 ISO_LATERAL_ACCEL = 3.0 # m/s^2
ISO_LATERAL_JERK = 5.0 # m/s^3 ISO_LATERAL_JERK = 5.0 # m/s^3
# Common angle/curvature safety limits. The road-roll allowance keeps the
# controller and panda limits aligned on normally banked roads.
AVERAGE_ROAD_ROLL = 0.06
MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL)
MAX_LATERAL_JERK = 3.0 + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL)
@dataclass @dataclass
class AngleSteeringLimits: class AngleSteeringLimits:
@@ -30,29 +24,6 @@ class AngleSteeringLimits:
MAX_ANGLE_RATE: float = math.inf MAX_ANGLE_RATE: float = math.inf
@dataclass
class CurvatureSteeringLimits:
CURVATURE_MAX: float
MAX_LATERAL_ACCEL: float = MAX_LATERAL_ACCEL
MAX_LATERAL_JERK: float = MAX_LATERAL_JERK
def apply_limits(self, apply_curvature: float, apply_curvature_last: float, v_ego: float, curvature: float,
lat_active: bool, steer_step: int) -> float:
"""Apply lateral acceleration and jerk constraints to curvature."""
v_ego = max(v_ego, 1)
max_curvature = self.MAX_LATERAL_ACCEL / (v_ego ** 2)
new_apply_curvature = float(np.clip(apply_curvature, -max_curvature, max_curvature))
max_jerk = (self.MAX_LATERAL_JERK / (v_ego ** 2)) * (steer_step * DT_CTRL)
new_apply_curvature = float(np.clip(new_apply_curvature, apply_curvature_last - max_jerk, apply_curvature_last + max_jerk))
if not lat_active:
new_apply_curvature = curvature
return float(np.clip(new_apply_curvature, -self.CURVATURE_MAX, self.CURVATURE_MAX))
def apply_driver_steer_torque_limits(apply_torque: int, apply_torque_last: int, driver_torque: float, LIMITS, steer_max: int = None): def apply_driver_steer_torque_limits(apply_torque: int, apply_torque_last: int, driver_torque: float, LIMITS, steer_max: int = None):
# some safety modes utilize a dynamic max steer # some safety modes utilize a dynamic max steer
if steer_max is None: if steer_max is None:
@@ -9,7 +9,6 @@ from opendbc.car.nissan import nissancan
from opendbc.car.nissan.values import CAR, CarControllerParams from opendbc.car.nissan.values import CAR, CarControllerParams
VisualAlert = structs.CarControl.HUDControl.VisualAlert VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
class CarController(CarControllerBase): class CarController(CarControllerBase):
@@ -29,34 +28,6 @@ class CarController(CarControllerBase):
can_sends = [] can_sends = []
if self.CP.openpilotLongitudinalControl and self.car_fingerprint == CAR.NISSAN_LEAF:
accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
stopping = actuators.longControlState == LongCtrlState.stopping
brake_mode = CC.longActive and (accel < CarControllerParams.PROPILOT_ACCEL_MIN or stopping)
if CC.longActive:
if brake_mode:
raw_accel = CarControllerParams.PROPILOT_BRAKE_RAW
else:
propulsion_accel = float(np.clip(accel, CarControllerParams.PROPILOT_ACCEL_MIN,
CarControllerParams.PROPILOT_ACCEL_MAX))
raw_accel = round(propulsion_accel * CarControllerParams.PROPILOT_ACCEL_SCALE +
CarControllerParams.PROPILOT_ACCEL_OFFSET)
else:
raw_accel = CarControllerParams.PROPILOT_INACTIVE_RAW
brake_pressure = round(max(0.0, -accel - 1.0) * CarControllerParams.BRAKE_GAIN) if brake_mode else 0
if stopping and CS.out.vEgo < self.CP.vEgoStopping:
brake_pressure = CarControllerParams.BRAKE_MAX
brake_pressure = int(np.clip(brake_pressure, 0, CarControllerParams.BRAKE_MAX))
can_sends.append(nissancan.create_accel_command(raw_accel, self.frame, CC.longActive))
can_sends.append(nissancan.create_brake_command(brake_pressure, self.frame,
CC.longActive and brake_pressure > 0, brake_mode))
if self.frame % 100 == 0:
can_sends.append(nissancan.create_leaf_adas_tester_present())
### STEER ### ### STEER ###
steer_hud_alert = 1 if hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0 steer_hud_alert = 1 if hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0
@@ -93,8 +64,7 @@ class CarController(CarControllerBase):
# We now cancel by making propilot think the seatbelt is unlatched, # We now cancel by making propilot think the seatbelt is unlatched,
# this generates a beep and a warning message every time you disengage # this generates a beep and a warning message every time you disengage
if self.CP.carFingerprint in (CAR.NISSAN_LEAF, CAR.NISSAN_LEAF_IC) and self.frame % 2 == 0: if self.CP.carFingerprint in (CAR.NISSAN_LEAF, CAR.NISSAN_LEAF_IC) and self.frame % 2 == 0:
can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg, can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg, pcm_cancel_cmd))
pcm_cancel_cmd and not self.CP.openpilotLongitudinalControl))
can_sends.append(nissancan.create_steering_control( can_sends.append(nissancan.create_steering_control(
self.packer, self.apply_angle_last, self.frame, CC.latActive, lkas_max_torque)) self.packer, self.apply_angle_last, self.frame, CC.latActive, lkas_max_torque))
@@ -112,8 +82,6 @@ class CarController(CarControllerBase):
new_actuators = actuators.as_builder() new_actuators = actuators.as_builder()
new_actuators.steeringAngleDeg = self.apply_angle_last new_actuators.steeringAngleDeg = self.apply_angle_last
if self.CP.openpilotLongitudinalControl:
new_actuators.accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
self.frame += 1 self.frame += 1
return new_actuators, can_sends return new_actuators, can_sends
@@ -26,9 +26,6 @@ class CarState(CarStateBase):
self.distance_button = 0 self.distance_button = 0
self.lkas_button = 0 self.lkas_button = 0
self.set_button = 0
self.res_button = 0
self.cancel_button = 0
def update(self, can_parsers, starpilot_toggles) -> structs.CarState: def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
cp = can_parsers[Bus.pt] cp = can_parsers[Bus.pt]
@@ -134,17 +131,6 @@ class CarState(CarStateBase):
buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}) buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
if self.CP.openpilotLongitudinalControl and self.CP.carFingerprint == CAR.NISSAN_LEAF:
prev_set_button = self.set_button
prev_res_button = self.res_button
prev_cancel_button = self.cancel_button
self.set_button = int(cp.vl["CRUISE_THROTTLE"]["SET_BUTTON"])
self.res_button = int(cp.vl["CRUISE_THROTTLE"]["RES_BUTTON"])
self.cancel_button = int(cp.vl["CRUISE_THROTTLE"]["CANCEL_BUTTON"])
buttonEvents += create_button_events(self.set_button, prev_set_button, {1: ButtonType.decelCruise})
buttonEvents += create_button_events(self.res_button, prev_res_button, {1: ButtonType.accelCruise})
buttonEvents += create_button_events(self.cancel_button, prev_cancel_button, {1: ButtonType.cancel})
fp_ret = custom.StarPilotCarState.new_message() fp_ret = custom.StarPilotCarState.new_message()
self.prev_lkas_button = self.lkas_button self.prev_lkas_button = self.lkas_button
+1 -159
View File
@@ -1,124 +1,14 @@
import time
from opendbc.car import get_safety_config, structs from opendbc.car import get_safety_config, structs
from opendbc.car.disable_ecu import disable_ecu, ecu_log
from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.interfaces import CarInterfaceBase
from opendbc.car.isotp_parallel_query import IsoTpParallelQuery
from opendbc.car.nissan.carcontroller import CarController from opendbc.car.nissan.carcontroller import CarController
from opendbc.car.nissan.carstate import CarState from opendbc.car.nissan.carstate import CarState
from opendbc.car.nissan.values import CAR, CarControllerParams, NissanSafetyFlags, \ from opendbc.car.nissan.values import CAR, NissanSafetyFlags
NISSAN_DIAGNOSTIC_REQUEST_KWP, NISSAN_DIAGNOSTIC_RESPONSE_KWP, NISSAN_RX_OFFSET
LEAF_ADAS_ECU_ADDR = 0x707
LEAF_ADAS_ECU_BUS = 0
LEAF_ADAS_COMMAND_BUS = 1
LEAF_ADAS_COMMAND_ADDRS = frozenset((0x1C3, 0x2B0))
LEAF_2025_SV_PLUS_CAMERA_FW = b'6WK2CDB\x04\x18\x00\x00\x00\x00\x00R=1\x18\x99\x10\x00\x00\x00\x80'
LEAF_2025_SV_PLUS_ALPHA_LONG_ENABLED = False
LEAF_KWP_EXTENDED_REQUEST = b"\x10\xC0"
LEAF_KWP_EXTENDED_RESPONSE = b"\x50\xC0"
LEAF_KWP_DISABLE_NORMAL_TX_NO_RESPONSE = b"\x28\x02"
LEAF_KWP_TAKEOVER_SESSIONS = (
(LEAF_KWP_EXTENDED_REQUEST, LEAF_KWP_EXTENDED_RESPONSE),
)
def is_leaf_2025_sv_plus_longitudinal(candidate, car_fw):
return LEAF_2025_SV_PLUS_ALPHA_LONG_ENABLED and candidate == CAR.NISSAN_LEAF and any(
fw.address == LEAF_ADAS_ECU_ADDR and bytes(fw.fwVersion) == LEAF_2025_SV_PLUS_CAMERA_FW
for fw in car_fw
)
def leaf_adas_commands_silent(can_recv, settle_time=0.05, observe_time=0.15):
"""Confirm the stock ADAS command sender stopped while bus 1 is still observable."""
if can_recv is None:
return False
try:
# Let already-published CAN batches age out, then discard everything queued
# before the communication-control response.
time.sleep(settle_time)
can_recv()
saw_adas_bus_traffic = False
deadline = time.monotonic() + observe_time
while time.monotonic() < deadline:
packets = can_recv(wait_for_one=True)
for packet in packets:
for msg in packet:
if msg.src != LEAF_ADAS_COMMAND_BUS:
continue
saw_adas_bus_traffic = True
if msg.address in LEAF_ADAS_COMMAND_ADDRS:
ecu_log(f"Nissan Leaf ADAS TX still active: {hex(msg.address)} on bus {msg.src}")
return False
except Exception as e:
ecu_log(f"Nissan Leaf ADAS TX silence verification exception: {e}")
return False
if not saw_adas_bus_traffic:
ecu_log("Nissan Leaf ADAS TX silence could not be verified: no bus 1 traffic observed")
return saw_adas_bus_traffic
def leaf_adas_commands_present(can_recv, settle_time=0.05, observe_time=0.15):
"""Confirm the stock ADAS command sender resumed on bus 1."""
if can_recv is None:
return False
try:
time.sleep(settle_time)
can_recv()
deadline = time.monotonic() + observe_time
while time.monotonic() < deadline:
for packet in can_recv(wait_for_one=True):
if any(msg.src == LEAF_ADAS_COMMAND_BUS and msg.address in LEAF_ADAS_COMMAND_ADDRS for msg in packet):
return True
except Exception as e:
ecu_log(f"Nissan Leaf ADAS TX recovery verification exception: {e}")
return False
ecu_log("Nissan Leaf ADAS normal TX recovery could not be verified")
return False
def restore_leaf_adas_tx(can_recv, can_send):
"""Return to the confirmed KWP default session and verify normal TX resumes."""
if can_recv is None or can_send is None:
return False
try:
ecu_log("Nissan Leaf ADAS TX restore using KWP default session 1081")
query = IsoTpParallelQuery(
can_send, can_recv, LEAF_ADAS_ECU_BUS, [LEAF_ADAS_ECU_ADDR],
[NISSAN_DIAGNOSTIC_REQUEST_KWP], [NISSAN_DIAGNOSTIC_RESPONSE_KWP],
response_offset=NISSAN_RX_OFFSET,
)
if query.get_data(0.2) and leaf_adas_commands_present(can_recv):
ecu_log("Nissan Leaf ADAS normal TX restored and command traffic confirmed")
return True
except Exception as e:
ecu_log(f"Nissan Leaf ADAS TX restore exception: {e}")
ecu_log("Nissan Leaf ADAS normal TX restore was not confirmed")
return False
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
CarState = CarState CarState = CarState
CarController = CarController CarController = CarController
@staticmethod
def get_pid_accel_limits(CP, current_speed, cruise_speed):
if CP.carFingerprint == CAR.NISSAN_LEAF and CP.openpilotLongitudinalControl:
return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX
return CarInterfaceBase.get_pid_accel_limits(CP, current_speed, cruise_speed)
@staticmethod @staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "nissan" ret.brand = "nissan"
@@ -132,56 +22,8 @@ class CarInterface(CarInterfaceBase):
ret.steerControlType = structs.CarParams.SteerControlType.angle ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.radarUnavailable = True ret.radarUnavailable = True
ret.alphaLongitudinalAvailable = is_leaf_2025_sv_plus_longitudinal(candidate, car_fw)
ret.openpilotLongitudinalControl = alpha_long and ret.alphaLongitudinalAvailable
ret.pcmCruise = not ret.openpilotLongitudinalControl
if ret.openpilotLongitudinalControl:
ret.safetyConfigs[0].safetyParam |= NissanSafetyFlags.LONG_CONTROL.value
ret.autoResumeSng = True
ret.stopAccel = -2.0
ret.vEgoStopping = 0.5
ret.vEgoStarting = 0.5
ret.stoppingDecelRate = 0.8
if candidate == CAR.NISSAN_ALTIMA: if candidate == CAR.NISSAN_ALTIMA:
# Altima has EPS on C-CAN unlike the others that have it on V-CAN # Altima has EPS on C-CAN unlike the others that have it on V-CAN
ret.safetyConfigs[0].safetyParam |= NissanSafetyFlags.ALT_EPS_BUS.value ret.safetyConfigs[0].safetyParam |= NissanSafetyFlags.ALT_EPS_BUS.value
return ret return ret
@staticmethod
def init(CP, can_recv, can_send):
if not (CP.openpilotLongitudinalControl and CP.alphaLongitudinalAvailable and CP.carFingerprint == CAR.NISSAN_LEAF):
return
from openpilot.common.params import Params
params = Params()
ecu_disabled = False
for diag_request, diag_response in LEAF_KWP_TAKEOVER_SESSIONS:
ecu_log(f"Nissan Leaf ADAS takeover using KWP session {diag_request.hex()}")
ecu_disabled = disable_ecu(can_recv, can_send, bus=LEAF_ADAS_ECU_BUS, addr=LEAF_ADAS_ECU_ADDR,
com_cont_req=LEAF_KWP_DISABLE_NORMAL_TX_NO_RESPONSE, require_response=False, retry=1,
diag_request=diag_request, diag_response=diag_response, response_offset=NISSAN_RX_OFFSET)
if ecu_disabled:
break
takeover_confirmed = ecu_disabled and leaf_adas_commands_silent(can_recv)
params.put_bool("EcuDisableFailed", not takeover_confirmed)
if takeover_confirmed:
ecu_log("Nissan Leaf ADAS TX disable and command silence confirmed; experimental longitudinal control enabled")
else:
# A response can be lost after the ECU accepts 0x28. Always attempt to
# restore stock transmission before falling back to stock longitudinal.
restore_leaf_adas_tx(can_recv, can_send)
CP.safetyConfigs[-1].safetyParam &= ~NissanSafetyFlags.LONG_CONTROL.value
CP.openpilotLongitudinalControl = False
CP.pcmCruise = True
ecu_log("Nissan Leaf ADAS takeover was not confirmed; falling back to stock longitudinal control")
@staticmethod
def deinit(CP, can_recv, can_send):
if not (CP.openpilotLongitudinalControl and CP.alphaLongitudinalAvailable and CP.carFingerprint == CAR.NISSAN_LEAF):
return
restore_leaf_adas_tx(can_recv, can_send)
@@ -1,48 +1,10 @@
import crcmod import crcmod
from opendbc.car.can_definitions import CanData
from opendbc.car.nissan.values import CAR from opendbc.car.nissan.values import CAR
# TODO: add this checksum to the CANPacker # TODO: add this checksum to the CANPacker
nissan_checksum = crcmod.mkCrcFun(0x11d, initCrc=0x00, rev=False, xorOut=0xff) nissan_checksum = crcmod.mkCrcFun(0x11d, initCrc=0x00, rev=False, xorOut=0xff)
def create_leaf_adas_tester_present():
"""KWP2000 tester-present with a response requested, for the 2025 Leaf ADAS ECU."""
return CanData(0x707, b"\x02\x3E\x01\x00\x00\x00\x00\x00", 0)
def create_accel_command(raw_command, frame, active):
"""Build the Leaf ADAS propulsion/regen request (0x2B0)."""
raw_command = int(raw_command)
raw12, fraction = divmod(raw_command, 4)
inverse = (~raw12) & 0xFFF
dat = bytes([
((inverse & 0xF) << 4) | ((inverse >> 4) & 0xF),
(raw12 >> 4) & 0xFF,
(((inverse >> 8) & 0xF) << 4) | (raw12 & 0xF),
0xAC, # normal ADAS ownership state; stock briefly uses 0x6C while handing control back
0x5B if active else 0x1B,
0x00,
((frame & 0xF) << 4) | 0xE,
(fraction << 2) | ((~fraction) & 0x3),
])
return CanData(0x2B0, dat, 1)
def create_brake_command(pressure, frame, active, brake_mode):
"""Build the Leaf ADAS friction-brake request (0x1C3), with pressure in 0.5-count units."""
pressure = int(pressure)
dat = bytearray(8)
dat[0] = (pressure >> 4) & 0x3F
dat[1] = (pressure & 0xF) << 4
dat[4] = 0x64
dat[5] = (0x80 if active else 0) | (0x04 if brake_mode else 0) | (frame & 0x3)
dat[6] = 0xFF
dat[7] = (0x01 + 0xC3 + sum(dat[:7])) & 0xFF
return CanData(0x1C3, bytes(dat), 1)
def create_steering_control(packer, apply_torque, frame, steer_on, lkas_max_torque): def create_steering_control(packer, apply_torque, frame, steer_on, lkas_max_torque):
values = { values = {
"COUNTER": frame % 0x10, "COUNTER": frame % 0x10,
@@ -1 +0,0 @@
@@ -1,264 +0,0 @@
from types import SimpleNamespace
import pytest
from opendbc.car import Bus, ButtonType, gen_empty_fingerprint, structs
from opendbc.car.can_definitions import CanData
from opendbc.car.nissan import interface as nissan_interface
from opendbc.car.nissan.carstate import CarState
from opendbc.car.nissan.interface import CarInterface, LEAF_2025_SV_PLUS_CAMERA_FW, leaf_adas_commands_present, \
leaf_adas_commands_silent, restore_leaf_adas_tx
from opendbc.car.nissan.values import CAR, CarControllerParams, NissanSafetyFlags
TEST_TOGGLES = SimpleNamespace(force_torque_controller=False, nnff=False, nnff_lite=False, trailer_load_kg=0)
SUPPORTED_LEAF_FW = [structs.CarParams.CarFw(
ecu=structs.CarParams.Ecu.fwdCamera,
fwVersion=LEAF_2025_SV_PLUS_CAMERA_FW,
address=0x707,
)]
@pytest.fixture
def experimental_leaf_long(monkeypatch):
"""Exercise the dormant implementation without making it available in production."""
monkeypatch.setattr(nissan_interface, "LEAF_2025_SV_PLUS_ALPHA_LONG_ENABLED", True)
def run_controller(alpha_long, accel=0.0, long_active=True, long_state=structs.CarControl.Actuators.LongControlState.pid):
CP = CarInterface.get_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, alpha_long, False, False, TEST_TOGGLES)
FPCP = CarInterface.get_starpilot_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, CP, TEST_TOGGLES)
CI = CarInterface(CP, FPCP)
CI.update([], TEST_TOGGLES)
CC = structs.CarControl()
CC.enabled = True
CC.longActive = long_active
CC.actuators.accel = accel
CC.actuators.longControlState = long_state
_, can_sends = CI.apply(CC.as_reader(), 0, TEST_TOGGLES)
return {msg[0]: msg for msg in can_sends}
def test_leaf_2025_sv_plus_alpha_long_is_disabled(monkeypatch):
stock = CarInterface.get_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, False, False, False, None)
alpha_long = CarInterface.get_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, True, False, False, None)
assert not stock.alphaLongitudinalAvailable
assert not stock.openpilotLongitudinalControl
assert stock.pcmCruise
assert not (stock.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL)
assert not alpha_long.alphaLongitudinalAvailable
assert not alpha_long.openpilotLongitudinalControl
assert alpha_long.pcmCruise
assert not alpha_long.autoResumeSng
assert not (alpha_long.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL)
disable_calls = []
monkeypatch.setattr("opendbc.car.nissan.interface.disable_ecu", lambda *args, **kwargs: disable_calls.append((args, kwargs)))
CarInterface.init(alpha_long, None, None)
assert not disable_calls
def test_dormant_leaf_2025_sv_plus_alpha_long_params(experimental_leaf_long):
stock = CarInterface.get_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, False, False, False, None)
alpha_long = CarInterface.get_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, True, False, False, None)
assert stock.alphaLongitudinalAvailable
assert not stock.openpilotLongitudinalControl
assert stock.pcmCruise
assert not (stock.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL)
assert alpha_long.alphaLongitudinalAvailable
assert alpha_long.openpilotLongitudinalControl
assert not alpha_long.pcmCruise
assert alpha_long.autoResumeSng
assert alpha_long.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL
assert CarInterface.get_pid_accel_limits(alpha_long, 0, 0) == (CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
@pytest.mark.parametrize(("candidate", "car_fw"), [
(CAR.NISSAN_LEAF, []),
(CAR.NISSAN_LEAF, [structs.CarParams.CarFw(address=0x707, fwVersion=b"different firmware")]),
(CAR.NISSAN_LEAF_IC, SUPPORTED_LEAF_FW),
])
def test_other_leaf_variants_do_not_offer_alpha_long(candidate, car_fw):
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), car_fw, True, False, False, None)
assert not CP.alphaLongitudinalAvailable
assert not CP.openpilotLongitudinalControl
assert CP.pcmCruise
assert not (CP.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL)
def test_non_leaf_does_not_offer_alpha_long():
CP = CarInterface.get_params(CAR.NISSAN_ROGUE, gen_empty_fingerprint(), [], True, False, False, None)
assert not CP.alphaLongitudinalAvailable
assert not CP.openpilotLongitudinalControl
assert CP.pcmCruise
assert not (CP.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL)
def test_stock_controller_does_not_send_longitudinal_messages():
can_sends = run_controller(False)
assert not ({0x2B0, 0x1C3, 0x707} & can_sends.keys())
def test_disabled_alpha_long_controller_does_not_send_longitudinal_messages():
can_sends = run_controller(True)
assert not ({0x2B0, 0x1C3, 0x707} & can_sends.keys())
def test_alpha_long_controller_sends_stock_shaped_commands_and_keepalive(experimental_leaf_long):
can_sends = run_controller(True)
assert can_sends[0x2B0][1].hex() == "ff6090ac5b000e03"
assert can_sends[0x1C3][1].hex() == "000000006400ff27"
assert can_sends[0x707][1].hex() == "023e010000000000"
assert all(can_sends[addr][2] == 1 for addr in (0x2B0, 0x1C3))
assert can_sends[0x707][2] == 0
def test_alpha_long_controller_clamps_to_panda_accel_limit(experimental_leaf_long):
can_sends = run_controller(True, accel=5.0)
assert can_sends[0x2B0][1].hex() == "007f8fac5b000e0c"
def test_alpha_long_controller_blends_friction_brake_below_regen_limit(experimental_leaf_long):
can_sends = run_controller(True, accel=-2.0)
assert can_sends[0x2B0][1].hex() == "a827d5ac5b000e09"
brake = can_sends[0x1C3][1]
assert ((brake[0] & 0x3F) << 4) | (brake[1] >> 4) == 264
assert brake[5] & 0x84 == 0x84
def test_alpha_long_controller_sends_inactive_commands_when_disengaged(experimental_leaf_long):
can_sends = run_controller(True, accel=1.0, long_active=False)
assert can_sends[0x2B0][1].hex() == "dc53a2ac1b000e03"
assert can_sends[0x1C3][1].hex() == "000000006400ff27"
@pytest.mark.parametrize(("signal", "button_type"), [("SET_BUTTON", ButtonType.decelCruise),
("RES_BUTTON", ButtonType.accelCruise)])
def test_leaf_set_resume_release_enables_alpha_long(signal, button_type, experimental_leaf_long):
CP = CarInterface.get_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, True, False, False, TEST_TOGGLES)
FPCP = CarInterface.get_starpilot_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, CP, TEST_TOGGLES)
CS = CarState(CP, FPCP)
parsers = CS.get_can_parsers(CP)
parsers[Bus.pt].vl["CRUISE_THROTTLE"][signal] = 1
pressed, _ = CS.update(parsers, TEST_TOGGLES)
parsers[Bus.pt].vl["CRUISE_THROTTLE"][signal] = 0
released, _ = CS.update(parsers, TEST_TOGGLES)
assert any(event.type == button_type and event.pressed for event in pressed.buttonEvents)
assert any(event.type == button_type and not event.pressed for event in released.buttonEvents)
assert CS.update_button_enable(released.buttonEvents)
@pytest.mark.parametrize("ecu_disabled", [False, True])
def test_leaf_ecu_disable_is_strict_and_falls_back(monkeypatch, ecu_disabled, experimental_leaf_long):
CP = CarInterface.get_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, True, False, False, None)
calls = []
def fake_disable_ecu(*args, **kwargs):
calls.append(kwargs)
return ecu_disabled
monkeypatch.setattr("opendbc.car.nissan.interface.disable_ecu", fake_disable_ecu)
monkeypatch.setattr("opendbc.car.nissan.interface.leaf_adas_commands_silent", lambda *_: ecu_disabled)
monkeypatch.setattr("opendbc.car.nissan.interface.restore_leaf_adas_tx", lambda *_: True)
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
CarInterface.init(CP, None, None)
assert len(calls) == 1
assert calls[0]["addr"] == 0x707
assert calls[0]["bus"] == 0
assert calls[0]["response_offset"] == 0x20
assert calls[0]["require_response"] is False
assert calls[0]["diag_request"] == b"\x10\xc0"
assert calls[0]["diag_response"] == b"\x50\xc0"
assert calls[0]["com_cont_req"] == b"\x28\x02"
assert calls[0]["retry"] == 1
assert CP.openpilotLongitudinalControl is ecu_disabled
assert CP.pcmCruise is not ecu_disabled
assert bool(CP.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL) is ecu_disabled
def test_leaf_kwp_no_response_disable_can_confirm_ecu_silence(monkeypatch, experimental_leaf_long):
CP = CarInterface.get_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, True, False, False, None)
monkeypatch.setattr("opendbc.car.nissan.interface.disable_ecu", lambda *args, **kwargs: True)
monkeypatch.setattr("opendbc.car.nissan.interface.leaf_adas_commands_silent", lambda *_: True)
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
CarInterface.init(CP, None, None)
assert CP.openpilotLongitudinalControl
assert not CP.pcmCruise
assert CP.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL
def test_leaf_positive_disable_response_without_command_silence_falls_back(monkeypatch, experimental_leaf_long):
CP = CarInterface.get_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, True, False, False, None)
restore_calls = []
monkeypatch.setattr("opendbc.car.nissan.interface.disable_ecu", lambda *args, **kwargs: True)
monkeypatch.setattr("opendbc.car.nissan.interface.leaf_adas_commands_silent", lambda *_: False)
monkeypatch.setattr("opendbc.car.nissan.interface.restore_leaf_adas_tx", lambda *args: restore_calls.append(args) or True)
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
CarInterface.init(CP, None, None)
assert len(restore_calls) == 1
assert not CP.openpilotLongitudinalControl
assert CP.pcmCruise
assert not (CP.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL)
def test_leaf_adas_command_silence_requires_live_bus_without_stock_commands(monkeypatch):
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
def unrelated_bus_traffic(wait_for_one=False):
return [] if not wait_for_one else [[CanData(0x123, b"\x00", 1)]]
assert leaf_adas_commands_silent(unrelated_bus_traffic, settle_time=0, observe_time=0.001)
def stock_command_traffic(wait_for_one=False):
return [] if not wait_for_one else [[CanData(0x2B0, b"\x00" * 8, 1)]]
assert not leaf_adas_commands_silent(stock_command_traffic, settle_time=0, observe_time=0.001)
assert not leaf_adas_commands_silent(lambda wait_for_one=False: [], settle_time=0, observe_time=0.001)
def test_leaf_adas_command_recovery_requires_stock_command(monkeypatch):
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
def stock_command_traffic(wait_for_one=False):
return [] if not wait_for_one else [[CanData(0x1C3, b"\x00" * 8, 1)]]
assert leaf_adas_commands_present(stock_command_traffic, settle_time=0, observe_time=0.001)
assert not leaf_adas_commands_present(lambda wait_for_one=False: [], settle_time=0, observe_time=0.001)
def test_leaf_adas_restore_returns_to_kwp_default_session(monkeypatch):
queries = []
class FakeQuery:
def __init__(self, can_send, can_recv, bus, addrs, request, response, response_offset):
queries.append((bus, addrs, request, response, response_offset))
def get_data(self, timeout):
return {(0x707, None): b""}
monkeypatch.setattr("opendbc.car.nissan.interface.IsoTpParallelQuery", FakeQuery)
monkeypatch.setattr("opendbc.car.nissan.interface.leaf_adas_commands_present", lambda *_: True)
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
assert restore_leaf_adas_tx(lambda **kwargs: [], lambda msgs: None)
assert queries == [(0, [0x707], [b"\x10\x81"], [b"\x50\x81"], 0x20)]
@@ -1,38 +0,0 @@
import pytest
from opendbc.car.nissan import nissancan
@pytest.mark.parametrize(
("raw_command", "frame", "active", "expected"),
[
(5320, 0, False, "dc53a2ac1b000e03"),
(6144, 0, True, "ff6090ac5b000e03"),
(8191, 15, True, "007f8fac5b00fe0c"),
(4096, 0, True, "ff40b0ac5b000e03"),
(2518, 0, True, "a827d5ac5b000e09"),
],
)
def test_leaf_accel_command_vectors(raw_command, frame, active, expected):
addr, dat, bus = nissancan.create_accel_command(raw_command, frame, active)
assert addr == 0x2B0
assert bus == 1
assert dat.hex() == expected
@pytest.mark.parametrize(
("pressure", "frame", "active", "brake_mode", "expected"),
[
(0, 0, False, False, "000000006400ff27"),
(8, 3, True, False, "008000006483ff2a"),
(142, 2, True, True, "08e000006486ff95"),
],
)
def test_leaf_brake_command_vectors(pressure, frame, active, brake_mode, expected):
addr, dat, bus = nissancan.create_brake_command(pressure, frame, active, brake_mode)
assert addr == 0x1C3
assert bus == 1
assert dat.hex() == expected
assert dat[7] == (0x01 + 0xC3 + sum(dat[:7])) & 0xFF
+2 -17
View File
@@ -22,27 +22,12 @@ class CarControllerParams:
LKAS_MAX_TORQUE = 1 # A value of 1 is easy to overpower LKAS_MAX_TORQUE = 1 # A value of 1 is easy to overpower
STEER_THRESHOLD = 1.0 STEER_THRESHOLD = 1.0
# 2025 Leaf ProPILOT longitudinal command limits. The propulsion request has
# 2048 counts per m/s^2 around a 6144-count zero point. Friction braking is
# blended in below -1 m/s^2 using the stock pressure range seen in logs.
ACCEL_MIN = -3.5
ACCEL_MAX = 2047 / 2048
PROPILOT_ACCEL_MIN = -1.0
PROPILOT_ACCEL_MAX = ACCEL_MAX
PROPILOT_ACCEL_OFFSET = 6144
PROPILOT_ACCEL_SCALE = 2048
PROPILOT_INACTIVE_RAW = 5320
PROPILOT_BRAKE_RAW = 2518
BRAKE_MAX = 659 # 0.5 pressure-count units; stock peak is 329.5
BRAKE_GAIN = 264.0
def __init__(self, CP): def __init__(self, CP):
pass pass
class NissanSafetyFlags(IntFlag): class NissanSafetyFlags(IntFlag):
ALT_EPS_BUS = 1 ALT_EPS_BUS = 1
LONG_CONTROL = 2
class Footnote(Enum): class Footnote(Enum):
@@ -75,13 +60,13 @@ class CAR(Platforms):
NissanCarSpecs(mass=1610, wheelbase=2.705) NissanCarSpecs(mass=1610, wheelbase=2.705)
) )
NISSAN_LEAF = NissanPlatformConfig( NISSAN_LEAF = NissanPlatformConfig(
[NissanCarDocs("Nissan Leaf 2018-25", video="https://youtu.be/vaMbtAh_0cY")], [NissanCarDocs("Nissan Leaf 2018-23", video="https://youtu.be/vaMbtAh_0cY")],
NissanCarSpecs(mass=1610, wheelbase=2.705), NissanCarSpecs(mass=1610, wheelbase=2.705),
{Bus.pt: 'nissan_leaf_2018_generated'}, {Bus.pt: 'nissan_leaf_2018_generated'},
) )
# Leaf with ADAS ECU found behind instrument cluster instead of glovebox # Leaf with ADAS ECU found behind instrument cluster instead of glovebox
# Currently the only known difference between them is the inverted seatbelt signal. # Currently the only known difference between them is the inverted seatbelt signal.
NISSAN_LEAF_IC = NISSAN_LEAF.override(car_docs=[NissanCarDocs("Nissan Leaf Instrument Cluster 2018-25", video=NISSAN_LEAF.car_docs[0].video)]) NISSAN_LEAF_IC = NISSAN_LEAF.override(car_docs=[NissanCarDocs("Nissan Leaf Instrument Cluster 2018-23", video=NISSAN_LEAF.car_docs[0].video)])
NISSAN_ROGUE = NissanPlatformConfig( NISSAN_ROGUE = NissanPlatformConfig(
[NissanCarDocs("Nissan Rogue 2018-20")], [NissanCarDocs("Nissan Rogue 2018-20")],
NissanCarSpecs(mass=1610, wheelbase=2.705) NissanCarSpecs(mass=1610, wheelbase=2.705)
+13 -122
View File
@@ -1,28 +1,10 @@
import numpy as np import numpy as np
from opendbc.can import CANPacker from opendbc.can import CANPacker
from opendbc.car import Bus, structs from opendbc.car import Bus
from opendbc.car.lateral import apply_driver_steer_torque_limits from opendbc.car.lateral import apply_driver_steer_torque_limits
from opendbc.car.interfaces import CarControllerBase from opendbc.car.interfaces import CarControllerBase
from opendbc.car.rivian.ext_controller import HIGH_ANGLE_CAP_FRAC, HIGH_ANGLE_THRESHOLD_DEG, ExternalController from opendbc.car.rivian.riviancan import create_lka_steering, create_longitudinal, create_wheel_touch, create_adas_status
from opendbc.car.rivian.riviancan import (create_acm_status, create_adas_status, create_angle_steering, from opendbc.car.rivian.values import CarControllerParams
create_lka_steering, create_longitudinal, create_wheel_touch)
from opendbc.car.rivian.toi_controller import TOI_MAX_ANGLE_DEG, ToiController
from opendbc.car.rivian.values import CarControllerParams, RivianFlags
GearShifter = structs.CarState.GearShifter
LateralControlMode = structs.CarControl.Actuators.LateralControlMode
def get_longitudinal_accel(requested_accel: float, gas_pressed: bool, long_active: bool = False,
v_ego: float = 0.0) -> float:
# Keep Rivian's command stream continuous when Panda's gas safety check becomes active.
if gas_pressed:
return 0.0
accel = requested_accel
if long_active:
accel += float(np.interp(v_ego, CarControllerParams.ACCEL_FF_DRAG_BP, CarControllerParams.ACCEL_FF_DRAG_V))
return float(np.clip(accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
class CarController(CarControllerBase): class CarController(CarControllerBase):
@@ -32,104 +14,29 @@ class CarController(CarControllerBase):
self.packer = CANPacker(dbc_names[Bus.pt]) self.packer = CANPacker(dbc_names[Bus.pt])
self.cancel_frames = 0 self.cancel_frames = 0
self.toi_controller = ToiController()
self.angle_harness = bool(CP.flags & RivianFlags.ANGLE_HARNESS)
self.ext_controller = ExternalController(CP) if self.angle_harness else None
self.angle_saturation_last = None
self.angle_saturation_params = None
self.toi_recovery_failed_last = None
self.toi_recovery_params = None
try:
# Keep opendbc importable standalone while exposing controller-only state
# to selfdrived's existing car-specific warning bridge.
from openpilot.common.params import Params
status_params = Params(memory=True)
self.toi_recovery_params = status_params
if self.angle_harness:
self.angle_saturation_params = status_params
except Exception:
pass
def _publish_angle_saturation(self) -> None:
params = getattr(self, "angle_saturation_params", None)
if params is None:
return
saturated = bool(self.ext_controller.angle_saturated)
if saturated != getattr(self, "angle_saturation_last", None):
put_bool = getattr(params, "put_bool_nonblocking", None) or params.put_bool
put_bool("RivianAngleSaturated", saturated)
self.angle_saturation_last = saturated
def _publish_toi_recovery_failed(self) -> None:
params = getattr(self, "toi_recovery_params", None)
if params is None:
return
toi_controller = self.ext_controller.toi_controller if self.angle_harness else self.toi_controller
failed = bool(toi_controller.recovery_failed)
if failed != getattr(self, "toi_recovery_failed_last", None):
put_bool = getattr(params, "put_bool_nonblocking", None) or params.put_bool
put_bool("RivianToiRecoveryFailed", failed)
self.toi_recovery_failed_last = failed
def update_live_params(self, roll, angle_offset_deg, stiffness_factor, steer_ratio):
if self.ext_controller is not None:
self.ext_controller.roll = roll
self.ext_controller.angle_offset_deg = angle_offset_deg
self.ext_controller.VM.update_params(max(stiffness_factor, 0.1), max(steer_ratio, 0.1))
def update(self, CC, CS, now_nanos, starpilot_toggles): def update(self, CC, CS, now_nanos, starpilot_toggles):
actuators = CC.actuators actuators = CC.actuators
can_sends = [] can_sends = []
lat_active = CC.latActive and CS.out.gearShifter == GearShifter.drive
apply_torque = 0 apply_torque = 0
torque_request = False
steer_max = round(float(np.interp(CS.out.vEgoRaw, CarControllerParams.STEER_MAX_LOOKUP[0], steer_max = round(float(np.interp(CS.out.vEgoRaw, CarControllerParams.STEER_MAX_LOOKUP[0],
CarControllerParams.STEER_MAX_LOOKUP[1]))) CarControllerParams.STEER_MAX_LOOKUP[1])))
if self.angle_harness: if CC.latActive:
# The Panda permission is capability-gated at fingerprint time; this new_torque = int(round(CC.actuators.torque * steer_max))
# runtime setting only selects which already-safe channel is active. apply_torque = apply_driver_steer_torque_limits(new_torque, self.apply_torque_last,
self.ext_controller.force_torque = not bool(getattr(starpilot_toggles, "rivian_angle_control", False)) CS.out.steeringTorque, CarControllerParams, steer_max)
self.ext_controller.update(CS, lat_active, actuators)
self._publish_angle_saturation()
apply_torque = self.ext_controller.torque_cmd
torque_request = self.ext_controller.toi_act_cmd
else:
torque_request, torque_allowed = self.toi_controller.update(
lat_active,
abs(CS.out.steeringAngleDeg) >= TOI_MAX_ANGLE_DEG,
bool(getattr(CS, "toi_fault", False)),
bool(getattr(CS, "toi_active", False)),
bool(getattr(CS, "toi_unavailable", False)),
)
if lat_active and torque_allowed:
new_torque = int(round(CC.actuators.torque * steer_max))
apply_torque = apply_driver_steer_torque_limits(new_torque, self.apply_torque_last,
CS.out.steeringTorque, CarControllerParams, steer_max)
if abs(CS.out.steeringAngleDeg) > HIGH_ANGLE_THRESHOLD_DEG:
cap = int(round(steer_max * HIGH_ANGLE_CAP_FRAC))
apply_torque = int(np.clip(apply_torque, -cap, cap))
# send steering command
self.apply_torque_last = apply_torque self.apply_torque_last = apply_torque
self._publish_toi_recovery_failed() can_sends.append(create_lka_steering(self.packer, self.frame, CS.acm_lka_hba_cmd, apply_torque, CC.enabled, CC.latActive))
can_sends.append(create_lka_steering(self.packer, self.frame, CS.acm_lka_hba_cmd,
apply_torque, CC.enabled, torque_request))
if self.angle_harness: if self.frame % 5 == 0:
can_sends.append(create_angle_steering(self.packer, self.frame, self.ext_controller.apply_angle_last, can_sends.append(create_wheel_touch(self.packer, CS.sccm_wheel_touch, CC.enabled))
self.ext_controller.angle_active))
feature_status = (1 if self.ext_controller.torque_active else 2) if lat_active else 0
can_sends.append(create_acm_status(self.packer, self.frame, feature_status))
if self.frame % 5 == 0 and not (self.CP.flags & RivianFlags.GEN2):
can_sends.append(create_wheel_touch(self.packer, CS.sccm_wheel_touch, lat_active if self.angle_harness else CC.enabled))
# Longitudinal control # Longitudinal control
if self.CP.openpilotLongitudinalControl: if self.CP.openpilotLongitudinalControl:
accel = get_longitudinal_accel(actuators.accel, CS.out.gasPressed, CC.longActive, CS.out.vEgo) accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
can_sends.append(create_longitudinal(self.packer, self.frame, accel, CC.enabled)) can_sends.append(create_longitudinal(self.packer, self.frame, accel, CC.enabled))
else: else:
interface_status = None interface_status = None
@@ -141,27 +48,11 @@ class CarController(CarControllerBase):
else: else:
self.cancel_frames = 0 self.cancel_frames = 0
for msg in CS.vdm_adas_status: can_sends.append(create_adas_status(self.packer, CS.vdm_adas_status, interface_status))
can_sends.append(create_adas_status(self.packer, msg, interface_status))
new_actuators = actuators.as_builder() new_actuators = actuators.as_builder()
# Always report the actual applied torque. In angle mode this is zero, which
# deliberately freezes the torque PID integrator instead of letting it wind
# up and dump saturated torque into the first cooperative handoff.
new_actuators.torque = apply_torque / steer_max new_actuators.torque = apply_torque / steer_max
new_actuators.torqueOutputCan = apply_torque new_actuators.torqueOutputCan = apply_torque
lateral_mode = LateralControlMode.inactive
if self.angle_harness:
new_actuators.steeringAngleDeg = self.ext_controller.apply_angle_last
if lat_active and self.ext_controller.toi_controller.recovering:
lateral_mode = LateralControlMode.torqueRecovering
elif lat_active and (self.ext_controller.torque_active or self.ext_controller.torque_prearm):
lateral_mode = LateralControlMode.torque
elif lat_active and self.ext_controller.angle_active:
lateral_mode = LateralControlMode.angle
elif lat_active:
lateral_mode = LateralControlMode.torqueRecovering if self.toi_controller.recovering else LateralControlMode.torque
new_actuators.lateralControlMode = lateral_mode
self.frame += 1 self.frame += 1
return new_actuators, can_sends return new_actuators, can_sends
+19 -59
View File
@@ -3,36 +3,20 @@ from cereal import custom
from opendbc.can import CANParser from opendbc.can import CANParser
from opendbc.car import Bus, structs from opendbc.car import Bus, structs
from opendbc.car.interfaces import CarStateBase from opendbc.car.interfaces import CarStateBase
from opendbc.car.rivian.carstate_ext import RivianLongitudinalState from opendbc.car.rivian.values import DBC, GEAR_MAP
from opendbc.car.rivian.faults import TOI_FAULT_ALERT_FRAMES, get_steering_faults
from opendbc.car.rivian.values import DBC, GEAR_MAP, RivianFlags
from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.conversions import Conversions as CV
GearShifter = structs.CarState.GearShifter GearShifter = structs.CarState.GearShifter
def get_cruise_available(flags: int, acm_feature_status: int) -> bool:
# VDM reports unavailable until after stock ACC activates, so it cannot gate
# the PCM enable edge. The ACM reports standby before activation and ACC once active.
return bool(flags & RivianFlags.LONGITUDINAL_HARNESS) or acm_feature_status in (0, 1)
class CarState(CarStateBase): class CarState(CarStateBase):
def __init__(self, CP, FPCP): def __init__(self, CP, FPCP):
super().__init__(CP, FPCP) super().__init__(CP, FPCP)
self.last_speed = 30 self.last_speed = 30
self.longitudinal_state = RivianLongitudinalState(CP)
self.acm_lka_hba_cmd: dict | None = None self.acm_lka_hba_cmd = None
self.sccm_wheel_touch: dict | None = None self.sccm_wheel_touch = None
self.vdm_adas_status: list[dict] = [] self.vdm_adas_status = None
self.hands_on_level = 0
self.eac_status = 0
self.eac_error_code = 0
self.toi_fault = False
self.toi_active = False
self.toi_unavailable = False
self.toi_fault_frames = 0
def update(self, can_parsers, starpilot_toggles) -> structs.CarState: def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
cp = can_parsers[Bus.pt] cp = can_parsers[Bus.pt]
@@ -60,30 +44,17 @@ class CarState(CarStateBase):
ret.steeringTorque = cp.vl["EPAS_SystemStatus"]["EPAS_TorsionBarTorque"] ret.steeringTorque = cp.vl["EPAS_SystemStatus"]["EPAS_TorsionBarTorque"]
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > 1.0, 5) ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > 1.0, 5)
self.eac_error_code = int(cp.vl["EPAS_AdasStatus"]["EPAS_EacErrorCode"]) ret.steerFaultTemporary = cp.vl["EPAS_AdasStatus"]["EPAS_EacErrorCode"] != 0
self.eac_status = int(cp.vl["EPAS_AdasStatus"]["EPAS_EacStatus"])
self.hands_on_level = int(cp.vl["EPAS_SystemStatus"]["EPAS_HandsOnLevel"])
self.toi_fault = cp.vl["EPAS_SystemStatus"]["H_CAN_EPSS_ToiFlt"] != 0
self.toi_active = cp.vl["EPAS_SystemStatus"]["H_CAN_EPSS_ToiActive"] != 0
self.toi_unavailable = cp.vl["EPAS_SystemStatus"]["H_CAN_EPS_ToiUnavailable"] != 0
toi_fault = self.toi_fault or self.toi_unavailable
self.toi_fault_frames = self.toi_fault_frames + 1 if toi_fault else 0
toi_fault_persistent = self.toi_fault_frames >= TOI_FAULT_ALERT_FRAMES
ret.steerFaultPermanent, ret.steerFaultTemporary, ret.steeringDisengage = get_steering_faults(
bool(self.CP.flags & RivianFlags.ANGLE_HARNESS), toi_fault, toi_fault_persistent,
self.eac_status, self.eac_error_code,
)
# Cruise state # Cruise state
speed = min(int(cp_adas.vl["ACM_tsrCmd"]["ACM_tsrSpdDisClsMain"]), 85) speed = min(int(cp_adas.vl["ACM_tsrCmd"]["ACM_tsrSpdDisClsMain"]), 85)
self.last_speed = speed if speed != 0 else self.last_speed self.last_speed = speed if speed != 0 else self.last_speed
acm_feature_status = int(cp_cam.vl["ACM_Status"]["ACM_FeatureStatus"]) ret.cruiseState.enabled = cp_cam.vl["ACM_Status"]["ACM_FeatureStatus"] == 1
ret.cruiseState.enabled = acm_feature_status == 1
# TODO: find cruise set speed on CAN # TODO: find cruise set speed on CAN
ret.cruiseState.speed = self.last_speed * CV.MPH_TO_MS # detected speed limit ret.cruiseState.speed = self.last_speed * CV.MPH_TO_MS # detected speed limit
if not self.CP.openpilotLongitudinalControl: if not self.CP.openpilotLongitudinalControl:
ret.cruiseState.speed = -1 ret.cruiseState.speed = -1
ret.cruiseState.available = get_cruise_available(self.CP.flags, acm_feature_status) ret.cruiseState.available = cp.vl["VDM_AdasSts"]["VDM_AdasInterfaceStatus"] in (1, 2)
ret.cruiseState.standstill = cp.vl["VDM_AdasSts"]["VDM_AdasVehicleHoldStatus"] == 1 ret.cruiseState.standstill = cp.vl["VDM_AdasSts"]["VDM_AdasVehicleHoldStatus"] == 1
# ACM_Status->ACM_FaultSupervisorState normally 1, appears to go to 3 when either: # ACM_Status->ACM_FaultSupervisorState normally 1, appears to go to 3 when either:
@@ -100,47 +71,36 @@ class CarState(CarStateBase):
# Gear # Gear
ret.gearShifter = GEAR_MAP.get(int(cp.vl["VDM_PropStatus"]["VDM_Prndl_Status"]), GearShifter.unknown) ret.gearShifter = GEAR_MAP.get(int(cp.vl["VDM_PropStatus"]["VDM_Prndl_Status"]), GearShifter.unknown)
# Gen 2 does not publish these signals. Stock ACC handles their disengage # Doors
# behavior at standstill, and the doors cannot be opened while driving. ret.doorOpen = any(cp_adas.vl["IndicatorLights"][door] != 2 for door in ("RearDriverDoor", "FrontPassengerDoor", "DriverDoor", "RearPassengerDoor"))
if not (self.CP.flags & RivianFlags.GEN2):
ret.doorOpen = any(cp_adas.vl["IndicatorLights"][door] != 2 for door in ("RearDriverDoor", "FrontPassengerDoor", "DriverDoor", "RearPassengerDoor"))
ret.seatbeltUnlatched = cp.vl["RCM_Status"]["RCM_Status_IND_WARN_BELT_DRIVER"] != 0
# Blinkers # Blinkers
ret.leftBlinker = cp_adas.vl["IndicatorLights"]["TurnLightLeft"] in (1, 2) ret.leftBlinker = cp_adas.vl["IndicatorLights"]["TurnLightLeft"] in (1, 2)
ret.rightBlinker = cp_adas.vl["IndicatorLights"]["TurnLightRight"] in (1, 2) ret.rightBlinker = cp_adas.vl["IndicatorLights"]["TurnLightRight"] in (1, 2)
# Seatbelt
ret.seatbeltUnlatched = cp.vl["RCM_Status"]["RCM_Status_IND_WARN_BELT_DRIVER"] != 0
# Blindspot
# ret.leftBlindspot = False
# ret.rightBlindspot = False
# AEB # AEB
ret.stockAeb = cp_cam.vl["ACM_AebRequest"]["ACM_EnableRequest"] != 0 ret.stockAeb = cp_cam.vl["ACM_AebRequest"]["ACM_EnableRequest"] != 0
# Messages needed by carcontroller # Messages needed by carcontroller
self.acm_lka_hba_cmd = copy.copy(cp_cam.vl["ACM_lkaHbaCmd"]) self.acm_lka_hba_cmd = copy.copy(cp_cam.vl["ACM_lkaHbaCmd"])
if not (self.CP.flags & RivianFlags.GEN2): self.sccm_wheel_touch = copy.copy(cp.vl["SCCM_WheelTouch"])
self.sccm_wheel_touch = copy.copy(cp.vl["SCCM_WheelTouch"]) self.vdm_adas_status = copy.copy(cp.vl["VDM_AdasSts"])
# This message can lag and deliver two samples in one parser cycle. Forward
# every sample so cancelling stock ACC remains reliable.
adas_status_msgs = cp.vl_all["VDM_AdasSts"]
self.vdm_adas_status = [dict(zip(adas_status_msgs, vals, strict=True))
for vals in zip(*adas_status_msgs.values(), strict=True)]
if not self.vdm_adas_status:
self.vdm_adas_status = [copy.copy(cp.vl["VDM_AdasSts"])]
self.longitudinal_state.update(ret, can_parsers)
fp_ret = custom.StarPilotCarState.new_message() fp_ret = custom.StarPilotCarState.new_message()
return ret, fp_ret return ret, fp_ret
def set_cruise_speed(self, speed: float) -> float:
return self.longitudinal_state.set_cruise_speed(speed)
@staticmethod @staticmethod
def get_can_parsers(CP): def get_can_parsers(CP):
parsers = { return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0), Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0),
Bus.adas: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 1), Bus.adas: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 1),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2), Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2),
} }
if CP.flags & RivianFlags.LONGITUDINAL_HARNESS:
parsers[Bus.alt] = CANParser(DBC[CP.carFingerprint][Bus.alt], [], 1)
return parsers
@@ -1,104 +0,0 @@
"""Rivian Extreme-harness state support."""
import math
from opendbc.car import Bus, structs
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.rivian.values import RivianFlags
ButtonType = structs.CarState.ButtonEvent.Type
MAX_SET_SPEED = 85 * CV.MPH_TO_MS
MIN_SET_SPEED = 20 * CV.MPH_TO_MS
class RivianLongitudinalState:
"""State provided by the Extreme harness park-assist CAN bridge."""
def __init__(self, CP):
self.CP = CP
self.set_speed = 10
self.increase_button = False
self.decrease_button = False
self.distance_button = 0
self.scroll_click_pressed = False
self.increase_counter = 0
self.decrease_counter = 0
self.stalk_down_counter = 0
def set_cruise_speed(self, speed: float) -> float:
if self.CP.openpilotLongitudinalControl:
self.set_speed = max(MIN_SET_SPEED, min(float(speed), MAX_SET_SPEED))
return self.set_speed
def update_longitudinal_upgrade(self, ret: structs.CarState, can_parsers) -> list:
cp_park = can_parsers[Bus.alt]
cp_adas = can_parsers[Bus.adas]
cp = can_parsers[Bus.pt]
button_events = []
prev_increase_button = self.increase_button
prev_decrease_button = self.decrease_button
prev_scroll_click_pressed = self.scroll_click_pressed
if self.CP.openpilotLongitudinalControl:
right_scroll = int(cp_park.vl["WheelButtons_Fwd"]["RightButton_Scroll"])
if right_scroll != 255:
if self.distance_button != right_scroll:
# Rivian's rotary value changes once per detent. A release-only gap
# event preserves the existing three-profile personality cycling.
button_events.append(structs.CarState.ButtonEvent(pressed=False, type=ButtonType.gapAdjustCruise))
self.distance_button = right_scroll
# Scroll-click is a separate two-bit signal from rotary movement. Treat
# it as a held distance button so the existing short/long/very-long
# mappings apply, including Traffic Mode on a very-long hold.
self.scroll_click_pressed = cp_park.vl["WheelButtons_Fwd"]["RightButton_ScrollClick"] == 2
if self.scroll_click_pressed != prev_scroll_click_pressed:
button_events.append(structs.CarState.ButtonEvent(pressed=self.scroll_click_pressed, type=ButtonType.gapAdjustCruise))
self.increase_button = cp_park.vl["WheelButtons_Fwd"]["RightButton_RightClick"] == 2
self.decrease_button = cp_park.vl["WheelButtons_Fwd"]["RightButton_LeftClick"] == 2
self.increase_counter = self.increase_counter + 1 if self.increase_button else 0
self.decrease_counter = self.decrease_counter + 1 if self.decrease_button else 0
metric = cp_adas.vl["Cluster"]["Cluster_Unit"] == 0
conversion = CV.KPH_TO_MS if metric else CV.MPH_TO_MS
long_press_step = 10.0 if metric else 5.0
set_speed_display = self.set_speed * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)
if self.increase_button:
if self.increase_counter % 66 == 0:
self.set_speed = math.ceil((set_speed_display + 1) / long_press_step) * long_press_step * conversion
elif not prev_increase_button:
self.set_speed += conversion
if self.decrease_button:
if self.decrease_counter % 66 == 0:
self.set_speed = math.floor((set_speed_display - 1) / long_press_step) * long_press_step * conversion
elif not prev_decrease_button:
self.set_speed -= conversion
if not ret.cruiseState.enabled:
self.set_speed = ret.vEgoCluster
stalk_down = int(cp.vl["VDM_AdasSts"]["VDM_UserAdasRequest"]) in (3, 4)
self.stalk_down_counter = self.stalk_down_counter + 1 if stalk_down else 0
if self.stalk_down_counter == 50:
self.set_speed = max(self.set_speed, ret.vEgoCluster)
self.set_speed = max(MIN_SET_SPEED, min(self.set_speed, MAX_SET_SPEED))
ret.cruiseState.speed = self.set_speed
ret.leftBlindspot = cp_park.vl["BSM_BlindSpotIndicator_Fwd"]["BSM_BlindSpotIndicator_Left"] != 0
ret.rightBlindspot = cp_park.vl["BSM_BlindSpotIndicator_Fwd"]["BSM_BlindSpotIndicator_Right"] != 0
return button_events
def update(self, ret: structs.CarState, can_parsers) -> None:
button_events = []
if self.CP.flags & RivianFlags.LONGITUDINAL_HARNESS:
button_events.extend(self.update_longitudinal_upgrade(ret, can_parsers))
ret.buttonEvents = button_events
@@ -1,432 +0,0 @@
"""Rivian Gen 1 hybrid steering for the Extreme harness."""
import math
from collections import deque
import numpy as np
from opendbc.car import rate_limit
from opendbc.car.common.filter_simple import FirstOrderFilter
from opendbc.car.lateral import apply_driver_steer_torque_limits, get_max_angle_delta_vm, get_max_angle_vm
from opendbc.car.rivian.toi_controller import TOI_MAX_ANGLE_DEG, TOI_REARM_ANGLE_DEG, ToiController
from opendbc.car.rivian.values import CAR, CarControllerParams as CCP, RivianFlags
from opendbc.car.vehicle_model import VehicleModel
# Limits observed in the Gen 1 EPAS firmware. Margins keep commands inside the
# firmware's absolute-angle and sliding-window rate checks.
EPAS_FW_MAX_ANGLE_BP = [0.0, 2.78, 5.56, 8.33, 12.50, 16.67, 22.22, 27.78]
EPAS_FW_MAX_ANGLE_V = [500, 500, 250, 150, 85, 56, 40, 25]
EPAS_FW_RATE_BP = [5.56, 8.33, 12.50, 16.67]
EPAS_FW_RATE_V = [4.50, 1.50, 0.60, 0.18]
EPAS_FW_ANGLE_MARGIN = 0.98
EPAS_FW_RATE_MARGIN = 0.94
PANDA_STEP_MARGIN = 0.9
MIN_TORQUE_FRAMES = 50
HANDOFF_EXIT_DEG = 15.0
UNWIND_HANDOFF_RATE = 40.0
HANDOFF_MAX_ANGLE_DEG = 25.0
DRIVER_HANDS_OFF_EXIT_FRAMES = 100
EAC_RECOVER_FRAMES = 15
EAC_REARM_RELEASE_FRAMES = 25
# The wheel's inertia loads the torsion bar while the column is swinging. Reject
# those transients so they cannot be mistaken for a driver override.
TORSION_RATE_WINDOW = 25
TORSION_MAX_RATE_SWING = 90.0
DRIVER_OVERRIDE_TORQUE = 6.0
DRIVER_OVERRIDE_FRAMES = 5
# Sustained light torsion bridges capacitive-sensor dropouts while the driver's
# hands slide on the wheel. This only delays recovery from a driver override.
PRESENCE_LPF_RC = 0.032
PRESENCE_TORQUE_THRESHOLD = 1.5
PRESENCE_MIN_FRAMES = 30
PRESENCE_HOLD_FRAMES = 100
# Above this angle the rack spends most of its time saturated. Keeping a small
# amount of headroom helps the torque controller recover as geometry unwinds.
HIGH_ANGLE_THRESHOLD_DEG = 90
HIGH_ANGLE_CAP_FRAC = 0.95
# A live angle->torque selection cannot release the EPAS angle servo before the
# rate-limited torque channel is ready to carry the curve. Ramp torque under the
# still-active angle command, then release angle once sufficient hold torque is
# available. These values come from AdventurePilot's road-tested handoff.
TORQUE_PREARM_EXIT_FRAC = 0.85
TORQUE_PREARM_MIN_HOLD = 20
TORQUE_PREARM_MAX_FRAMES = 150
TORQUE_PREARM_STALL_FRAMES = 12
TORQUE_PREARM_ABORT_LOCKOUT = 50
# The torque controller is deliberately frozen while angle steering is active,
# so angle saturation needs its own debounced envelope check for the stock
# "turn exceeds steering limit" warning.
ANGLE_SAT_MIN_LAT_ACCEL = 1.0
ANGLE_SAT_FRAMES = 30
def apply_rivian_steer_angle_limits_vm(apply_angle: float, apply_angle_last: float, v_ego_raw: float, steering_angle: float,
lat_active: bool, limits, VM: VehicleModel) -> float:
"""Apply Rivian's jerk, accel, and safety constraints to its angle channel."""
v_ego_raw = max(v_ego_raw, 1)
# When the speed-scheduled angle envelope shrinks, Rivian must unwind toward
# it through the jerk limit instead of snapping directly to the new bound.
max_angle = get_max_angle_vm(v_ego_raw, VM, limits)
new_apply_angle = np.clip(apply_angle, -max_angle, max_angle)
max_angle_delta = get_max_angle_delta_vm(v_ego_raw, VM, limits)
max_angle_delta = min(max_angle_delta, limits.ANGLE_LIMITS.MAX_ANGLE_RATE)
new_apply_angle = rate_limit(new_apply_angle, apply_angle_last, -max_angle_delta, max_angle_delta)
if not lat_active:
new_apply_angle = steering_angle
return float(np.clip(new_apply_angle, -limits.ANGLE_LIMITS.STEER_ANGLE_MAX, limits.ANGLE_LIMITS.STEER_ANGLE_MAX))
class _RateBudget:
WINDOW_USER_FRAMES = 16
WINDOW_TIME_S = 0.16
def __init__(self):
self.history = deque([0.0] * self.WINDOW_USER_FRAMES, maxlen=self.WINDOW_USER_FRAMES)
def push(self, sent_angle: float) -> None:
self.history.append(round(sent_angle * 10) / 10)
def bounds(self, threshold_dps: float, margin: float) -> tuple[float, float]:
cmd_oldest = self.history[0]
budget = threshold_dps * self.WINDOW_TIME_S * margin
return cmd_oldest - budget, cmd_oldest + budget
def get_safety_CP():
from opendbc.car.rivian.interface import CarInterface
return CarInterface.get_non_essential_params(CAR.RIVIAN_R1_GEN1)
class ExternalController:
"""Hybrid Gen 1 steering: EPAS angle control with cooperative torque fallback."""
def __init__(self, CP):
self.VM = VehicleModel(CP)
self.VM_safety = VehicleModel(get_safety_CP())
self.gen2 = bool(CP.flags & RivianFlags.GEN2)
self.wheel_touch_cnt = 0
self.torsion_cnt = 0
self.torsion_sign = 0
self.driver_override_cnt = 0
self.rate_hist = deque([0.0] * TORSION_RATE_WINDOW, maxlen=TORSION_RATE_WINDOW)
self.hands_on = False
self.torsion_lpf = FirstOrderFilter(0.0, PRESENCE_LPF_RC, 0.01)
self.presence_cnt = 0
self.presence_sign = 0
self.presence_hold = 0
self.hands_off_frames = 0
self.torque_active = False
self.torque_active_frames = 0
# Handback protections depend on why torque mode was entered. Driver
# recovery gets the release timer; both driver and Galaxy recovery get the
# low-angle gate.
self.driver_override_recovery = False
self.galaxy_torque_recovery = False
self.lat_active_last = False
self.eac_dead_frames = 0
self.eac_rearm_release_frames = 0
self.eac_rearm_attempted = False
# Galaxy can switch an angle-capable truck to torque while driving. The
# prearm state makes that transition make-before-break.
self.force_torque = False
self.torque_prearm = False
self.prearm_frames = 0
self.prearm_torque_peak = 0
self.prearm_stall_frames = 0
self.prearm_abort_lockout = 0
self.prearm_last_outcome = ""
self.prearm_last_hold = 0
self.prearm_last_frames = 0
self.prearm_last_peak = 0
self.apply_angle_last = 0.0
self.angle_active = False
self.angle_saturated = False
self.angle_sat_frames = 0
self.rate_budget = _RateBudget()
self.roll = 0.0
self.angle_offset_deg = 0.0
self.apply_torque_last = 0
self.torque_cmd = 0
self.toi_controller = ToiController()
self.toi_act_cmd = False
def update(self, CS, lat_active: bool, actuators) -> None:
self._update_hands_on(CS)
desired_angle = math.degrees(self.VM.get_steer_from_curvature(
-float(actuators.curvature), CS.out.vEgo, self.roll)) + self.angle_offset_deg
self._update_torque_active(CS, lat_active, desired_angle, actuators)
desired_lat_accel = float(actuators.curvature) * CS.out.vEgo ** 2
self._update_angle(CS, lat_active, desired_angle, desired_lat_accel)
self._update_torque(CS, actuators)
def _update_wheel_touched(self, wheel_touched: bool, minimum_count: int) -> bool:
self.wheel_touch_cnt += 1 if wheel_touched else -1
self.wheel_touch_cnt = int(np.clip(self.wheel_touch_cnt, 0, minimum_count * 2 + 1))
return self.wheel_touch_cnt > minimum_count
def _update_torsion(self, torque: float, steering_rate: float, threshold: float, minimum_count: int) -> bool:
self.rate_hist.append(steering_rate)
if max(self.rate_hist) - min(self.rate_hist) > TORSION_MAX_RATE_SWING:
self.torsion_cnt = 0
return False
abs_torque = abs(torque)
pressed = abs_torque > threshold
sign = int(np.sign(torque))
if pressed and self.torsion_sign and sign != self.torsion_sign:
self.torsion_cnt = 0
else:
self.torsion_cnt += max(1, math.ceil(abs_torque / threshold)) if pressed else -1
self.torsion_cnt = int(np.clip(self.torsion_cnt, 0, minimum_count * 2 + 1))
if pressed:
self.torsion_sign = sign
return self.torsion_cnt > minimum_count
def _update_torsion_presence(self, torque: float) -> bool:
filtered = self.torsion_lpf.update(torque)
sign = 1 if filtered > PRESENCE_TORQUE_THRESHOLD else -1 if filtered < -PRESENCE_TORQUE_THRESHOLD else 0
self.presence_cnt = self.presence_cnt + 1 if sign != 0 and sign == self.presence_sign else int(sign != 0)
self.presence_sign = sign
if self.presence_cnt >= PRESENCE_MIN_FRAMES:
self.presence_hold = PRESENCE_HOLD_FRAMES
elif self.presence_hold > 0:
self.presence_hold -= 1
return self.presence_hold > 0
def _update_hands_on(self, CS) -> None:
wheel_touch = False
if not self.gen2:
calibration = CS.sccm_wheel_touch["SETME_X52"]
capacitive = CS.sccm_wheel_touch["SCCM_WheelTouch_CapacitiveValue"] > calibration * 0.9
wheel_touch = self._update_wheel_touched(capacitive, 25)
torsion = self._update_torsion(CS.out.steeringTorque, CS.out.steeringRateDeg, 4.0, 9)
# Keep rejecting ordinary inertial torsion, but do not mask a sustained,
# high-effort driver override just because the wheel is already moving fast.
strong_override = abs(CS.out.steeringTorque) >= DRIVER_OVERRIDE_TORQUE and CS.out.steeringPressed
self.driver_override_cnt += 1 if strong_override else -1
self.driver_override_cnt = int(np.clip(self.driver_override_cnt, 0, DRIVER_OVERRIDE_FRAMES))
presence = self._update_torsion_presence(CS.out.steeringTorque)
self.hands_on = wheel_touch or torsion or self.driver_override_cnt >= DRIVER_OVERRIDE_FRAMES or CS.hands_on_level > 1
self.hands_off_frames = 0 if self.hands_on or presence else self.hands_off_frames + 1
def _reset_prearm(self) -> None:
self.torque_prearm = False
self.prearm_frames = 0
self.prearm_torque_peak = 0
self.prearm_stall_frames = 0
def _end_prearm(self, outcome: str, hold_target: int) -> None:
self.prearm_last_outcome = outcome
self.prearm_last_hold = hold_target
self.prearm_last_frames = self.prearm_frames
self.prearm_last_peak = self.prearm_torque_peak
self._reset_prearm()
def _update_torque_active(self, CS, lat_active: bool, desired_angle: float, actuators) -> None:
self.torque_active_frames = self.torque_active_frames + 1 if self.torque_active else 0
epas_ready = CS.eac_status == 1 and CS.eac_error_code == 0
eac_active = CS.eac_status == 2
epas_inhibited = CS.eac_status == 0 and CS.eac_error_code == 0
gap = abs(desired_angle - CS.out.steeringAngleDeg)
if not lat_active:
self.torque_active = False
self.driver_override_recovery = False
self.galaxy_torque_recovery = False
self.eac_dead_frames = 0
self.eac_rearm_release_frames = 0
self.eac_rearm_attempted = False
self.prearm_abort_lockout = 0
self._reset_prearm()
self.lat_active_last = False
return
if self.force_torque:
# A stale angle-recovery count must not trigger after switching modes.
self.eac_dead_frames = 0
self.eac_rearm_release_frames = 0
self.eac_rearm_attempted = False
self.driver_override_recovery = False
self.lat_active_last = True
if self.torque_active:
self.galaxy_torque_recovery = True
self._reset_prearm()
return
if self.prearm_abort_lockout > 0:
self.prearm_abort_lockout -= 1
self._reset_prearm()
return
steer_max = round(float(np.interp(CS.out.vEgoRaw, CCP.STEER_MAX_LOOKUP[0], CCP.STEER_MAX_LOOKUP[1])))
hold_target = abs(int(round(float(actuators.torque) * steer_max)))
epas_holding = eac_active
driver_took_over = self.hands_on and CS.out.steeringPressed
if not epas_holding or driver_took_over or hold_target < TORQUE_PREARM_MIN_HOLD:
self.torque_active = True
self.galaxy_torque_recovery = True
self._reset_prearm()
return
# Keep angle active while the independently rate-limited torque channel
# ramps underneath it. Progress is evaluated from the prior frame.
self.torque_prearm = True
self.prearm_frames += 1
if abs(self.apply_torque_last) > self.prearm_torque_peak:
self.prearm_torque_peak = abs(self.apply_torque_last)
self.prearm_stall_frames = 0
else:
self.prearm_stall_frames += 1
reached = abs(self.apply_torque_last) >= TORQUE_PREARM_EXIT_FRAC * hold_target
stalled = self.prearm_stall_frames >= TORQUE_PREARM_STALL_FRAMES
if reached:
self.torque_active = True
self.galaxy_torque_recovery = True
self._end_prearm("reached", hold_target)
elif self.prearm_frames >= TORQUE_PREARM_MAX_FRAMES:
if stalled:
self._end_prearm("abort", hold_target)
self.prearm_abort_lockout = TORQUE_PREARM_ABORT_LOCKOUT
else:
self.torque_active = True
self.galaxy_torque_recovery = True
self._end_prearm("backstop", hold_target)
return
# Cancelling a force request during prearm immediately returns to the
# already-active angle channel. A completed torque handoff uses the normal
# cooperative release logic below to return to angle safely.
self.prearm_abort_lockout = 0
self._reset_prearm()
if not self.torque_active:
self.galaxy_torque_recovery = False
if (self.torque_active and epas_inhibited and
not self.hands_on and not CS.out.steeringPressed):
self.eac_rearm_release_frames = min(self.eac_rearm_release_frames + 1, EAC_REARM_RELEASE_FRAMES)
else:
self.eac_rearm_release_frames = 0
if self.hands_on and CS.out.steeringPressed:
self.torque_active = True
self.driver_override_recovery = True
self.galaxy_torque_recovery = False
self.eac_rearm_attempted = False
elif self.eac_dead_frames >= EAC_RECOVER_FRAMES:
self.torque_active = True
self.driver_override_recovery = False
self.galaxy_torque_recovery = False
elif not self.lat_active_last and not epas_ready:
self.torque_active = True
self.driver_override_recovery = False
self.galaxy_torque_recovery = False
self.eac_rearm_attempted = False
elif self.torque_active and self.torque_active_frames >= MIN_TORQUE_FRAMES and not self.hands_on:
fw_max = float(np.interp(CS.out.vEgoRaw, EPAS_FW_MAX_ANGLE_BP, EPAS_FW_MAX_ANGLE_V)) * EPAS_FW_ANGLE_MARGIN
in_envelope = abs(CS.out.steeringAngleDeg) < fw_max
threshold_dps = float(np.interp(CS.out.vEgoRaw, EPAS_FW_RATE_BP, EPAS_FW_RATE_V)) * 100.0
lower, upper = self.rate_budget.bounds(threshold_dps, EPAS_FW_RATE_MARGIN)
rate_settled = lower <= CS.out.steeringAngleDeg <= upper and abs(CS.out.steeringRateDeg) < UNWIND_HANDOFF_RATE
rearm_ready = (epas_inhibited and not self.eac_rearm_attempted and
self.eac_rearm_release_frames >= EAC_REARM_RELEASE_FRAMES and
not CS.out.steeringPressed and not CS.out.steerFaultTemporary and
not CS.out.steerFaultPermanent)
handoff_angle_ready = (not (self.driver_override_recovery or self.galaxy_torque_recovery) or
abs(CS.out.steeringAngleDeg) < HANDOFF_MAX_ANGLE_DEG)
driver_handoff_ready = (not self.driver_override_recovery or
self.hands_off_frames >= DRIVER_HANDS_OFF_EXIT_FRAMES)
if ((epas_ready or rearm_ready) and in_envelope and rate_settled and
gap < HANDOFF_EXIT_DEG and handoff_angle_ready and driver_handoff_ready):
self.torque_active = False
self.driver_override_recovery = False
self.galaxy_torque_recovery = False
self.eac_rearm_attempted = rearm_ready
if eac_active:
self.eac_rearm_attempted = False
if not self.torque_active and not eac_active:
self.eac_dead_frames += 1
else:
self.eac_dead_frames = 0
self.lat_active_last = True
def _update_angle(self, CS, lat_active: bool, desired_angle: float, desired_lat_accel: float) -> None:
self.angle_active = lat_active and not self.torque_active
v_lookahead = max(CS.out.vEgoRaw + max(CS.out.aEgo, 0.0), 1.0)
apply_angle = apply_rivian_steer_angle_limits_vm(desired_angle, self.apply_angle_last, v_lookahead,
CS.out.steeringAngleDeg, self.angle_active, CCP, self.VM_safety)
saturated = False
if self.angle_active:
fw_max = float(np.interp(CS.out.vEgoRaw, EPAS_FW_MAX_ANGLE_BP, EPAS_FW_MAX_ANGLE_V)) * EPAS_FW_ANGLE_MARGIN
safety_max = get_max_angle_vm(max(CS.out.vEgoRaw, 1.0), self.VM_safety, CCP)
deliverable_angle = min(fw_max, safety_max)
saturated = abs(desired_lat_accel) > ANGLE_SAT_MIN_LAT_ACCEL and abs(desired_angle) > deliverable_angle
apply_angle = float(np.clip(apply_angle, -fw_max, fw_max))
threshold_dps = float(np.interp(CS.out.vEgoRaw, EPAS_FW_RATE_BP, EPAS_FW_RATE_V)) * 100.0
lower, upper = self.rate_budget.bounds(threshold_dps, EPAS_FW_RATE_MARGIN)
apply_angle = float(np.clip(apply_angle, lower, upper))
step = get_max_angle_delta_vm(max(CS.out.vEgoRaw, 1.0), self.VM_safety, CCP) * PANDA_STEP_MARGIN
apply_angle = float(np.clip(apply_angle, self.apply_angle_last - step, self.apply_angle_last + step))
self.angle_sat_frames = self.angle_sat_frames + 1 if saturated else 0
self.angle_saturated = self.angle_sat_frames >= ANGLE_SAT_FRAMES
self.apply_angle_last = apply_angle
self.rate_budget.push(apply_angle)
def _update_torque(self, CS, actuators) -> None:
torque_requested = self.torque_active or self.torque_prearm
self.toi_act_cmd, torque_allowed = self.toi_controller.update(
torque_requested,
abs(CS.out.steeringAngleDeg) >= TOI_MAX_ANGLE_DEG,
bool(getattr(CS, "toi_fault", False)),
bool(getattr(CS, "toi_active", False)),
bool(getattr(CS, "toi_unavailable", False)),
prearming=self.torque_prearm,
high_angle_rearm=abs(CS.out.steeringAngleDeg) <= TOI_REARM_ANGLE_DEG,
hold_high_angle_release=self.driver_override_recovery,
)
if not torque_requested:
self.apply_torque_last = 0
self.torque_cmd = 0
return
if not torque_allowed:
# The EPAS has either not acknowledged the request yet or is completing a
# high-angle release. Reset the limiter to the torque actually sent.
self.apply_torque_last = 0
self.torque_cmd = 0
return
steer_max = round(float(np.interp(CS.out.vEgoRaw, CCP.STEER_MAX_LOOKUP[0], CCP.STEER_MAX_LOOKUP[1])))
requested_torque = int(round(float(actuators.torque) * steer_max))
torque_cmd = apply_driver_steer_torque_limits(requested_torque, self.apply_torque_last,
CS.out.steeringTorque, CCP, steer_max)
if abs(CS.out.steeringAngleDeg) > HIGH_ANGLE_THRESHOLD_DEG:
cap = int(round(steer_max * HIGH_ANGLE_CAP_FRAC))
torque_cmd = int(np.clip(torque_cmd, -cap, cap))
self.apply_torque_last = torque_cmd
self.torque_cmd = torque_cmd
-12
View File
@@ -1,12 +0,0 @@
TOI_FAULT_ALERT_FRAMES = 25
def get_steering_faults(angle_harness: bool, toi_fault: bool, toi_fault_persistent: bool,
eac_status: int, eac_error_code: int) -> tuple[bool, bool, bool]:
if angle_harness:
# The torque controller handles the short ToiFlt release/rearm handshake
# internally. Escalate only if EPAS does not recover inside that window.
temporary = toi_fault_persistent or (eac_status == 2 and eac_error_code != 0)
return eac_status == 4, temporary, eac_status == 2 and eac_error_code == 12
return False, toi_fault or eac_error_code != 0, False

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