mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-21 00:03:45 +08:00
Car docs: show more information about cars (#25415)
* back to actual information * remove some star code * round speeds * Try out showing lateral acceleration * remove that * Fix speed units * Add harness and try rounding to nearest half before scapping it fix ^2 ^2 * Add back steering torque star * Fix static analysis * auto-generate header * fix static analysis. set to Harness.none by default * rm old-commit-hash: 747bcb013dabdb1f220dc97a37270b42cb4eae03
This commit is contained in:
@@ -7,22 +7,10 @@
|
||||
|
||||
A supported vehicle is one that just works when you install a comma device. Every car performs differently with openpilot, but all supported cars should provide a better experience than any stock system.
|
||||
|
||||
## How We Rate The Cars
|
||||
|
||||
{% for star_row in STAR_DESCRIPTIONS.values() %}
|
||||
{% for name, stars in star_row.items() %}
|
||||
### {{name}}
|
||||
{% for star, description in stars %}
|
||||
- {{star_icon.format(star)}} - {{description}}
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
# {{all_car_info | length}} Supported Cars
|
||||
|
||||
|{{Column | map(attribute='value') | join('|')}}|
|
||||
|---|---|---|:---:|:---:|:---:|:---:|
|
||||
|---|---|---|{% 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, footnote_tag)}}|{% endfor %}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ from typing import Dict
|
||||
|
||||
from cereal import car
|
||||
from selfdrive.car import dbc_dict
|
||||
from selfdrive.car.docs_definitions import CarInfo, Harness
|
||||
from selfdrive.car.docs_definitions import CarInfo
|
||||
Ecu = car.CarParams.Ecu
|
||||
|
||||
SPEED_FROM_RPM = 0.008587
|
||||
@@ -18,7 +18,7 @@ class CAR:
|
||||
BODY = "COMMA BODY"
|
||||
|
||||
CAR_INFO: Dict[str, CarInfo] = {
|
||||
CAR.BODY: CarInfo("comma body", package="All", harness=Harness.none),
|
||||
CAR.BODY: CarInfo("comma body", package="All"),
|
||||
}
|
||||
|
||||
FW_VERSIONS = {
|
||||
|
||||
+9
-19
@@ -8,16 +8,15 @@ from natsort import natsorted
|
||||
from typing import Dict, List
|
||||
|
||||
from common.basedir import BASEDIR
|
||||
from selfdrive.car.docs_definitions import STAR_DESCRIPTIONS, StarColumns, TierColumns, CarInfo, Column, Star
|
||||
from selfdrive.car.docs_definitions import CarInfo, Column
|
||||
from selfdrive.car.car_helpers import interfaces, get_interface_attr
|
||||
from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR as HKG_RADAR_START_ADDR
|
||||
|
||||
|
||||
def get_all_footnotes(only_tier_cols: bool = False) -> Dict[Enum, int]:
|
||||
def get_all_footnotes() -> Dict[Enum, int]:
|
||||
all_footnotes = []
|
||||
hide_cols = set(StarColumns) - set(TierColumns) if only_tier_cols else []
|
||||
for footnotes in get_interface_attr("Footnote", ignore_none=True).values():
|
||||
all_footnotes.extend([fn for fn in footnotes if fn.value.column not in hide_cols])
|
||||
all_footnotes.extend(footnotes)
|
||||
return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)}
|
||||
|
||||
|
||||
@@ -25,9 +24,9 @@ CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md")
|
||||
CARS_MD_TEMPLATE = os.path.join(BASEDIR, "selfdrive", "car", "CARS_template.md")
|
||||
|
||||
|
||||
def get_all_car_info(only_tier_cols: bool = False) -> List[CarInfo]:
|
||||
def get_all_car_info() -> List[CarInfo]:
|
||||
all_car_info: List[CarInfo] = []
|
||||
footnotes = get_all_footnotes(only_tier_cols)
|
||||
footnotes = get_all_footnotes()
|
||||
for model, car_info in get_interface_attr("CAR_INFO", combine_brands=True).items():
|
||||
# Hyundai exception: those with radar have openpilot longitudinal
|
||||
fingerprint = {0: {}, 1: {HKG_RADAR_START_ADDR: 8}, 2: {}, 3: {}}
|
||||
@@ -57,21 +56,13 @@ def group_by_make(all_car_info: List[CarInfo]) -> Dict[str, List[CarInfo]]:
|
||||
return dict(sorted_car_info)
|
||||
|
||||
|
||||
def generate_cars_md(all_car_info: List[CarInfo], template_fn: str, only_tier_cols: bool) -> str:
|
||||
def generate_cars_md(all_car_info: List[CarInfo], template_fn: str) -> str:
|
||||
with open(template_fn, "r") as f:
|
||||
template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True)
|
||||
|
||||
cols = list(Column)
|
||||
if only_tier_cols:
|
||||
hide_cols = set(StarColumns) - set(TierColumns)
|
||||
cols = [c for c in cols if c not in hide_cols]
|
||||
for car in all_car_info:
|
||||
for c in hide_cols:
|
||||
del car.row[c]
|
||||
|
||||
footnotes = [fn.value.text for fn in get_all_footnotes(only_tier_cols)]
|
||||
footnotes = [fn.value.text for fn in get_all_footnotes()]
|
||||
cars_md: str = template.render(all_car_info=all_car_info, group_by_make=group_by_make,
|
||||
footnotes=footnotes, Star=Star, Column=cols, STAR_DESCRIPTIONS=STAR_DESCRIPTIONS)
|
||||
footnotes=footnotes, Column=Column)
|
||||
return cars_md
|
||||
|
||||
|
||||
@@ -79,11 +70,10 @@ if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Auto generates supported cars documentation",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
|
||||
parser.add_argument("--tier-columns", action="store_true", help="Include only columns that count in the tier")
|
||||
parser.add_argument("--template", default=CARS_MD_TEMPLATE, help="Override default template filename")
|
||||
parser.add_argument("--out", default=CARS_MD_OUT, help="Override default generated filename")
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.out, 'w') as f:
|
||||
f.write(generate_cars_md(get_all_car_info(args.tier_columns), args.template, args.tier_columns))
|
||||
f.write(generate_cars_md(get_all_car_info(), args.template))
|
||||
print(f"Generated and written to {args.out}")
|
||||
|
||||
@@ -2,7 +2,7 @@ import re
|
||||
from collections import namedtuple
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Optional, Tuple, Union, no_type_check
|
||||
from typing import Dict, List, Optional, Tuple, Union
|
||||
|
||||
from cereal import car
|
||||
from common.conversions import Conversions as CV
|
||||
@@ -15,20 +15,15 @@ NO_AUTO_RESUME_STOCK_LONG = {"toyota", "gm"}
|
||||
NO_AUTO_RESUME = NO_AUTO_RESUME_STOCK_LONG | {"nissan", "subaru"}
|
||||
|
||||
|
||||
class Tier(Enum):
|
||||
GOLD = 0
|
||||
SILVER = 1
|
||||
BRONZE = 2
|
||||
|
||||
|
||||
class Column(Enum):
|
||||
MAKE = "Make"
|
||||
MODEL = "Model"
|
||||
PACKAGE = "Supported Package"
|
||||
LONGITUDINAL = "openpilot ACC"
|
||||
FSR_LONGITUDINAL = "Stop and Go"
|
||||
FSR_STEERING = "Steer to 0"
|
||||
LONGITUDINAL = "ACC"
|
||||
FSR_LONGITUDINAL = "No ACC accel below"
|
||||
FSR_STEERING = "No ALC below"
|
||||
STEERING_TORQUE = "Steering Torque"
|
||||
HARNESS = "Harness"
|
||||
|
||||
|
||||
class Star(Enum):
|
||||
@@ -37,9 +32,46 @@ class Star(Enum):
|
||||
EMPTY = "empty"
|
||||
|
||||
|
||||
StarColumns = list(Column)[3:]
|
||||
TierColumns = (Column.FSR_LONGITUDINAL, Column.FSR_STEERING, Column.STEERING_TORQUE)
|
||||
CarFootnote = namedtuple("CarFootnote", ["text", "column", "star"], defaults=[None])
|
||||
class Harness(Enum):
|
||||
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"
|
||||
|
||||
|
||||
CarFootnote = namedtuple("CarFootnote", ["text", "column"], defaults=[None])
|
||||
|
||||
|
||||
def get_footnotes(footnotes: List[Enum], column: Column) -> List[Enum]:
|
||||
@@ -83,7 +115,7 @@ class CarInfo:
|
||||
footnotes: List[Enum] = field(default_factory=list)
|
||||
min_steer_speed: Optional[float] = None
|
||||
min_enable_speed: Optional[float] = None
|
||||
harness: Optional[Enum] = None
|
||||
harness: Enum = Harness.none
|
||||
|
||||
def init(self, CP: car.CarParams, all_footnotes: Dict[Enum, int]):
|
||||
# TODO: set all the min steer speeds in carParams and remove this
|
||||
@@ -103,11 +135,11 @@ class CarInfo:
|
||||
Column.MAKE: self.make,
|
||||
Column.MODEL: self.model,
|
||||
Column.PACKAGE: self.package,
|
||||
# StarColumns
|
||||
Column.LONGITUDINAL: Star.FULL if CP.openpilotLongitudinalControl and not CP.radarOffCan else Star.EMPTY,
|
||||
Column.FSR_LONGITUDINAL: Star.FULL if self.min_enable_speed <= 0. else Star.EMPTY,
|
||||
Column.FSR_STEERING: Star.FULL if self.min_steer_speed <= 0. else Star.EMPTY,
|
||||
Column.LONGITUDINAL: "openpilot" if CP.openpilotLongitudinalControl and not CP.radarOffCan else "Stock",
|
||||
Column.FSR_LONGITUDINAL: f"{max(self.min_enable_speed * CV.MS_TO_MPH, 0):.0f} mph",
|
||||
Column.FSR_STEERING: f"{max(self.min_steer_speed * CV.MS_TO_MPH, 0):.0f} mph",
|
||||
Column.STEERING_TORQUE: Star.EMPTY,
|
||||
Column.HARNESS: self.harness.value,
|
||||
}
|
||||
|
||||
# Set steering torque star from max lateral acceleration
|
||||
@@ -115,26 +147,7 @@ class CarInfo:
|
||||
if CP.maxLateralAccel >= GOOD_TORQUE_THRESHOLD:
|
||||
self.row[Column.STEERING_TORQUE] = Star.FULL
|
||||
|
||||
if CP.notCar:
|
||||
for col in StarColumns:
|
||||
self.row[col] = Star.FULL
|
||||
|
||||
self.all_footnotes = all_footnotes
|
||||
for column in StarColumns:
|
||||
# Demote if footnote specifies a star
|
||||
for fn in get_footnotes(self.footnotes, column):
|
||||
if fn.value.star is not None:
|
||||
self.row[column] = fn.value.star
|
||||
|
||||
# openpilot ACC star doesn't count for tiers
|
||||
full_stars = [s for col, s in self.row.items() if col in TierColumns].count(Star.FULL)
|
||||
if full_stars == len(TierColumns):
|
||||
self.tier = Tier.GOLD
|
||||
elif full_stars == len(TierColumns) - 1:
|
||||
self.tier = Tier.SILVER
|
||||
else:
|
||||
self.tier = Tier.BRONZE
|
||||
|
||||
self.year_list = get_year_list(self.years)
|
||||
self.detail_sentence = self.get_detail_sentence(CP)
|
||||
|
||||
@@ -167,10 +180,9 @@ class CarInfo:
|
||||
else:
|
||||
raise Exception(f"This notCar does not have a detail sentence: {CP.carFingerprint}")
|
||||
|
||||
@no_type_check
|
||||
def get_column(self, column: Column, star_icon: str, footnote_tag: str) -> str:
|
||||
item: Union[str, Star] = self.row[column]
|
||||
if column in StarColumns:
|
||||
if isinstance(item, Star):
|
||||
item = star_icon.format(item.value)
|
||||
elif column == Column.MODEL and len(self.years):
|
||||
item += f" {self.years}"
|
||||
@@ -182,61 +194,3 @@ class CarInfo:
|
||||
|
||||
return item
|
||||
|
||||
|
||||
class Harness(Enum):
|
||||
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"
|
||||
|
||||
|
||||
STAR_DESCRIPTIONS = {
|
||||
"Gas & Brakes": { # icon and row name
|
||||
Column.FSR_LONGITUDINAL.value: [
|
||||
[Star.FULL.value, "openpilot operates down to 0 mph."],
|
||||
[Star.EMPTY.value, "openpilot operates only above a minimum speed. See your car's manual for the minimum speed."],
|
||||
],
|
||||
},
|
||||
"Steering": {
|
||||
Column.FSR_STEERING.value: [
|
||||
[Star.FULL.value, "openpilot can control the steering wheel down to 0 mph."],
|
||||
[Star.EMPTY.value, "No steering control below certain speeds. See your car's manual for the minimum speed."],
|
||||
],
|
||||
Column.STEERING_TORQUE.value: [
|
||||
[Star.FULL.value, "Car has enough steering torque to comfortably take most highway turns."],
|
||||
[Star.EMPTY.value, "Limited ability to make tighter turns."],
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ class TestCarDocs(unittest.TestCase):
|
||||
self.all_cars = get_all_car_info()
|
||||
|
||||
def test_generator(self):
|
||||
generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE, False)
|
||||
generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE)
|
||||
with open(CARS_MD_OUT, "r") as f:
|
||||
current_cars_md = f.read()
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from typing import Dict, List, Union
|
||||
from cereal import car
|
||||
from common.conversions import Conversions as CV
|
||||
from selfdrive.car import dbc_dict
|
||||
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness, Star
|
||||
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness
|
||||
|
||||
Ecu = car.CarParams.Ecu
|
||||
MIN_ACC_SPEED = 19. * CV.MPH_TO_MS
|
||||
@@ -89,7 +89,7 @@ class Footnote(Enum):
|
||||
DSU = CarFootnote(
|
||||
"When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace " +
|
||||
"stock Adaptive Cruise Control (ACC). <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b>",
|
||||
Column.LONGITUDINAL, star=Star.HALF)
|
||||
Column.LONGITUDINAL)
|
||||
CAMRY = CarFootnote(
|
||||
"openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.",
|
||||
Column.FSR_LONGITUDINAL)
|
||||
|
||||
Reference in New Issue
Block a user