Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

car docs: list all needed hardware #28212

Merged
merged 20 commits into from
May 22, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
504 changes: 252 additions & 252 deletions docs/CARS.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions selfdrive/car/CARS_template.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{% set footnote_tag = '[<sup>{}</sup>](#footnotes)' %}
{% set star_icon = '[![star](assets/icon-star-{}.svg)](##)' %}
{% set video_icon = '<a href="{}" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>' %}
{# Force harness column wider by using a blank image with max width. #}
{# Force hardware column wider by using a blank image with max width. #}
{% set width_tag = '<a href="##"><img width=2000></a>%s<br>&nbsp;' %}
{% set harness_col_name = 'Harness Kit' %}
{% set wide_harness_col_name = width_tag|format(harness_col_name) -%}
{% set hardware_col_name = 'Hardware Needed' %}
{% set wide_hardware_col_name = width_tag|format(hardware_col_name) -%}

<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->

Expand All @@ -14,7 +14,7 @@ A supported vehicle is one that just works when you install a comma three. All s

# {{all_car_info | length}} Supported Cars

|{{Column | map(attribute='value') | join('|') | replace(harness_col_name, wide_harness_col_name)}}|
|{{Column | map(attribute='value') | join('|') | replace(hardware_col_name, wide_hardware_col_name)}}|
|---|---|---|{% for _ in range((Column | length) - 3) %}{{':---:|'}}{% endfor +%}
{% for car_info in all_car_info %}
|{% for column in Column %}{{car_info.get_column(column, star_icon, video_icon, footnote_tag)}}|{% endfor %}
Expand Down
10 changes: 5 additions & 5 deletions selfdrive/car/chrysler/values.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from cereal import car
from panda.python import uds
from selfdrive.car import dbc_dict
from selfdrive.car.docs_definitions import CarInfo, Harness, HarnessKit
from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts
from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16

Ecu = car.CarParams.Ecu
Expand Down Expand Up @@ -60,7 +60,7 @@ def __init__(self, CP):
@dataclass
class ChryslerCarInfo(CarInfo):
package: str = "Adaptive Cruise Control (ACC)"
harness_kit: HarnessKit = HarnessKit(Harness.fca)
car_parts: CarParts = CarParts.default([CarPart.fca])


CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = {
Expand All @@ -74,10 +74,10 @@ class ChryslerCarInfo(CarInfo):
],
CAR.JEEP_CHEROKEE: ChryslerCarInfo("Jeep Grand Cherokee 2016-18", video_link="https://www.youtube.com/watch?v=eLR9o2JkuRk"),
CAR.JEEP_CHEROKEE_2019: ChryslerCarInfo("Jeep Grand Cherokee 2019-21", video_link="https://www.youtube.com/watch?v=jBe4lWnRSu4"),
CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-23", harness_kit=HarnessKit(Harness.ram)),
CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-23", car_parts=CarParts.default([CarPart.ram])),
CAR.RAM_HD: [
ChryslerCarInfo("Ram 2500 2020-22", harness_kit=HarnessKit(Harness.ram)),
ChryslerCarInfo("Ram 3500 2019-22", harness_kit=HarnessKit(Harness.ram)),
ChryslerCarInfo("Ram 2500 2020-22", car_parts=CarParts.default([CarPart.ram])),
ChryslerCarInfo("Ram 3500 2019-22", car_parts=CarParts.default([CarPart.ram])),
],
}

Expand Down
183 changes: 121 additions & 62 deletions selfdrive/car/docs_definitions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import re
from collections import namedtuple
import copy
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List, Optional, Tuple, Union
Expand All @@ -21,7 +20,7 @@ class Column(Enum):
FSR_STEERING = "No ALC below"
STEERING_TORQUE = "Steering Torque"
AUTO_RESUME = "Resume from stop"
HARNESS = "Harness Kit"
HARDWARE = "Hardware Needed"
VIDEO = "Video"


Expand All @@ -31,60 +30,120 @@ class Star(Enum):
EMPTY = "empty"


class Harness(Enum):
maxime-desroches marked this conversation as resolved.
Show resolved Hide resolved
maxime-desroches marked this conversation as resolved.
Show resolved Hide resolved
nidec = "Honda Nidec"
bosch_a = "Honda Bosch A"
bosch_b = "Honda Bosch B"
toyota = "Toyota"
subaru_a = "Subaru A"
subaru_b = "Subaru B"
fca = "FCA"
ram = "Ram"
vw = "VW"
j533 = "J533"
hyundai_a = "Hyundai A"
hyundai_b = "Hyundai B"
hyundai_c = "Hyundai C"
hyundai_d = "Hyundai D"
hyundai_e = "Hyundai E"
hyundai_f = "Hyundai F"
hyundai_g = "Hyundai G"
hyundai_h = "Hyundai H"
hyundai_i = "Hyundai I"
hyundai_j = "Hyundai J"
hyundai_k = "Hyundai K"
hyundai_l = "Hyundai L"
hyundai_m = "Hyundai M"
hyundai_n = "Hyundai N"
hyundai_o = "Hyundai O"
hyundai_p = "Hyundai P"
hyundai_q = "Hyundai Q"
custom = "Developer"
obd_ii = "OBD-II"
gm = "GM"
nissan_a = "Nissan A"
nissan_b = "Nissan B"
mazda = "Mazda"
ford_q3 = "Ford Q3"
ford_q4 = "Ford Q4"
none = "None"


class HarnessPart(Enum):
harness_box = "harness box"
comma_power_v2 = "comma power v2"
rj45_cable = "RJ45 cable (7 ft)"
long_obdc_cable = "long OBD-C cable"
usbc_coupler = "USB-C coupler"


DEFAULT_HARNESS_PARTS: List[HarnessPart] = [HarnessPart.harness_box, HarnessPart.comma_power_v2, HarnessPart.rj45_cable]
class PartType(Enum):
connector = "Connector"
device = "Device"
cable = "Cable"
accessory = "Accessory"
mount = "Mount"


@dataclass
class HarnessKit:
connector: Harness = Harness.none
parts: List[HarnessPart] = field(default_factory=lambda: copy.copy(DEFAULT_HARNESS_PARTS))
class Part:
name: str

@property
maxime-desroches marked this conversation as resolved.
Show resolved Hide resolved
def type(self) -> PartType:
raise NotImplementedError


@dataclass
class Connector(Part):
@property
def type(self) -> PartType:
return PartType.connector


class Accessory(Part):
@property
def type(self) -> PartType:
return PartType.accessory


class Mount(Part):
@property
def type(self) -> PartType:
return PartType.mount


class Cable(Part):
@property
def type(self) -> PartType:
return PartType.cable


class Device(Part):
@property
def type(self) -> PartType:
return PartType.device


class CarPart(Enum):
maxime-desroches marked this conversation as resolved.
Show resolved Hide resolved
maxime-desroches marked this conversation as resolved.
Show resolved Hide resolved
nidec = Connector("Honda Nidec connector")
bosch_a = Connector("Honda Bosch A connector")
bosch_b = Connector("Honda Bosch B connector")
toyota = Connector("Toyota connector")
subaru_a = Connector("Subaru A connector")
subaru_b = Connector("Subaru B connector")
fca = Connector("FCA connector")
ram = Connector("Ram connector")
vw = Connector("VW connector")
j533 = Connector("J533 connector")
hyundai_a = Connector("Hyundai A connector")
hyundai_b = Connector("Hyundai B connector")
hyundai_c = Connector("Hyundai C connector")
hyundai_d = Connector("Hyundai D connector")
hyundai_e = Connector("Hyundai E connector")
hyundai_f = Connector("Hyundai F connector")
hyundai_g = Connector("Hyundai G connector")
hyundai_h = Connector("Hyundai H connector")
hyundai_i = Connector("Hyundai I connector")
hyundai_j = Connector("Hyundai J connector")
hyundai_k = Connector("Hyundai K connector")
hyundai_l = Connector("Hyundai L connector")
hyundai_m = Connector("Hyundai M connector")
hyundai_n = Connector("Hyundai N connector")
hyundai_o = Connector("Hyundai O connector")
hyundai_p = Connector("Hyundai P connector")
hyundai_q = Connector("Hyundai Q connector")
custom = Connector("Developer connector")
obd_ii = Connector("OBD-II connector")
gm = Connector("GM connector")
nissan_a = Connector("Nissan A connector")
nissan_b = Connector("Nissan B connector")
mazda = Connector("Mazda connector")
ford_q3 = Connector("Ford Q3 connector")
ford_q4 = Connector("Ford Q4 connector")

comma_3 = Device("comma 3")
red_panda = Device("red panda")

harness_box = Accessory("harness box")
comma_power_v2 = Accessory("comma power v2")

mount = Mount("mount")
angled_mount = Mount("angled mount")

rj45_cable_7ft = Cable("RJ45 cable (7 ft)")
long_obdc_cable = Cable("long OBD-C cable")
usb_a_2_a_cable = Cable("USB A-A cable")
usbc_otg_cable = Cable("USB C OTG cable")
usbc_coupler = Cable("USB-C coupler")
obd_c_cable_1_5ft = Cable("OBD-C cable (1.5 ft)")
right_angle_obd_c_cable_1_5ft = Cable("right angle OBD-C cable (1.5 ft)")


DEFAULT_CAR_PARTS: List[CarPart] = [CarPart.harness_box, CarPart.comma_power_v2, CarPart.rj45_cable_7ft, CarPart.mount, CarPart.right_angle_obd_c_cable_1_5ft]


@dataclass
class CarParts:
parts: List[CarPart] = field(default_factory=list)

@classmethod
def default(cls, add: List[CarPart] = None, remove: List[CarPart] = None):
p = [part for part in (add or []) + DEFAULT_CAR_PARTS if part not in (remove or [])]
return cls(p)
maxime-desroches marked this conversation as resolved.
Show resolved Hide resolved


CarFootnote = namedtuple("CarFootnote", ["text", "column", "docs_only", "shop_footnote"], defaults=(False, False))
Expand Down Expand Up @@ -154,8 +213,8 @@ class CarInfo:
min_steer_speed: Optional[float] = None
min_enable_speed: Optional[float] = None

# harness connectors + all the parts needed
harness_kit: HarnessKit = HarnessKit()
# all the parts needed for the supported car
car_parts: CarParts = CarParts()

def init(self, CP: car.CarParams, all_footnotes: Dict[Enum, int]):
self.car_name = CP.carName
Expand Down Expand Up @@ -184,13 +243,13 @@ def init(self, CP: car.CarParams, all_footnotes: Dict[Enum, int]):
if self.min_enable_speed is None:
self.min_enable_speed = CP.minEnableSpeed

# harness column
harness_col = self.harness_kit.connector.value
if self.harness_kit.connector is not Harness.none:
# hardware column
hardware_col = "None"
if self.car_parts.parts:
model_years = self.model + (' ' + self.years if self.years else '')
harness_connector = f'- 1 <a href="https://comma.ai/shop/comma-three.html?make={self.make}&model={model_years}">{harness_col} connector</a>'
harness_parts = '<br>'.join([f"- {self.harness_kit.parts.count(part)} {part.value}" for part in sorted(set(self.harness_kit.parts), key=lambda part: part.value)])
harness_col = f'<details><summary>View</summary><sub>{harness_connector}<br>{harness_parts}</sub></details>'
buy_link = f'<a href="https://comma.ai/shop/comma-three.html?make={self.make}&model={model_years}">Buy Here</a>'
parts = '<br>'.join([f"- {self.car_parts.parts.count(part)} {part.value.name}" for part in sorted(set(self.car_parts.parts), key=lambda part: part.name)])
hardware_col = f'<details><summary>View</summary><sub>{parts}<br>{buy_link}</sub></details>'

self.row: Dict[Enum, Union[str, Star]] = {
Column.MAKE: self.make,
Expand All @@ -201,7 +260,7 @@ def init(self, CP: car.CarParams, all_footnotes: Dict[Enum, int]):
Column.FSR_STEERING: f"{max(self.min_steer_speed * CV.MS_TO_MPH, 0):.0f} mph",
Column.STEERING_TORQUE: Star.EMPTY,
Column.AUTO_RESUME: Star.FULL if CP.autoResumeSng else Star.EMPTY,
Column.HARNESS: harness_col,
Column.HARDWARE: hardware_col,
Column.VIDEO: self.video_link if self.video_link is not None else "", # replaced with an image and link from template in get_column
}

Expand Down
9 changes: 6 additions & 3 deletions selfdrive/car/ford/values.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from cereal import car
from selfdrive.car import AngleRateLimit, dbc_dict
from selfdrive.car.docs_definitions import CarInfo, Harness, HarnessKit
from selfdrive.car.docs_definitions import CarInfo, CarPart, CarParts
from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries

Ecu = car.CarParams.Ecu
Expand Down Expand Up @@ -62,11 +62,14 @@ class RADAR:

DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("ford_lincoln_base_pt", RADAR.DELPHI_MRR))

maxime-desroches marked this conversation as resolved.
Show resolved Hide resolved

@dataclass
class FordCarInfo(CarInfo):
package: str = "Co-Pilot360 Assist+"
harness_kit: HarnessKit = HarnessKit(Harness.ford_q3)
car_parts: CarParts = CarParts.default([CarPart.ford_q3])

def init_make(self, CP: car.CarParams):
if CP.carFingerprint in (CAR.BRONCO_SPORT_MK1, CAR.MAVERICK_MK1):
self.car_parts = CarParts.default([CarPart.ford_q3, CarPart.angled_mount], remove=[CarPart.mount])
maxime-desroches marked this conversation as resolved.
Show resolved Hide resolved


CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
Expand Down
6 changes: 3 additions & 3 deletions selfdrive/car/gm/values.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from cereal import car
from selfdrive.car import dbc_dict
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness, HarnessKit, HarnessPart
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarPart, CarParts, Column
Ecu = car.CarParams.Ecu


Expand Down Expand Up @@ -89,9 +89,9 @@ class GMCarInfo(CarInfo):

def init_make(self, CP: car.CarParams):
if CP.networkLocation == car.CarParams.NetworkLocation.fwdCamera:
self.harness_kit = HarnessKit(Harness.gm)
self.car_parts = CarParts.default([CarPart.gm])
else:
self.harness_kit = HarnessKit(Harness.obd_ii, parts=[HarnessPart.long_obdc_cable, HarnessPart.usbc_coupler])
self.car_parts = CarParts([CarPart.obd_ii, CarPart.long_obdc_cable, CarPart.usbc_coupler, CarPart.mount, CarPart.right_angle_obd_c_cable_1_5ft])
maxime-desroches marked this conversation as resolved.
Show resolved Hide resolved
self.footnotes.append(Footnote.OBD_II)


Expand Down
6 changes: 3 additions & 3 deletions selfdrive/car/honda/values.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from common.conversions import Conversions as CV
from panda.python import uds
from selfdrive.car import dbc_dict
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness, HarnessKit
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, CarPart, CarParts, Column
from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16

Ecu = car.CarParams.Ecu
Expand Down Expand Up @@ -110,9 +110,9 @@ class HondaCarInfo(CarInfo):

def init_make(self, CP: car.CarParams):
if CP.carFingerprint in HONDA_BOSCH:
self.harness_kit = HarnessKit(Harness.bosch_b) if CP.carFingerprint in HONDA_BOSCH_RADARLESS else HarnessKit(Harness.bosch_a)
self.car_parts = CarParts.default([CarPart.bosch_b]) if CP.carFingerprint in HONDA_BOSCH_RADARLESS else CarParts.default([CarPart.bosch_a])
else:
self.harness_kit = HarnessKit(Harness.nidec)
self.car_parts = CarParts.default([CarPart.nidec])


CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = {
Expand Down