diff --git a/docs/CARS_generated.md b/docs/CARS_generated.md index 63b0306258..784cd4206f 100644 --- a/docs/CARS_generated.md +++ b/docs/CARS_generated.md @@ -1,6 +1,6 @@ ## Gold Cars -|Make|Model (US Market Reference)|Supported Package|openpilot Longitudinal|FSR Longitudinal|FSR Steering|Steering Torque|Actively Maintained| +|Make|Model|Supported Package|openpilot Longitudinal|FSR Longitudinal|FSR Steering|Steering Torque|Actively Maintained| |---|---|---|:---:|:---:|:---:|:---:|:---:| |Genesis|G70 2020|All|||||| |Hyundai|Elantra 2021|SCC + LKAS|||||| @@ -25,7 +25,7 @@ |Lexus|RX 2021|All|||||| |Lexus|RX Hybrid 2021|All|||||| |Toyota|Alphard 2020|All|||||| -|Toyota|Camry 2022|All|||||| +|Toyota|Camry 2022|All||2|||| |Toyota|Camry Hybrid 2022|All|||||| |Toyota|Corolla Hybrid TSS2 2022|All|||||| |Toyota|Corolla TSS2 2022|All|||||| @@ -38,9 +38,8 @@ ## Silver Cars -|Make|Model (US Market Reference)|Supported Package|openpilot Longitudinal|FSR Longitudinal|FSR Steering|Steering Torque|Actively Maintained| +|Make|Model|Supported Package|openpilot Longitudinal|FSR Longitudinal|FSR Steering|Steering Torque|Actively Maintained| |---|---|---|:---:|:---:|:---:|:---:|:---:| -|Acura|RDX 2021|All|||||| |Audi|A3 2019|ACC + Lane Assist|||||| |Audi|A3 Sportback e-tron 2018|ACC + Lane Assist|||||| |Audi|Q2 2018|ACC + Lane Assist|||||| @@ -48,15 +47,6 @@ |Genesis|G70 2018|All|||||| |Genesis|G80 2018|All|||||| |Genesis|G90 2018|All|||||| -|Honda|Accord 2021|All|||||| -|Honda|Accord Hybrid 2021|All|||||| -|Honda|CR-V 2021|Honda Sensing|||||| -|Honda|CR-V Hybrid 2019|Honda Sensing|||||| -|Honda|Civic (Bosch) 2020|All|||||| -|Honda|Civic 2018|Honda Sensing|||||| -|Honda|Civic Sedan 1.6 DIESEL 2020|All|||||| -|Honda|E 2020|All|||||| -|Honda|Insight 2021|All|||||| |Hyundai|Ioniq Electric 2020|SCC + LKAS|||||| |Hyundai|Ioniq Hybrid 2022|SCC + LFA|||||| |Hyundai|Ioniq Plug-In Hybrid 2021|SCC + LKAS|||||| @@ -68,27 +58,25 @@ |Kia|Optima SX 2019 & 2016 2019|SCC + LKAS|||||| |Kia|Sorento GT-Line 2019|SCC + LKAS|||||| |Kia|Stinger GT2 2018|SCC + LKAS|||||| -|Lexus|CT Hybrid 2018|LSS|||||| -|Lexus|ES Hybrid 2018|LSS|||||| -|Lexus|NX 2019|All|||||| -|Lexus|NX Hybrid 2019|All|||||| -|Lexus|RX 2018|All|||||| -|Lexus|RX Hybrid 2019|All|||||| +|Lexus|CT Hybrid 2018|LSS|1||||| +|Lexus|ES Hybrid 2018|LSS|1||||| +|Lexus|NX 2019|All|1||||| +|Lexus|NX Hybrid 2019|All|1||||| +|Lexus|RX 2018|All|1||||| +|Lexus|RX Hybrid 2019|All|1||||| |SEAT|Ateca 2018|Driver Assistance|||||| |SEAT|Leon 2020|Driver Assistance|||||| |Toyota|Avalon 2022|All|||||| |Toyota|C-HR 2021|All|||||| |Toyota|C-HR Hybrid 2019|All|||||| -|Toyota|Camry 2020|All|||||| -|Toyota|Camry Hybrid 2020|All|||||| -|Toyota|Highlander 2019|All|||||| -|Toyota|Highlander Hybrid 2019|All|||||| -|Toyota|Prius 2020|TSS-P|||||| -|Toyota|Prius v 2017|TSS-P|||||| -|Toyota|RAV4 Hybrid 2018|TSS-P|||||| -|Toyota|Sienna 2020|All|||||| -|Volkswagen|Arteon 2021|Driver Assistance|||||| -|Volkswagen|Atlas 2022|Driver Assistance|||||| +|Toyota|Camry 2020|All||2|||| +|Toyota|Camry Hybrid 2020|All||2|||| +|Toyota|Highlander 2019|All|1||||| +|Toyota|Highlander Hybrid 2019|All|1||||| +|Toyota|RAV4 Hybrid 2018|TSS-P|1||||| +|Toyota|Sienna 2020|All|1||||| +|Volkswagen|Arteon 20216|Driver Assistance|||||| +|Volkswagen|Atlas 20226|Driver Assistance|||||| |Volkswagen|Golf 2020|Driver Assistance|||||| |Volkswagen|Golf Alltrack 2018|Driver Assistance|||||| |Volkswagen|Golf GTE 2016|Driver Assistance|||||| @@ -98,15 +86,15 @@ |Volkswagen|Golf SportsVan 2016|Driver Assistance|||||| |Volkswagen|Jetta 2020|Driver Assistance|||||| |Volkswagen|Jetta GLI 2021|Driver Assistance|||||| -|Volkswagen|Passat 2018|Driver Assistance|||||| +|Volkswagen|Passat 20185|Driver Assistance|||||| |Volkswagen|Polo 2020|Driver Assistance|||||| -|Volkswagen|T-Cross 2021|Driver Assistance|||||| -|Volkswagen|T-Roc 2021|Driver Assistance|||||| -|Volkswagen|Taos 2022|Driver Assistance|||||| -|Volkswagen|Tiguan 2020|Driver Assistance|||||| +|Volkswagen|T-Cross 20216|Driver Assistance|||||| +|Volkswagen|T-Roc 20216|Driver Assistance|||||| +|Volkswagen|Taos 20226|Driver Assistance|||||| +|Volkswagen|Tiguan 20206|Driver Assistance|||||| |Volkswagen|Touran 2017|Driver Assistance|||||| |Volkswagen|e-Golf 2020|Driver Assistance|||||| -|Škoda|Kamiq 2021|Driver Assistance|||||| +|Škoda|Kamiq 20214|Driver Assistance|||||| |Škoda|Karoq 2019|Driver Assistance|||||| |Škoda|Kodiaq 2019|Driver Assistance|||||| |Škoda|Octavia 2019|Driver Assistance|||||| @@ -116,28 +104,36 @@ ## Bronze Cars -|Make|Model (US Market Reference)|Supported Package|openpilot Longitudinal|FSR Longitudinal|FSR Steering|Steering Torque|Actively Maintained| +|Make|Model|Supported Package|openpilot Longitudinal|FSR Longitudinal|FSR Steering|Steering Torque|Actively Maintained| |---|---|---|:---:|:---:|:---:|:---:|:---:| -|Acura|ILX 2019|AcuraWatch Plus|||||| -|Acura|RDX 2018|AcuraWatch Plus|||||| -|Cadillac|Escalade ESV 2016|ACC + LKAS|||||| -|Chevrolet|Volt Premier 2018|Adaptive Cruise|||||| +|Acura|ILX 2019|AcuraWatch Plus|||||| +|Acura|RDX 2018|AcuraWatch Plus|||||| +|Acura|RDX 2021|All|||||| +|Cadillac|Escalade ESV 20163|ACC + LKAS|||||| +|Chevrolet|Volt Premier 20183|Adaptive Cruise|||||| |Chrysler|Pacifica 2018|Adaptive Cruise|||||| |Chrysler|Pacifica 2020|Adaptive Cruise|||||| |Chrysler|Pacifica Hybrid 2017|Adaptive Cruise|||||| |Chrysler|Pacifica Hybrid 2018|Adaptive Cruise|||||| |Chrysler|Pacifica Hybrid 2019|Adaptive Cruise|||||| -|GMC|Acadia Denali 2018|Adaptive Cruise|||||| -|Honda|CR-V 2016|Touring|||||| -|Honda|CR-V EU 2016|Touring|||||| -|Honda|Fit 2019|Honda Sensing|||||| -|Honda|Freed 2020|Honda Sensing|||||| -|Honda|HR-V 2020|Honda Sensing|||||| +|GMC|Acadia Denali 20183|Adaptive Cruise|||||| +|Honda|Accord 2021|All|||||| +|Honda|Accord Hybrid 2021|All|||||| +|Honda|CR-V 2016|Touring|||||| +|Honda|CR-V 2021|Honda Sensing|||||| +|Honda|CR-V Hybrid 2019|Honda Sensing|||||| +|Honda|Civic Hatchback 2021|All|||||| +|Honda|Civic Sedan/Coupe 2018|Honda Sensing|||||| +|Honda|Civic Sedan/Coupe 2020|All|||||| +|Honda|E 2020|All|||||| +|Honda|Fit 2019|Honda Sensing|||||| +|Honda|Freed 2020|Honda Sensing|||||| +|Honda|HR-V 2020|Honda Sensing|||||| +|Honda|Insight 2021|All|||||| |Honda|Odyssey 2020|Honda Sensing|||||| -|Honda|Odyssey CHN 2020|Honda Sensing|||||| -|Honda|Passport 2021|All|||||| -|Honda|Pilot 2021|Honda Sensing|||||| -|Honda|Ridgeline 2021|Honda Sensing|||||| +|Honda|Passport 2021|All|||||| +|Honda|Pilot 2021|Honda Sensing|||||| +|Honda|Ridgeline 2021|Honda Sensing|||||| |Hyundai|Elantra 2019|SCC + LKAS|||||| |Hyundai|Genesis 2016|SCC + LKAS|||||| |Hyundai|Ioniq Electric Limited 2019|SCC + LKAS|||||| @@ -156,10 +152,12 @@ |Subaru|Forester 2021|EyeSight|||||| |Subaru|Impreza Limited 2019|EyeSight|||||| |Subaru|Impreza Sport 2021|EyeSight|||||| -|Toyota|Avalon 2021|TSS-P|||||| +|Toyota|Avalon 2021|TSS-P|1||||| |Toyota|Avalon 2022|TSS-P|||||| -|Toyota|Avalon Hybrid 2021|TSS-P|||||| -|Toyota|Corolla 2019|All|||||| -|Toyota|RAV4 2018|TSS-P|||||| -|Volkswagen|California 2021|Driver Assistance|||||| -|Volkswagen|Caravelle 2020|Driver Assistance|||||| +|Toyota|Avalon Hybrid 2021|TSS-P|1||||| +|Toyota|Corolla 2019|All|1||||| +|Toyota|Prius 2020|TSS-P|1|||7|| +|Toyota|Prius v 2017|TSS-P|1|||7|| +|Toyota|RAV4 2018|TSS-P|1||||| +|Volkswagen|California 20216|Driver Assistance|||||| +|Volkswagen|Caravelle 20206|Driver Assistance|||||| diff --git a/docs/cars.py b/docs/cars.py index 8062477479..a81296f71d 100755 --- a/docs/cars.py +++ b/docs/cars.py @@ -2,10 +2,14 @@ from collections import defaultdict, namedtuple from enum import Enum import os +from typing import Dict from common.basedir import BASEDIR from common.params import Params from selfdrive.car.car_helpers import interfaces, get_interface_attr +from selfdrive.car.toyota.values import CAR as TOYOTA +from selfdrive.car.volkswagen.values import CAR as VOLKSWAGEN +from selfdrive.car.gm.values import CAR as GM from selfdrive.test.test_routes import non_tested_cars @@ -15,54 +19,127 @@ class Tier(Enum): BRONZE = "Bronze" -class Car: - 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 +class Column(Enum): + MAKE = "Make" + MODEL = "Model" + PACKAGE = "Supported Package" + LONGITUDINAL = "openpilot Longitudinal" + FSR_LONGITUDINAL = "FSR Longitudinal" + FSR_STEERING = "FSR Steering" + STEERING_TORQUE = "Steering Torque" + SUPPORTED = "Actively Maintained" - 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): - return {5: Tier.GOLD, 4: Tier.SILVER}.get(sum(self.stars), Tier.BRONZE) +StarColumns = list(Column)[3:] +CarException = namedtuple("CarException", ["cars", "text", "column", "star"], defaults=[None]) def make_row(columns): return "|{}|".format("|".join(columns)) -# TODO: unify with column names below? -Stars = namedtuple("Stars", ["op_long", "fsr_long", "fsr_lat", "steering_torque", "well_supported"]) +def get_star_icon(variant): + return ''.format(variant) + + +def get_exceptions(CP) -> Dict[Column, CarException]: + exceptions = {} + for car_exception in CAR_EXCEPTIONS: + if CP.carFingerprint in car_exception.cars: + exceptions[car_exception.column] = car_exception + return exceptions -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"] +CAR_EXCEPTIONS = [ + CarException([TOYOTA.LEXUS_CTH, TOYOTA.LEXUS_ESH, TOYOTA.LEXUS_NX, TOYOTA.LEXUS_NXH, TOYOTA.LEXUS_RX, + TOYOTA.LEXUS_RXH, TOYOTA.AVALON, TOYOTA.AVALONH_2019, TOYOTA.COROLLA, TOYOTA.HIGHLANDER, + TOYOTA.HIGHLANDERH, TOYOTA.PRIUS, TOYOTA.PRIUS_V, TOYOTA.RAV4, TOYOTA.RAV4H, TOYOTA.SIENNA], + "When disconnecting the Driver Support Unit (DSU), openpilot Adaptive Cruise Control (ACC) will replace " + "stock Adaptive Cruise Control (ACC). NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).", + Column.LONGITUDINAL, star="half"), + CarException([TOYOTA.CAMRY, TOYOTA.CAMRY_TSS2, TOYOTA.CAMRYH], + "28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.", + Column.FSR_LONGITUDINAL), + CarException([GM.ESCALADE_ESV, GM.VOLT, GM.ACADIA], + "Requires an [OBD-II](https://comma.ai/shop/products/comma-car-harness) car harness and [community built ASCM harness]" + "(https://github.com/commaai/openpilot/wiki/GM#hardware). NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).", + Column.MODEL), + CarException([VOLKSWAGEN.SKODA_KAMIQ_MK1], + "Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.", + Column.MODEL), + CarException([VOLKSWAGEN.PASSAT_MK8], + "Not including the USA/China market Passat, which is based on the (currently) unsupported PQ35/NMS platform.", + Column.MODEL), + CarException([VOLKSWAGEN.ARTEON_MK1, VOLKSWAGEN.ATLAS_MK1, VOLKSWAGEN.TRANSPORTER_T61, VOLKSWAGEN.TCROSS_MK1, + VOLKSWAGEN.TROC_MK1, VOLKSWAGEN.TAOS_MK1, VOLKSWAGEN.TIGUAN_MK2], + 'Model-years 2021 and beyond may have a new camera harness design, which isn\'t yet available from the comma ' + 'store. Before ordering, remove the Lane Assist camera cover and check to see if the connector is black ' + '(older design) or light brown (newer design). For the newer design, in the interim, choose "VW J533 Development" ' + 'from the vehicle drop-down for a harness that integrates at the CAN gateway inside the dashboard.', + Column.MODEL), + CarException([TOYOTA.PRIUS, TOYOTA.PRIUS_V], + "An inaccurate steering wheel angle sensor makes precise control difficult.", + Column.STEERING_TORQUE, star="half"), +] + + +class Car: + def __init__(self, car_info, CP): + self.make, self.model = car_info.name.split(' ', 1) + self.car_fingerprint = CP.carFingerprint + 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.exceptions = get_exceptions(CP) + self.stars = self._calculate_stars(CP, car_info) + + @property + def row(self): + # TODO: add YouTube videos + row = [self.make, self.model_string, self.package, *map(get_star_icon, self.stars)] + + # Check for car exceptions + for row_idx, column in enumerate(Column): + exception = self.exceptions.get(column, None) + if exception is not None: + superscript_number = CAR_EXCEPTIONS.index(exception) + 1 + row[row_idx] += "{}".format(superscript_number) + + return make_row(row) + + @property + def tier(self): + return {5: Tier.GOLD, 4: Tier.SILVER}.get(self.stars.count("full"), Tier.BRONZE) + + def _calculate_stars(self, CP, car_info): + # Some minimum steering speeds are not yet in CarParams + min_steer_speed = CP.minSteerSpeed + if car_info.min_steer_speed is not None: + min_steer_speed = car_info.min_steer_speed + assert CP.minSteerSpeed == 0, "Minimum steer speed set in both CarInfo and CarParams for {}".format( + CP.carFingerprint) + + # TODO: make sure well supported check is complete + stars = [CP.openpilotLongitudinalControl, CP.minEnableSpeed <= 1e-3, min_steer_speed <= 1e-3, + CP.carName in MAKES_GOOD_STEERING_TORQUE, CP.carFingerprint not in non_tested_cars] + + # Check for star demotions from exceptions + for idx, (star, column) in enumerate(zip(stars, StarColumns)): + star = "full" if star else "empty" + exception = self.exceptions.get(column, None) + if exception is not None and exception.star is not None: + star = exception.star.lower() + stars[idx] = star + return stars def generate_cars_md(): @@ -90,14 +167,10 @@ def generate_cars_md(): 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(make_row([column.value for column in Column])) 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.extend(map(lambda car: car.row, cars)) cars_md_doc.append("") # newline return '\n'.join(cars_md_doc) diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 24fe0f062f..924dcbf1f7 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -7,7 +7,7 @@ from common.numpy_fast import clip # kg of standard extra cargo to count for drive, gas, etc... STD_CARGO_KG = 136. -CarInfo = namedtuple('CarInfo', ['name', 'years', 'package', 'min_steer_speed'], defaults=[0]) +CarInfo = namedtuple('CarInfo', ['name', 'years', 'package', 'min_steer_speed'], defaults=[None]) def gen_empty_fingerprint():