From fdd8bdd076b1db29115abc39b6d5715044250403 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 8 Mar 2022 01:45:12 -0800 Subject: [PATCH] auto-generate CARS.md --- docs/assets/icon-star-empty.png | Bin 0 -> 3930 bytes docs/assets/icon-star-full.png | Bin 0 -> 4063 bytes docs/assets/icon-star-half.png | Bin 0 -> 5541 bytes docs/assets/icon-star-old.png | Bin 0 -> 18496 bytes docs/cars.py | 126 +++++++++++++++++++---------- selfdrive/car/car_helpers.py | 22 +++-- selfdrive/car/mock/values.py | 8 ++ selfdrive/car/volkswagen/values.py | 20 ++--- 8 files changed, 116 insertions(+), 60 deletions(-) create mode 100644 docs/assets/icon-star-empty.png create mode 100644 docs/assets/icon-star-full.png create mode 100644 docs/assets/icon-star-half.png create mode 100644 docs/assets/icon-star-old.png diff --git a/docs/assets/icon-star-empty.png b/docs/assets/icon-star-empty.png new file mode 100644 index 0000000000000000000000000000000000000000..c78dd806976835b7315b47b2594e215b47442fe6 GIT binary patch literal 3930 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 QC_h?&v4I7uLC-bef6~q+Pyhe` literal 0 HcmV?d00001 diff --git a/docs/assets/icon-star-full.png b/docs/assets/icon-star-full.png new file mode 100644 index 0000000000000000000000000000000000000000..66a027ee75a33ec1c0f3ff59b4bd5fafe8bdd3ae GIT binary patch literal 4063 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 literal 0 HcmV?d00001 diff --git a/docs/assets/icon-star-half.png b/docs/assets/icon-star-half.png new file mode 100644 index 0000000000000000000000000000000000000000..cd5bc2d361a3564421c46b9f8edfe770d02e05e8 GIT binary patch literal 5541 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 R_-;4~P*>K0RVZ4a{}13gWHSH& literal 0 HcmV?d00001 diff --git a/docs/assets/icon-star-old.png b/docs/assets/icon-star-old.png new file mode 100644 index 0000000000000000000000000000000000000000..c82d435d1d6f59de047b9cfd98e69a3a5ad175fd GIT binary patch literal 18496 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 literal 0 HcmV?d00001 diff --git a/docs/cars.py b/docs/cars.py index 16194004ac..a2fe12052d 100755 --- a/docs/cars.py +++ b/docs/cars.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 from enum import Enum +import os -from selfdrive.car import CarInfo -from selfdrive.car.car_helpers import interfaces -from selfdrive.car.fingerprints import get_attr_from_cars, all_known_cars -from selfdrive.config import Conversions as CV +from common.basedir import BASEDIR +from selfdrive.car.car_helpers import interfaces, get_interface_attr +from selfdrive.test.test_routes import non_tested_cars +from collections import defaultdict, namedtuple class Tier(Enum): @@ -14,56 +15,95 @@ class Tier(Enum): class Car: - def __init__(self, CP, car_info): - self.CP = CP - self.info = car_info - self.make, self.model = self.info.name.split(' ', 1) + def __init__(self, car_info, CP): + self.make, self.model = car_info.name.split(' ', 1) + + assert len(car_info.years), 'Model {} has no years listed'.format(CP.carFingerprint) + + # TODO: properly format model years + years = ' ' + str(max(car_info.years)) + self.model_string = "{}{}".format(self.model, years) + self.package = car_info.package + + self.stars = Stars( + CP.openpilotLongitudinalControl, + CP.minEnableSpeed <= 1e-3, # TODO: 0 is probably okay + CP.minSteerSpeed <= 1e-3, + CP.carName in MAKES_GOOD_STEERING_TORQUE, + # TODO: make sure this check is complete + CP.carFingerprint not in non_tested_cars, + ) + + def format_stars(self): + # TODO: exceptions and half stars + return [STAR_ICON_FULL if cat else STAR_ICON_EMPTY for cat in self.stars] @property def tier(self): - if self.CP.openpilotLongitudinalControl: - return Tier.GOLD - return Tier.BRONZE + return {5: Tier.GOLD, 4: Tier.SILVER}.get(sum(self.stars), Tier.BRONZE) - @property - def years(self): - years = - for year in self.info.years: +def make_row(columns): + return "|{}|".format("|".join(columns)) - def __str__(self): - min_alc = int(max(0, self.CP.minSteerSpeed) * CV.MS_TO_MPH) - min_acc = int(max(0, self.CP.minEnableSpeed) * CV.MS_TO_MPH) - acc = "openpilot" if self.CP.openpilotLongitudinalControl else "Stock" - years = {} - return f"| {self.make} | {self.model} | {self.info.package} | {acc} | {min_acc}mph | {min_alc}mph |" +# TODO: unify with column names below? +Stars = namedtuple("Stars", ["op_long", "fsr_long", "fsr_lat", "steering_torque", "well_supported"]) + +STAR_ICON_FULL = '' +STAR_ICON_HALF = '' +STAR_ICON_EMPTY = '' + +CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS_generated.md") +CAR_TABLE_COLUMNS = make_row(['Make', 'Model (US Market Reference)', 'Supported Package', 'openpilot Longitudinal', + 'FSR Longitudinal', 'FSR Steering', 'Steering Torque', 'Actively Maintained']) +CAR_TABLE_HEADER = make_row(["---"] * 3 + [":---:"] * 5) # first three aren't centered +CAR_ROW_TEMPLATE = make_row(["{}"] * 8) + +# TODO: which other makes? +MAKES_GOOD_STEERING_TORQUE = ["toyota", "hyundai", "volkswagen"] -if __name__ == "__main__": - print("# Supported Cars") - - print("Cars are sorted into three tiers:\n") - print(" Gold - a full openpilot experience\n") - print(" Silver - a pretty good, albeit limited experience\n") - print(" Bronze - significantly limited\n") - - for t in Tier: - print(f"## {t.value} Cars") - print("| Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below |") - print("| ----------| ------------------------------| ------------------| -----------------| -------------------| ------------------|") - for fingerprint, car_info in sorted(get_attr_from_cars('CAR_INFO').items(), key=lambda x: x[0]): - # print(car_info) - CI, _, _ = interfaces[fingerprint] - CP = CI.get_params(fingerprint) +def generate_cars_md(): + tiered_cars = defaultdict(list) + + for _, models in get_interface_attr("CAR_INFO").items(): + for model, car_info in models.items(): + CP = interfaces[model][0].get_params(model) # Skip community supported if CP.dashcamOnly: continue - if isinstance(car_info, CarInfo): - car_info = (car_info,) + # Some candidates have multiple variants + if not isinstance(car_info, list): + car_info = [car_info] + + for _car_info in car_info: + car = Car(_car_info, CP) + tiered_cars[car.tier].append(car) + + # Build CARS.md + cars_md_doc = [] + for tier in Tier: + # Sort by make, model name, and year + cars = sorted(tiered_cars[tier], key=lambda car: car.make + car.model_string) + + cars_md_doc.append("## {} Cars\n".format(tier.name.title())) + cars_md_doc.append(CAR_TABLE_COLUMNS) + cars_md_doc.append(CAR_TABLE_HEADER) + for car in cars: + line = CAR_ROW_TEMPLATE.format(car.make, + car.model_string, + car.package, + *car.format_stars()) + cars_md_doc.append(line) + cars_md_doc.append("") # newline + + return '\n'.join(cars_md_doc) + + +if __name__ == "__main__": + # TODO: add argparse for generating json or html (undecided) - for info in car_info: - car = Car(CP, info) - if car.tier == t: - print(car) + with open(CARS_MD_OUT, 'w') as f: + f.write(generate_cars_md()) diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index c347f76627..53062f9586 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -58,19 +58,27 @@ def load_interfaces(brand_names): return ret -def _get_interface_names(): - # read all the folders in selfdrive/car and return a dict where: - # - keys are all the car names that which we have an interface for - # - values are lists of spefic car models for a given car +def get_interface_attr(attr): brand_names = {} for car_folder in [x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]: try: brand_name = car_folder.split('/')[-1] - model_names = __import__(f'selfdrive.car.{brand_name}.values', fromlist=['CAR']).CAR - model_names = [getattr(model_names, c) for c in model_names.__dict__.keys() if not c.startswith("__")] - brand_names[brand_name] = model_names + attr_data = getattr(__import__(f'selfdrive.car.{brand_name}.values', fromlist=[attr]), attr) + brand_names[brand_name] = attr_data except (ImportError, OSError): pass + return brand_names + + +def _get_interface_names(): + # read all the folders in selfdrive/car and return a dict where: + # - keys are all the car names that which we have an interface for + # - values are lists of specific car models for a given brand + + brand_names = {} + for brand_name, model_names in get_interface_attr("CAR").items(): + model_names = [getattr(model_names, c) for c in model_names.__dict__.keys() if not c.startswith("__")] + brand_names[brand_name] = model_names return brand_names diff --git a/selfdrive/car/mock/values.py b/selfdrive/car/mock/values.py index 0dd91565bd..57ffdd39bc 100644 --- a/selfdrive/car/mock/values.py +++ b/selfdrive/car/mock/values.py @@ -1,2 +1,10 @@ +from typing import Dict + +from selfdrive.car import CarInfo + + class CAR: MOCK = 'mock' + + +CAR_INFO: Dict[int, CarInfo] = {} diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 31f3f92228..f301361416 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -91,7 +91,7 @@ class CAR: CAR_INFO = { CAR.ARTEON_MK1: CarInfo("Volkswagen Arteon", {2018, 2021}, "Driver Assistance"), CAR.ATLAS_MK1: CarInfo("Volkswagen Atlas", {2018, 2019, 2022}, "Driver Assistance"), - CAR.GOLF_MK7: ( + CAR.GOLF_MK7: [ CarInfo("Volkswagen e-Golf", {2014, 2019, 2020}, "Driver Assistance"), CarInfo("Volkswagen Golf", {2015, 2016, 2017, 2018, 2019, 2020}, "Driver Assistance"), CarInfo("Volkswagen Golf Alltrack", {2017, 2018}, "Driver Assistance"), @@ -100,26 +100,26 @@ CAR_INFO = { CarInfo("Volkswagen Golf R", {2016, 2017, 2018, 2019}, "Driver Assistance"), CarInfo("Volkswagen Golf SportsVan", {2016}, "Driver Assistance"), CarInfo("Volkswagen Golf SportWagen", {2016}, "Driver Assistance"), - ), - CAR.JETTA_MK7: ( + ], + CAR.JETTA_MK7: [ CarInfo("Volkswagen Jetta", {2018, 2019, 2020}, "Driver Assistance"), CarInfo("Volkswagen Jetta GLI", {2021}, "Driver Assistance"), - ), + ], CAR.PASSAT_MK8: CarInfo("Volkswagen Passat", {2016, 2017, 2018}, "Driver Assistance"), CAR.POLO_MK6: CarInfo("Volkswagen Polo", {2020}, "Driver Assistance"), CAR.TAOS_MK1: CarInfo("Volkswagen Taos", {2022}, "Driver Assistance"), CAR.TCROSS_MK1: CarInfo("Volkswagen T-Cross", {2021}, "Driver Assistance"), CAR.TIGUAN_MK2: CarInfo("Volkswagen Tiguan", {2020}, "Driver Assistance"), CAR.TOURAN_MK2: CarInfo("Volkswagen Touran", {2017}, "Driver Assistance"), - CAR.TRANSPORTER_T61: ( + CAR.TRANSPORTER_T61: [ CarInfo("Volkswagen Caravelle", {2020}, "Driver Assistance"), CarInfo("Volkswagen California", {2021}, "Driver Assistance"), - ), + ], CAR.TROC_MK1: CarInfo("Volkswagen T-Roc", {2021}, "Driver Assistance"), - CAR.AUDI_A3_MK3: ( + CAR.AUDI_A3_MK3: [ CarInfo("Audi A3", {2014, 2015, 2016, 2017, 2018, 2019}, "ACC + Lane Assist"), CarInfo("Audi A3 Sportback e-tron", {2017, 2018}, "ACC + Lane Assist"), - ), + ], CAR.AUDI_Q2_MK1: CarInfo("Audi Q2", {2018}, "ACC + Lane Assist"), CAR.AUDI_Q3_MK2: CarInfo("Audi Q3", {2020, 2021}, "ACC + Lane Assist"), CAR.SEAT_ATECA_MK1: CarInfo("SEAT Ateca", {2018}, "Driver Assistance"), @@ -129,10 +129,10 @@ CAR_INFO = { CAR.SKODA_KODIAQ_MK1: CarInfo("Škoda Kodiaq", {2018, 2019}, "Driver Assistance"), CAR.SKODA_SCALA_MK1: CarInfo("Škoda Scala", {2020}, "Driver Assistance"), CAR.SKODA_SUPERB_MK3: CarInfo("Škoda Superb", {2015, 2017, 2018}, "Driver Assistance"), - CAR.SKODA_OCTAVIA_MK3: ( + CAR.SKODA_OCTAVIA_MK3: [ CarInfo("Škoda Octavia", {2015, 2018, 2019}, "Driver Assistance"), CarInfo("Škoda Octavia RS", {2016}, "Driver Assistance"), - ), + ], } # All supported cars should return FW from the engine, srs, eps, and fwdRadar. Cars