diff --git a/cereal/car.capnp b/cereal/car.capnp index 3df23d99214ea2..c724b43f72dc00 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -610,6 +610,7 @@ struct CarParams { volkswagenMqbEvo @29; chryslerCusw @30; psa @31; + fcaGiorgio @32; # certain FCA/Stellantis vehicles including Jeep, Alfa Romeo, and Maserati } enum SteerControlType { diff --git a/docs/CARS.md b/docs/CARS.md index 8fafc483f2ded3..1ab3dd0c64ac79 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,13 +4,14 @@ A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified. -# 287 Supported Cars +# 288 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| |Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Alfa|Romeo Stelvio 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 RJ45 cable (7 ft)
- 1 VW A connector
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/launch_env.sh b/launch_env.sh index 81578aff0157e3..81fe4ee0beb11b 100755 --- a/launch_env.sh +++ b/launch_env.sh @@ -11,3 +11,5 @@ if [ -z "$AGNOS_VERSION" ]; then fi export STAGING_ROOT="/data/safe_staging" + +export FINGERPRINT="ALFA_ROMEO_STELVIO_1ST_GEN" diff --git a/opendbc b/opendbc index de39b143a31cd2..739bc5004b851a 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit de39b143a31cd29b4df4c0cbba71316c1bc8e71b +Subproject commit 739bc5004b851a5daebcf5d7eb437c3f38b3eac6 diff --git a/panda b/panda index 376408bb4f6706..cb63c2a9fef00a 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 376408bb4f6706b682eb6d607bedd14958665084 +Subproject commit cb63c2a9fef00aedcb80dff1135ae120943947f8 diff --git a/selfdrive/car/fca_giorgio/__init__.py b/selfdrive/car/fca_giorgio/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/selfdrive/car/fca_giorgio/carcontroller.py b/selfdrive/car/fca_giorgio/carcontroller.py new file mode 100644 index 00000000000000..daaee560f3c2e4 --- /dev/null +++ b/selfdrive/car/fca_giorgio/carcontroller.py @@ -0,0 +1,46 @@ +from opendbc.can.packer import CANPacker +from openpilot.selfdrive.car import apply_driver_steer_torque_limits +from openpilot.selfdrive.car.interfaces import CarControllerBase + +from openpilot.selfdrive.car.fca_giorgio import fca_giorgiocan +from openpilot.selfdrive.car.fca_giorgio.values import CANBUS, CarControllerParams + + +class CarController(CarControllerBase): + def __init__(self, dbc_name, CP, VM): + self.CP = CP + self.CCP = CarControllerParams(CP) + self.packer_pt = CANPacker(dbc_name) + + self.apply_steer_last = 0 + self.frame = 0 + + def update(self, CC, CS, now_nanos): + actuators = CC.actuators + can_sends = [] + + # **** Steering Controls ************************************************ # + + if self.frame % self.CCP.STEER_STEP == 0: + if CC.latActive: + new_steer = int(round(actuators.steer * self.CCP.STEER_MAX)) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.CCP) + else: + apply_steer = 0 + + self.apply_steer_last = apply_steer + can_sends.append(fca_giorgiocan.create_steering_control(self.packer_pt, CANBUS.pt, apply_steer, CC.latActive)) + + # **** HUD Controls ***************************************************** # + + if self.frame % self.CCP.HUD_1_STEP == 0: + can_sends.append(fca_giorgiocan.create_lka_hud_1_control(self.packer_pt, CANBUS.pt, CC.latActive)) + if self.frame % self.CCP.HUD_2_STEP == 0: + can_sends.append(fca_giorgiocan.create_lka_hud_2_control(self.packer_pt, CANBUS.pt, CC.latActive)) + + new_actuators = actuators.as_builder() + new_actuators.steer = self.apply_steer_last / self.CCP.STEER_MAX + new_actuators.steerOutputCan = self.apply_steer_last + + self.frame += 1 + return new_actuators, can_sends diff --git a/selfdrive/car/fca_giorgio/carstate.py b/selfdrive/car/fca_giorgio/carstate.py new file mode 100644 index 00000000000000..8bd42e4bd4035a --- /dev/null +++ b/selfdrive/car/fca_giorgio/carstate.py @@ -0,0 +1,88 @@ +import numpy as np +from cereal import car +from openpilot.common.conversions import Conversions as CV +from openpilot.selfdrive.car.interfaces import CarStateBase +from opendbc.can.parser import CANParser +from openpilot.selfdrive.car.fca_giorgio.values import DBC, CANBUS, CarControllerParams + + +GearShifter = car.CarState.GearShifter + +class CarState(CarStateBase): + def __init__(self, CP): + super().__init__(CP) + self.frame = 0 + self.CCP = CarControllerParams(CP) + + def update(self, pt_cp, cam_cp): + ret = car.CarState.new_message() + # Update vehicle speed and acceleration from ABS wheel speeds. + ret.wheelSpeeds = self.get_wheel_speeds( + pt_cp.vl["ABS_1"]["WHEEL_SPEED_FL"], + pt_cp.vl["ABS_1"]["WHEEL_SPEED_FR"], + pt_cp.vl["ABS_1"]["WHEEL_SPEED_RL"], + pt_cp.vl["ABS_1"]["WHEEL_SPEED_RR"], + unit=1.0 + ) + + ret.vEgoRaw = float(np.mean([ret.wheelSpeeds.fl, ret.wheelSpeeds.fr, ret.wheelSpeeds.rl, ret.wheelSpeeds.rr])) + ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) + ret.standstill = ret.vEgoRaw == 0 + + ret.steeringAngleDeg = pt_cp.vl["EPS_1"]["STEERING_ANGLE"] + ret.steeringRateDeg = pt_cp.vl["EPS_1"]["STEERING_RATE"] + ret.steeringTorque = pt_cp.vl["EPS_2"]["DRIVER_TORQUE"] + ret.steeringTorqueEps = pt_cp.vl["EPS_3"]["EPS_TORQUE"] + ret.steeringPressed = ret.steeringTorque > 80 + ret.yawRate = pt_cp.vl["ABS_2"]["YAW_RATE"] + ret.steerFaultPermanent = bool(pt_cp.vl["EPS_2"]["LKA_FAULT"]) + + # TODO: unsure if this is accel pedal or engine throttle + #ret.gas = pt_cp.vl["ENGINE_1"]["ACCEL_PEDAL"] + ret.gasPressed = ret.gas > 0 + ret.brake = pt_cp.vl["ABS_4"]["BRAKE_PRESSURE"] + ret.brakePressed = bool(pt_cp.vl["ABS_3"]["BRAKE_PEDAL_SWITCH"]) + #ret.parkingBrake = TODO + + if bool(pt_cp.vl["ENGINE_1"]["REVERSE"]): + ret.gearShifter = GearShifter.reverse + else: + ret.gearShifter = GearShifter.drive + + ret.cruiseState.available = pt_cp.vl["ACC_1"]["CRUISE_STATUS"] in (1, 2, 3) + ret.cruiseState.enabled = pt_cp.vl["ACC_1"]["CRUISE_STATUS"] in (2, 3) + ret.cruiseState.speed = pt_cp.vl["ACC_1"]["HUD_SPEED"] * CV.KPH_TO_MS + + ret.leftBlinker = bool(pt_cp.vl["BCM_1"]["LEFT_TURN_STALK"]) + ret.rightBlinker = bool(pt_cp.vl["BCM_1"]["RIGHT_TURN_STALK"]) + # ret.buttonEvents = TODO + # ret.espDisabled = TODO + + self.frame += 1 + return ret + + + @staticmethod + def get_can_parser(CP): + messages = [ + # sig_address, frequency + ("ABS_1", 100), + ("ABS_2", 100), + ("ABS_3", 100), + ("ABS_4", 100), + ("ENGINE_1", 100), + ("EPS_1", 100), + ("EPS_2", 100), + ("EPS_3", 100), + ("ACC_1", 12), # 12hz inactive / 50hz active + ("BCM_1", 4), # 4Hz plus triggered updates + ] + + return CANParser(DBC[CP.carFingerprint]["pt"], messages, CANBUS.pt) + + + @staticmethod + def get_cam_can_parser(CP): + messages = [] + + return CANParser(DBC[CP.carFingerprint]["pt"], messages, CANBUS.cam) diff --git a/selfdrive/car/fca_giorgio/fca_giorgiocan.py b/selfdrive/car/fca_giorgio/fca_giorgiocan.py new file mode 100644 index 00000000000000..ea27227bc9edd5 --- /dev/null +++ b/selfdrive/car/fca_giorgio/fca_giorgiocan.py @@ -0,0 +1,24 @@ +def create_steering_control(packer, bus, apply_steer, lkas_enabled): + values = { + "LKA_ACTIVE": lkas_enabled, + "LKA_TORQUE": apply_steer, + } + + return packer.make_can_msg("LKA_COMMAND", bus, values) + + +def create_lka_hud_1_control(packer, bus, lat_active): + values = { + "NEW_SIGNAL_5": 1, + "NEW_SIGNAL_4": 6, + } + + return packer.make_can_msg("LKA_HUD_1", bus, values) + + +def create_lka_hud_2_control(packer, bus, lat_active): + values = { + "NEW_SIGNAL_1": 1, + } + + return packer.make_can_msg("LKA_HUD_2", bus, values) diff --git a/selfdrive/car/fca_giorgio/fingerprints.py b/selfdrive/car/fca_giorgio/fingerprints.py new file mode 100644 index 00000000000000..46416c07a19296 --- /dev/null +++ b/selfdrive/car/fca_giorgio/fingerprints.py @@ -0,0 +1,12 @@ +from cereal import car +from openpilot.selfdrive.car.fca_giorgio.values import CAR + +Ecu = car.CarParams.Ecu + +FW_VERSIONS = { + CAR.ALFA_ROMEO_STELVIO_1ST_GEN: { + (Ecu.engine, 0x7e0, None): [ + b'PLACEHOLDER', + ], + } +} diff --git a/selfdrive/car/fca_giorgio/interface.py b/selfdrive/car/fca_giorgio/interface.py new file mode 100644 index 00000000000000..f6e401e5eafce1 --- /dev/null +++ b/selfdrive/car/fca_giorgio/interface.py @@ -0,0 +1,37 @@ +from cereal import car +from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car.interfaces import CarInterfaceBase +from openpilot.selfdrive.car.fca_giorgio.values import CAR + + +class CarInterface(CarInterfaceBase): + @staticmethod + def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, docs): + ret.carName = "fca_giorgio" + ret.radarUnavailable = True + + # Set global parameters + + ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.fcaGiorgio)] + + # Global lateral tuning defaults, can be overridden per-vehicle + + ret.steerLimitTimer = 1.0 + ret.steerActuatorDelay = 0.1 + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + + # Global longitudinal tuning defaults, can be overridden per-vehicle + + ret.pcmCruise = not ret.openpilotLongitudinalControl + + return ret + + # returns a car.CarState + def _update(self, c): + ret = self.CS.update(self.cp, self.cp_cam) + + events = self.create_common_events(ret, pcm_enable=not self.CS.CP.openpilotLongitudinalControl) + + ret.events = events.to_msg() + return ret + diff --git a/selfdrive/car/fca_giorgio/radar_interface.py b/selfdrive/car/fca_giorgio/radar_interface.py new file mode 100644 index 00000000000000..e654bd61fd4afd --- /dev/null +++ b/selfdrive/car/fca_giorgio/radar_interface.py @@ -0,0 +1,4 @@ +from openpilot.selfdrive.car.interfaces import RadarInterfaceBase + +class RadarInterface(RadarInterfaceBase): + pass diff --git a/selfdrive/car/fca_giorgio/values.py b/selfdrive/car/fca_giorgio/values.py new file mode 100644 index 00000000000000..a61825fc124c8a --- /dev/null +++ b/selfdrive/car/fca_giorgio/values.py @@ -0,0 +1,67 @@ +from dataclasses import dataclass, field + +from openpilot.selfdrive.car import dbc_dict, CarSpecs, DbcDict, PlatformConfig, Platforms +from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarParts +from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries + + +class CarControllerParams: + STEER_STEP = 1 + HUD_1_STEP = 50 + HUD_2_STEP = 25 + + STEER_MAX = 300 + STEER_DRIVER_ALLOWANCE = 80 + STEER_DRIVER_MULTIPLIER = 3 # weight driver torque heavily + STEER_DRIVER_FACTOR = 1 # from dbc + STEER_DELTA_UP = 4 + STEER_DELTA_DOWN = 4 + + def __init__(self, CP): + pass + + +class CANBUS: + pt = 0 + cam = 2 + + +@dataclass +class FcaGiorgioPlatformConfig(PlatformConfig): + dbc_dict: DbcDict = field(default_factory=lambda: dbc_dict('fca_giorgio', None)) + + +@dataclass(frozen=True, kw_only=True) +class FcaGiorgioCarSpecs(CarSpecs): + centerToFrontRatio: float = 0.45 + steerRatio: float = 14.2 + + +@dataclass +class FcaGiorgioCarDocs(CarDocs): + package: str = "Adaptive Cruise Control (ACC) & Lane Assist" + car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.vw_a])) + + +class CAR(Platforms): + config: FcaGiorgioPlatformConfig + + ALFA_ROMEO_STELVIO_1ST_GEN = FcaGiorgioPlatformConfig( + [FcaGiorgioCarDocs("Alfa Romeo Stelvio 2017-24")], + FcaGiorgioCarSpecs(mass=1660, wheelbase=2.82), + ) + + +FW_QUERY_CONFIG = FwQueryConfig( + requests=[ + # TODO: check data to ensure ABS does not skip ISO-TP frames on bus 0 + Request( + [StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST], + [StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE], + bus=0, + ), + ], +) + + +DBC = CAR.create_dbc_map() diff --git a/selfdrive/car/torque_data/override.toml b/selfdrive/car/torque_data/override.toml index 993eb3fb3c0fa5..98a8cdf91ab772 100644 --- a/selfdrive/car/torque_data/override.toml +++ b/selfdrive/car/torque_data/override.toml @@ -48,6 +48,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "VOLKSWAGEN_CADDY_MK3" = [1.2, 1.2, 0.1] "VOLKSWAGEN_PASSAT_NMS" = [2.5, 2.5, 0.1] "VOLKSWAGEN_SHARAN_MK2" = [2.5, 2.5, 0.1] +"ALFA_ROMEO_STELVIO_1ST_GEN" = [1.9, 1.9, 0.11] "HYUNDAI_SANTA_CRUZ_1ST_GEN" = [2.7, 2.7, 0.1] "KIA_SPORTAGE_5TH_GEN" = [2.6, 2.6, 0.1] "GENESIS_GV70_1ST_GEN" = [2.42, 2.42, 0.1] diff --git a/selfdrive/car/values.py b/selfdrive/car/values.py index bf5d378ab4f58c..f58c87ea6633e7 100644 --- a/selfdrive/car/values.py +++ b/selfdrive/car/values.py @@ -1,6 +1,7 @@ from typing import get_args from openpilot.selfdrive.car.body.values import CAR as BODY from openpilot.selfdrive.car.chrysler.values import CAR as CHRYSLER +from openpilot.selfdrive.car.fca_giorgio.values import CAR as FCA_GIORGIO from openpilot.selfdrive.car.ford.values import CAR as FORD from openpilot.selfdrive.car.gm.values import CAR as GM from openpilot.selfdrive.car.honda.values import CAR as HONDA @@ -13,7 +14,7 @@ from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA from openpilot.selfdrive.car.volkswagen.values import CAR as VOLKSWAGEN -Platform = BODY | CHRYSLER | FORD | GM | HONDA | HYUNDAI | MAZDA | MOCK | NISSAN | SUBARU | TESLA | TOYOTA | VOLKSWAGEN +Platform = BODY | CHRYSLER | FCA_GIORGIO | FORD | GM | HONDA | HYUNDAI | MAZDA | MOCK | NISSAN | SUBARU | TESLA | TOYOTA | VOLKSWAGEN BRANDS = get_args(Platform) PLATFORMS: dict[str, Platform] = {str(platform): platform for brand in BRANDS for platform in brand}