Skip to main content

Documentation 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.

All car-specific code lives in the opendbc repository, not in openpilot itself. Each supported brand implements a standard interface under 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:
opendbc/car/[brand]/
├── interface.py        # CarInterface class — car identification and parameter tuning
├── carstate.py         # CarState builder — CAN parsing and state assembly
├── carcontroller.py    # CarController — control actuation over CAN
├── [brand]can.py       # CAN message composition helpers
├── values.py           # Platform definitions, actuation limits, constants
└── radar_interface.py  # Radar point parsing (brand-specific, if applicable)
Safety firmware and tests live alongside the Python code in the opendbc repository:
opendbc/safety/modes/[brand].h          # Brand safety logic (C, MISRA C:2012)
opendbc/safety/tests/test_[brand].py    # CI safety tests

Key classes

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).
# Typical structure inside interface.py
class CarInterface(CarInterfaceBase):
  @staticmethod
  def get_params(candidate, fingerprint, car_fw, experimental_long, docs):
    ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
    ret.carName = "toyota"
    ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.toyota)]
    ret.steerActuatorDelay = 0.12
    ret.steerLimitTimer = 0.4
    # ... brand-specific tuning
    return ret

  def _update(self, CC):
    ret = self.CS.update(self.cp, self.cp_cam)
    # ... build events
    return ret, []
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:
SignalExample 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
# Typical structure inside carstate.py
class CarState(CarStateBase):
  def update(self, cp, cp_cam):
    ret = car.CarState.new_message()
    ret.vEgo = cp.vl["SPEED"]["SPEED"] * CV.KPH_TO_MS
    ret.steeringAngleDeg = cp.vl["STEER_ANGLE_SENSOR"]["STEER_ANGLE"]
    ret.brakePressed = cp.vl["BRAKE_MODULE"]["BRAKE_PRESSED"] != 0
    ret.steeringTorque = cp.vl["STEER_TORQUE_SENSOR"]["STEER_TORQUE_EPS"]
    ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD
    # ... more signals
    return ret
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
# Typical structure inside carcontroller.py
class CarController:
  def __init__(self, dbc_name, CP):
    self.CP = CP
    self.steer_rate_limited = False
    self.packer = CANPacker(dbc_name)

  def update(self, CC, CS, now_nanos):
    actuators = CC.actuators
    can_sends = []

    # Steering
    if self.frame % 1 == 0:
      steer = actuators.steer
      can_sends.append(toyotacan.create_steer_command(
        self.packer, steer, CC.latActive
      ))

    self.frame += 1
    return actuators, can_sends
values.py is the source of truth for everything static about a brand’s supported cars. It defines:
  • CAR — An enum (typically using StrEnum) listing every supported car platform by fingerprint string.
  • CarControllerParams — Dataclass holding actuation limits:
    • STEER_MAX — Maximum steering torque (or angle) the controller will command
    • STEER_DELTA_UP / STEER_DELTA_DOWN — Maximum torque rate of change per cycle
    • STEER_ERROR_MAX — Torque error threshold before the controller cuts out
    • STEER_DRIVER_ALLOWANCE — Driver torque at which the controller backs off
  • DBC — Mapping from CAR enum values to DBC file names used by CANParser
  • Platform-specific flagsIntFlag enums (e.g., ToyotaFlags) encoding per-model feature toggles
# Excerpt from a values.py
class CarControllerParams:
  STEER_MAX = 1500
  STEER_DELTA_UP = 10      # max torque increase per cycle
  STEER_DELTA_DOWN = 25    # max torque decrease per cycle (faster drop for safety)
  STEER_ERROR_MAX = 350
  STEER_DRIVER_ALLOWANCE = 100
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:
  1. Python interface layerCarController respects the limits in CarControllerParams and stops sending actuation commands when openpilot disengages.
  2. Panda firmware — The C safety mode in opendbc/safety/modes/[brand].h runs on the panda microcontroller and independently enforces actuator limits and driver override detection, regardless of what the host software sends.
See the panda safety model page for the full safety architecture.

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).
# Excerpt from selfdrive/car/car_specific.py
class CarSpecificEvents:
  def __init__(self, CP: structs.CarParams):
    self.CP = CP

  def update(self, CS: car.CarState, CS_prev: car.CarState, CC: car.CarControl):
    events = self.create_common_events(CS, CS_prev)

    if self.CP.brand == 'toyota':
      if self.CP.openpilotLongitudinalControl:
        if CS.cruiseState.standstill and not CS.brakePressed:
          events.add(EventName.resumeRequired)
        if CS.vEgo < self.CP.minEnableSpeed:
          events.add(EventName.belowEngageSpeed)

    return events

Build docs developers (and LLMs) love