All car-specific code lives in the opendbc repository, not in openpilot itself. Each supported brand implements a standard interface underDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/commaai/openpilot/llms.txt
Use this file to discover all available pages before exploring further.
opendbc/car/[brand]/ that openpilot’s car driver process (card) loads at runtime. This separation means car ports, DBC files, and safety firmware are all versioned and reviewed together, independent of the core openpilot control stack.
Brand directory layout
Every supported brand follows the same directory structure:Key classes
CarInterface — interface.py
CarInterface — interface.py
CarInterface is the entry point for every brand. openpilot loads it by fingerprinting the CAN bus to identify the connected vehicle, then calls getCarParams() to retrieve the full parameter set for that car.getCarParams(candidate, fingerprint, car_fw, ...)Returns a CarParams capnp struct that describes the car to the rest of openpilot. This includes:- Longitudinal and lateral control mode (torque, PID, angle-based)
- Minimum enable speed and minimum steer speed
- Steering ratio, wheelbase, and mass
- Whether openpilot controls longitudinal (
openpilotLongitudinalControl) - PCM cruise flag (
pcmCruise) — whether the stock ACC ECU controls engagement - Actuator limits populated from
values.py
update(CC, can_strings)Called at 100 Hz by card. Parses raw CAN strings via CarState.update() and returns a new CarState capnp message representing the current vehicle state.apply(CC, now_nanos)Called at 100 Hz. Takes the CarControl struct from controlsd and invokes CarController.update() to generate and send CAN messages to the car’s actuators. Returns a tuple of (actuators, can_sends).CarState — carstate.py
CarState — carstate.py
CarState reads raw CAN messages from the car’s bus and assembles a structured CarState capnp message that the rest of openpilot consumes. It is called every control cycle (100 Hz) from CarInterface.update().The update(cp, cp_cam, ...) method receives one or more CANParser objects (cp for the main CAN bus, cp_cam for the forward camera CAN bus on some platforms) and reads signal values from DBC-defined message frames.Typical signals parsed:| Signal | Example CAN message |
|---|---|
Vehicle speed (vEgo) | SPEED or WHEEL_SPEEDS |
Steering angle (steeringAngleDeg) | STEER_ANGLE_SENSOR |
Brake pressed (brakePressed) | BRAKE_MODULE |
Gas pressed (gasPressed) | GAS_PEDAL |
Cruise state (cruiseState.enabled) | PCM_CRUISE |
Door open (doorOpen) | BODY_CONTROL_STATE |
Steering torque applied by driver (steeringTorque) | STEER_TORQUE_SENSOR |
CarController — carcontroller.py
CarController — carcontroller.py
CarController translates the high-level CarControl struct (desired steering angle or torque, desired acceleration) into CAN messages for the car’s ADAS ECUs. It is instantiated once per session and its update() method is called at 100 Hz.The controller constructs CAN frames using helpers from [brand]can.py and returns a list of (address, data, bus) tuples that card sends to the panda hardware interface.Key responsibilities:- Apply steering torque or angle commands within the limits defined in
values.py - Handle PCM ACC commands (set speed, resume, cancel) on cars where openpilot controls longitudinal
- Enforce actuator rate limits and cut commands when openpilot is not engaged
- Send keep-alive heartbeat messages where required by the car’s ADAS ECU
values.py — limits, platforms, and constants
values.py — limits, platforms, and constants
values.py is the source of truth for everything static about a brand’s supported cars. It defines:CAR— An enum (typically usingStrEnum) listing every supported car platform by fingerprint string.CarControllerParams— Dataclass holding actuation limits:STEER_MAX— Maximum steering torque (or angle) the controller will commandSTEER_DELTA_UP/STEER_DELTA_DOWN— Maximum torque rate of change per cycleSTEER_ERROR_MAX— Torque error threshold before the controller cuts outSTEER_DRIVER_ALLOWANCE— Driver torque at which the controller backs off
DBC— Mapping fromCARenum values to DBC file names used byCANParser- Platform-specific flags —
IntFlagenums (e.g.,ToyotaFlags) encoding per-model feature toggles
radar_interface.py — radar point parsing
radar_interface.py — radar point parsing
radar_interface.py is present for brands where openpilot can consume the car’s own radar data. It parses RADAR_TRACK or equivalent CAN messages and produces a RadarData capnp message containing a list of RadarPoint objects with range, relative speed, and azimuth.Not all brands implement a radar interface. When a brand’s radar is on the camera CAN bus, a second CANParser (cp_ RadarData) is initialized for that bus.openpilot’s plannerd fuses radar points with the supercombo model’s lead-vehicle predictions. On cars without a radar interface, openpilot relies exclusively on camera-based lead detection.Safety files
Safety logic is enforced at two levels:- Python interface layer —
CarControllerrespects the limits inCarControllerParamsand stops sending actuation commands when openpilot disengages. - Panda firmware — The C safety mode in
opendbc/safety/modes/[brand].hruns on the panda microcontroller and independently enforces actuator limits and driver override detection, regardless of what the host software sends.
openpilot-specific file
For historical reasons, a small amount of car-specific logic remains in the main openpilot repository and has not yet been migrated to opendbc:selfdrive/car/car_specific.py — Contains the CarSpecificEvents class, which maps brand-specific vehicle state (e.g., PCM cruise engagement on Honda, standstill resume on Toyota, low-speed steer alerts on Chrysler) to openpilot event names consumed by selfdrived. A brand-agnostic create_common_events() method handles events that are identical across all brands (door open, seatbelt, wrong gear, steer fault, and so on).
