Compare commits

..

1 Commits

Author SHA1 Message Date
firestar5683 1a527cb927 rl3 2026-07-22 15:59:31 -05:00
1685 changed files with 330816 additions and 170142 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
id: gha-cache
if: ${{ !contains(runner.name, 'nsc') && inputs.save != 'false' }}
uses: 'actions/cache@v5'
uses: 'actions/cache@v4'
with:
path: ${{ inputs.path }}
key: ${{ inputs.key }}
@@ -43,7 +43,7 @@ runs:
- name: setup github cache
id: gha-cache-ro
if: ${{ !contains(runner.name, 'nsc') && inputs.save == 'false' }}
uses: 'actions/cache/restore@v5'
uses: 'actions/cache/restore@v4'
with:
path: ${{ inputs.path }}
key: ${{ inputs.key }}
@@ -14,7 +14,7 @@ runs:
${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \
scons -j$(nproc) --cache-populate"
- name: Save scons cache
uses: actions/cache/save@v5
uses: actions/cache/save@v4
if: github.ref == 'refs/heads/master'
with:
path: .ci_cache/scons_cache
+9 -3
View File
@@ -23,6 +23,11 @@ on:
type: boolean
default: true
required: false
build_ui:
description: "Build UI (selfdrive/ui)"
type: boolean
default: true
required: false
build_params:
description: "Build params Python extension"
type: boolean
@@ -83,7 +88,7 @@ jobs:
fi
- name: Checkout target branch
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
ref: ${{ env.BUILD_BRANCH }}
fetch-depth: 0
@@ -151,6 +156,7 @@ jobs:
fi
TARGETS=()
[[ "${{ inputs.build_ui }}" == "true" ]] && TARGETS+=("selfdrive/ui/ui")
[[ "${{ inputs.build_params }}" == "true" ]] && TARGETS+=("common/params_pyx.so")
[[ "${{ inputs.build_cereal }}" == "true" ]] && TARGETS+=("cereal/messaging/bridge")
if [[ "${{ inputs.build_panda }}" == "true" ]]; then
@@ -178,8 +184,8 @@ jobs:
fi
if [[ ${#TARGETS[@]} -eq 0 ]]; then
echo "No partial targets selected; defaulting to panda"
TARGETS=("panda/board/obj/panda.bin.signed")
echo "No partial targets selected; defaulting to UI + panda"
TARGETS=("selfdrive/ui/ui" "panda/board/obj/panda.bin.signed")
fi
echo "Running partial build for targets: ${TARGETS[*]}"
+1 -1
View File
@@ -48,7 +48,7 @@ jobs:
fi
- name: Checkout target branch
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
ref: ${{ env.BUILD_BRANCH }}
fetch-depth: 0
@@ -17,17 +17,17 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- name: Log in to GHCR
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push runner image
uses: docker/build-push-action@v7
uses: docker/build-push-action@v6
with:
context: .
file: tools/truenas_github_runner/Dockerfile
+3
View File
@@ -54,6 +54,9 @@ cereal/gen
selfdrive/ui/translations/tmp
selfdrive/car/tests/cars_dump
system/camerad/test/ae_gray_test
selfdrive/ui/ui.macos
selfdrive/ui/ui.larch64
.coverage*
coverage.xml
htmlcov
+16 -1
View File
@@ -11,6 +11,14 @@
"tools/sim/run_bridge.py"
]
},
{
"id": "cpp_process",
"type": "pickString",
"description": "Select the process to debug",
"options": [
"selfdrive/ui/ui"
]
},
{
"id": "args",
"description": "Arguments to pass to the process",
@@ -32,6 +40,13 @@
"justMyCode": true,
"args": "${input:args}"
},
{
"name": "C++: openpilot Process",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/${input:cpp_process}",
"cwd": "${workspaceFolder}"
},
{
"name": "Attach LLDB to Replay drive",
"type": "lldb",
@@ -67,4 +82,4 @@
]
}
]
}
}
+118 -52
View File
@@ -1,5 +1,4 @@
import os
import importlib
import shutil
import subprocess
import sys
@@ -38,6 +37,10 @@ AddOption('--coverage',
action='store_true',
help='build with test coverage options')
AddOption('--clazy',
action='store_true',
help='build with clazy')
AddOption('--ccflags',
action='store',
type='string',
@@ -129,41 +132,6 @@ elif arch == "aarch64" and AGNOS:
arch = "larch64"
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.
# Use the system toolchain explicitly on macOS for reliable local builds.
cc = '/usr/bin/clang' if arch == "Darwin" else 'clang'
@@ -305,10 +273,7 @@ env = Environment(
"-Wno-vla-cxx-extension",
] + cflags + ccflags,
# Managed dependencies must precede the compatibility sysroot. The sysroot
# can intentionally retain legacy libraries for C3 support, but new release
# binaries must link against the versions shipped in the managed venv.
CPPPATH=capnproto_include_dirs + ffmpeg_include_dirs + cpppath + [
CPPPATH=cpppath + [
"#",
"#third_party/acados/include",
"#third_party/acados/include/blasfeo/include",
@@ -327,11 +292,11 @@ env = Environment(
RANLIB=ranlib,
LINKFLAGS=ldflags,
RPATH=ffmpeg_runtime_lib_dirs + rpath,
RPATH=rpath,
CFLAGS=["-std=gnu11"] + cflags,
CXXFLAGS=["-std=c++1z"] + cxxflags,
LIBPATH=capnproto_lib_dirs + ffmpeg_lib_dirs + libpath + [
LIBPATH=libpath + [
"#msgq_repo",
"#third_party",
"#selfdrive/pandad",
@@ -389,7 +354,116 @@ else:
np_version = SCons.Script.Value(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
SConscript(['common/SConscript'])
@@ -410,15 +484,7 @@ SConscript(['opendbc_repo/SConscript'], exports={'env': env_swaglog})
SConscript(['cereal/SConscript'])
Import('socketmaster', 'msgq')
if capnproto is not None:
messaging = [
socketmaster,
msgq,
File(os.path.join(capnproto.LIB_DIR, "libcapnp.a")),
File(os.path.join(capnproto.LIB_DIR, "libkj.a")),
]
else:
messaging = [socketmaster, msgq, 'capnp', 'kj']
messaging = [socketmaster, msgq, 'capnp', 'kj',]
Export('messaging')
+3
View File
@@ -46,6 +46,9 @@ while [[ $# -gt 0 ]]; do
shortcut_includes_panda=1
add_panda_targets
;;
--ui|-ui)
shortcut_targets+=("selfdrive/ui/ui")
;;
--cereal|-cereal)
shortcut_targets+=(
"cereal/libcereal.a"
+3 -11
View File
@@ -1,5 +1,3 @@
import subprocess
Import('env', 'common', 'msgq')
cereal_dir = Dir('.')
@@ -7,15 +5,9 @@ gen_dir = Dir('gen')
# Build cereal
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],
schema_files,
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))
env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files],
schema_files,
f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/")
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
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
pulseAndGlide @30 :Bool; # developer-only wheel-button pulse-and-glide mode is enabled
}
struct StarPilotDeviceState @0xda96579883444c35 {
@@ -220,27 +219,11 @@ struct StarPilotPlan @0xf98d843bfd7004a3 {
disableThrottle @35 :Bool;
trackingLead @36 :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 {
leadLeft @0 :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 {
dRel @0 :Float32;
@@ -270,7 +253,6 @@ struct StarPilotSelfdriveState @0xf416ec09499d9d19 {
alertSize @3 :AlertSize;
alertType @4 :Text;
alertSound @5 :Car.CarControl.HUDControl.AudibleAlert;
vEgo @6 :Float32;
enum AlertStatus {
normal @0;
@@ -300,15 +282,7 @@ struct StarPilotLateralManeuverPlanDEPRECATED @0xcb9fd56c7057593a {
desiredCurvature @0 :Float32; # 1/m
}
struct StarPilotLateralState @0xc2243c65e0340384 {
active @0 :Bool;
frictionThreshold @1 :Float32;
frictionScale @2 :Float32;
feedforward @3 :Float32;
frictionJerk @4 :Float32;
frictionJerkDeadzone @5 :Float32;
lowSpeedFactor @6 :Float32;
unwindDetected @7 :Bool;
struct CustomReserved11 @0xc2243c65e0340384 {
}
struct CustomReserved12 @0x9ccdc8676701b412 {
Binary file not shown.
Binary file not shown.
+6 -58
View File
@@ -130,13 +130,8 @@ struct OnroadEvent @0xc4fa6047f024e718 {
userBookmark @95;
excessiveActuation @96;
audioFeedback @97;
bigModelLoading @100;
bigModelFailed @102;
soundsUnavailableDEPRECATED @47;
stockLkasDEPRECATED @98;
lateralManeuverDEPRECATED @99;
bigModelReadyDEPRECATED @101;
}
}
@@ -472,10 +467,6 @@ struct CanData {
struct DeviceState @0xa4d8b5af2aa492eb {
deviceType @45 :InitData.DeviceType;
# usb
chestnutPresent @51 :Bool;
usbState @52 :UsbState;
networkType @22 :NetworkType;
networkInfo @31 :NetworkInfo;
networkStrength @24 :NetworkStrength;
@@ -507,8 +498,7 @@ struct DeviceState @0xa4d8b5af2aa492eb {
pmicTempC @39 :List(Float32);
intakeTempC @46 :Float32;
exhaustTempC @47 :Float32;
gnssTempC @48 :Float32;
bottomSocTempC @50 :Float32;
caseTempC @48 :Float32;
maxTempC @44 :Float32; # max of other temps, used to control fan
thermalZones @38 :List(ThermalZone);
thermalStatus @14 :ThermalStatus;
@@ -522,10 +512,10 @@ struct DeviceState @0xa4d8b5af2aa492eb {
}
enum ThermalStatus {
ok @0;
warmDEPRECATED @1;
overheated @2;
critical @3;
green @0;
yellow @1;
red @2;
danger @3;
}
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 {
mdMonoTime @6 :UInt64;
carStateMonoTime @11 :UInt64;
@@ -1327,11 +1282,6 @@ struct LongitudinalPlan @0xe00b5b3eba12876c {
solverExecutionTime @35 :Float32;
leadTrajectoryX0 @40 :List(Float32);
leadTrajectoryV0 @41 :List(Float32);
leadTrajectoryX1 @42 :List(Float32);
leadTrajectoryV1 @43 :List(Float32);
enum LongitudinalPlanSource {
cruise @0;
lead0 @1;
@@ -2737,7 +2687,6 @@ struct Event {
procLog @33 :ProcLog;
clocks @35 :Clocks;
deviceState @6 :DeviceState;
chestnutState @152 :ChestnutState;
logMessage @18 :Text;
errorLogMessage @85 :Text;
@@ -2757,7 +2706,6 @@ struct Event {
userBookmark @93 :UserBookmark;
bookmarkButton @148 :UserBookmark;
audioFeedback @149 :AudioFeedback;
visionSpeedLimitBookmark @153 :UserBookmark;
lateralManeuverPlan @150 :LateralManeuverPlan;
# *********** debug ***********
@@ -2794,7 +2742,7 @@ struct Event {
starpilotSelfdriveState @115 :Custom.StarPilotSelfdriveState;
customReserved9 @116 :Custom.CustomReserved9;
starpilotLateralManeuverPlanDEPRECATED @136 :Custom.StarPilotLateralManeuverPlanDEPRECATED;
starpilotLateralState @137 :Custom.StarPilotLateralState;
customReserved11 @137 :Custom.CustomReserved11;
customReserved12 @138 :Custom.CustomReserved12;
customReserved13 @139 :Custom.CustomReserved13;
customReserved14 @140 :Custom.CustomReserved14;
-8
View File
@@ -268,7 +268,6 @@ class SubMaster:
class PubMaster:
def __init__(self, services: List[str]):
self.sock = {}
self._zmq_readers_settled = set()
for s in services:
self.sock[s] = pub_sock(s)
@@ -278,13 +277,6 @@ class PubMaster:
self.sock[s].send(dat)
def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
if "ZMQ" in os.environ:
if s not in self._zmq_readers_settled:
time.sleep(min(timeout, 1.0))
self._zmq_readers_settled.add(s)
elif dt >= 0.05:
time.sleep(min(timeout, 1.0))
return True
for _ in range(int(timeout*(1./dt))):
if self.sock[s].all_readers_updated():
return True
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}},
{ "gpsNMEA", {"gpsNMEA", true, 9.000000, -1, 256000}},
{ "deviceState", {"deviceState", true, 2.000000, 1, 256000}},
{ "chestnutState", {"chestnutState", true, 10.000000, 10, 256000}},
{ "touch", {"touch", true, 20.000000, 1, 256000}},
{ "can", {"can", true, 100.000000, 2053, 10485760}},
{ "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}},
{ "bookmarkButton", {"bookmarkButton", 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}},
{ "driverEncodeData", {"driverEncodeData", 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}},
{ "livestreamDriverEncodeData", {"livestreamDriverEncodeData", false, 20.000000, -1, 2097152}},
{ "customReserved9", {"customReserved9", true, 0.000000, 1, 256000}},
{ "starpilotLateralState", {"starpilotLateralState", true, 100.000000, 10, 256000}},
{ "customReservedRawData0", {"customReservedRawData0", true, 0.000000, -1, 256000}},
{ "customReservedRawData1", {"customReservedRawData1", 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),
"gpsNMEA": (True, 9.),
"deviceState": (True, 2., 1),
"chestnutState": (True, 10., 10),
"touch": (True, 20., 1),
"can": (True, 100., 2053, QueueSize.BIG), # decimation gives ~3 msgs in a full segment
"controlsState": (True, 100., 10, QueueSize.MEDIUM),
@@ -86,7 +85,6 @@ _services: dict[str, tuple] = {
"rawAudioData": (False, 20.),
"bookmarkButton": (True, 0., 1),
"audioFeedback": (True, 0., 1),
"visionSpeedLimitBookmark": (False, 0., 1),
"roadEncodeData": (False, 20., None, QueueSize.BIG),
"driverEncodeData": (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),
"livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM),
"customReserved9": (True, 0., 1),
"starpilotLateralState": (True, 100., 10),
"customReservedRawData0": (True, 0.),
"customReservedRawData1": (True, 0.),
"customReservedRawData2": (True, 0.),
+7 -15
View File
@@ -58,34 +58,26 @@ def file_chunked_exists(path) -> bool:
class ChunkStream(io.RawIOBase):
def __init__(self, paths):
self._paths = iter(paths)
self._file = None
self._buffer = memoryview(b"")
def readable(self):
return True
def readinto(self, buffer):
count = 0
view = memoryview(buffer)
while count < len(buffer):
if self._file is None:
if not self._buffer:
path = next(self._paths, None)
if path is None:
break
self._file = open(path, "rb")
bytes_read = self._file.readinto(view[count:])
if not bytes_read:
self._file.close()
self._file = None
self._buffer = memoryview(Path(path).read_bytes())
continue
count += bytes_read
take = min(len(buffer) - count, len(self._buffer))
buffer[count:count + take] = self._buffer[:take]
self._buffer = self._buffer[take:]
count += take
return count
def close(self):
if self._file is not None:
self._file.close()
self._file = None
super().close()
def open_file_chunked(path):
chunks = get_existing_chunks(path)
+1 -1
View File
@@ -2,7 +2,7 @@ from openpilot.common.params import Params
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"
else:
return "gpsLocation"
Binary file not shown.
+12 -88
View File
@@ -16,14 +16,10 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"AthenadUploadQueue", {PERSISTENT, JSON}},
{"AthenadRecentlyViewedRoutes", {PERSISTENT, STRING}},
{"BootCount", {PERSISTENT, INT}},
{"BluetoothAudioAddress", {PERSISTENT, STRING}},
{"BluetoothAudioTestActive", {CLEAR_ON_MANAGER_START | DONT_LOG, BOOL}},
{"BluetoothEnabled", {PERSISTENT, BOOL, "0"}},
{"CalibrationParams", {PERSISTENT, BYTES}},
{"CameraDebugExpGain", {CLEAR_ON_MANAGER_START, STRING}},
{"CameraDebugExpTime", {CLEAR_ON_MANAGER_START, STRING}},
{"CarBatteryCapacity", {PERSISTENT, INT}},
{"CarGpsAvailable", {CLEAR_ON_MANAGER_START, BOOL}},
{"CarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}},
{"CarParamsCache", {CLEAR_ON_MANAGER_START, BYTES}},
{"CarParamsPersistent", {PERSISTENT, BYTES}},
@@ -66,8 +62,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"GsmRoaming", {PERSISTENT, BOOL}},
{"HardwareSerial", {PERSISTENT, STRING}},
{"HasAcceptedTerms", {PERSISTENT, STRING, "0"}},
// Internal kill switch; the platform verification allowlist remains the hard safety gate.
{"HondaBoschARadar", {PERSISTENT, BOOL, "1"}},
{"HondaGasFactorParams", {PERSISTENT, FLOAT}},
{"HondaLateralPidKiScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
{"HondaLateralPidKpScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
@@ -76,7 +70,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsEngaged", {PERSISTENT, BOOL}},
{"IsLdwEnabled", {PERSISTENT, BOOL}},
{"IsLiveStreaming", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsMetric", {PERSISTENT, BOOL}},
{"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsOnroad", {PERSISTENT, BOOL}},
@@ -87,7 +80,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}},
{"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"JoystickControlDevice", {PERSISTENT, STRING}},
{"LanguageSetting", {PERSISTENT, STRING, "main_en"}},
{"LastAthenaPingTime", {CLEAR_ON_MANAGER_START, INT}},
{"LastGPSPosition", {PERSISTENT, STRING}},
@@ -102,8 +94,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"LiveDelay", {PERSISTENT, BYTES}},
{"LiveParameters", {PERSISTENT, JSON}},
{"LiveParametersV2", {PERSISTENT, BYTES}},
{"LivestreamEncoderBitrate", {CLEAR_ON_MANAGER_START | DONT_LOG, INT}},
{"LivestreamRequestKeyframe", {CLEAR_ON_MANAGER_START | DONT_LOG, BOOL}},
{"LiveTorqueParameters", {PERSISTENT | DONT_LOG, BYTES}},
{"LateralManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"LocationFilterInitialState", {PERSISTENT, BYTES}},
@@ -135,17 +125,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"RecordAudioFeedback", {PERSISTENT, BOOL, "0"}},
{"RecordFront", {PERSISTENT, BOOL}},
{"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}},
{"ShowDebugInfo", {PERSISTENT, BOOL}},
{"ShowAllToggles", {PERSISTENT, BOOL, "0", "0", 3}},
{"TryRaylibUI", {PERSISTENT, BOOL, "1"}},
{"UseOldUI", {PERSISTENT, BOOL, "0", std::nullopt, 0, SETTINGS_SIMPLE}},
{"UsePrebuilt", {PERSISTENT, BOOL, "1"}},
{"RouteCount", {PERSISTENT, INT, "0"}},
{"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
@@ -168,7 +152,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
{"UsbGpuActive", {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}},
{"Version", {PERSISTENT, STRING}},
@@ -195,7 +178,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ApiCache_DriveStats", {PERSISTENT, JSON, "{}", "{}"}},
{"AutomaticallyDownloadModels", {PERSISTENT, BOOL, "1", "0", 1}},
{"AutomaticUpdates", {PERSISTENT, BOOL, "1", "1", 0}},
{"AllowGpuModelDownloadWithoutGpu", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"AvailableModelNames", {PERSISTENT, STRING, "", "", 1}},
{"AvailableModelSeries", {PERSISTENT, STRING, "", "", 1}},
{"AvailableModels", {PERSISTENT, STRING, "", "", 1}},
@@ -211,7 +193,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CalibratedLateralAcceleration", {PERSISTENT, FLOAT, "2.0", "2.0", 2}},
{"CalibrationProgress", {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"}},
{"DisableWideRoad", {PERSISTENT, BOOL, "0", "0", 3}},
{"CancelModelDownload", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
@@ -222,8 +204,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CECurves", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"CECurvesLead", {PERSISTENT, BOOL, "0", "0", 1}},
{"CELead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CEModelStopTime", {PERSISTENT, FLOAT, "7.7", "0.0", 2, SETTINGS_SIMPLE}},
{"CEOpenRoad", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"CEModelStopTime", {PERSISTENT, FLOAT, "7.0", "0.0", 2, SETTINGS_SIMPLE}},
{"CESignalLaneDetection", {PERSISTENT, BOOL, "1", "0", 2}},
{"CESignalSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"CESlowerLead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
@@ -248,7 +229,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ConditionalExperimental", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CurvatureData", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"CurveSpeedController", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CurveSpeedControllerNoLead", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"CustomAlerts", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"CustomAccelProfile", {PERSISTENT, BOOL, "0", "0", 3}},
{"CustomAccelProfileInitialized", {PERSISTENT, BOOL, "0", "0", 3}},
@@ -286,7 +266,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}},
{"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}},
{"DisableOpenpilotLongitudinal", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"DiscordUsername", {PERSISTENT, STRING, "", "", 0}},
@@ -304,11 +284,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"DownloadAllModels", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"DownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"DriverCamera", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"Model", {PERSISTENT, STRING, "rdf43", "rdf43", 1}},
{"ModelVersion", {PERSISTENT, STRING, "v15", "v15", 1}},
{"DrivingModel", {PERSISTENT, STRING, "rdf43", "rdf43", 1}},
{"DrivingModelName", {PERSISTENT, STRING, "Regret Driven Framework V4", "Regret Driven Framework V4", 1}},
{"DrivingModelVersion", {PERSISTENT, STRING, "v15", "v15", 1}},
{"Model", {PERSISTENT, STRING, "sc2", "sc2", 1}},
{"ModelVersion", {PERSISTENT, STRING, "v11", "v11", 1}},
{"DrivingModel", {PERSISTENT, STRING, "sc2", "sc2", 1}},
{"DrivingModelName", {PERSISTENT, STRING, "South Carolina", "South Carolina", 1}},
{"DrivingModelVersion", {PERSISTENT, STRING, "v11", "v11", 1}},
{"DynamicPathWidth", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"DynamicPedalsOnUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"EngageVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
@@ -344,22 +324,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ForceStops", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"ForceStopDistanceOffset", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ForceStandstill", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"FordLKASButtonControlMigrated", {PERSISTENT, BOOL, "0", "0"}},
{"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}},
{"FLMActiveProfileId", {PERSISTENT, STRING, "", "", 2}},
{"FLMSubmittedTune", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
{"FLMTrialBaseline", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"FLMTrialApplied", {PERSISTENT, BOOL, "0", "0", 2}},
{"FPSCounter", {PERSISTENT, BOOL, "0", "0", 3}},
@@ -369,14 +336,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"StarPilotCarParamsPersistent", {PERSISTENT, BYTES, "", ""}},
{"StarPilotDongleId", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"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, "{}", "{}"}},
{"StarPilotTogglesUpdated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"FrogsGoMoosTweak", {PERSISTENT, BOOL, "1", "0", 2}},
{"GoatScream", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"GoatScreamCriticalAlerts", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"GreenLightAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
@@ -409,21 +371,13 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"IssueReported", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
{"KonikDongleId", {PERSISTENT, STRING, "", "", 0}},
{"KonikMinutes", {PERSISTENT, INT, "0", "0", 0}},
{"LaneCentering", {PERSISTENT, BOOL, "0", "0", 2}},
{"LaneCenteringPauseOnSignal", {PERSISTENT, BOOL, "1", "1", 2}},
{"LaneCenteringE2EAuthority", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
{"LaneCenterOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"LaneChanges", {PERSISTENT, BOOL, "1", "1", 0, SETTINGS_SIMPLE}},
{"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}},
{"LaneChangeTime", {PERSISTENT, FLOAT, "1.0", "0.0", 1, SETTINGS_SIMPLE}},
{"LaneDetectionWidth", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
{"LaneLinesColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
{"LaneLinesWidth", {PERSISTENT, FLOAT, "4.0", "2.0", 2, SETTINGS_SIMPLE}},
{"LastMapsUpdate", {PERSISTENT, STRING, "", ""}},
{"MapsDownloadProgress", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"MapsDownloadSizeCache", {PERSISTENT, STRING, "{}", "{}"}},
{"LateralTune", {PERSISTENT, BOOL, "1", "0", 1}},
{"LeadDepartingAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"LeadDetectionThreshold", {PERSISTENT, INT, "35", "50", 3}},
@@ -461,7 +415,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"MapsSelected", {PERSISTENT, STRING, "", "", 0}},
{"MapSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
{"NavDesiresAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
{"NavLanePositioningAllowed", {PERSISTENT, BOOL, "0", "0", 2}},
{"NavLongitudinalAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
{"ClearNavOnOffroad", {PERSISTENT, BOOL, "1", "1", 2, SETTINGS_SIMPLE}},
{"ClearNavOnOffroadTimeoutMinutes", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
@@ -486,8 +439,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ModelDrivesAndScores", {PERSISTENT, JSON, "{}", "{}"}},
{"ModelReleasedDates", {PERSISTENT, STRING, "", "", 1}},
{"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}},
{"ModelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"ModelUI", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
@@ -515,11 +466,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"OnroadDistanceButtonPressed", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"FavoriteVirtualAccelCruiseCounter", {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"}},
{"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}},
{"OverpassRequests", {PERSISTENT, JSON, "{}", "{}"}},
{"PathColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
@@ -531,18 +478,12 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"PauseLateralSpeed", {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}},
{"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}},
{"GalaxyUploadPending", {PERSISTENT, BOOL, "0", "0", 0}},
{"PreferredSchedule", {PERSISTENT, INT, "2", "0", 0}},
{"PreviousSpeedLimit", {PERSISTENT, FLOAT, "0.0", "0.0"}},
{"PromptDistractedVolume", {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}},
{"QOLLongitudinal", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"QOLVisuals", {PERSISTENT, BOOL, "1", "0", 0, SETTINGS_SIMPLE}},
@@ -568,9 +509,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"RelaxedJerkDeceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"RelaxedJerkSpeed", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"RelaxedJerkSpeedDecrease", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"RivianAngleControl", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"RivianAngleSaturated", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL, "0", "0"}},
{"RivianToiRecoveryFailed", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL, "0", "0"}},
{"ReverseCruise", {PERSISTENT, BOOL, "0", "0", 1}},
{"RecoveryPower", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"RoadEdgesWidth", {PERSISTENT, FLOAT, "2.0", "2.0", 2, SETTINGS_SIMPLE}},
{"RoadNameUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
@@ -636,8 +575,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"VisionSpeedLimitAutoBookmark", {PERSISTENT, BOOL, "0", "0", 0}},
{"VisionSpeedLimitAutoPreserveSegment", {PERSISTENT, BOOL, "0", "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}},
{"StandardFollow", {PERSISTENT, FLOAT, "1.45", "1.45", 2}},
{"StandardFollowHigh", {PERSISTENT, FLOAT, "1.2", "1.2", 2}},
@@ -678,8 +615,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"SwitchbackModeEnabled", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
{"SubaruSNG", {PERSISTENT, BOOL, "1", "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}},
{"TeslaCoopSteering", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"TestAlert", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
@@ -700,7 +635,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"TuningLevel", {PERSISTENT, INT, "0", "0", 0}},
{"TuningLevelConfirmed", {PERSISTENT, BOOL, "0", "0", 0}},
{"TurnDesires", {PERSISTENT, BOOL, "0", "0", 2}},
{"TurnSteeringLimitMuteSpeed", {PERSISTENT, INT, "0", "0", 0}},
{"UnlockDoors", {PERSISTENT, BOOL, "1", "0", 0}},
{"Updated", {PERSISTENT, STRING, "0", "0"}},
{"UpdateSpeedLimits", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
@@ -713,16 +647,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"UseSI", {PERSISTENT, BOOL, "1", "1", 3}},
{"UserFavorites", {PERSISTENT, STRING, "", "", 1}},
{"UseVienna", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"VASMAnnotationConfig", {PERSISTENT, JSON, "{}", "{}", 2}},
{"VASMConfidenceThreshold", {PERSISTENT, FLOAT, "0.94", "0.94", 2}},
{"VASMEnabled", {PERSISTENT, BOOL, "0", "0", 1}},
{"VASMLeftActive", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VASMLeftConfidence", {CLEAR_ON_MANAGER_START, STRING, "0.0", "0.0", 2}},
{"VASMLastUpdateMonoTime", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VASMRightActive", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VASMRightConfidence", {CLEAR_ON_MANAGER_START, STRING, "0.0", "0.0", 2}},
{"VASMSmoothSeconds", {PERSISTENT, FLOAT, "0.2", "0.2", 2}},
{"VASMTimestampEof", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VEgoStarting", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"VEgoStartingStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"VEgoStopping", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
Binary file not shown.
+1 -4
View File
@@ -50,10 +50,7 @@ class OpenpilotPrefix:
symlink_path = Params().get_param_path()
if os.path.exists(symlink_path):
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
# removed it and there is no link left to unlink
if os.path.islink(symlink_path):
os.remove(symlink_path)
os.remove(symlink_path)
shutil.rmtree(self.msgq_path, ignore_errors=True)
if PC:
shutil.rmtree(Paths.log_root(), ignore_errors=True)
-1
View File
@@ -22,7 +22,6 @@ class Priority:
# - modeld = 55
# - camerad = 54
CTRL_LOW = 51 # plannerd & radard
UI = 50
# CORE 3
# - pandad = 55
+13
View File
@@ -7,6 +7,19 @@ class Spinner:
def __init__(self):
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")
venv_python = os.path.join(BASEDIR, ".venv", "bin", "python")
python_exec = venv_python if os.path.isfile(venv_python) else "python3"
-18
View File
@@ -1,5 +1,3 @@
from pathlib import Path
from openpilot.common import file_chunker
@@ -16,19 +14,3 @@ def test_chunked_stream_round_trip(tmp_path, monkeypatch):
assert file_chunker.read_file_chunked(path) == payload
with file_chunker.open_file_chunked(path) as stream:
assert stream.read(9) + stream.read() == payload
def test_unchunked_stream_does_not_materialize_file(tmp_path, monkeypatch):
path = tmp_path / "fat.onnx"
payload = b"large model read through bounded buffers"
path.write_bytes(payload)
original_read_bytes = Path.read_bytes
def reject_whole_file_read(candidate):
if candidate == path:
raise AssertionError("streaming must not call Path.read_bytes()")
return original_read_bytes(candidate)
monkeypatch.setattr(Path, "read_bytes", reject_whole_file_read)
with file_chunker.open_file_chunked(path) as stream:
assert stream.read() == payload
@@ -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)
+5 -2
View File
@@ -50,8 +50,11 @@ class TestParams:
assert self.params.get("CarParams", block=True) == b"test"
def test_params_unknown_key_fails(self):
assert self.params.get("swag") is None
assert not self.params.get_bool("swag")
with pytest.raises(UnknownKeyName):
self.params.get("swag")
with pytest.raises(UnknownKeyName):
self.params.get_bool("swag")
with pytest.raises(UnknownKeyName):
self.params.put("swag", "abc")
+12
View File
@@ -9,6 +9,18 @@ class TextWindow:
def __init__(self, text):
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")
venv_python = os.path.join(BASEDIR, ".venv", "bin", "python")
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
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():
# on systemd systems, the default time is the systemd build time
systemd_path = Path("/lib/systemd/systemd")
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 MIN_DATE
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 time
import functools
from subprocess import Popen, PIPE, STDOUT, TimeoutExpired
from subprocess import Popen, PIPE, TimeoutExpired
import zstandard as zstd
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
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
# runs, so a long lived, chatty child would eventually fill the pipe buffer and block forever.
with tempfile.TemporaryFile() as log_file:
proc = Popen(cmd, env=env, stdout=log_file, stderr=STDOUT)
proc.log_file = log_file
proc = Popen(cmd, env=env, stdout=PIPE, stderr=PIPE)
try:
yield proc
finally:
if proc.poll() is None:
proc.terminate()
try:
yield proc
finally:
if proc.poll() is None:
proc.terminate()
try:
proc.wait(timeout=5)
except TimeoutExpired:
proc.kill()
proc.wait(timeout=5)
except TimeoutExpired:
proc.kill()
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"
+2 -22
View File
@@ -8,15 +8,6 @@ from pathlib import Path
import pytest
try:
int(os.environ.get("DEBUG", "0"))
except ValueError:
os.environ["DEBUG"] = "0"
if platform.system() == "Darwin":
os.environ["SP_HEADLESS_TEST"] = "1"
def _prepend_host_pytest_runtime() -> None:
if platform.system() != "Darwin" or os.getenv("SP_DISABLE_HOST_PYTEST_REDIRECT") == "1":
return
@@ -98,7 +89,8 @@ def openpilot_function_fixture(request):
# ensure the test doesn't change the prefix
assert "OPENPILOT_PREFIX" in os.environ and prefix == os.environ["OPENPILOT_PREFIX"]
manager.manager_cleanup()
# cleanup any started processes
manager.manager_cleanup()
# some processes disable gc for performance, re-enable here
if not gc.isenabled():
@@ -126,9 +118,6 @@ def tici_setup_fixture(request, openpilot_function_fixture):
@pytest.hookimpl(tryfirst=True)
def pytest_collection_modifyitems(config, items):
skipper = pytest.mark.skip(reason="Skipping tici test on PC")
darwin_fake_event_skipper = pytest.mark.skip(reason="Fake socket events are unavailable on macOS")
darwin_tmpfs_skipper = pytest.mark.skip(reason="tmpfs mount tests require Linux")
darwin_proxy_skipper = pytest.mark.skip(reason="Athena local proxy socket test requires Linux select semantics")
for item in items:
if "tici" in item.keywords:
if not TICI:
@@ -141,15 +130,6 @@ def pytest_collection_modifyitems(config, items):
class_property_value = getattr(item.cls, class_property_name)
item.add_marker(pytest.mark.xdist_group(class_property_value))
if platform.system() == "Darwin" and item.path.name in ("test_fuzzy.py", "test_processes.py") and "process_replay" in item.path.parts:
item.add_marker(darwin_fake_event_skipper)
if platform.system() == "Darwin" and item.path.name == "test_git.py" and "updated" in item.path.parts:
item.add_marker(darwin_tmpfs_skipper)
if platform.system() == "Darwin" and item.name == "test_start_local_proxy" and "athena" in item.path.parts:
item.add_marker(darwin_proxy_skipper)
@pytest.hookimpl(trylast=True)
def pytest_configure(config):
+146 -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.
# 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|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|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 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 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|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|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 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 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>|||
|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>|||
|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>|||
|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|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|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|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>|||
|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>|||
|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>|||
|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|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>|||
|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>|||
|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>|||
|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>|||
|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|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|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>|||
|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>||
|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>|||
|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|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|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|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 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 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>|||
|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|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>|||
|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>|||
|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|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 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|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|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 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 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|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 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 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|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 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-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-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 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 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|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 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|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 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 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|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 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 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 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|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|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|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|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|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|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|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 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|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|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 (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 (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 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 (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 (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>|||
|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>|||
|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>||
|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>||
|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>||
|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>|||
|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>|||
|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>||
|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>||
|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>|||
|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>|||
|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>|||
|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>|||
|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 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 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 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 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 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 (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 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|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|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</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</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</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</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</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</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</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|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 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 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 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|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|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|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</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|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</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 (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|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|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|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|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|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</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</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</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 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 (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|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|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 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|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|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|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 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 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 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 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|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 (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 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 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 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 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 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 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 (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 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 (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 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 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|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 (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 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 (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|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 (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 (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|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 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 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 (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>|||
|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>||
|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 (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|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 (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 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 (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|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>||
@@ -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 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 (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 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|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 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 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 (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|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>|||
@@ -326,54 +215,44 @@ 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 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>|||
|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 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>|||
|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|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>||
|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|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,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,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-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>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>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>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>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|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|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|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>|||
|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>|
|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>|||
|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>|||
|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|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|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 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|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|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|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|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|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|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|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|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|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>|||
|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>|||
|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>||
|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|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|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|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|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|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|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>|||
|Š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>|||
|Š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>|||
|Š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>|||
|Š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>|||
|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>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>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>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>|||
|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>|||
|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|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>|
|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>|||
|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>|||
|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>|||
|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|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|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|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|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|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|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|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|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>|||
|Š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)|||
|Š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)|||
|Š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>|||
|Š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|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|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|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|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|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>|||
|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>|||
|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>|||
|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>|||
|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>|||
|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|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 +265,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 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|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 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 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>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 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>|||
@@ -419,91 +298,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 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>||
|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 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 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 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|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 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|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|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|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|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|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-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|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 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 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 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 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 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 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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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>|||
|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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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|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>|||
### 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>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>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>6</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/nissan" target="_blank">Nissan</a>. <br />
<sup>7</sup>In the non-US market, openpilot requires the car to come equipped with EyeSight with Lane Keep Assistance. <br />
<sup>8</sup>Enabling longitudinal control (alpha) will disable all EyeSight functionality, including AEB, LDW, and RAB. <br />
<sup>9</sup>Some 2023 model years have HW4. To check which hardware type your vehicle has, look for <b>Autopilot computer</b> under <b>Software -> Additional Vehicle Information</b> on your vehicle's touchscreen. See <a href="https://www.notateslaapp.com/news/2173/how-to-check-if-your-tesla-has-hardware-4-ai4-or-hardware-3">this page</a> for more information. <br />
<sup>10</sup>See more setup details for <a href="https://github.com/commaai/openpilot/wiki/tesla" target="_blank">Tesla</a>. <br />
<sup>11</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>12</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>13</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
<sup>14</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma four functionality. <br />
<sup>15</sup>Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC. <br />
<sup>16</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br />
<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>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>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>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>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>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 />
## 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?
+10 -56
View File
@@ -4,8 +4,8 @@ This workflow rebuilds StarPilot driving and driver-monitoring artifacts for the
## Safety
- The supported build device is `comma@192.168.3.109`.
- Never run these commands against `192.168.3.110`.
- The supported build device is `comma@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.
- 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/`.
- `logs/`: one remote compilation log per model.
- `results/`: source and artifact checksum records.
- `manifests/`: source `model_names_v22.json` and namespaced release `model_names_v23.json`.
- The v23 manifest and compiled artifacts are published together in the resource repository's `Models` branch.
- `manifests/`: generated `model_names_v22.json`.
## Initialize And Extract
@@ -47,10 +46,7 @@ python3 scripts/model_rebuild_pipeline.py extract \
--base-manifest /path/to/model_names_v21.json
```
The original catalog sources are defined in `scripts/model_source_map_v22.json`.
Recovered late-model and supercombo sources, including RDF2, are defined in
`scripts/model_source_map_v23.json`. The v23 map is intentionally separate so
adding a recovered iteration cannot alter the older model source history.
Source commits are defined in `scripts/model_source_map_v22.json`.
## Compile
@@ -69,7 +65,7 @@ python3 scripts/model_rebuild_pipeline.py compile \
--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:
@@ -92,12 +88,6 @@ For a model that cannot run on the device GPU, compile with the USB AMD GPU atta
./models --lebowski --gpu
```
The ASM2464PD bridge must run the current tinygrad custom firmware from
https://github.com/tinygrad/asm2464pd-firmware. Its USB product string starts
with `custom`; the legacy `USB 3.2 PCIe TinyEnclosure` patch is not compatible
with comma's current external-GPU runtime. Firmware flashing is a separate,
explicit hardware setup step and StarPilot never performs it automatically.
The dynamic flag (`--lebowski` above) sets the output and manifest model ID;
when only one source model is staged, its ONNX filename does not need to match
that ID. Input format and behavior version are inferred. `--external-gpu`
@@ -159,51 +149,15 @@ All four files must be updated together.
## Manifest
The current test branch uses manifest v25 and requests v25 only. Seed the new
manifest from the previous catalog, then replace entries as artifacts are
rebuilt with the pinned runtime:
```bash
cp /path/to/model_names_v24.json /path/to/model_names_v25.json
```
The current tinygrad pin is `f6fc4e3f2c3db5fae1e19cbfbc3ad9fc579a12ae`, from
`openpilot` `origin/master` (`bump tg + TC_MIN_GLOBALS`). StarPilot's
multi-model `modeld` remains in place; do not replace it with upstream's
single-model `modeld`.
For the older namespace migration workflow, generate the base manifest after
compilation and namespace the release artifacts as v23:
Generate v22 after compilation:
```bash
python3 scripts/model_rebuild_pipeline.py manifest \
--base-manifest /path/to/model_names_v21.json
```
```bash
python3 scripts/namespace_model_artifacts.py \
--workspace /Volumes/T5/StarPilot-Model-Rebuild-2026-06-22 \
--base-manifest /Volumes/T5/StarPilot-Model-Rebuild-2026-06-22/manifests/model_names_v22.json \
--manifest-version v23 --suffix 3
```
The namespace command changes IDs such as `tr1422` to `tr14223`, renames the
compiled and upload-ready files, and writes an ID map. It preserves display
names and behavioral versions. The current model manager requests v25 only; the
manifest is fetched from `Models/model_names_v25.json`. Devices still running
the prior branch continue to request their existing manifest version.
After importing newly compiled sources, normalize the release namespace before
copying files into either resource repository:
```bash
python3 scripts/reconcile_v23_artifacts.py \
--workspace /Volumes/T5/StarPilot-Model-Rebuild-2026-06-22
```
This maps recovered source IDs to their v23 release IDs, removes duplicate
macOS metadata files, and adds `rdf23` for Regret Driven Framework V2. It does
not overwrite a conflicting artifact.
The generator preserves existing IDs and behavioral metadata and adds
`deeprl3v2`. Manifest v22 implies the unified single-PKL runtime layout.
Repository-hosted multipart files are discovered by naming convention, so no
size, hash, format, or part-count metadata is required.
@@ -217,6 +171,6 @@ Compilation validates JIT capture/replay, pickle round-trip, finite outputs, met
2. Confirm `modeld` stays running.
3. Confirm finite `modelV2` path, lane-line, lead, pose, and action data.
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
```
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:
+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.
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
@@ -71,10 +71,10 @@ This runs:
- `SP_TICI_SYSROOT=/opt/tici-sysroot`
- `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
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.
@@ -112,6 +112,7 @@ Preferred host-side shorthand commands on this branch:
```bash
./c3
./c4
./raybig
./dev replay
./dev cabana
./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.
Direct script entrypoints are also available:
Legacy direct script entrypoints still exist if needed:
```bash
scripts/launch_ui_c3_desktop.sh
scripts/launch_ui_desktop.sh
scripts/launch_ui_c4_desktop.sh
scripts/launch_ui_raybig_desktop.sh
```
+81 -3
View File
@@ -51,6 +51,8 @@ function agnos_init {
# StarPilot variables
sudo chmod 0777 /cache
sudo rm -f /data/misc/display/color_cal/color_cal /data/misc/display/color_cal/source.sha256
# Check if AGNOS update is required
AGNOS_CURRENT_VERSION="$(< /VERSION)"
AGNOS_UPDATE_REQUIRED=1
@@ -147,10 +149,86 @@ function launch {
while true; do sleep 1; done
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"
# Published trees carry this marker and must never compile on-device.
# Developers can remove it explicitly when working from a source tree.
if [ ! -f "$DIR/prebuilt" ]; then
if [ "$USE_PREBUILT" = "1" ] && [ -f $DIR/prebuilt ] && ! prebuilt_runtime_compatible; then
echo "Prebuilt runtime artifacts are incompatible on this device; rebuilding locally."
USE_PREBUILT=0
fi
sp_launch_timing "prebuilt_compat_done"
if [ "$USE_PREBUILT" != "1" ] || [ ! -f $DIR/prebuilt ]; then
sp_launch_timing "build_start"
./build.py
sp_launch_timing "build_done"
+1 -1
View File
@@ -21,7 +21,7 @@ fi
export QCOM_PRIORITY=12
if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="19.6.16"
export AGNOS_VERSION="12.8.28"
fi
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" "$@"
-3
View File
@@ -21,9 +21,6 @@ static size_t fnv1a_hash(const std::string &str) {
static std::string namespaced_endpoint(std::string endpoint) {
const char *namespace_env = std::getenv("OPENPILOT_ZMQ_NAMESPACE");
if (namespace_env == nullptr || namespace_env[0] == '\0') {
namespace_env = std::getenv("OPENPILOT_PREFIX");
}
if (namespace_env != nullptr && namespace_env[0] != '\0') {
endpoint = std::string(namespace_env) + ":" + endpoint;
}
+4
View File
@@ -15,6 +15,10 @@ const bool MUST_USE_ZMQ = false;
bool messaging_use_zmq(){
if (std::getenv("ZMQ") || MUST_USE_ZMQ) {
if (std::getenv("OPENPILOT_PREFIX")) {
std::cerr << "OPENPILOT_PREFIX not supported with ZMQ backend\n";
assert(false);
}
return true;
}
return false;
Binary file not shown.
Binary file not shown.
+14 -148
View File
@@ -1,36 +1,24 @@
<!--- 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|
|---|---|---|:---:|
|Acura|ADX 2025-26|All|[Upstream](#upstream)|
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|[Upstream](#upstream)|
|Acura|ILX 2019|All|[Upstream](#upstream)|
|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 2017-19|All|[Upstream](#upstream)|
|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 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 2019-21|All|[Upstream](#upstream)|
|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|TLX 2015-17|Advance Package|[Upstream](#upstream)|
|Acura|TLX 2015-17|Advance Package|[Community](#community)|
|Acura|TLX 2018-20|All|[Upstream](#upstream)|
|Acura|TLX 2018-20|All|[Community](#community)|
|Acura|TLX 2021|All|[Upstream](#upstream)|
|Acura|TLX 2022-23|All|[Community](#community)|
|Acura|TLX 2024-25|All|[Upstream](#upstream)|
|Acura|ZDX 2024|All|[Not compatible](#can-bus-security)|
|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)|
@@ -38,54 +26,14 @@
|Audi|A5 2016-24|All|[Not compatible](#flexray)|
|Audi|Q2 2018|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|RS3 2018|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)|
|Buick|LaCrosse 2017-19|Driver Confidence Package 2|[Upstream](#upstream)|
|Buick|LaCrosse ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Buick|LaCrosse US ASCM Harness 2019|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Buick|Regal Essence 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Cadillac|ATS Premium Performance 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Cadillac|CT6 No-ACC 2016-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Cadillac|Escalade 2017|Driver Assist Package|[Upstream](#upstream)|
|Cadillac|Escalade ASCM Harness 2018|Driver Assist Package|[Upstream](#upstream)|
|Cadillac|Escalade ESV 2016|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|Cadillac|Escalade ESV 2019|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|Cadillac|Escalade ESV Platinum ASCM Harness 2019|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|Cadillac|XT4 2023|Driver Assist Package|[Upstream](#upstream)|
|Cadillac|XT4 No-ACC 2023|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Cadillac|XT5 2022|Driver Assist Package|[Upstream](#upstream)|
|Cadillac|XT5 No-ACC 2022|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Cadillac|XT6 2020|Driver Assist Package|[Upstream](#upstream)|
|Chevrolet|Blazer 2019-25|Driver Assist Package|[Upstream](#upstream)|
|Chevrolet|Bolt EV & EUV ACC 2022-23|Premier or Premier Redline Trim without Super Cruise Package|[Upstream](#upstream)|
|Chevrolet|Bolt EV & EUV ACC w Pedal 2022-23|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Bolt EV & EUV No-ACC 2022-23|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Bolt EV No-ACC 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Bolt EV No-ACC 2018-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|[Upstream](#upstream)|
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|[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 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 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 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Chrysler|Pacifica 2021-23|All|[Upstream](#upstream)|
@@ -93,10 +41,8 @@
|Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|comma|body|All|[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)|
|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 2023-24|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|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 Lightning 2022-25|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|Ford|Focus 2018-22|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|Ford|Focus Hybrid 2018-22|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|Ford|Focus 2018|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|Ford|Focus Hybrid 2018|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 2024|All|[Upstream](#upstream)|
@@ -120,14 +65,11 @@
|Ford|Maverick 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
|Ford|Maverick Hybrid 2022|LARIAT Luxury|[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|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 2019-21|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 2018-19|All|[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|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 Electrified 2026|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|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 No-ACC 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|GMC|Yukon No-ACC 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Holden|Astra 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Honda|Accord 2016-17|Honda Sensing|[Upstream](#upstream)|
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|[Dashcam mode](#dashcam)|
|Honda|Accord 2016-17|Honda Sensing|[Community](#community)|
|Honda|Accord 2018-22|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 2023-25|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 (Europe only) 2023|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|CR-V 2015-16|Touring Trim|[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|e 2020|All|[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|HR-V 2019-22|Honda Sensing|[Upstream](#upstream)|
|Honda|HR-V 2023-25|All|[Upstream](#upstream)|
@@ -185,40 +114,27 @@
|Honda|N-Box 2018|All|[Upstream](#upstream)|
|Honda|Odyssey 2018-20|Honda Sensing|[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 2026|All|[Upstream](#upstream)|
|Honda|Pilot 2016-22|Honda Sensing|[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|Ridgeline 2017-25|Honda Sensing|[Upstream](#upstream)|
|Hyundai|Azera 2022|All|[Upstream](#upstream)|
|Hyundai|Azera Hybrid 2019|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|Elantra 2017-18|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 2024-25|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 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|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 (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 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 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 2020|All|[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|Kona 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|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 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 (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 (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|Palisade 2020-22|All|[Upstream](#upstream)|
|Hyundai|Palisade 2023-25|HDA2|[Community](#community)|
|Hyundai|Palisade (with HDA II) 2023-25|Highway Driving Assist II|[Upstream](#upstream)|
|Hyundai|Palisade (without HDA II) 2023-25|Highway Driving Assist|[Upstream](#upstream)|
|Hyundai|Palisade 2023-24|HDA2|[Community](#community)|
|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 2021-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|Sonata 2018-19|Smart Cruise Control (SCC)|[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 (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Staria 2023|All|[Upstream](#upstream)|
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|[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 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 (without HDA II) 2025|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 2019-21|Adaptive Cruise Control (ACC)|[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 (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 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 (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 (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 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 (without HDA II) 2025|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|Niro EV 2019|All|[Upstream](#upstream)|
@@ -310,25 +198,17 @@
|Kia|Optima Hybrid 2017|Advanced Smart Cruise Control|[Dashcam mode](#dashcam)|
|Kia|Optima Hybrid 2019|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 2019|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 2026|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 (without HDA II) 2026|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 2022-23|All|[Upstream](#upstream)|
|Kia|Telluride 2020-22|All|[Upstream](#upstream)|
|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|ES 2017-18|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 2021-23|All|[Upstream](#upstream)|
|Nissan|Altima 2019-20, 2024|ProPILOT Assist|[Upstream](#upstream)|
|Nissan|Leaf 2018-25|ProPILOT Assist|[Upstream](#upstream)|
|Nissan|Leaf Instrument Cluster 2018-25|ProPILOT Assist|[Upstream](#upstream)|
|Nissan|Leaf 2018-23|ProPILOT Assist|[Upstream](#upstream)|
|Nissan|Rogue 2018-20|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)|
@@ -373,36 +252,30 @@
|Ram|2500 2020-24|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 2025|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|Ateca 2016-23|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 2023-25|All|[Upstream](#upstream)|
|Subaru|Ascent 2023|All|[Dashcam mode](#dashcam)|
|Subaru|Crosstrek 2018-19|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|Forester 2017-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|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|Impreza 2017-19|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 2020-22|All|[Upstream](#upstream)|
|Subaru|Legacy 2025|All|[Upstream](#upstream)|
|Subaru|Outback 2015-17|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 2023-24|All|[Upstream](#upstream)|
|Subaru|Outback 2023|All|[Dashcam mode](#dashcam)|
|Subaru|Solterra 2023-25|Any|[Not compatible](#can-bus-security)|
|Subaru|XV 2018-19|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|Kamiq 2021-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|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 HW4) 2024-26|All|[Upstream](#upstream)|
|Tesla|Model S (Pre-AP) 2012-14|All|[Community](#community)|
|Tesla|Model 3 (with HW4) 2024-25|All|[Upstream](#upstream)|
|Tesla|Model X (with HW4) 2024|All|[Dashcam mode](#dashcam)|
|Tesla|Model Y (with HW3) 2020-23|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 Hybrid 2017-19|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|Prius 2016|Toyota Safety Sense P|[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|Sequoia 2023-25|Any|[Not compatible](#can-bus-security)|
|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|Tundra 2022-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 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|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 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
@@ -578,4 +444,4 @@ Toyota, and the GM Global B platform.
All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a
CAN bus isn't the only way that the computers in your car can communicate. Most, if not all, vehicles from the following
manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars
may one day be supported, but we have no immediate plans to support FlexRay.
may one day be supported, but we have no immediate plans to support FlexRay.
+1 -1
View File
@@ -19,7 +19,7 @@ test:
run: codespell {files} -L tge,stdio -S *.dbc
files: git ls-tree -r HEAD --name-only
cpplint:
run: cpplint --exclude=opendbc/safety/tests/misra/cppcheck/ --exclude=opendbc/safety/tests/.venv/ --exclude=opendbc/can/*_pyx.cpp --recursive --quiet --counting=detailed --linelength=240 --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces opendbc/
run: cpplint --exclude=opendbc/safety/tests/misra/cppcheck/ --exclude=opendbc/can/*_pyx.cpp --recursive --quiet --counting=detailed --linelength=240 --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces opendbc/
misra:
run: opendbc/safety/tests/misra/test_misra.sh
-5
View File
@@ -132,7 +132,6 @@ class CANParser:
self.dbc: DBC = DBC(dbc_name)
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.ts_nanos: dict[int | str, dict[str, int]] = {}
self.addresses: set[int] = set()
@@ -167,8 +166,6 @@ class CANParser:
signals_dict = {s: 0.0 for s in signal_names}
dict.__setitem__(self.vl, msg.address, 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.name] = self.vl_all[msg.address]
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_all_addr[sig.name] = state.all_vals[i]
ts_addr[sig.name] = state.timestamps[-1]
self.vl_raw[address] = bytes(dat)
self.vl_raw[state.name] = bytes(dat)
if not bus_empty:
self.last_nonempty_nanos = t
@@ -1,6 +1,5 @@
import copy
from opendbc.can import CANPacker, CANParser
from opendbc.car.honda.hondacan import honda_checksum
class TestCanChecksums:
@@ -91,13 +90,6 @@ class TestCanChecksums:
assert parser.vl['LKAS_HUD']['CHECKSUM'] == std
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'):
"""Test AUTOSAR E2E Profile 2 CRCs"""
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]
torqueOutputCan @8: Float32; # value sent over can to the car
speed @6: Float32; # m/s
lateralControlMode @9: LateralControlMode;
enum LongControlState @0xe40f3a917d908282{
off @0;
@@ -382,13 +381,6 @@ struct CarControl {
stopping @2;
starting @3;
}
enum LateralControlMode {
inactive @0;
torque @1;
angle @2;
torqueRecovering @3;
}
}
struct CruiseControl {
@@ -518,7 +510,6 @@ struct CarParams {
startingState @70 :Bool; # Does this car make use of special starting state
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
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
carVin @38 :Text; # VIN number queried during fingerprinting
@@ -644,8 +635,6 @@ struct CarParams {
fcaGiorgio @32;
rivian @33;
volkswagenMeb @34;
teslaPreAP @35;
volvo @36;
}
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)
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.
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
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 candidate is None and 170 in pt and 188 in pt and msg_211_len in (2, 3):
if msg_211_len == 3:
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,
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 = _normalize_gm_bolt_candidate(candidate, fingerprints, vin)
candidate = _normalize_gm_bolt_candidate(candidate, fingerprints)
candidate = _normalize_gm_volt_candidate(candidate, fingerprints)
candidate = _normalize_forced_candidate(candidate)
fingerprinted_candidate = candidate
+5 -13
View File
@@ -23,11 +23,9 @@ def ecu_log(msg):
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,
require_response=False, diag_request=EXT_DIAG_REQUEST, diag_response=EXT_DIAG_RESPONSE, response_offset=0x8):
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):
"""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.
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.
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:
try:
ecu_log("sending ECU reset before communication control...")
reset_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [RESET_REQUEST], [RESET_RESPONSE],
response_offset=response_offset)
reset_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [RESET_REQUEST], [RESET_RESPONSE])
reset_query.get_data(timeout=timeout)
time.sleep(0.2)
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:
# Enter extended diagnostic session
ecu_log(f"attempt {i+1}/{retry}: diag session...")
query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [diag_request], [diag_response],
response_offset=response_offset)
query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [EXT_DIAG_REQUEST], [EXT_DIAG_RESPONSE])
for _, _ in query.get_data(timeout).items():
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
ecu_log("sending CC...")
cc_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [com_cont_req], [b''],
response_offset=response_offset)
cc_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [com_cont_req], [b''])
cc_response = cc_query.get_data(timeout)
# Log what we got back
cc_success = False
cc_rejected = False
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'}")
# Check for positive response (0x68 = 0x28 + 0x40)
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_log("=== ECU DISABLE REJECTED ===")
return False
elif require_response:
ecu_log("CC response required but none received; retrying...")
continue
else:
# No response - consider it sent (ECU might have stopped responding)
ecu_log("=== ECU DISABLE SENT (no response) ===")
@@ -142,7 +142,6 @@ class CarHarness(EnumBase):
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])
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_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])
+1 -1
View File
@@ -55,7 +55,7 @@ class CAR(Platforms):
EXTRA_HYUNDAI = ExtraPlatformConfig(
[
CommunityCarDocs("Hyundai Palisade 2023-25", package="HDA2"),
CommunityCarDocs("Hyundai Palisade 2023-24", package="HDA2"),
CommunityCarDocs("Kia Telluride 2023-24", package="HDA2"),
],
)
+1 -1
View File
@@ -245,6 +245,7 @@ MIGRATION = {
"KIA SELTOS 2021": HYUNDAI.KIA_SELTOS,
"KIA SPORTAGE 5TH GEN": HYUNDAI.KIA_SPORTAGE_5TH_GEN,
"KIA SPORTAGE 2026": HYUNDAI.KIA_SPORTAGE_2026,
"KIA SPORTAGE HYBRID 2026": HYUNDAI.KIA_SPORTAGE_HEV_2026,
"KIA SORENTO GT LINE 2018": HYUNDAI.KIA_SORENTO,
"KIA SORENTO 4TH GEN": HYUNDAI.KIA_SORENTO_4TH_GEN,
"KIA SORENTO 2024": HYUNDAI.KIA_SORENTO_2024,
@@ -264,7 +265,6 @@ MIGRATION = {
"GENESIS G70 2020": HYUNDAI.GENESIS_G70_2020,
"GENESIS GV70 1ST GEN": HYUNDAI.GENESIS_GV70_1ST_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 G90 2017": HYUNDAI.GENESIS_G90,
"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.values import CarControllerParams, FordFlags, CAR
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
VisualAlert = structs.CarControl.HUDControl.VisualAlert
@@ -82,9 +80,6 @@ class CarController(CarControllerBase):
self.steer_alert_last = False
self.lead_distance_bars_last = None
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):
can_sends = []
@@ -96,9 +91,6 @@ class CarController(CarControllerBase):
steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw)
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
if self.ford_lateral is not None:
self.ford_lateral.update_inputs()
### acc buttons ###
if CC.cruiseControl.cancel:
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,
direction=direction, ramp_type=ramp_type, curvature=-self.apply_curvature_last))
else:
lateral_mode = self.ford_lateral.mode
lateral_mode_ready = lateral_mode == self.ford_lateral_announced_mode
# Keep the original Ford path available without changing its command behavior.
if lateral_mode == FordLateralMode.native:
if (self.frame % CarControllerParams.STEER_STEP) == 0:
if not lateral_mode_ready:
self.apply_curvature_last = 0.0
apply_curvature = 0.0
elif self.CP.carFingerprint in (CAR.FORD_BRONCO_SPORT_MK1, CAR.FORD_F_150_MK14):
self.anti_overshoot_curvature_last = anti_overshoot(
actuators.curvature, self.anti_overshoot_curvature_last, CS.out.vEgoRaw)
apply_curvature = self.anti_overshoot_curvature_last
else:
apply_curvature = actuators.curvature
current_curvature = -CS.out.yawRate / max(CS.out.vEgoRaw, 0.1)
self.apply_curvature_last = apply_ford_curvature_limits(
apply_curvature, self.apply_curvature_last, current_curvature,
CS.out.vEgoRaw, 0., CC.latActive and lateral_mode_ready, self.CP)
if self.CP.flags & FordFlags.CANFD:
mode = 1 if CC.latActive and lateral_mode_ready else 0
counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10
can_sends.append(fordcan.create_lat_ctl2_msg(
self.packer, self.CAN, mode, 0., 0., -self.apply_curvature_last, 0., counter))
else:
can_sends.append(fordcan.create_lat_ctl_msg(
self.packer, self.CAN, CC.latActive and lateral_mode_ready, 0., 0., -self.apply_curvature_last, 0.))
elif (self.frame % CarControllerParams.STEER_STEP) == 0:
if not lateral_mode_ready:
lateral = FordLateralResult(shadow_curvature=self.ford_lateral._current_curvature(CS))
elif lateral_mode == FordLateralMode.angle:
lateral = self.ford_lateral.update_angle(CC, CS, actuators)
# send steer msg at 20Hz
if (self.frame % CarControllerParams.STEER_STEP) == 0:
# Bronco and some other cars consistently overshoot curv requests
# Apply some deadzone + smoothing convergence to avoid oscillations
if 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:
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:
# 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
can_sends.append(starpilot_fordcan.create_lat_ctl2_msg(
self.packer, self.CAN, 1 if lateral.active else 0,
lateral.ramp_type, lateral.precision_type,
-lateral.path_offset, -lateral.path_angle,
-lateral.curvature, -lateral.curvature_rate, counter))
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(starpilot_fordcan.create_lat_ctl_msg(
self.packer, self.CAN, lateral.active,
lateral.ramp_type, lateral.precision_type,
-lateral.path_offset, -lateral.path_angle,
-lateral.curvature, -lateral.curvature_rate))
can_sends.append(fordcan.create_lat_ctl_msg(self.packer, self.CAN, CC.latActive, 0., 0., -self.apply_curvature_last, 0.))
# send lka msg at 33Hz
if (self.frame % CarControllerParams.LKA_STEP) == 0:
if lateral_mode == FordLateralMode.native:
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN))
else:
angle_mode = lateral_mode == FordLateralMode.angle
shadow_curvature = -self.ford_lateral._current_curvature(CS)
if angle_mode:
shadow_curvature = -self.ford_shadow_curvature
can_sends.append(starpilot_fordcan.create_lka_msg(
self.packer, self.CAN, angle_mode=angle_mode, shadow_curvature=shadow_curvature))
self.ford_lateral_announced_mode = lateral_mode
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN))
### longitudinal control ###
# send acc msg at 50Hz
@@ -255,15 +215,9 @@ class CarController(CarControllerBase):
if (self.frame % CarControllerParams.ACC_UI_STEP) == 0 or send_ui:
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,
fcw_alert, CS.out.cruiseState.standstill, show_distance_bars,
hud_control, CS.acc_tja_status_stock_values,
hands_free_cluster))
hud_control, CS.acc_tja_status_stock_values))
self.main_on_last = main_on
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.ford.fordcan import CanBus
from opendbc.car.ford.values import DBC, CarControllerParams, FordFlags
from opendbc.car.gps import get_car_gps_config
from opendbc.car.interfaces import CarStateBase
ButtonType = structs.CarState.ButtonEvent.Type
@@ -17,71 +16,26 @@ class CarState(CarStateBase):
super().__init__(CP, FPCP)
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
if CP.transmissionType == TransmissionType.automatic:
if CP.flags & FordFlags.CANFD:
self.shifter_values = can_define.dv["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"]
elif CP.flags & FordFlags.ALT_STEER_ANGLE:
self.shifter_values = can_define.dv["TransGearData"]["GearLvrPos_D_Actl"]
else:
self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"]
self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"]
self.distance_button = 0
self.lc_button = 0
self.lkas_available = False
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:
cp = can_parsers[Bus.pt]
cp_cam = can_parsers[Bus.cam]
self._update_car_gps(cp)
ret = structs.CarState()
if self.CP.flags & FordFlags.ALT_STEER_ANGLE:
sensors_valid = (
int((cp.vl["ParkAid_Data"]["ExtSteeringAngleReq2"] + 1000) * 10) not in (32766, 32767)
and cp.vl["ParkAid_Data"]["EPASExtAngleStatReq"] == 0
and cp.vl["ParkAid_Data"]["ApaSys_D_Stat"] in (0, 1)
)
ret.vehicleSensorsInvalid = not sensors_valid
else:
# The ABS can recalibrate the steering pinion offset briefly after startup.
ret.vehicleSensorsInvalid = cp.vl["SteeringPinion_Data"]["StePinCompAnEst_D_Qf"] != 3
# Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement
# The vehicle usually recovers out of this state within a minute of normal driving
ret.vehicleSensorsInvalid = cp.vl["SteeringPinion_Data"]["StePinCompAnEst_D_Qf"] != 3
# car speed
ret.vEgoRaw = cp.vl["BrakeSysFeatures"]["Veh_V_ActlBrk"] * CV.KPH_TO_MS
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.standstill = cp.vl["DesiredTorqBrk"]["VehStop_D_Stat"] == 1
@@ -94,14 +48,7 @@ class CarState(CarStateBase):
ret.parkingBrake = cp.vl["DesiredTorqBrk"]["PrkBrkStatus"] in (1, 2)
# steering wheel
if self.CP.flags & FordFlags.ALT_STEER_ANGLE:
steering_angle_init = cp.vl["SteeringPinion_Data_Alt"]["StePinRelInit_An_Sns"]
if not ret.vehicleSensorsInvalid:
steering_angle_est = cp.vl["ParkAid_Data"]["ExtSteeringAngleReq2"]
self.steering_angle_offset_deg = steering_angle_est - steering_angle_init
ret.steeringAngleDeg = steering_angle_init + self.steering_angle_offset_deg
else:
ret.steeringAngleDeg = cp.vl["SteeringPinion_Data"]["StePinComp_An_Est"]
ret.steeringAngleDeg = cp.vl["SteeringPinion_Data"]["StePinComp_An_Est"]
ret.steeringTorque = cp.vl["EPAS_INFO"]["SteeringColumnTorque"]
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE, 5)
ret.steerFaultTemporary = cp.vl["EPAS_INFO"]["EPAS_Failure"] == 1
@@ -110,12 +57,10 @@ class CarState(CarStateBase):
if self.CP.flags & FordFlags.CANFD:
# 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 |= self.lateral_control_status not in (1, 2, 3)
ret.steerFaultTemporary |= cp.vl["Lane_Assist_Data3_FD1"]["LatCtlSte_D_Stat"] not in (1, 2, 3)
# cruise state
is_metric = cp.vl["INSTRUMENT_PANEL"]["METRIC_UNITS"] == 1 if not self.CP.flags & FordFlags.CANFD else \
cp_cam.vl["IPMA_Data2"]["IsaVLimUnit_D_Rq"] == 1
is_metric = cp.vl["INSTRUMENT_PANEL"]["METRIC_UNITS"] == 1 if not self.CP.flags & FordFlags.CANFD else False
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.available = cp.vl["EngBrakeData"]["CcStat_D_Actl"] in (3, 4, 5)
@@ -127,12 +72,7 @@ class CarState(CarStateBase):
# gear
if self.CP.transmissionType == TransmissionType.automatic:
if self.CP.flags & FordFlags.CANFD:
gear = self.shifter_values.get(cp.vl["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"])
elif self.CP.flags & FordFlags.ALT_STEER_ANGLE:
gear = self.shifter_values.get(cp.vl["TransGearData"]["GearLvrPos_D_Actl"])
else:
gear = self.shifter_values.get(cp.vl["PowertrainData_10"]["TrnRng_D_Rq"])
gear = self.shifter_values.get(cp.vl["PowertrainData_10"]["TrnRng_D_Rq"])
ret.gearShifter = self.parse_gear_shifter(gear)
elif self.CP.transmissionType == TransmissionType.manual:
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.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
@staticmethod
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 {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CanBus(CP).main),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, CanBus(CP).camera),
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).main),
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',
],
(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-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',
@@ -26,21 +24,6 @@ FW_VERSIONS = {
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: {
(Ecu.eps, 0x730, None): [
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: {
(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-FA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.abs, 0x760, None): [
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',
],
(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-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: {
(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-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',
@@ -124,7 +96,6 @@ FW_VERSIONS = {
],
(Ecu.abs, 0x760, None): [
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): [
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: {
(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-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',
@@ -166,11 +136,8 @@ FW_VERSIONS = {
},
CAR.FORD_F_150_LIGHTNING_MK1: {
(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'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'TL38-2D053-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x706, None): [
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',
],
(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'RB5T-14D049-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(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',
],
},
@@ -201,8 +164,6 @@ FW_VERSIONS = {
b'LK9C-2D053-CN\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(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',
],
(Ecu.fwdCamera, 0x706, None): [
@@ -213,42 +174,15 @@ FW_VERSIONS = {
CAR.FORD_FOCUS_MK4: {
(Ecu.eps, 0x730, None): [
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): [
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): [
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): [
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: {
@@ -273,25 +207,17 @@ FW_VERSIONS = {
},
CAR.FORD_RANGER_MK2: {
(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'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'RB3C-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(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-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'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',
],
(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',
],
(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,
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
assist status.
@@ -197,8 +197,6 @@ def create_acc_ui_msg(packer, CAN: CanBus, CP, main_on: bool, enabled: bool, fcw
status = 3 # ActiveInterventionLeft
elif hud_control.rightLaneDepart:
status = 4 # ActiveInterventionRight
elif hands_free_cluster:
status = 7 # Hands-free assistance display
else:
status = 2 # Active
elif main_on:
+4 -9
View File
@@ -31,13 +31,12 @@ class CarInterface(CarInterfaceBase):
ret.radarUnavailable = Bus.radar not in DBC[candidate]
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.steerAtStandstill = True
ret.longitudinalTuning.kiBP = [0.]
ret.longitudinalTuning.kiV = [0.5]
ret.longitudinalTuning.kpV = [0.]
if not ret.radarUnavailable and DBC[candidate][Bus.radar] == RADAR.DELPHI_MRR:
# average of 33.3 Hz radar timestep / 4 scan modes = 60 ms
@@ -45,19 +44,15 @@ class CarInterface(CarInterfaceBase):
ret.radarDelay = 0.06
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)]
if CAN.main >= 4:
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
ret.safetyConfigs = cfgs
ret.alphaLongitudinalAvailable = True
ret.openpilotLongitudinalControl = bool(alpha_long)
if ret.openpilotLongitudinalControl:
ret.alphaLongitudinalAvailable = ret.radarUnavailable
if alpha_long or not ret.radarUnavailable:
ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.LONG_CONTROL.value
ret.openpilotLongitudinalControl = True
if ret.flags & FordFlags.CANFD:
ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.CANFD.value
@@ -1,5 +1,4 @@
import numpy as np
from collections import deque
from typing import cast
from collections import defaultdict
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_MIN_LONG_RANGE_DIST = 30 # meters
DELPHI_MRR_CLUSTER_THRESHOLD = 5 # meters, lateral distance and relative velocity are weighted
STEER_ASSIST_DATA_ADDR = 0x3D7
@dataclass
@@ -91,17 +89,12 @@ def _create_delphi_mrr_radar_can_parser(CP) -> CANParser:
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):
def __init__(self, CP):
super().__init__(CP)
self.points: list[list[float]] = []
self.clusters: list[Cluster] = []
self.v_rel_history = deque(maxlen=20)
self.updated_messages = set()
self.track_id = 0
@@ -118,9 +111,6 @@ class RadarInterface(RadarInterfaceBase):
elif self.radar == RADAR.DELPHI_MRR:
self.rcp = _create_delphi_mrr_radar_can_parser(CP)
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:
raise ValueError(f"Unsupported radar: {self.radar}")
@@ -145,45 +135,10 @@ class RadarInterface(RadarInterfaceBase):
_update = self._update_delphi_mrr(ret)
if not _update:
return None
elif self.radar == RADAR.STEER_ASSIST_DATA:
self._update_steer_assist()
ret.points = list(self.pts.values())
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):
for ii in sorted(self.updated_messages):
cpt = self.rcp.vl[ii]
@@ -1,19 +1,12 @@
import random
from collections.abc import Iterable
from types import SimpleNamespace
from hypothesis import settings, given, strategies as st
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.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, FordSafetyFlags, get_platform_codes, match_vin_to_car
from opendbc.car.ford.values import CAR, FW_QUERY_CONFIG, FW_PATTERN, get_platform_codes
from opendbc.car.ford.fingerprints import FW_VERSIONS
Ecu = CarParams.Ecu
@@ -27,7 +20,6 @@ ECU_ADDRESSES = {
Ecu.engine: 0x7E0, # Powertrain Control Module (PCM)
Ecu.shiftByWire: 0x732, # Gear Shift Module (GSM)
Ecu.debug: 0x7D0, # Accessory Protocol Interface Module (APIM)
Ecu.hud: 0x720, # Instrument Cluster Module (ICM)
}
@@ -49,16 +41,6 @@ ECU_PART_NUMBER = {
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):
for (ecu, addr, subaddr) in FW_QUERY_CONFIG.extra_ecus:
assert ecu in ECU_ADDRESSES, "Unknown ECU"
@@ -68,13 +50,10 @@ class TestFordFW:
@parameterized.expand(FW_VERSIONS.items())
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():
assert ecu in ECU_ADDRESSES, "Unknown ECU"
assert ecu in ECU_PART_NUMBER, "Unexpected ECU"
assert addr == ECU_ADDRESSES[ecu], "ECU address mismatch"
assert subaddr is None, "Unexpected ECU subaddress"
if ecu not in ECU_PART_NUMBER:
continue
for fw in fws:
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"}
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"
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.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
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
@@ -54,15 +53,11 @@ class FordFlags(IntFlag):
# Static flags
CANFD = 1
LKA_STEERING = 2
ALT_STEER_ANGLE = 4
HEV_CLUSTER_DATA = 8
HEV_BATTERY_DATA = 16
class RADAR:
DELPHI_ESR = 'ford_fusion_2018_adas'
DELPHI_MRR = 'FORD_CADS'
STEER_ASSIST_DATA = 'ford_lincoln_base_pt'
class Footnote(Enum):
@@ -92,10 +87,6 @@ class FordCarDocs(CarDocs):
@dataclass
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: {
Bus.pt: 'ford_lincoln_base_pt',
Bus.radar: RADAR.DELPHI_MRR,
@@ -115,7 +106,6 @@ class FordPlatformConfig(PlatformConfig):
class FordCANFDPlatformConfig(FordPlatformConfig):
dbc_dict: DbcDict = field(default_factory=lambda: {
Bus.pt: 'ford_lincoln_base_pt',
Bus.radar: RADAR.STEER_ASSIST_DATA,
})
def init(self):
@@ -132,26 +122,17 @@ class FordLKASteeringPlatformConfig(FordPlatformConfig):
@dataclass
class FordF150LightningPlatform(FordCANFDPlatformConfig):
pass
def init(self):
super().init()
MY_2020, MY_2021, MY_2022, MY_2023, MY_2024, MY_2025 = 'L', 'M', 'N', 'P', 'R', 'S'
F150_VDS_CODES = {'F1C', 'F1E', 'W1C', 'W1E', 'X1C', 'X1E', 'W1R', 'W1P', 'W1S', 'W1T'}
F150_ELECTRIC_CODES = {'L', 'V'}
MACH_E_VDS_CODES = {'K1R', 'K1S', 'K2S', 'K3R', 'K3S', 'K4S'}
# Don't show in docs until this issue is resolved. See https://github.com/commaai/openpilot/issues/30302
self.car_docs = []
class CAR(Platforms):
FORD_BRONCO_SPORT_MK1 = FordPlatformConfig(
[FordCarDocs("Ford Bronco Sport 2021-24")],
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(
[
@@ -159,7 +140,6 @@ class CAR(Platforms):
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),
wmis={'1FM'}, vds_codes={'CU0', 'CU9'}, years={MY_2020, MY_2021, MY_2022},
)
FORD_ESCAPE_MK4_5 = FordCANFDPlatformConfig(
[
@@ -168,7 +148,6 @@ class CAR(Platforms):
FordCarDocs("Ford Kuga Plug-in Hybrid 2024", "All"),
],
CarSpecs(mass=1750, wheelbase=2.71, steerRatio=16.7),
wmis={'1FM'}, vds_codes={'CU0', 'CU9'}, years={MY_2023, MY_2024},
)
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
],
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(
[FordCarDocs("Ford Expedition 2022-24", "Co-Pilot360 Assist 2.0", hybrid=False)],
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(
[FordCarDocs("Ford F-150 2021-23", "Co-Pilot360 Assist 2.0", hybrid=True)],
CarSpecs(mass=3334, wheelbase=3.99, steerRatio=17.0),
wmis={'1FT'}, vds_codes=F150_VDS_CODES, years={MY_2021, MY_2022, MY_2023},
CarSpecs(mass=2000, wheelbase=3.69, steerRatio=17.0),
)
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),
wmis={'1FT'}, vds_codes=F150_VDS_CODES, years={MY_2022, MY_2023, MY_2024, MY_2025},
)
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),
)
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(
[
FordCarDocs("Ford Maverick 2022", "LARIAT Luxury", hybrid=True),
FordCarDocs("Ford Maverick 2023-24", "Co-Pilot360 Assist", hybrid=True),
],
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(
[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
wmis={'3FM'}, vds_codes=MACH_E_VDS_CODES, years={MY_2021, MY_2022, MY_2023, MY_2024},
)
FORD_RANGER_MK2 = FordCANFDPlatformConfig(
[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),
wmis={'1FT'}, vds_codes={'ER4'}, years={MY_2024},
)
FORD_TRANSIT_MK5 = FordLKASteeringPlatformConfig(
[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):
candidates.add(candidate)
return candidates or match_vin_to_car(vin)
def match_vin_to_car(vin: str) -> set[str]:
if not is_valid_vin(vin):
return set()
vin_obj = Vin(vin)
vds = vin[3:7]
model_year = vin[9]
candidates = {platform for platform in CAR if vin_obj.wmi in platform.config.wmis and
model_year in platform.config.years and
any(code in vds for code in platform.config.vds_codes)}
if {CAR.FORD_F_150_MK14, CAR.FORD_F_150_LIGHTNING_MK1} & candidates:
electric = vin[7] in F150_ELECTRIC_CODES
candidates.discard(CAR.FORD_F_150_MK14 if electric else CAR.FORD_F_150_LIGHTNING_MK1)
return {str(candidate) for candidate in candidates}
return candidates
# 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
ASBUILT_BLOCKS: list[tuple[int, list]] = [
(1, [Ecu.debug, Ecu.fwdCamera, Ecu.eps, Ecu.hud]),
(2, [Ecu.abs, Ecu.debug, Ecu.eps, Ecu.hud]),
(3, [Ecu.abs, Ecu.debug, Ecu.eps, Ecu.hud]),
(4, [Ecu.debug, Ecu.fwdCamera, Ecu.hud]),
(1, [Ecu.debug, Ecu.fwdCamera, Ecu.eps]),
(2, [Ecu.abs, Ecu.debug, Ecu.eps]),
(3, [Ecu.abs, Ecu.debug, Ecu.eps]),
(4, [Ecu.debug, Ecu.fwdCamera]),
(5, [Ecu.debug]),
(6, [Ecu.debug]),
(7, [Ecu.debug]),
@@ -348,13 +297,13 @@ FW_QUERY_CONFIG = FwQueryConfig(
Request(
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST],
[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,
),
Request(
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST],
[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,
auxiliary=True,
),
@@ -371,9 +320,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
# Note: We are unlikely to get a response from behind the gateway
(Ecu.shiftByWire, 0x732, None), # Gear Shift 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
match_fw_to_car_fuzzy=match_fw_to_car_fuzzy,
)
@@ -101,7 +101,6 @@ class Request:
@dataclass
class FwQueryConfig:
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
# Overrides and removes from essential ecus for specific models and ecus (exact matching)
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,
# 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
# 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):
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
if len(self.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()
candidates = {c: f for c, f in FW_VERSIONS.items() if
is_brand(MODEL_TO_BRAND[c], match_brand) and
c not in FW_QUERY_CONFIGS[MODEL_TO_BRAND[c]].fuzzy_only_platforms}
is_brand(MODEL_TO_BRAND[c], match_brand)}
for candidate, fws in candidates.items():
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
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
if len(r.whitelist_ecus) == 0 or ecu_type in r.whitelist_ecus:
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
for brand, config, r in REQUESTS:
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:
brand_rx_addrs[brand].add((uds.get_rx_addr_for_tx_addr(ecu[1], r.rx_offset), ecu[2]))
+3 -45
View File
@@ -69,9 +69,6 @@ TRUCK_LONG_SMOOTH_CARS = {
TRUCK_FRICTION_BRAKE_ENGAGE = 40
TRUCK_FRICTION_BRAKE_RELEASE = 8
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 = {
CAR.CHEVROLET_BLAZER,
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:
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]))
mid_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.97, 0.91, 0.85, 0.85]))
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.79]))
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
mid_scale += (1.0 - mid_scale) * follow_relief
@@ -235,27 +232,6 @@ def shape_truck_positive_accel(accel: float, v_ego: float, enabled: bool,
return accel
def smooth_truck_follow_accel(accel: float, previous_accel: float, v_ego: float,
enabled: bool, lead_visible: bool, stopping: bool) -> float:
if (
not enabled or not lead_visible or stopping or v_ego < 25.0 or
accel > TRUCK_FOLLOW_MICRO_ACCEL_MAX or accel < TRUCK_FOLLOW_MICRO_ACCEL_MIN or
previous_accel > TRUCK_FOLLOW_MICRO_ACCEL_MAX or previous_accel < TRUCK_FOLLOW_MICRO_ACCEL_MIN
):
return accel
max_delta = TRUCK_FOLLOW_MICRO_ACCEL_SLEW * DT_CTRL * 4
return previous_accel + float(np.clip(accel - previous_accel, -max_delta, max_delta))
def shape_truck_pitch_accel(pitch_accel: float, v_ego: float, enabled: bool) -> float:
if not enabled:
return pitch_accel
scale = float(np.interp(v_ego, [8.0, 15.0, 25.0, 35.0], [0.60, 0.45, 0.30, 0.25]))
return pitch_accel * scale
def shape_truck_friction_brake(apply_brake: int, accel_cmd: float, stopping: bool, active: bool) -> tuple[int, bool]:
if apply_brake <= 0:
return 0, False
@@ -508,10 +484,6 @@ class CarController(CarControllerBase):
self.xt4_cc_button_burst_last_counter = -1
self.xt4_cc_button_observed_counter = -1
self.xt4_cc_button_counter_frame = 0
self.gm_cc_last_direction_button = CruiseButtons.INIT
self.gm_cc_last_direction_frame = 0
self.gm_cc_pending_reverse_button = CruiseButtons.INIT
self.gm_cc_pending_reverse_frame = 0
self.lka_steering_cmd_counter = 0
self.lka_icon_status_last = (False, False)
@@ -573,7 +545,6 @@ class CarController(CarControllerBase):
self.bolt_acc_pedal_friction_release_frames = 0
self.bolt_acc_pedal_friction_low_speed_active = False
self.truck_friction_brake_active = False
self.truck_follow_accel = 0.0
def _reset_volt_one_pedal(self):
self.volt_one_pedal_pid.reset()
@@ -995,12 +966,10 @@ class CarController(CarControllerBase):
self.regen_release_counter = 0
self.regen_min_on_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):
stop_accel = getattr(starpilot_toggles, "stopAccel", self.CP.stopAccel)
self.apply_gas = self.params.INACTIVE_REGEN
self.apply_brake = int(min(-100 * stop_accel, self.params.MAX_BRAKE))
self.truck_follow_accel = 0.0
else:
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))
@@ -1047,7 +1016,6 @@ class CarController(CarControllerBase):
getattr(self.CP, "transmissionType", None) == TransmissionType.automatic and
not self.CP.enableGasInterceptorDEPRECATED
)
accel_due_to_pitch = shape_truck_pitch_accel(accel_due_to_pitch, CS.out.vEgo, truck_long_smoothing)
accel_input = actuators.accel + accel_due_to_pitch
if truck_long_smoothing:
accel_input = shape_truck_positive_accel(
@@ -1059,16 +1027,6 @@ class CarController(CarControllerBase):
)
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))
scaled_torque = torque + self.params.ZERO_GAS
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 DT_CTRL
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.gm.values import (
ALT_ACCS,
@@ -105,31 +104,6 @@ class CarState(CarStateBase):
self.lkas_enabled = 0
self.pcm_acc_status = AccState.OFF
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]):
if not self.CP.pcmCruise:
@@ -145,8 +119,6 @@ class CarState(CarStateBase):
cam_cp = can_parsers[Bus.cam]
loopback_cp = can_parsers[Bus.loopback]
self._update_car_gps(pt_cp)
ret = structs.CarState()
volt_like = {
@@ -456,9 +428,6 @@ class CarState(CarStateBase):
@staticmethod
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 = {
CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_2019,
@@ -482,7 +451,6 @@ class CarState(CarStateBase):
("PSCMSteeringAngle", 100),
("ECMAcceleratorPos", 80),
("SportMode", 0),
*gps_messages,
]
prndl2_rate = 10 if CP.carFingerprint in kaofui_state_cars else 40
+15 -14
View File
@@ -30,20 +30,20 @@ FINGERPRINTS = {
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
}],
CAR.CHEVROLET_VOLT_CC: [
# Captured no-ACC Volt fingerprints for OBD-C/L&P harness installations
# 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
},
{
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
{
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.CHEVROLET_VOLT_CC: [
# FIXME: Need a message to distinguish flashed from non-flashed
# 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
# },
# {
# 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
# {
# 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: [{
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({
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_CC: FINGERPRINTS[CAR.CHEVROLET_VOLT],
CAR.GMC_ACADIA_ASCM: FINGERPRINTS[CAR.GMC_ACADIA],
CAR.CHEVROLET_MALIBU_ASCM: FINGERPRINTS[CAR.CHEVROLET_MALIBU],
CAR.CADILLAC_ESCALADE_ASCM: FINGERPRINTS[CAR.CADILLAC_ESCALADE],
+11 -63
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.common.conversions import Conversions as CV
from opendbc.car.gm.values import CAR, CanBus, CruiseButtons, GMFlags
@@ -20,14 +20,6 @@ MALIBU_BUTTON_MAP = {
ACC_CRUISE_STATE_ADAPTIVE = 2
XT4_CC_BUTTON_BURST_FRAMES = 6
XT4_CC_BUTTON_COUNTER_DELAY_FRAMES = 1
BOLT_CC_BUTTON_CARS = {
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
CAR.CHEVROLET_BOLT_CC_2022_2023,
}
BOLT_CC_TARGET_DEADBAND_MPH = 0.75
BOLT_CC_REVERSE_CONFIRM_S = 0.6
BOLT_CC_DIRECTION_MEMORY_S = 1.5
def malibu_phase_map_for_button(button):
@@ -306,65 +298,26 @@ def create_lka_icon_command(bus, active, critical, steer):
return CanData(0x104c006c, dat, bus)
def stabilize_bolt_cc_button(controller, CP, requested_button):
if CP.carFingerprint not in BOLT_CC_BUTTON_CARS:
return requested_button
direction_buttons = (CruiseButtons.RES_ACCEL, CruiseButtons.DECEL_SET)
if requested_button not in direction_buttons:
controller.gm_cc_pending_reverse_button = CruiseButtons.INIT
return requested_button
last_button = getattr(controller, "gm_cc_last_direction_button", CruiseButtons.INIT)
last_frame = getattr(controller, "gm_cc_last_direction_frame", -int(BOLT_CC_DIRECTION_MEMORY_S / DT_CTRL) - 1)
recently_sent = (controller.frame - last_frame) * DT_CTRL <= BOLT_CC_DIRECTION_MEMORY_S
reversing_to_accel = (last_button == CruiseButtons.DECEL_SET and
requested_button == CruiseButtons.RES_ACCEL and recently_sent)
if reversing_to_accel:
pending_button = getattr(controller, "gm_cc_pending_reverse_button", CruiseButtons.INIT)
if pending_button != requested_button:
controller.gm_cc_pending_reverse_button = requested_button
controller.gm_cc_pending_reverse_frame = controller.frame
return CruiseButtons.INIT
pending_frame = getattr(controller, "gm_cc_pending_reverse_frame", controller.frame)
if (controller.frame - pending_frame) * DT_CTRL < BOLT_CC_REVERSE_CONFIRM_S:
return CruiseButtons.INIT
controller.gm_cc_pending_reverse_button = CruiseButtons.INIT
return requested_button
def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggles):
accel = actuators.accel
v_ego = CS.out.vEgo
cruise_btn = CruiseButtons.INIT
rate = 1 if abs(accel) <= 0.15 else 0.2
is_metric = getattr(starpilot_toggles, "is_metric", False)
ms_convert = CV.MS_TO_KPH if is_metric else CV.MS_TO_MPH
ms_convert = CV.MS_TO_KPH if getattr(starpilot_toggles, "is_metric", False) else CV.MS_TO_MPH
speed_setpoint = int(round(CS.out.cruiseState.speed * ms_convert))
projected_setpoint = (v_ego * 1.01 + 3 * accel) * ms_convert
desired_setpoint = int(round(projected_setpoint))
bolt_cc = CS.CP.carFingerprint in BOLT_CC_BUTTON_CARS
target_deadband = BOLT_CC_TARGET_DEADBAND_MPH * (CV.MPH_TO_KPH if is_metric else 1.0) if bolt_cc else 0.0
comparison_setpoint = projected_setpoint if bolt_cc else desired_setpoint
desired_setpoint = int(round((v_ego * 1.01 + 3 * accel) * ms_convert))
if CS.CP.minEnableSpeed - (desired_setpoint / ms_convert) > 3.25:
cruise_btn = CruiseButtons.CANCEL
elif comparison_setpoint < speed_setpoint - target_deadband and speed_setpoint > CS.CP.minEnableSpeed * ms_convert + 1:
cruise_btn = CruiseButtons.DECEL_SET
elif comparison_setpoint > speed_setpoint + target_deadband:
cruise_btn = CruiseButtons.RES_ACCEL
cruise_btn = stabilize_bolt_cc_button(controller, CS.CP, cruise_btn)
if cruise_btn == CruiseButtons.CANCEL:
controller.apply_speed = 0
elif cruise_btn == CruiseButtons.DECEL_SET:
elif desired_setpoint < speed_setpoint and speed_setpoint > CS.CP.minEnableSpeed * ms_convert + 1:
cruise_btn = CruiseButtons.DECEL_SET
controller.apply_speed = speed_setpoint - 1
elif cruise_btn == CruiseButtons.RES_ACCEL:
elif desired_setpoint > speed_setpoint:
cruise_btn = CruiseButtons.RES_ACCEL
controller.apply_speed = speed_setpoint + 1
else:
cruise_btn = CruiseButtons.INIT
controller.apply_speed = speed_setpoint
if CS.CP.carFingerprint == CAR.CADILLAC_XT4_CC:
@@ -407,9 +360,6 @@ def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggl
# Or bus 2, since we're forwarding... but I think it does
if (cruise_btn != CruiseButtons.INIT) and ((controller.frame - controller.last_button_frame) * DT_CTRL > rate):
controller.last_button_frame = controller.frame
if bolt_cc and cruise_btn in (CruiseButtons.RES_ACCEL, CruiseButtons.DECEL_SET):
controller.gm_cc_last_direction_button = cruise_btn
controller.gm_cc_last_direction_frame = controller.frame
if CS.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
phase_map = malibu_phase_map_for_button(cruise_btn)
if phase_map:
@@ -420,11 +370,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
msgs = [create_buttons(packer, CanBus.POWERTRAIN, idx, cruise_btn)]
# A camera-forward Volt CC install needs the button spoof on both sides.
# The OBD-C/L&P gateway variant has no camera bus and remains PT-only.
if (CS.CP.carFingerprint == CAR.CHEVROLET_VOLT_CC and
getattr(CS.CP, "networkLocation", None) == structs.CarParams.NetworkLocation.fwdCamera and
not (CS.CP.flags & GMFlags.NO_CAMERA.value)):
# Flashed camera-forward Volt CC installs also need the button spoof on the
# camera side. Removed-camera installs set NO_CAMERA and keep this PT-only.
if CS.CP.carFingerprint == CAR.CHEVROLET_VOLT_CC and not (CS.CP.flags & GMFlags.NO_CAMERA.value):
msgs.append(create_buttons(packer, CanBus.CAMERA, idx, cruise_btn))
return msgs
else:
+2 -9
View File
@@ -70,10 +70,6 @@ NON_LINEAR_TORQUE_PARAMS = {
"left": [1.525, 1.05, 0.155, 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 = {
@@ -273,6 +269,7 @@ class CarInterface(CarInterfaceBase):
kaofui_camera_cars = {
CAR.CHEVROLET_VOLT_CAMERA,
CAR.CHEVROLET_VOLT_CC,
CAR.CHEVROLET_MALIBU_HYBRID_CC,
}
bolt_cc_camera_cars = {
@@ -606,7 +603,6 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalTuning.kpV = [0.095, 0.085, 0.065, 0.050]
ret.longitudinalTuning.kiV = [0.07, 0.10, 0.15, 0.24]
ret.longitudinalTuning.kfDEPRECATED = 0.20
ret.longitudinalActuatorDelay = 0.6
else:
ret.longitudinalTuning.kfDEPRECATED = 0.25
@@ -684,8 +680,6 @@ class CarInterface(CarInterfaceBase):
if candidate in CC_ONLY_CAR:
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]:
ret.flags |= GMFlags.FORCE_BRAKE_C9.value
@@ -699,7 +693,7 @@ class CarInterface(CarInterfaceBase):
if ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]:
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.
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_CAMERA.value
@@ -785,7 +779,6 @@ class CarInterface(CarInterfaceBase):
ret.alternativeExperience |= ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE
if candidate == CAR.CHEVROLET_TRAX:
ret.steerActuatorDelay = 0.46
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
return ret
@@ -55,9 +55,7 @@ from opendbc.car.gm.carcontroller import (
get_stock_cc_active_for_cancel,
shape_bolt_acc_pedal_low_speed_friction,
shape_truck_friction_brake,
shape_truck_pitch_accel,
shape_truck_positive_accel,
smooth_truck_follow_accel,
should_use_fixed_stopping_brake,
should_activate_auto_hold,
should_activate_volt_one_pedal,
@@ -363,8 +361,6 @@ def test_live_camera_path_does_not_send_pt_keepalive():
def test_acc_2cd_replacement_only_used_with_live_camera_path():
assert should_send_acc_2cd(SimpleNamespace(
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(
carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=GMFlags.NO_CAMERA.value))
assert not should_send_acc_2cd(SimpleNamespace(
@@ -865,36 +861,6 @@ def test_shape_truck_positive_accel_does_not_relax_without_speed_error():
assert no_error == base
def test_shape_truck_positive_accel_keeps_more_highway_follow_authority():
city = shape_truck_positive_accel(0.28, 26.0, True)
highway = shape_truck_positive_accel(0.28, 34.0, True)
assert highway >= city
def test_smooth_truck_follow_accel_slews_small_highway_commands():
shaped = smooth_truck_follow_accel(0.50, 0.0, 30.0, True, True, False)
assert shaped == pytest.approx(0.06)
def test_smooth_truck_follow_accel_does_not_delay_safety_requests():
assert smooth_truck_follow_accel(-0.40, 0.20, 30.0, True, True, False) == -0.40
assert smooth_truck_follow_accel(0.20, -0.40, 30.0, True, True, False) == 0.20
assert smooth_truck_follow_accel(-0.20, 0.20, 30.0, True, True, True) == -0.20
assert smooth_truck_follow_accel(-0.20, 0.20, 20.0, True, True, False) == -0.20
assert smooth_truck_follow_accel(-0.20, 0.20, 30.0, True, False, False) == -0.20
def test_shape_truck_pitch_accel_attenuates_highway_grade_feedforward():
assert shape_truck_pitch_accel(-0.30, 30.0, True) == pytest.approx(-0.0825)
assert shape_truck_pitch_accel(0.30, 30.0, True) == pytest.approx(0.0825)
def test_shape_truck_pitch_accel_is_inactive_without_truck_tuning():
assert shape_truck_pitch_accel(-0.30, 30.0, False) == pytest.approx(-0.30)
def test_shape_truck_friction_brake_suppresses_boundary_chatter():
assert shape_truck_friction_brake(14, -0.3, False, False) == (0, False)
@@ -20,7 +20,6 @@ from opendbc.car.gm.carcontroller import (
)
import opendbc.car.gm.interface as gm_interface
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.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
@@ -66,76 +65,7 @@ class TestGMFingerprint:
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:
@parameterized.expand([
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
CAR.CHEVROLET_BOLT_CC_2022_2023,
CAR.CHEVROLET_MALIBU_HYBRID_CC,
])
def test_bolt_pedal_long_uses_shared_planning_delay_without_retuning_pid(self, car_model):
CarInterface = interfaces[car_model]
fingerprint = _empty_fingerprint()
fingerprint[0][0x201] = 8
params = Params()
try:
params.put_bool("GMPedalLongitudinal", True)
car_params = CarInterface.get_params(
car_model,
fingerprint,
[],
alpha_long=False,
is_release=False,
docs=False,
starpilot_toggles=_test_starpilot_toggles(),
)
finally:
params.remove("GMPedalLongitudinal")
assert car_params.longitudinalActuatorDelay == pytest.approx(0.6)
assert list(car_params.longitudinalTuning.kpV) == pytest.approx([0.095, 0.085, 0.065, 0.050])
assert list(car_params.longitudinalTuning.kiV) == pytest.approx([0.07, 0.10, 0.15, 0.24])
assert car_params.longitudinalTuning.kfDEPRECATED == pytest.approx(0.20)
def test_bolt_acc_pedal_pid_accel_limits_keep_full_negative_authority(self):
cp = SimpleNamespace(
enableGasInterceptorDEPRECATED=True,
@@ -239,45 +169,6 @@ class TestGMInterface:
assert car_params.flags & GMFlags.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):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
fingerprint = {
@@ -610,7 +501,6 @@ class TestGMCarController:
CP=SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CC,
flags=0,
networkLocation=structs.CarParams.NetworkLocation.fwdCamera,
minEnableSpeed=24 * CV.MPH_TO_MS,
),
buttons_counter=2,
@@ -632,7 +522,6 @@ class TestGMCarController:
CP=SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CC,
flags=GMFlags.NO_CAMERA.value,
networkLocation=structs.CarParams.NetworkLocation.gateway,
minEnableSpeed=24 * CV.MPH_TO_MS,
),
buttons_counter=2,
@@ -668,80 +557,6 @@ class TestGMCarController:
assert [msg[2] for msg in msgs] == [0]
@parameterized.expand([
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
CAR.CHEVROLET_BOLT_CC_2022_2023,
])
def test_bolt_cc_redneck_ignores_small_setpoint_error(self, car_model):
packer = CANPacker(DBC[car_model][Bus.pt])
controller = SimpleNamespace(frame=int(2.0 / DT_CTRL), last_button_frame=0, apply_speed=0)
cs = SimpleNamespace(
CP=SimpleNamespace(
carFingerprint=car_model,
minEnableSpeed=24 * CV.MPH_TO_MS,
),
buttons_counter=2,
out=SimpleNamespace(
vEgo=(60.6 * CV.MPH_TO_MS) / 1.01,
cruiseState=SimpleNamespace(speed=60 * CV.MPH_TO_MS),
),
)
msgs = gmcan.create_gm_cc_spam_command(packer, controller, cs, SimpleNamespace(accel=0.0), SimpleNamespace(is_metric=False))
assert msgs == []
assert controller.apply_speed == 60
def test_non_bolt_cc_redneck_keeps_existing_setpoint_selector(self):
packer = CANPacker(DBC[CAR.CHEVROLET_EQUINOX_CC][Bus.pt])
controller = SimpleNamespace(frame=int(2.0 / DT_CTRL), last_button_frame=0, apply_speed=0)
cs = SimpleNamespace(
CP=SimpleNamespace(
carFingerprint=CAR.CHEVROLET_EQUINOX_CC,
flags=GMFlags.CC_LONG.value,
minEnableSpeed=24 * CV.MPH_TO_MS,
),
buttons_counter=2,
out=SimpleNamespace(
vEgo=(60.6 * CV.MPH_TO_MS) / 1.01,
cruiseState=SimpleNamespace(speed=60 * CV.MPH_TO_MS),
),
)
msgs = gmcan.create_gm_cc_spam_command(packer, controller, cs, SimpleNamespace(accel=0.0), SimpleNamespace(is_metric=False))
assert len(msgs) == 1
assert controller.apply_speed == 61
def test_bolt_cc_redneck_requires_persistent_acceleration_after_deceleration(self):
cp = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021)
controller = SimpleNamespace(
frame=100,
gm_cc_last_direction_button=CruiseButtons.DECEL_SET,
gm_cc_last_direction_frame=100,
gm_cc_pending_reverse_button=CruiseButtons.INIT,
gm_cc_pending_reverse_frame=0,
)
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.RES_ACCEL) == CruiseButtons.INIT
controller.frame += int(0.5 / DT_CTRL)
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.RES_ACCEL) == CruiseButtons.INIT
controller.frame += int(0.11 / DT_CTRL)
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.RES_ACCEL) == CruiseButtons.RES_ACCEL
def test_bolt_cc_redneck_deceleration_is_not_debounced(self):
cp = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021)
controller = SimpleNamespace(
frame=100,
gm_cc_last_direction_button=CruiseButtons.RES_ACCEL,
gm_cc_last_direction_frame=100,
gm_cc_pending_reverse_button=CruiseButtons.INIT,
gm_cc_pending_reverse_frame=0,
)
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.DECEL_SET) == CruiseButtons.DECEL_SET
def test_xt4_cc_redneck_spam_matches_physical_button_burst(self):
packer = CANPacker(DBC[CAR.CADILLAC_XT4_CC][Bus.pt])
controller = SimpleNamespace(
@@ -69,6 +69,7 @@ class TestGMCan:
assert bus == 0
assert dat.hex() == "20000000000000"
def test_gas_regen_command_matches_starpilot_volt_2019(self):
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_2019]["pt"])
addr, dat, bus = gmcan.create_gas_regen_command(packer, 0, 5000, 1, True, False, include_always_one3=True, use_volt_layout=True)
+32 -29
View File
@@ -175,7 +175,6 @@ class GMSafetyFlags(IntFlag):
FLAG_GM_REMOTE_START_BOOTS_COMMA = 8192
FLAG_GM_PANDA_3D1_SCHED = 16384
FLAG_GM_PANDA_PADDLE_SCHED = 32768
FLAG_GM_VOLT_CC_GATEWAY = 16384
class Footnote(Enum):
@@ -215,12 +214,16 @@ class GMPlatformConfig(PlatformConfig):
@dataclass
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
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):
@@ -238,17 +241,17 @@ class CAR(Platforms):
},
)
CHEVROLET_VOLT_ASCM = GMPlatformConfig(
[GMCarDocs("Chevrolet Volt ASCM Harness 2017-18", min_enable_speed=0, video="https://youtu.be/QeMCN_4TFfQ")],
[GMCarDocs("Chevrolet Volt 2017-18 ASCM Harness", min_enable_speed=0, video="https://youtu.be/QeMCN_4TFfQ")],
CHEVROLET_VOLT.specs,
dbc_dict=CHEVROLET_VOLT.dbc_dict,
)
CHEVROLET_VOLT_CAMERA = GMPlatformConfig(
[GMCarDocs("Chevrolet Volt Camera Harness 2017-18", "Flashed camera-forward integration with ACC")],
[GMCarDocs("Chevrolet Volt 2017-18 Camera Harness", "Flashed camera-forward integration with ACC")],
CHEVROLET_VOLT.specs,
dbc_dict=CHEVROLET_VOLT.dbc_dict,
)
CHEVROLET_VOLT_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Volt No-ACC 2016-18 (OBD Harness)", "Redneck ACC", min_enable_speed=0)],
[GMCarDocs("Chevrolet Volt 2017-18 - No-ACC", min_enable_speed=0)],
CHEVROLET_VOLT.specs,
dbc_dict=CHEVROLET_VOLT.dbc_dict,
)
@@ -261,7 +264,7 @@ class CAR(Platforms):
GMCarSpecs(mass=1496, wheelbase=2.83, steerRatio=15.8, centerToFrontRatio=0.4),
)
CHEVROLET_MALIBU_ASCM = GMPlatformConfig(
[GMCarDocs("Chevrolet Malibu ASCM Harness 2017-19")],
[GMCarDocs("Chevrolet Malibu 2017-19 ASCM Harness")],
CHEVROLET_MALIBU.specs,
)
GMC_ACADIA = GMASCMPlatformConfig(
@@ -269,7 +272,7 @@ class CAR(Platforms):
GMCarSpecs(mass=1975, wheelbase=2.86, steerRatio=14.4, centerToFrontRatio=0.4),
)
GMC_ACADIA_ASCM = GMPlatformConfig(
[GMCarDocs("GMC Acadia ASCM Harness 2018", video="https://www.youtube.com/watch?v=0ZN6DdsBUZo")],
[GMCarDocs("GMC Acadia 2018 ASCM Harness", video="https://www.youtube.com/watch?v=0ZN6DdsBUZo")],
GMC_ACADIA.specs,
)
BUICK_LACROSSE = GMASCMPlatformConfig(
@@ -277,11 +280,11 @@ class CAR(Platforms):
GMCarSpecs(mass=1712, wheelbase=2.91, steerRatio=15.8, centerToFrontRatio=0.4),
)
BUICK_LACROSSE_ASCM = GMPlatformConfig(
[GMCarDocs("Buick LaCrosse ASCM Harness 2017-19")],
[GMCarDocs("Buick LaCrosse 2017-19 ASCM Harness")],
BUICK_LACROSSE.specs,
)
BUICK_LACROSSE_ASCM_19US = GMPlatformConfig(
[GMCarDocs("Buick LaCrosse US ASCM Harness 2019")],
[GMCarDocs("Buick LaCrosse 2019 US ASCM Harness")],
BUICK_LACROSSE.specs,
)
BUICK_REGAL = GMASCMPlatformConfig(
@@ -293,7 +296,7 @@ class CAR(Platforms):
GMCarSpecs(mass=2564, wheelbase=2.95, steerRatio=17.3),
)
CADILLAC_ESCALADE_ASCM = GMPlatformConfig(
[GMCarDocs("Cadillac Escalade ASCM Harness 2018", "Driver Assist Package")],
[GMCarDocs("Cadillac Escalade 2018 ASCM Harness", "Driver Assist Package")],
CADILLAC_ESCALADE.specs,
)
CADILLAC_ESCALADE_ESV = GMASCMPlatformConfig(
@@ -305,29 +308,29 @@ class CAR(Platforms):
CADILLAC_ESCALADE_ESV.specs,
)
CADILLAC_ESCALADE_ESV_2019_ASCM = GMPlatformConfig(
[GMCarDocs("Cadillac Escalade ESV Platinum ASCM Harness 2019", "Adaptive Cruise Control (ACC) & LKAS")],
[GMCarDocs("Cadillac Escalade ESV Platinum 2019 ASCM Harness", "Adaptive Cruise Control (ACC) & LKAS")],
CADILLAC_ESCALADE_ESV_2019.specs,
)
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),
)
CHEVROLET_BOLT_ACC_2022_2023_PEDAL = GMPlatformConfig(
[GMCarDocs("Chevrolet Bolt EV & EUV ACC w Pedal 2022-23")],
[GMCarDocs("Chevrolet Bolt EV 2022-23 ACC w Pedal")],
CHEVROLET_BOLT_ACC_2022_2023.specs,
)
CHEVROLET_BOLT_CC_2022_2023 = GMPlatformConfig(
[GMCarDocs("Chevrolet Bolt EV & EUV No-ACC 2022-23")],
[GMCarDocs("Chevrolet Bolt EV 2022-23 - No-ACC")],
CHEVROLET_BOLT_ACC_2022_2023.specs,
)
CHEVROLET_BOLT_CC_2018_2021 = GMPlatformConfig(
[GMCarDocs("Chevrolet Bolt EV No-ACC 2018-21")],
[GMCarDocs("Chevrolet Bolt EV 2018-21 - No-ACC")],
CHEVROLET_BOLT_ACC_2022_2023.specs,
)
CHEVROLET_BOLT_CC_2017 = GMPlatformConfig(
[GMCarDocs("Chevrolet Bolt EV No-ACC 2017")],
[GMCarDocs("Chevrolet Bolt EV 2017 - No-ACC")],
CHEVROLET_BOLT_ACC_2022_2023.specs,
)
@@ -340,8 +343,8 @@ class CAR(Platforms):
)
CHEVROLET_SILVERADO_CC = GMPlatformConfig(
[
GMCarDocs("Chevrolet Silverado 1500 No-ACC 2020-21"),
GMCarDocs("GMC Sierra 1500 No-ACC 2020-21"),
GMCarDocs("Chevrolet Silverado 1500 - No-ACC"),
GMCarDocs("GMC Sierra 1500 - No-ACC"),
],
CHEVROLET_SILVERADO.specs,
)
@@ -358,7 +361,7 @@ class CAR(Platforms):
CarSpecs(mass=2731, wheelbase=3.302, steerRatio=17.3, centerToFrontRatio=0.49),
)
GMC_YUKON_CC = GMPlatformConfig(
[GMCarDocs("GMC Yukon No-ACC 2019-20")],
[GMCarDocs("GMC Yukon - No-ACC")],
CarSpecs(mass=2541, wheelbase=2.95, steerRatio=16.3, centerToFrontRatio=0.4),
)
GMC_YUKON = GMPlatformConfig(
@@ -370,7 +373,7 @@ class CAR(Platforms):
GMCarSpecs(mass=1660, wheelbase=2.78, steerRatio=14.4, centerToFrontRatio=0.4),
)
CADILLAC_XT4_CC = GMPlatformConfig(
[GMCarDocs("Cadillac XT4 No-ACC 2023")],
[GMCarDocs("Cadillac XT4 - No-ACC")],
CADILLAC_XT4.specs,
)
CADILLAC_XT5 = GMSDGMPlatformConfig(
@@ -402,35 +405,35 @@ class CAR(Platforms):
CarSpecs(mass=2050, wheelbase=2.86, steerRatio=16.0, centerToFrontRatio=0.5),
)
CADILLAC_CT6_CC = GMPlatformConfig(
[GMCarDocs("Cadillac CT6 No-ACC 2016-20")],
[GMCarDocs("Cadillac CT6 - No-ACC")],
CarSpecs(mass=2358, wheelbase=3.11, steerRatio=17.7, centerToFrontRatio=0.4),
)
CADILLAC_XT5_CC = GMPlatformConfig(
[GMCarDocs("Cadillac XT5 No-ACC 2022")],
[GMCarDocs("Cadillac XT5 - No-ACC")],
CADILLAC_XT5.specs,
)
CHEVROLET_EQUINOX_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Equinox No-ACC 2019-22")],
[GMCarDocs("Chevrolet Equinox 2019-22 - No-ACC")],
CHEVROLET_EQUINOX.specs,
)
CHEVROLET_MALIBU_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Malibu No-ACC 2023")],
[GMCarDocs("Chevrolet Malibu 2023 - No-ACC")],
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=18.25, centerToFrontRatio=0.4, tireStiffnessFactor=0.997),
)
CHEVROLET_MALIBU_HYBRID_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Malibu Hybrid No-ACC 2017")],
[GMCarDocs("Chevrolet Malibu Hybrid 2017 - No-ACC")],
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4),
)
CHEVROLET_SUBURBAN_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Suburban Premier No-ACC 2016-20")],
[GMCarDocs("Chevrolet Suburban Premier 2016-20 - No-ACC")],
CHEVROLET_SUBURBAN.specs,
)
CHEVROLET_TRAILBLAZER_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Trailblazer No-ACC 2021-22")],
[GMCarDocs("Chevrolet Trailblazer 2021-22 - No-ACC")],
CHEVROLET_TRAILBLAZER.specs,
)
CHEVROLET_TRAX = GMPlatformConfig(
[GMCarDocs("Chevrolet TRAX 2024-25")],
[GMCarDocs("Chevrolet TRAX 2024")],
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 (
CAR,
CruiseButtons,
CruiseSettings,
HONDA_BOSCH,
HONDA_BOSCH_CANFD,
HONDA_BOSCH_RADARLESS,
@@ -17,7 +16,6 @@ from opendbc.car.honda.values import (
HondaFlags,
)
from opendbc.car.interfaces import CarControllerBase
from opendbc.car.common.pid import PIDController
from openpilot.common.params import Params
VisualAlert = structs.CarControl.HUDControl.VisualAlert
@@ -213,14 +211,6 @@ class CarController(CarControllerBase):
self.CAN = hondacan.CanBus(CP)
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.brake_steady = 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_wind_factor_before_gasmax = self.bosch_wind_factor
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:
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
pcm_cancel_cmd = CC.cruiseControl.cancel
gas_interceptor_command = 0.0
min_gas = self.params.BOSCH_GAS_LOOKUP_BP[0]
if len(CC.orientationNED) == 3:
self.pitch = CC.orientationNED[1]
hill_brake = math.sin(self.pitch) * ACCELERATION_DUE_TO_GRAVITY
@@ -323,56 +308,11 @@ class CarController(CarControllerBase):
# Send CAN commands
can_sends = []
# Bosch radar ownership. On CAN-FD, leave the stock radar active until the comma relay is open,
# then enter extended diagnostics and disable radar RX/TX. This prevents a gap between stock
# ACC_CONTROL disappearing and panda permitting openpilot's replacement stream.
# tester present - w/ no response (keeps radar disabled)
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 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:
if self.frame % 10 == 0:
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.
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
if self.CP.carFingerprint in HONDA_BOSCH:
if self.mvl_accord_mode and (accel < min_gas) and (1e-3 < CS.out.vEgo < 3.0):
brake_addon = self.mvl_brake_pid.update(error=accel - CS.out.aEgo, speed=CS.out.vEgo)
target_accel = min(accel, accel + brake_addon)
else:
if self.mvl_accord_mode:
self.mvl_brake_pid.reset()
target_accel = accel
self.accel = float(np.clip(target_accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX))
# MVL uses requested accel (not extra-brake-adjusted accel) to decide propulsion crossover.
gas_pedal_force = (accel if self.mvl_accord_mode else self.accel) + hill_brake
self.accel = float(np.clip(accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX))
gas_pedal_force = self.accel + hill_brake
if self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS:
gas_pedal_force += wind_brake_mps2 * self.bosch_wind_factor
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:
gas_learn_speed = 150.0
elif self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR):
gas_learn_speed = 300.0
else:
gas_learn_speed = 50.0
gas_factor_floor = 0.01 if self.mvl_accord_mode else 0.1
gas_learn_force = (gas_pedal_force - min_gas) if self.mvl_accord_mode else gas_pedal_force
self.bosch_gas_factor = float(np.clip(
self.bosch_gas_factor + gas_error / gas_learn_speed * gas_learn_force,
gas_factor_floor, 3.0,
))
self.bosch_gas_factor = float(np.clip(self.bosch_gas_factor + gas_error / gas_learn_speed * gas_pedal_force, 0.1, 3.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
@@ -452,8 +378,7 @@ class CarController(CarControllerBase):
else:
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 <= wind_brake_threshold:
if gas_pedal_force <= 0.0:
self.bosch_wind_factor = max(self.bosch_wind_factor, self.bosch_wind_factor_before_brake)
else:
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_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 \
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 = float(np.interp(gas_pedal_force * self.bosch_gas_factor, 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.bosch_last_gas = self.gas
stopping = actuators.longControlState == LongCtrlState.stopping
self.stopping_counter = self.stopping_counter + 1 if stopping else 0
if not self.mvl_accord_mode or mvl_radar_owned:
can_sends.extend(
hondacan.create_acc_commands(
self.packer, self.CAN, CC.enabled, CC.longActive, self.accel, self.gas, self.stopping_counter, self.CP,
gas_force=gas_pedal_force if self.mvl_accord_mode else None,
)
)
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)
)
else:
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))
@@ -521,16 +440,9 @@ class CarController(CarControllerBase):
idx = (self.frame // 2) % 0x10
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
# 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)
)
# Send dashboard UI commands.
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
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)
@@ -546,7 +458,7 @@ class CarController(CarControllerBase):
if self.CP.openpilotLongitudinalControl:
# 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))
if self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH:
can_sends.append(hondacan.create_legacy_brake_command(self.packer, self.CAN.pt))
@@ -557,29 +469,6 @@ class CarController(CarControllerBase):
else:
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:
self.param_store.put_float("HondaGasFactorParams", self.bosch_gas_factor)
self.param_store.put_float("HondaWindFactorParams", self.bosch_wind_factor)
+5 -105
View File
@@ -68,33 +68,11 @@ class CarState(CarStateBase):
self.initial_accFault_cleared = False
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:
cp = can_parsers[Bus.pt]
cp_cam = can_parsers[Bus.cam]
if self.CP.enableBsm:
cp_body = can_parsers[Bus.body]
if self.CP.carFingerprint == CAR.HONDA_ACCORD_11G:
cp_radar = can_parsers[Bus.radar]
ret = structs.CarState()
@@ -107,10 +85,6 @@ class CarState(CarStateBase):
prev_cruise_setting = self.cruise_setting
self.cruise_setting = cp.vl["SCM_BUTTONS"]["CRUISE_SETTING"]
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
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"]]
ret.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TJA_LOW_SPEED_LOCKOUT",
"TMP_FAULT")
if self.CP.carFingerprint in (HONDA_BOSCH_ALT_RADAR | {CAR.HONDA_ACCORD_11G}):
# MVL treats CAN-FD low-speed lockout as an expected EPS state too.
if self.CP.carFingerprint in HONDA_BOSCH_ALT_RADAR:
# TODO: See if this logic works for all other Honda
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
ret.steerFaultTemporary = steer_status != "NORMAL" and not expected_low_speed_lockout
@@ -227,18 +201,17 @@ class CarState(CarStateBase):
if self.CP.flags & HondaFlags.BOSCH_ALT_BRAKE:
ret.brakePressed = cp.vl["BRAKE_MODULE"]["BRAKE_PRESSED"] != 0
else:
powertrain_data = cp.vl["POWERTRAIN_DATA"]
# brake switch has shown some single time step noise, so only considered when
# switch is on for at least 2 consecutive CAN samples
# brake switch rises earlier than brake pressed but is never 1 when in park
brake_switch_vals = cp.vl_all["POWERTRAIN_DATA"]["BRAKE_SWITCH"]
if len(brake_switch_vals):
brake_switch = powertrain_data["BRAKE_SWITCH"] != 0
brake_switch = cp.vl["POWERTRAIN_DATA"]["BRAKE_SWITCH"] != 0
if len(brake_switch_vals) > 1:
self.brake_switch_prev = brake_switch_vals[-2] != 0
self.brake_switch_active = brake_switch and self.brake_switch_prev
self.brake_switch_prev = brake_switch
ret.brakePressed = (powertrain_data["BRAKE_PRESSED"] != 0) or self.brake_switch_active
ret.brakePressed = (cp.vl["POWERTRAIN_DATA"]["BRAKE_PRESSED"] != 0) or self.brake_switch_active
ret.brake = cp.vl["VSA_STATUS"]["USER_BRAKE"]
ret.cruiseState.enabled = cp.vl["POWERTRAIN_DATA"]["ACC_STATUS"] != 0
@@ -275,63 +248,6 @@ class CarState(CarStateBase):
if self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_CANFD):
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:
# 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
@@ -353,27 +269,11 @@ class CarState(CarStateBase):
return ret, fp_ret
def get_can_parsers(self, CP):
pt_messages = [("GAS_SENSOR", 0)] if CP.enableGasInterceptorDEPRECATED else []
if CP.carFingerprint == CAR.HONDA_ACCORD_11G:
# Both deliberately go silent during the handover, so skip alive/timeout checks.
pt_messages += [("ACC_CONTROL", float("nan")), ("STEERING_CONTROL", float("nan"))]
pt_parser = CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CanBus(CP).pt)
if CP.enableGasInterceptorDEPRECATED:
pt_parser.message_states[0x201].ignore_checksum = True
pt_parser.message_states[0x201].ignore_counter = True
parsers = {
Bus.pt: pt_parser,
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).pt),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).camera),
}
if CP.enableBsm:
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
@@ -257,6 +257,7 @@ FW_VERSIONS = {
(Ecu.eps, 0x18da30f1, None): [
b'39990-TBA-C120\x00\x00',
b'39990-TBA-C020\x00\x00',
b'39990-TBA-C120\x00\x00',
b'39990-TEA-T330\x00\x00',
b'39990-TEA-T820\x00\x00',
b'39990-TEZ-T020\x00\x00',
@@ -993,7 +994,6 @@ FW_VERSIONS = {
b'36161-T47-A060\x00\x00',
b'36161-T47-A070\x00\x00',
b'8S102-T20-AA10\x00\x00',
b'8S102-T20-AA20\x00\x00',
b'8S102-T43-J540\x00\x00',
b'8S102-T47-AA10\x00\x00',
b'8S102-T47-AA20\x00\x00',
@@ -1002,7 +1002,6 @@ FW_VERSIONS = {
b'8S102-T56-A070\x00\x00',
b'8S102-T60-AA10\x00\x00',
b'8S102-T64-A040\x00\x00',
b'8S102-T64-A050\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-T20-AB40\x00\x00',
@@ -1039,8 +1038,6 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'8S102-30A-A050\x00\x00',
b'8S102-30A-A060\x00\x00',
b'8S102-30A-A070\x00\x00',
b'8S102-30A-A080\x00\x00',
],
},
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.honda.values import (HondaFlags, HONDA_BOSCH, HONDA_BOSCH_ALT_RADAR, HONDA_BOSCH_RADARLESS,
HONDA_BOSCH_CANFD, CarControllerParams)
from opendbc.car.honda.values import CAR
# CAN bus layout with relay
# 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)
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 = []
min_gas_accel = CarControllerParams.BOSCH_GAS_LOOKUP_BP[0]
control_on = 5 if enabled else 0
if gas_force is None:
gas_force = accel
gas_command = gas if active and gas_force > min_gas_accel else -30000
gas_command = gas if active and accel > min_gas_accel else -30000
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_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,
}
if CP.carFingerprint in HONDA_BOSCH_RADARLESS:
if car_fingerprint in HONDA_BOSCH_RADARLESS:
acc_control_values.update({
"CONTROL_ON": enabled,
"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,
}
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:
acc_hud_values['ACC_ON'] = int(enabled)
# Preserve StarPilot's existing Bosch HUD behavior outside CAN-FD. MVL's CAN-FD
# replacement radar expects FCW/CMBS enabled, while legacy Bosch keeps them off.
canfd = CP.carFingerprint == CAR.HONDA_ACCORD_11G
acc_hud_values['FCM_OFF'] = 0 if canfd else 1
acc_hud_values['FCM_OFF_2'] = 0 if canfd else 1
acc_hud_values['FCM_OFF'] = 1
acc_hud_values['FCM_OFF_2'] = 1
else:
# Shows the distance bars, TODO: stock camera shows updates temporarily while disabled
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, {})
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 = {
'CRUISE_BUTTONS': button_val,
'CRUISE_SETTING': cruise_setting,
'CRUISE_SETTING': 0,
}
# Existing StarPilot callers should retain their previous payload; only the CAN-FD camera
# takeover path explicitly echoes the live ambient-light byte.
if ambient_light is not None:
values['AMBIENT_LIGHT_MAYBE'] = ambient_light
if bus is None:
# send buttons to camera on radarless (camera does ACC) cars
bus = CAN.camera if car_fingerprint in HONDA_BOSCH_RADARLESS else CAN.pt
# 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)
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:
s = 0
extended = address > 0x7FF
@@ -344,5 +243,5 @@ def honda_checksum(address: int, sig, d: bytearray) -> int:
s += (x & 0xF) + (x >> 4)
s = 8 - s
if extended:
s += 10 if address in HONDA_CANFD_MVL_CHECKSUM_IDS else 3
s += 3
return s & 0xF
+5 -29
View File
@@ -1,11 +1,10 @@
#!/usr/bin/env python3
import numpy as np
from openpilot.common.params import Params, UnknownKeyName
from opendbc.car import get_safety_config, structs, uds
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.disable_ecu import disable_ecu
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
from opendbc.car.honda.carcontroller import CarController
from opendbc.car.honda.carstate import CarState
@@ -45,17 +44,7 @@ class CarInterface(CarInterfaceBase):
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
ret.safetyConfigs = cfgs
# HONDA_BOSCH_A describes the physical harness family. Radar remains unavailable until the
# exact platform is added to HONDA_BOSCH_A_RADAR_VERIFIED after real-capture validation.
try:
# The explicit default keeps the verified platform usable on installs that have not yet
# persisted the internal kill-switch parameter; the verified-platform set remains mandatory.
bosch_a_radar_tryout = not docs and Params().get_bool("HondaBoschARadar", default=True)
except UnknownKeyName:
bosch_a_radar_tryout = False
ret.radarUnavailable = not (candidate in HONDA_BOSCH_A and
candidate in HONDA_BOSCH_A_RADAR_VERIFIED and
bosch_a_radar_tryout)
ret.radarUnavailable = True
# Disable the radar and let openpilot control longitudinal
# WARNING: THIS DISABLES AEB!
# 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]
elif candidate == CAR.HONDA_ACCORD_11G:
# MVL Boston sp-honda-dev-202608 tuning (48211d6a63).
ret.longitudinalActuatorDelay = 0.05
ret.steerActuatorDelay = 0.3
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 12789], [0, 12789]]
ret.lateralTuning.pid.kf = 0.000035
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.115], [0.052]]
CarControllerParams.BOSCH_GAS_LOOKUP_BP = [0.0, 2.0]
ret.steerActuatorDelay = 0.22
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 5200], [0, 2560, 12747]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
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
@@ -329,8 +314,6 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.RADARLESS.value
if candidate in HONDA_BOSCH_CANFD:
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
# 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
def init(CP, can_recv, can_send, communication_control=None):
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
if communication_control is None:
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.DISABLE_RX_DISABLE_TX,
@@ -1,13 +1,8 @@
#!/usr/bin/env python3
import math
from collections import deque
from dataclasses import dataclass, field
from opendbc.can import CANParser
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.honda.values import DBC
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)
# ============================================================================
# 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):
def __init__(self, CP):
super().__init__(CP)
self.track_id = 0
self.radar_fault = False
self.radar_wrong_config = False
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:
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:
# Nidec
self.rcp = _create_nidec_can_parser(CP.carFingerprint)
self.trigger_msg = 0x445
self.track_id = 0
self.radar_fault = False
self.radar_wrong_config = False
self.trigger_msg = 0x445
self.updated_messages = set()
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)
vls = self.rcp.update(can_strings)
self.updated_messages.update(vls)
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
rr = self._update(self.updated_messages)
self.updated_messages.clear()
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):
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()
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
import pytest
from opendbc.car import Bus, structs
from opendbc.car import structs
from opendbc.car.structs import CarParams
from opendbc.car import gen_empty_fingerprint
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_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):
toggles = get_test_toggles()
fingerprint = gen_empty_fingerprint()
+12 -78
View File
@@ -57,9 +57,6 @@ class HondaSafetyFlags(IntFlag):
RADARLESS = 8
BOSCH_CANFD = 16
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):
@@ -120,17 +117,11 @@ class HondaCarDocs(CarDocs):
self.car_parts = CarParts.common([harness])
if CP.alphaLongitudinalAvailable:
self.footnotes.append(Footnote.EXP_LONG)
class Footnote(Enum):
CIVIC_DIESEL = CarFootnote(
"2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.",
Column.FSR_STEERING)
EXP_LONG = CarFootnote(
"Enabling longitudinal control (alpha) will disable all CMBS functionality, including AEB and FCW.",
Column.LONGITUDINAL)
@dataclass
@@ -171,12 +162,7 @@ class CAR(Platforms):
HondaCarDocs("Honda N-Box 2018", "All", min_steer_speed=5.),
],
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).
# 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'},
{Bus.pt: 'acura_rdx_2020_can_generated'},
)
HONDA_ACCORD = HondaBoschPlatformConfig(
[
@@ -186,21 +172,15 @@ class CAR(Platforms):
],
# 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),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
flags=HondaFlags.ALLOW_MANUAL_TRANS,
)
HONDA_ACCORD_11G = HondaBoschCANFDPlatformConfig(
[
HondaCarDocs("Honda Accord 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),
{Bus.pt: 'honda_common_canfd_generated', Bus.radar: 'honda_common_canfd_generated'},
],
CarSpecs(mass=3477 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.0, centerToFrontRatio=0.39),
)
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),
],
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).
# 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'},
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
)
HONDA_CIVIC_BOSCH_DIESEL = HondaBoschPlatformConfig(
[], # don't show in docs
HONDA_CIVIC_BOSCH.specs,
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
)
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)],
# 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),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.body: 'honda_crv_ex_2017_body_generated', Bus.radar: 'honda_bosch_a_radar'},
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.body: 'honda_crv_ex_2017_body_generated'},
flags=HondaFlags.BOSCH_ALT_BRAKE,
)
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)],
# 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),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated', Bus.radar: 'honda_bosch_a_radar'},
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
)
HONDA_HRV_3G = HondaBoschPlatformConfig(
[HondaCarDocs("Honda HR-V 2023-25", "All")],
@@ -285,12 +245,7 @@ class CAR(Platforms):
ACURA_RDX_3G = HondaBoschPlatformConfig(
[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
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'acura_rdx_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
{Bus.pt: 'acura_rdx_2020_can_generated'},
flags=HondaFlags.BOSCH_ALT_BRAKE,
)
ACURA_RDX_3G_MMR = HondaBoschPlatformConfig(
@@ -302,32 +257,17 @@ class CAR(Platforms):
HONDA_INSIGHT = HondaBoschPlatformConfig(
[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
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_insight_ex_2019_can_generated', Bus.radar: 'honda_bosch_a_radar'},
{Bus.pt: 'honda_insight_ex_2019_can_generated'},
)
HONDA_E = HondaBoschPlatformConfig(
[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),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'acura_rdx_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
{Bus.pt: 'acura_rdx_2020_can_generated'},
)
HONDA_E_ADVANCE = HondaBoschPlatformConfig(
[], # 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),
# Bus.radar = the hand-written 16-slot Bosch-A object bank DBC (see radar_interface.py for the decode).
# RX-parse only; the decode itself takes no CAN authority, so factory AEB/CMBS/FCW stay live as long as
# stock longitudinal remains in control. Enabling openpilot longitudinal (alpha) disables all CMBS
# functionality, including AEB and FCW -- see Footnote.EXP_LONG and CarInterface.init()'s UDS
# CommunicationControl call, which suppresses the stock radar's longitudinal TX for the same reason.
{Bus.pt: 'honda_e_advance_2020_can_generated', Bus.radar: 'honda_bosch_a_radar'},
{Bus.pt: 'honda_e_advance_2020_can_generated'},
)
HONDA_PILOT_4G = HondaBoschCANFDPlatformConfig(
[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_CANFD = CAR.with_flags(HondaFlags.BOSCH_CANFD)
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_CAMERA_MESSAGE_CARS = {
CAR.HONDA_ACCORD,
+44 -153
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.hyundaicanfd import CanBus
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, \
KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID
CANFD_RADAR_LIVE_LONGITUDINAL_CAR, kia_ev6_gt_line_longitudinal_tuning
from opendbc.car.interfaces import CarControllerBase
from opendbc.car.vehicle_model import VehicleModel
from openpilot.common.params import Params
from openpilot.starpilot.common.testing_grounds import testing_ground
VisualAlert = structs.CarControl.HUDControl.VisualAlert
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_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
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_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]
@@ -45,7 +42,6 @@ GENESIS_G90_RELEASE_DECEL_STEP_V = [0.16, 0.18, 0.18]
GENESIS_G90_RELEASE_MAX_SPEED = 0.8
IONIQ_6_LONG_MIN_JERK = 0.5 * 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_V = [0.3 / 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:
return CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE) or \
kia_ev6_gt_line_longitudinal_tuning(
CP.carFingerprint, getattr(CP, "carVin", ""),
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
return CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9) or \
kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, getattr(CP, "carVin", ""))
def should_reset_ev6_gt_line_longitudinal_tuning(CP, long_control_state: LongCtrlState) -> bool:
return kia_ev6_gt_line_longitudinal_tuning(
CP.carFingerprint, getattr(CP, "carVin", ""),
testing_ground.use(KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID),
) and \
return kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, getattr(CP, "carVin", "")) and \
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)
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,
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)
@@ -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,
long_control_state: LongCtrlState, long_active: bool,
ev6_gt_line: bool = False, low_speed_stop_brake_cap: bool = False,
ev9: bool = False) -> Ioniq6LongitudinalTuningState:
ev6_gt_line: bool = False, low_speed_stop_brake_cap: bool = False) -> Ioniq6LongitudinalTuningState:
starting = long_control_state == LongCtrlState.starting
stopping = long_control_state == LongCtrlState.stopping
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)
state.jerk_upper = desired_jerk_upper
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:
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
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):
def __init__(self, dbc_names, CP):
super().__init__(dbc_names, CP)
@@ -458,11 +411,11 @@ class CarController(CarControllerBase):
self.ecu_disable_failed = False
self._ecu_disable_checked = False
self._params = Params()
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR:
if CP.carFingerprint == CAR.KIA_EV9:
self._ev9_long_tuning = EV9LongitudinalTuningState()
self._left_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_frames = 0
self._ioniq_6_long_tuning = Ioniq6LongitudinalTuningState()
@@ -470,7 +423,6 @@ class CarController(CarControllerBase):
self._dash_lat_disengage_blink_frame = 0
self._dash_lat_disengage_init = False
self._dash_prev_lat_active = False
self._ray_lkas11_active = False
def _update_dash_icon_state(self, CC):
if CC.latActive:
@@ -563,8 +515,6 @@ class CarController(CarControllerBase):
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,
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
apply_angle = measured_steering_angle
@@ -620,8 +570,6 @@ class CarController(CarControllerBase):
if not CC.latActive:
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
# FIXME: we don't use this with CAN FD?
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
# 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 \
actuators.longControlState in (LongCtrlState.starting, LongCtrlState.pid, LongCtrlState.stopping)
is_ev6_gt_line = kia_ev6_gt_line_longitudinal_tuning(
self.CP.carFingerprint, getattr(self.CP, "carVin", ""),
testing_ground.use(KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID),
)
is_ccnc_angle_long = self.CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR
if is_ccnc_angle_long and (self._ev9_long_tuning.stop_request or not CC.enabled or CC.cruiseControl.override):
is_ev6_gt_line = kia_ev6_gt_line_longitudinal_tuning(self.CP.carFingerprint, getattr(self.CP, "carVin", ""))
is_ev9 = self.CP.carFingerprint == CAR.KIA_EV9
if is_ev9 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)
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,
@@ -663,30 +608,25 @@ class CarController(CarControllerBase):
CS.out.vEgo, CS.out.aEgo,
actuators.longControlState, self.long_active_ecu,
ev6_gt_line=is_ev6_gt_line,
low_speed_stop_brake_cap=is_ccnc_angle_long,
ev9=self.CP.carFingerprint == CAR.KIA_EV9)
low_speed_stop_brake_cap=is_ev9)
use_egmp_smoothed_accel = use_egmp_dynamic_long_tuning and (
accel_cmd >= self._ioniq_6_long_tuning.actual_accel or
self._ioniq_6_long_tuning.launch_active or
self._ioniq_6_long_tuning.stopping or
self.CP.carFingerprint == CAR.KIA_EV9
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):
use_egmp_smoothed_accel = False
if is_ccnc_angle_long and should_track_stop_accel_directly_for_car(
self.CP.carFingerprint, self._ioniq_6_long_tuning.stopping, CS.out.vEgo,
accel_cmd, self._ioniq_6_long_tuning.actual_accel,
):
if is_ev9 and should_track_stop_accel_directly(self._ioniq_6_long_tuning.stopping, CS.out.vEgo,
accel_cmd, self._ioniq_6_long_tuning.actual_accel):
use_egmp_smoothed_accel = False
if use_egmp_dynamic_long_tuning:
if use_egmp_smoothed_accel:
accel = self._ioniq_6_long_tuning.actual_accel
stopping = self._ioniq_6_long_tuning.stopping
else:
decel_step = get_canfd_scc_decel_step(self.CP)
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._ioniq_6_long_tuning.desired_accel = accel_cmd
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))
else:
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()
if self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
@@ -738,45 +678,24 @@ class CarController(CarControllerBase):
self.frame += 1
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_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
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
hud_control)
if blended_hda2:
can_sends.extend(hyundaicanfd.create_steering_messages(
self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque, 0.0,
))
if self.long_active_ecu:
can_sends.extend(hyundaican.create_lkas11_can_canfd_blended(
self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
left_lane_warning, right_lane_warning, CS.msg_364,
include_alerts=False,
counter_mod=0xF,
))
if self.frame % 5 == 0:
can_sends.append(hyundaicanfd.create_suppress_lfa(
self.packer, self.CAN, CS.lfa_block_msg, False,
))
elif can_canfd_blended:
if can_canfd_blended:
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))
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,
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
left_lane_warning, right_lane_warning, lka_icon))
if self.CP.carFingerprint == CAR.KIA_RAY_EV:
self._ray_lkas11_active = True
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,
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
left_lane_warning, right_lane_warning))
# Button messages
if not self.long_active_ecu:
@@ -793,23 +712,13 @@ class CarController(CarControllerBase):
can_sends.extend(self._create_can_redneck_button_messages(CS))
if self.long_active_ecu and can_canfd_blended:
if blended_hda2:
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame, blended_hda2=True))
can_sends.extend(hyundaican.create_radar_aux_messages(self.packer, self.CAN, self.frame, hda2=blended_hda2))
can_sends.extend(hyundaican.create_radar_aux_messages(self.packer, self.CAN, self.frame))
if self.frame % 2 == 0 and self.long_active_ecu:
# TODO: unclear if this is needed
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
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 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:
if can_canfd_blended:
can_sends.extend(hyundaican.create_acc_commands_can_canfd_blended(self.packer, CC.enabled, accel, jerk,
int(self.frame / 2), hud_control,
set_speed_in_units, stopping,
@@ -817,11 +726,10 @@ class CarController(CarControllerBase):
else:
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
hud_control, set_speed_in_units, stopping,
CC.cruiseControl.override, use_fca, self.CP,
main_cruise_enabled))
CC.cruiseControl.override, use_fca, self.CP))
# 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))
# 5 Hz ACC options
@@ -850,12 +758,7 @@ class CarController(CarControllerBase):
)
# steering control
# The first-generation Electrified GV70 expects the synthesized LKAS status
# payload. Forwarding its stock status bits leaves lane-safety state asserted
# while StarPilot is suppressing the stock LFA path.
preserve_stock_lkas = bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING) and \
not self.long_active_ecu and self.CP.carFingerprint != CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN and \
preserve_stock_canfd_lkas_status(self.CP.carFingerprint)
preserve_stock_lkas = bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING) and not self.long_active_ecu
angle_lkas_alt = bool(self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and
self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT)
ccnc_angle_long = self.CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and \
@@ -874,11 +777,10 @@ class CarController(CarControllerBase):
forward_stock_lkas = angle_lkas_alt and (
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:
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled,
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,
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
@@ -910,8 +812,7 @@ class CarController(CarControllerBase):
CC.leftBlinker, CC.rightBlinker, CS.msg_161, CS.msg_162, CS.msg_1b5,
CS.is_metric, CS.out, CS.out.cruiseState.available, lfa_icon))
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, cluster_base_values,
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled, CS.stock_lfahda_cluster_msg,
lfa_icon=lfa_icon))
# blinkers
@@ -996,19 +897,16 @@ class CarController(CarControllerBase):
CC.leftBlinker,
CC.rightBlinker))
if self.frame % 2 == 0:
if self.CP.carFingerprint == CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN:
acc_kwargs = {}
else:
lead_visible, lead_distance, lead_rel_speed = self._get_canfd_scc_lead_state(CC, CS, now_nanos)
acc_kwargs = {
"main_mode_acc": int(CS.out.cruiseState.available),
"direct_accel": True,
"jerk_lower": 5.0,
"jerk_upper": 3.0 if CC.actuators.longControlState == LongCtrlState.pid else 1.0,
"lead_distance": lead_distance,
"lead_rel_speed": lead_rel_speed,
"lead_visible": lead_visible,
}
lead_visible, lead_distance, lead_rel_speed = self._get_canfd_scc_lead_state(CC, CS, now_nanos)
acc_kwargs = {
"main_mode_acc": int(CS.out.cruiseState.available),
"direct_accel": True,
"jerk_lower": 5.0,
"jerk_upper": 3.0 if CC.actuators.longControlState == LongCtrlState.pid else 1.0,
"lead_distance": lead_distance,
"lead_rel_speed": lead_rel_speed,
"lead_visible": lead_visible,
}
if use_egmp_dynamic_long_tuning:
if use_egmp_smoothed_accel:
acc_kwargs["jerk_lower"] = self._ioniq_6_long_tuning.jerk_lower
@@ -1040,10 +938,7 @@ class CarController(CarControllerBase):
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
# cruise cancel - suppress when stock ACC is the fallback (ECU disable failed),
# so openpilot doesn't fight/cancel the user's stock cruise
suppress_brake_cancel = suppress_redundant_gv70_brake_cancel(
self.CP, CS.out.brakePressed, CC.latActive,
)
if CC.cruiseControl.cancel and not self.ecu_disable_failed and not suppress_brake_cancel:
if CC.cruiseControl.cancel and not self.ecu_disable_failed:
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
self.last_button_frame = self.frame
@@ -1054,13 +949,9 @@ class CarController(CarControllerBase):
# cruise standstill resume
elif CC.cruiseControl.resume:
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS and self.CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR:
for _ in range(20):
can_sends.append(hyundaicanfd.create_buttons(
self.packer, self.CP, self.CAN, (CS.buttons_counter + 1) % 0x100,
Buttons.RES_ACCEL, base_values=CS.cruise_buttons_msg,
))
self.last_button_frame = self.frame
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
# TODO: resume for alt button cars
pass
else:
for _ in range(20):
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.RES_ACCEL))
+34 -121
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.values import HyundaiFlags, HyundaiStarPilotFlags, HyundaiStarPilotSafetyFlags, CAR, DBC, Buttons, CarControllerParams, \
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
from opendbc.car.interfaces import CarStateBase
@@ -29,11 +28,6 @@ IONIQ_6_BLINDSPOT_LEFT_MASK = 0x10
CANFD_CAMERA_LEAD_MIN_DISTANCE = 0.1
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]:
if CP.flags & HyundaiFlags.EV:
@@ -55,15 +49,6 @@ def calculate_canfd_speed_limit(CP, FPCP, cp, cp_cam, speed_factor):
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]:
state_int = int(state)
return bool(state_int & IONIQ_6_BLINDSPOT_LEFT_MASK), bool(state_int & IONIQ_6_BLINDSPOT_RIGHT_MASK)
@@ -132,15 +117,12 @@ class CarState(CarStateBase):
"CRUISE_BUTTONS"
self.is_metric = False
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.msg_161 = {}
self.msg_162 = {}
self.msg_1b5 = {}
self.msg_364 = {}
self.lfa_block_msg = {}
self.stock_lkas_msg = {}
self.stock_lfa_msg = {}
self.stock_lfahda_cluster_msg = {}
@@ -155,7 +137,7 @@ class CarState(CarStateBase):
self.blindspots_front_corner_1_ts = 0
self.left_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.main_cruise_on = False
self.angle_steering_angle = 0.0
@@ -173,10 +155,8 @@ class CarState(CarStateBase):
# 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)
def update_main_cruise(self, ret: structs.CarState,
button_events: list[structs.CarState.ButtonEvent] | None = None) -> bool:
button_events = ret.buttonEvents if button_events is None else button_events
if any(be.type == ButtonType.mainCruise and be.pressed for be in button_events):
def update_main_cruise(self, ret: structs.CarState) -> bool:
if any(be.type == ButtonType.mainCruise and be.pressed for be in ret.buttonEvents):
self.main_cruise_on = not self.main_cruise_on
return bool(ret.cruiseState.available and self.main_cruise_on)
@@ -242,23 +222,15 @@ class CarState(CarStateBase):
return button_events
def create_lkas_button_events(self, cp: CANParser, prev_lda_button: int) -> list[structs.CarState.ButtonEvent]:
if self.CP.carFingerprint == CAR.HYUNDAI_SONATA:
self.lda_button = int(cp.vl["BCM_PO_11"]["LDA_BTN"]) if cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0 else 0
elif self.CP.carFingerprint == CAR.HYUNDAI_SONATA_HYBRID:
if self.CP.carFingerprint == CAR.HYUNDAI_SONATA_HYBRID:
self.lda_button = self.get_sonata_hybrid_lkas_button_state(cp)
elif self.CP.carFingerprint == CAR.HYUNDAI_ELANTRA_HEV_2024:
lda_samples = [
*cp.vl_all["CLU13"]["CF_Clu_LdwsLkasSW"],
*cp.vl_all["BCM_PO_11"]["LDA_BTN"],
]
if lda_samples:
self.lda_button = int(any(lda_samples))
# Some classic HKG platforms publish the LKAS button on the cluster bus instead of BCM_PO_11.
elif cp.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0:
self.lda_button = int(cp.vl["CLU13"]["CF_Clu_LdwsLkasSW"])
elif cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0:
self.lda_button = int(cp.vl["BCM_PO_11"]["LDA_BTN"])
else:
source_states = (
int(cp.vl["CLU13"]["CF_Clu_LdwsLkasSW"]) if cp.ts_nanos["CLU13"]["CF_Clu_LdwsLkasSW"] > 0 else 0,
int(cp.vl["BCM_PO_11"]["LDA_BTN"]) if cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0 else 0,
)
self.lda_button = int(any(source_states))
self.lda_button = 0
return create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas})
@@ -336,19 +308,14 @@ class CarState(CarStateBase):
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
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
no_scc = bool(self.CP.flags & HyundaiFlags.NON_SCC)
if self.CP.carFingerprint == CAR.KIA_RAY_EV:
pass
if 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
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)
ret.cruiseState.available = cp.vl[cruise_available_msg][cruise_available_sig] != 0
@@ -356,12 +323,6 @@ class CarState(CarStateBase):
ret.cruiseState.standstill = False
ret.cruiseState.nonAdaptive = False
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:
scc_msg = "SCC12" if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED else "SCC11"
ret.cruiseState.available = cp_cruise.vl[scc_msg]["MainMode_ACC"] == 1
@@ -370,14 +331,8 @@ class CarState(CarStateBase):
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
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.CANFD_LKA_STEERING:
self.lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x2a4"])
else:
self.msg_364 = copy.copy(cp_cam.vl["ALERTS_364"])
self.msg_364 = copy.copy(cp_cam.vl["ALERTS_364"])
# TODO: Find brake pressure
ret.brake = 0
@@ -436,24 +391,22 @@ class CarState(CarStateBase):
ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
# save the entire LKAS11 and CLU11
if self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED and self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
self.lkas11 = {}
else:
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
self.clu11 = copy.copy(cp.vl["CLU11"])
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
if not 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})
prev_cruise_buttons = self.cruise_buttons[-1]
prev_main_buttons = self.main_buttons[-1]
prev_lda_button = self.lda_button
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:
lkas_button_events = self.create_alt_bus_lda_button_events(cp_alt)
else:
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),
*main_button_events,
*create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}),
*lkas_button_events]
ret.blockPcmEnable = not self.recent_button_interaction()
@@ -466,9 +419,6 @@ class CarState(CarStateBase):
ret.lowSpeedAlert = self.low_speed_alert
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
@@ -561,8 +511,7 @@ class CarState(CarStateBase):
ret.cruiseState.standstill = False
else:
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
ret.cruiseState.available = get_canfd_cruise_available(
self.CP, cp, cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1)
ret.cruiseState.available = cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1
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.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
@@ -582,9 +531,7 @@ class CarState(CarStateBase):
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.left_paddle = 0
if self.CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR:
self.cruise_buttons_msg = copy.copy(cp.vl[self.cruise_btns_msg_canfd])
elif self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
self.cruise_buttons_msg = copy.copy(cp.vl["CRUISE_BUTTONS"])
self.left_paddle = cp.vl["CRUISE_BUTTONS"]["LEFT_PADDLE"]
self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
@@ -617,7 +564,7 @@ class CarState(CarStateBase):
*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.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.blockPcmEnable = not self.recent_button_interaction()
@@ -644,18 +591,14 @@ class CarState(CarStateBase):
def get_can_parsers_canfd(self, CP):
msgs = []
cam_msgs = []
if CP.carFingerprint in CANFD_ALT_BUTTONS_RESUME_CAR:
msgs.append(("CRUISE_BUTTONS_ALT", 50))
elif not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
# The EV9 can stop publishing this during the non-ECU-disabled startup
# state. Keep decoding it when present without making CAN invalid.
if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
# TODO: this can be removed once we add dynamic support to vl_all
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:
# EV9 camera status can disappear for an extended period when the
# documented ECU startup sequence is skipped.
msgs.append(("FR_CMR_02_100ms", 0 if CP.carFingerprint == CAR.KIA_EV9 else 10))
msgs.append(("FR_CMR_02_100ms", 10))
msgs.append(("FR_CMR_03_50ms", 0))
cam_msgs.append(("LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS", 0))
else:
@@ -671,7 +614,8 @@ class CarState(CarStateBase):
("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
]
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))
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR:
msgs.append(("BLINDSPOTS_FRONT_CORNER_2", 0))
@@ -690,41 +634,10 @@ class CarState(CarStateBase):
if CP.flags & HyundaiFlags.CANFD:
return self.get_can_parsers_canfd(CP)
if CP.flags & HyundaiFlags.CAN_CANFD_BLENDED and CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
msgs = [
("MDPS12", 100),
("TCS11", 100),
("TCS13", 50),
("TCS15", 10),
("CLU11", 50),
("CLU15", 5),
("ESP12", 100),
("CGW1", 10),
("CGW2", 5),
("WHL_SPD11", 50),
("SAS11", 100),
("SCC12", 0 if CP.openpilotLongitudinalControl and CP.flags & HyundaiFlags.CANFD_LKA_STEERING else 50),
("EMS12", 100),
("EMS16", 100),
("LVR12", 100),
("BCM_PO_11", 0),
("CLU13", 0),
]
if CP.enableBsm:
msgs.append(("LCA11", 20))
return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], msgs, CanBus(CP).ECAN),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [("CAM_0x2a4", 20)], CanBus(CP).CAM),
}
msgs = [
("BCM_PO_11", 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):
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 ',
],
},
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: {
(Ecu.fwdRadar, 0x7d0, None): [
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',
],
},
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,
torque_fault, lkas11, sys_warning, sys_state, enabled,
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 [
"CF_Lkas_LdwsActivemode",
"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_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_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):
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
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 1 = White 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 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
# 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
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 3 = green car + lanes, green steering wheel
# 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
# 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
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]
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,
torque_fault, lkas11, sys_warning, sys_state, enabled,
left_lane, right_lane,
left_lane_depart, right_lane_depart, msg_364,
include_alerts=True, counter_mod=0x10):
left_lane_depart, right_lane_depart, msg_364):
bus = CanBus(CP).ECAN
values = {
"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,
"CF_Lkas_ActToi": steer_req,
"CF_Lkas_ToiFlt": torque_fault,
"CF_Lkas_MsgCount": frame % counter_mod,
"CF_Lkas_MsgCount": frame % 0x10,
"NEW_SIGNAL_1": 0,
"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("BYTE6", 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)
ret = [packer.make_can_msg("LKAS11", bus, values)]
if include_alerts:
ret.append(packer.make_can_msg("ALERTS_364", bus, alerts_364))
return ret
return [
packer.make_can_msg("LKAS11", bus, values),
packer.make_can_msg("ALERTS_364", bus, alerts_364),
]
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
def create_acc_commands_can_canfd_blended_hda2(packer, enabled, accel, accel_last, upper_jerk, idx,
hud_control, set_speed, stopping, long_override, use_fca, CP):
commands = []
bus = CanBus(CP).ECAN
jerk = 5.0
if not enabled or long_override:
accel_raw, accel_value = 0.0, 0.0
else:
accel_raw = accel
accel_value = max(accel_last - jerk / 50.0, min(accel, accel_last + jerk / 50.0))
message_values = [
("SCC11", {
"aReqRaw": accel_raw,
"aReqValue": accel_value,
"JerkUpperLimit": upper_jerk,
"JerkLowerLimit": jerk if enabled else 1.0,
}),
("SCC12", {
"MainMode_ACC": 1,
"ACCMode_Inactive": 0 if enabled else 1,
"TauGapSet": hud_control.leadDistanceBars,
"VSetDis": set_speed,
"ACC_ObjDist": 1,
"ACCMode": 2 if enabled and long_override else 1 if enabled else 0,
"StopReq": 1 if stopping else 0,
}),
("SCC14", {
"ACC_ObjRelSpd": 0,
"ObjValid": 0,
"ObjStatus": 2 if hud_control.leadVisible and enabled else 1 if hud_control.leadVisible else 0,
}),
]
if use_fca and not (CP.flags & HyundaiFlags.CAMERA_SCC):
# These values reproduce the stock status bytes without requesting AEB/FCA actuation.
message_values.append(("FCA11", {
"cr_vsm_deccmd": 255,
"cf_vsm_deccmdact": 0,
}))
for name, values in message_values:
values["COUNTER"] = idx % 0xF
values["CHECKSUM"] = create_checksum_can_canfd_blended(packer, bus, name, values)
commands.append(packer.make_can_msg(name, bus, values))
return commands
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP,
main_cruise_enabled=True):
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP):
commands = []
scc11_values = {
"MainMode_ACC": int(bool(main_cruise_enabled)),
"MainMode_ACC": 1,
"TauGapSet": hud_control.leadDistanceBars,
"VSetDis": set_speed if enabled else 0,
"AliveCounterACC": idx % 0x10,
@@ -380,27 +324,17 @@ def create_frt_radar_opt(packer):
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 = []
message_specs = (
("RADAR_0x363", 2, {"FCA_ESA": 1}),
("RADAR_0x398", 5, {"BYTE4": 0x80, "BYTE5": 0x5D}),
("RADAR_0x399", 5, {"BYTE2": 0x02}),
("RADAR_0x39a", 5, {"BYTE7": 0xFF}),
("RADAR_0x39b", 5, {}),
("RADAR_0x39c", 5, {"BYTE5": 0xE0, "BYTE6": 0x79}),
("RADAR_0x43a", 20, {"BYTE2": 0x07}),
) if hda2 else (
for addr, freq, values in (
("RADAR_0x363", 2, {"FCA_ESA": 1}),
("RADAR_0x398", 5, {"BYTE4": 0x80, "BYTE5": 0x10}),
)
for addr, freq, values in message_specs:
):
if frame % freq != 0:
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)
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.common.conversions import Conversions as CV
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:
@@ -63,61 +63,6 @@ def _update_checksum(packer, address: int, dat: bytearray) -> None:
_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):
address = packer.dbc.name_to_msg["LFA"].address
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):
if lka_icon is None:
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
control_values = {
@@ -180,8 +117,6 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
else:
lkas_values = copy.copy(control_values)
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:
# 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 = []
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
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(lkas_msg, CAN.ACAN, lkas_values))
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):
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({
"COUNTER": cnt,
"SET_ME_1": 1,
"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
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)
@@ -826,7 +750,7 @@ def create_fca_warning_light(packer, CAN, frame):
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
# 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))
if blended_hda2:
return ret
ret.extend(create_fca_warning_light(packer, CAN, frame))
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.
_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000020000fcff000000000020000055ff000068000000")
_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
# rolling integrity fields and the decoded state above are changed at runtime.
_CCNC_ADRV_TEMPLATES = {
@@ -939,19 +859,6 @@ _CCNC_ADRV_TEMPLATES = {
0x1E0: bytes.fromhex("00000002000000000000000000000000"),
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 = {
CAR.KIA_EV9: {
@@ -963,26 +870,12 @@ _CCNC_ADRV_PERIODS = {
0x1E0: 5,
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,
car_fingerprint=None) -> CanData:
if car_fingerprint == CAR.KIA_EV9:
template = _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE
elif car_fingerprint == CAR.HYUNDAI_IONIQ_5_PE:
template = _HYUNDAI_IONIQ_5_PE_ACCEL_BRAKE_ALT_TEMPLATE
else:
template = _ACCEL_BRAKE_ALT_TEMPLATE
template = _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE if car_fingerprint == CAR.KIA_EV9 else _ACCEL_BRAKE_ALT_TEMPLATE
d = bytearray(template)
d[2] = counter & 0xFF # COUNTER (bit 16, 8-bit)
d[4] = (d[4] & ~0x01) | (0x01 if brake_pressed else 0x00) # BRAKE_PRESSED (bit 32)
+30 -90
View File
@@ -9,18 +9,15 @@ from opendbc.car.hyundai.values import HyundaiFlags, CAR, CarControllerParams, \
RADAR_LIVE_LONGITUDINAL_CAR, \
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, \
LEGACY_LONGITUDINAL_CAR, \
CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR, \
HyundaiStarPilotSafetyFlags, \
hyundai_cancel_button_enables_cruise, \
kia_ev6_gt_line_longitudinal_tuning, \
KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID
kia_ev6_gt_line_longitudinal_tuning
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.disable_ecu import disable_ecu, ecu_log
from opendbc.car.hyundai.carcontroller import CarController
from opendbc.car.hyundai.carstate import CarState
from opendbc.car.hyundai.radar_interface import RadarInterface
from openpilot.starpilot.common.testing_grounds import testing_ground
ButtonType = structs.CarState.ButtonEvent.Type
Ecu = structs.CarParams.Ecu
@@ -31,7 +28,6 @@ ENABLE_BUTTONS = (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.can
# Track when ECU disable happened - used to permanently suppress CAN errors from disabled ECU
ECU_DISABLE_TIMESTAMP = 0.0
KONA_NON_SCC_FCA_RADAR_ADDR = 0x602
KIA_EV9_ACCEL_MAX = 2.2
def apply_platform_longitudinal_params(ret: structs.CarParams) -> None:
@@ -65,25 +61,6 @@ def apply_ecu_disable_failure_fallback(CP: structs.CarParams, params) -> None:
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:
if candidate != CAR.HYUNDAI_KONA_NON_SCC:
return False
@@ -103,13 +80,11 @@ class CarInterface(CarInterfaceBase):
@staticmethod
def get_pid_accel_limits(CP, current_speed, cruise_speed):
accel_max = KIA_EV9_ACCEL_MAX if CP.carFingerprint == CAR.KIA_EV9 else CarControllerParams.ACCEL_MAX
return ACCEL_MIN, accel_max
return ACCEL_MIN, CarControllerParams.ACCEL_MAX
@staticmethod
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, gt_line_testing_ground):
if kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin):
apply_kia_ev6_gt_line_longitudinal_params(CP)
@staticmethod
@@ -122,10 +97,6 @@ class CarInterface(CarInterfaceBase):
# "LFA steering" if camera directly sends LFA to the MDPS
cam_can = CanBus(None, fingerprint).CAM
lka_steering = 0x50 in fingerprint[cam_can] or 0x110 in fingerprint[cam_can]
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
lka_steering = Ecu.adas in [fw.ecu for fw in car_fw] or 0x50 in fingerprint[cam_can]
if lka_steering:
ret.flags |= HyundaiFlags.CANFD_LKA_STEERING.value
CAN = CanBus(None, fingerprint, lka_steering)
if ret.flags & HyundaiFlags.CANFD:
@@ -152,8 +123,7 @@ class CarInterface(CarInterfaceBase):
ret.flags |= HyundaiFlags.CANFD_LKA_STEERING_ALT.value
# This HDA II Carnival uses the alternate 0x1AA cruise-button frame even
# though other LKA-steering platforms use 0x1CF.
if candidate in (CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN) and \
0x1aa in fingerprint[CAN.ECAN] and 0x1cf not in fingerprint[CAN.ECAN]:
if candidate == CAR.KIA_CARNIVAL_2025 and 0x1aa in fingerprint[CAN.ECAN] and 0x1cf not in fingerprint[CAN.ECAN]:
ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
else:
# no LKA steering
@@ -195,17 +165,12 @@ class CarInterface(CarInterfaceBase):
# panda safety or the carcontroller; the MDPS tolerating held torque at 0 speed
# is being validated on-road.
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:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CCNC.value
else:
# Shared configuration for non CAN-FD cars
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR or candidate in LEGACY_LONGITUDINAL_CAR
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED and ret.flags & HyundaiFlags.CANFD_LKA_STEERING and \
candidate not in CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR:
ret.alphaLongitudinalAvailable = False
ret.enableBsm = 0x58b in fingerprint[CAN.ECAN]
# Send LFA message on cars with HDA
@@ -230,20 +195,13 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_REFRESH_MSGS.value
# 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
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_CANFD_BLENDED.value
if ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_LKA_STEERING.value
if hyundai_cancel_button_enables_cruise(candidate):
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
ret.centerToFront = ret.wheelbase * 0.4
@@ -303,8 +261,8 @@ class CarInterface(CarInterfaceBase):
if candidate == CAR.HYUNDAI_ELANTRA_2021:
ret.longitudinalActuatorDelay = 0.22
ret.stopAccel = -0.85
ret.stoppingDecelRate = 0.35
ret.stopAccel = -1.5
ret.stoppingDecelRate = 0.5
if candidate == CAR.HYUNDAI_ELANTRA_HEV_2024:
ret.longitudinalActuatorDelay = 0.22
@@ -312,17 +270,6 @@ class CarInterface(CarInterfaceBase):
if candidate == CAR.HYUNDAI_IONIQ_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:
apply_kia_ev9_longitudinal_params(ret)
@@ -359,42 +306,35 @@ class CarInterface(CarInterfaceBase):
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
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value:
addr, bus = 0x730, CanBus(CP).ECAN
skip_disable_ecu = False
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and egmp_in_ready_state(can_recv, bus):
apply_ecu_disable_failure_fallback(CP, params)
ecu_log(f"=== ECU DISABLE SKIPPED - READY detected, safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
skip_disable_ecu = True
# Try ECU disable. If it succeeds (IGN-ON mode), enable longitudinal.
# If it fails (READY mode returns NRC 0x22, or timeout), strip LONG safety flag
# so panda forwards stock SCC messages normally (lateral-only mode).
ecu_log(f"=== ECU DISABLE attempt: addr=0x{addr:x}, bus={bus} ===")
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:
# Try ECU disable. If it succeeds (IGN-ON mode), enable longitudinal.
# If it fails (READY mode returns NRC 0x22, or timeout), strip LONG safety flag
# so panda forwards stock SCC messages normally (lateral-only mode).
ecu_log(f"=== ECU DISABLE attempt: addr=0x{addr:x}, bus={bus} ===")
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 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 ===")
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
# Ioniq 6: 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:
if ecu_disabled:
params.put_bool("EcuDisableFailed", False)
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 ===")
apply_ecu_disable_failure_fallback(CP, params)
ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
else:
if ecu_disabled:
params.put_bool("EcuDisableFailed", False)
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
if CP.flags & HyundaiFlags.ENABLE_BLINKERS:
File diff suppressed because it is too large Load Diff
+31 -61
View File
@@ -45,12 +45,8 @@ class CarControllerParams:
self.STEER_DRIVER_MULTIPLIER = 2
self.STEER_THRESHOLD = 100
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 = 2
self.STEER_DELTA_DOWN = 3
else:
self.STEER_DELTA_UP = 10
self.STEER_DELTA_DOWN = 8
self.STEER_DELTA_UP = 10
self.STEER_DELTA_DOWN = 8
else:
self.STEER_DELTA_UP = 2
self.STEER_DELTA_DOWN = 3
@@ -81,14 +77,11 @@ class CarControllerParams:
self.STEER_DELTA_DOWN = 3
elif CP.flags & HyundaiFlags.CAN_CANFD_BLENDED:
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
self.STEER_MAX = 384
else:
self.STEER_MAX = 404
self.STEER_DRIVER_ALLOWANCE = 50
self.STEER_THRESHOLD = 150
self.STEER_DELTA_UP = 2
self.STEER_DELTA_DOWN = 3
self.STEER_MAX = 404
self.STEER_DRIVER_ALLOWANCE = 50
self.STEER_THRESHOLD = 150
self.STEER_DELTA_UP = 2
self.STEER_DELTA_DOWN = 3
# Default for most HKG
else:
@@ -115,15 +108,12 @@ class HyundaiSafetyFlags(IntFlag):
class HyundaiStarPilotSafetyFlags(IntFlag):
AOL_MAIN_LKAS_ON_ENGAGE = 128
AOL_MAIN_LKAS_SYNC = 32
HAS_LDA_BUTTON = 1024
AOL_LKAS_ON_ENGAGE = 2048
class HyundaiStarPilotFlags(IntFlag):
SPEED_LIMIT_AVAILABLE = 1
MAIN_CRUISE_STATE_TRACKING = 2 ** 2
class HyundaiFlags(IntFlag):
@@ -486,12 +476,8 @@ class CAR(Platforms):
[
HyundaiCarDocs("Hyundai Palisade (without HDA II) 2023-25", "Highway Driving Assist",
car_parts=CarParts.common([CarHarness.hyundai_a])),
HyundaiCarDocs("Hyundai Palisade (with HDA II) 2023-25", "Highway Driving Assist II",
car_parts=CarParts.common([CarHarness.hyundai_r])),
HyundaiCarDocs("Kia Telluride (without HDA II) 2023-25", "Highway Driving Assist",
car_parts=CarParts.common([CarHarness.hyundai_l])),
HyundaiCarDocs("Kia Telluride (with HDA II) 2023-24", "Highway Driving Assist II",
car_parts=CarParts.common([CarHarness.hyundai_p])),
],
HYUNDAI_PALISADE.specs,
flags=HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.CAN_CANFD_BLENDED | HyundaiFlags.RADAR_SCC,
@@ -527,8 +513,8 @@ class CAR(Platforms):
car_parts=CarParts.common([CarHarness.hyundai_q]))
],
HYUNDAI_IONIQ_5.specs,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING | HyundaiFlags.CCNC,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
)
HYUNDAI_IONIQ_5_N = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Ioniq 5 N (with HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_s]))],
@@ -877,16 +863,6 @@ class CAR(Platforms):
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
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(
[HyundaiCarDocs("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))],
CarSpecs(mass=2060, wheelbase=3.01, steerRatio=16.5),
@@ -945,11 +921,6 @@ class CAR(Platforms):
HYUNDAI_KONA_EV.specs,
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(
[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),
@@ -988,27 +959,32 @@ CANCEL_BUTTON_ENABLE_CARS = frozenset({
CAR.HYUNDAI_PALISADE_2023,
})
CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR = frozenset({
CAR.HYUNDAI_PALISADE_2023,
})
KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES = frozenset({
"C4DLC",
})
KIA_EV6_GT_LINE_LONG_TUNING_TESTING_GROUND_ID = "5"
ALT_BUS_LDA_BUTTON_CARS = frozenset()
ALT_BUS_LDA_BUTTON_SWL_STAT_CARS = frozenset()
# These classic HKG platforms publish the LKAS button on CLU13 over the alt bus.
# 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:
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:
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 (vin_match or testing_ground_active)
def kia_ev6_gt_line_longitudinal_tuning(car_fingerprint, vin: str) -> bool:
return car_fingerprint == CAR.KIA_EV6 and isinstance(vin, str) and \
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]]:
@@ -1061,7 +1037,7 @@ def match_fw_to_car_fuzzy(live_fw_versions, vin, offline_fw_versions) -> set[str
if not any(found_platform_code in expected_platform_codes for found_platform_code in found_platform_codes):
break
if ecu[0] in DATE_FW_ECUS and candidate not in DATELESS_FUZZY_CARS:
if ecu[0] in DATE_FW_ECUS:
# If ECU can have a FW date, require it to exist
# (this excludes candidates in the database without dates)
if not len(expected_dates) or not len(found_dates):
@@ -1100,7 +1076,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)
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_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
# TODO: use abs, it has the platform code and part number on many platforms
@@ -1109,8 +1085,6 @@ PLATFORM_CODE_ECUS = [Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps]
# TODO: there are date codes in the ABS firmware versions in hex
DATE_FW_ECUS = [Ecu.fwdCamera]
DATELESS_FUZZY_CARS = {CAR.HYUNDAI_KONA_NON_SCC}
# Note: an ECU on CAN FD cars may sometimes send 0x30080aaaaaaaaaaa (flow control continue) while we
# are attempting to query ECUs. This currently does not seem to affect fingerprinting from the camera
FW_QUERY_CONFIG = FwQueryConfig(
@@ -1199,14 +1173,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.
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_ANGLE_LONGITUDINAL_CAR = {CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE}
CANFD_ALT_BUTTONS_RESUME_CAR = {CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN}
CANFD_CORNER_RADAR_BSM_CAR = {CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_IONIQ_5_PE, CAR.KIA_EV9}
CANFD_ANGLE_LONGITUDINAL_CAR = {CAR.KIA_EV9}
CANFD_CORNER_RADAR_BSM_CAR = {CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9}
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 | {
CAR.HYUNDAI_IONIQ,
@@ -1234,9 +1207,6 @@ NON_SCC_CAR = CAR.with_flags(HyundaiFlags.NON_SCC)
# HyundaiFlags.CANFD_RADAR_SCC | HyundaiFlags.CANFD_NO_RADAR_DISABLE | )
UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.LEGACY) | CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL)
LEGACY_LONGITUDINAL_CAR = {
CAR.GENESIS_G80,
CAR.KIA_XCEED_PHEV,
}
LEGACY_LONGITUDINAL_CAR = {CAR.KIA_XCEED_PHEV}
DBC = CAR.create_dbc_map()
+10 -32
View File
@@ -187,18 +187,12 @@ class CarInterfaceBase(ABC):
ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase)
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 = ("nnff", "nnff_lite")
toggles_to_check = ("force_torque_controller", "nnff", "nnff_lite")
modified_civic_force_torque = (
candidate == HONDA.HONDA_CIVIC_BOSCH and
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 (
force_torque_conversion or
any(getattr(starpilot_toggles, toggle, False) for toggle in toggles_to_check) or
modified_civic_force_torque
):
@@ -219,6 +213,9 @@ class CarInterfaceBase(ABC):
if platform not in MOCK:
if platform in CHRYSLER:
if candidate == CHRYSLER.RAM_HD_5TH_GEN:
if 570 not in fingerprint[0]:
fp_ret.flags |= ChryslerStarPilotFlags.RAM_HD_ALT_BUTTONS.value
if 0x4FF in fingerprint[0]:
fp_ret.flags |= ChryslerStarPilotFlags.NO_MIN_STEERING_SPEED.value
CP.minSteerSpeed = 0.
@@ -241,14 +238,11 @@ class CarInterfaceBase(ABC):
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)
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
CP.openpilotLongitudinalControl = True
if candidate == HYUNDAI.HYUNDAI_ELANTRA_HEV_2024 and CP.openpilotLongitudinalControl:
fp_ret.flags |= HyundaiStarPilotFlags.MAIN_CRUISE_STATE_TRACKING.value
hyundai_has_lda_button = not (CP.flags & HyundaiFlags.CANFD) and (
hyundai_has_lda_button = (
0x391 in fingerprint[0] or
0x50C in fingerprint[0] or
candidate in ALT_BUS_LDA_BUTTON_CARS or
@@ -257,25 +251,9 @@ class CarInterfaceBase(ABC):
if hyundai_has_lda_button:
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value
if getattr(starpilot_toggles, "always_on_lateral_lkas", False):
# LKASButtonControl == 9 means BUTTON_FUNCTIONS["AOL_TOGGLE"] in starpilot_variables.
if params.get_bool("AlwaysOnLateral") and params.get_int("LKASButtonControl") == 9:
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
if candidate in (HYUNDAI.HYUNDAI_ELANTRA_HEV_2024, HYUNDAI.HYUNDAI_SONATA_HYBRID) and \
getattr(starpilot_toggles, "always_on_lateral_main", False):
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_MAIN_LKAS_ON_ENGAGE.value
if candidate == HYUNDAI.HYUNDAI_SONATA_HYBRID:
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
# The refresh Elantra's safety mapping comes from the resolved Galaxy
# toggle above, not from this legacy persisted-parameter fallback.
if candidate != HYUNDAI.HYUNDAI_ELANTRA_HEV_2024 and \
params.get_bool("AlwaysOnLateral") and params.get_int("LKASButtonControl") == 9:
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
if candidate == HYUNDAI.HYUNDAI_SONATA_HYBRID and getattr(starpilot_toggles, "always_on_lateral_lkas", False) and \
getattr(starpilot_toggles, "main_cruise_aol_toggle", False):
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_MAIN_LKAS_SYNC.value
elif platform in TOYOTA:
fp_ret.canUsePedal = not CP.autoResumeSng
fp_ret.canUseSDSU = candidate not in UNSUPPORTED_DSU_CAR and candidate not in TSS2_CAR
@@ -286,7 +264,7 @@ class CarInterfaceBase(ABC):
if 0x2FF in fingerprint[0] or (0x2AA in fingerprint[0] and candidate in NO_DSU_CAR):
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]:
fp_ret.flags |= ToyotaStarPilotFlags.ZSS.value
+1 -30
View File
@@ -1,7 +1,7 @@
import math
import numpy as np
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
FRICTION_THRESHOLD = 0.3
@@ -10,12 +10,6 @@ FRICTION_THRESHOLD = 0.3
ISO_LATERAL_ACCEL = 3.0 # m/s^2
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
class AngleSteeringLimits:
@@ -30,29 +24,6 @@ class AngleSteeringLimits:
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):
# some safety modes utilize a dynamic max steer
if steer_max is None:
@@ -9,7 +9,6 @@ from opendbc.car.nissan import nissancan
from opendbc.car.nissan.values import CAR, CarControllerParams
VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
class CarController(CarControllerBase):
@@ -29,34 +28,6 @@ class CarController(CarControllerBase):
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_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,
# 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:
can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg,
pcm_cancel_cmd and not self.CP.openpilotLongitudinalControl))
can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg, pcm_cancel_cmd))
can_sends.append(nissancan.create_steering_control(
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.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
return new_actuators, can_sends
@@ -26,9 +26,6 @@ class CarState(CarStateBase):
self.distance_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:
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})
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()
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.disable_ecu import disable_ecu, ecu_log
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.carstate import CarState
from opendbc.car.nissan.values import CAR, CarControllerParams, NissanSafetyFlags, \
NISSAN_DIAGNOSTIC_REQUEST_KWP, NISSAN_DIAGNOSTIC_RESPONSE_KWP, NISSAN_RX_OFFSET
LEAF_ADAS_ECU_ADDR = 0x707
LEAF_ADAS_ECU_BUS = 0
LEAF_ADAS_COMMAND_BUS = 1
LEAF_ADAS_COMMAND_ADDRS = frozenset((0x1C3, 0x2B0))
LEAF_2025_SV_PLUS_CAMERA_FW = b'6WK2CDB\x04\x18\x00\x00\x00\x00\x00R=1\x18\x99\x10\x00\x00\x00\x80'
LEAF_2025_SV_PLUS_ALPHA_LONG_ENABLED = False
LEAF_KWP_EXTENDED_REQUEST = b"\x10\xC0"
LEAF_KWP_EXTENDED_RESPONSE = b"\x50\xC0"
LEAF_KWP_DISABLE_NORMAL_TX_NO_RESPONSE = b"\x28\x02"
LEAF_KWP_TAKEOVER_SESSIONS = (
(LEAF_KWP_EXTENDED_REQUEST, LEAF_KWP_EXTENDED_RESPONSE),
)
def is_leaf_2025_sv_plus_longitudinal(candidate, car_fw):
return LEAF_2025_SV_PLUS_ALPHA_LONG_ENABLED and candidate == CAR.NISSAN_LEAF and any(
fw.address == LEAF_ADAS_ECU_ADDR and bytes(fw.fwVersion) == LEAF_2025_SV_PLUS_CAMERA_FW
for fw in car_fw
)
def leaf_adas_commands_silent(can_recv, settle_time=0.05, observe_time=0.15):
"""Confirm the stock ADAS command sender stopped while bus 1 is still observable."""
if can_recv is None:
return False
try:
# Let already-published CAN batches age out, then discard everything queued
# before the communication-control response.
time.sleep(settle_time)
can_recv()
saw_adas_bus_traffic = False
deadline = time.monotonic() + observe_time
while time.monotonic() < deadline:
packets = can_recv(wait_for_one=True)
for packet in packets:
for msg in packet:
if msg.src != LEAF_ADAS_COMMAND_BUS:
continue
saw_adas_bus_traffic = True
if msg.address in LEAF_ADAS_COMMAND_ADDRS:
ecu_log(f"Nissan Leaf ADAS TX still active: {hex(msg.address)} on bus {msg.src}")
return False
except Exception as e:
ecu_log(f"Nissan Leaf ADAS TX silence verification exception: {e}")
return False
if not saw_adas_bus_traffic:
ecu_log("Nissan Leaf ADAS TX silence could not be verified: no bus 1 traffic observed")
return saw_adas_bus_traffic
def leaf_adas_commands_present(can_recv, settle_time=0.05, observe_time=0.15):
"""Confirm the stock ADAS command sender resumed on bus 1."""
if can_recv is None:
return False
try:
time.sleep(settle_time)
can_recv()
deadline = time.monotonic() + observe_time
while time.monotonic() < deadline:
for packet in can_recv(wait_for_one=True):
if any(msg.src == LEAF_ADAS_COMMAND_BUS and msg.address in LEAF_ADAS_COMMAND_ADDRS for msg in packet):
return True
except Exception as e:
ecu_log(f"Nissan Leaf ADAS TX recovery verification exception: {e}")
return False
ecu_log("Nissan Leaf ADAS normal TX recovery could not be verified")
return False
def restore_leaf_adas_tx(can_recv, can_send):
"""Return to the confirmed KWP default session and verify normal TX resumes."""
if can_recv is None or can_send is None:
return False
try:
ecu_log("Nissan Leaf ADAS TX restore using KWP default session 1081")
query = IsoTpParallelQuery(
can_send, can_recv, LEAF_ADAS_ECU_BUS, [LEAF_ADAS_ECU_ADDR],
[NISSAN_DIAGNOSTIC_REQUEST_KWP], [NISSAN_DIAGNOSTIC_RESPONSE_KWP],
response_offset=NISSAN_RX_OFFSET,
)
if query.get_data(0.2) and leaf_adas_commands_present(can_recv):
ecu_log("Nissan Leaf ADAS normal TX restored and command traffic confirmed")
return True
except Exception as e:
ecu_log(f"Nissan Leaf ADAS TX restore exception: {e}")
ecu_log("Nissan Leaf ADAS normal TX restore was not confirmed")
return False
from opendbc.car.nissan.values import CAR, NissanSafetyFlags
class CarInterface(CarInterfaceBase):
CarState = CarState
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
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "nissan"
@@ -132,56 +22,8 @@ class CarInterface(CarInterfaceBase):
ret.steerControlType = structs.CarParams.SteerControlType.angle
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:
# Altima has EPS on C-CAN unlike the others that have it on V-CAN
ret.safetyConfigs[0].safetyParam |= NissanSafetyFlags.ALT_EPS_BUS.value
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
from opendbc.car.can_definitions import CanData
from opendbc.car.nissan.values import CAR
# TODO: add this checksum to the CANPacker
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):
values = {
"COUNTER": frame % 0x10,

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