diff --git a/RELEASES.md b/RELEASES.md index b47a18a3de..5b63be2e43 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,6 @@ Version 0.8.16 (2022-XX-XX) ======================== +* Subaru Outback 2020-22 support Version 0.8.15 (2022-07-20) ======================== diff --git a/docs/CARS.md b/docs/CARS.md index c84008bd63..b9986f358b 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -19,7 +19,7 @@ A supported vehicle is one that just works when you install a comma device. Ever - [![star](assets/icon-star-empty.svg)](##) - Limited ability to make tighter turns. -# 196 Supported Cars +# 197 Supported Cars |Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque| |---|---|---|:---:|:---:|:---:|:---:| @@ -139,6 +139,7 @@ A supported vehicle is one that just works when you install a comma device. Ever |Subaru|Forester 2019-21|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Subaru|Impreza 2017-19|EyeSight|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Subaru|Impreza 2020-22|EyeSight|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| +|Subaru|Outback 2020-22|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Subaru|XV 2018-19|EyeSight|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Subaru|XV 2020-21|EyeSight|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Kamiq 2021[6](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| diff --git a/panda b/panda index a1686ca3ca..4b86b83991 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit a1686ca3ca55b004179f10bfc45af5fbd701ca64 +Subproject commit 4b86b83991e6be699c1eba79ea82846533f55467 diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index a336572051..b5429daef2 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -1,17 +1,20 @@ from opendbc.can.packer import CANPacker from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car.subaru import subarucan -from selfdrive.car.subaru.values import DBC, PREGLOBAL_CARS, CarControllerParams +from selfdrive.car.subaru.values import DBC, GLOBAL_GEN2, PREGLOBAL_CARS, CarControllerParams class CarController: def __init__(self, dbc_name, CP, VM): self.CP = CP self.apply_steer_last = 0 - self.es_distance_cnt = -1 + self.frame = 0 + self.es_lkas_cnt = -1 + self.es_distance_cnt = -1 + self.es_dashstatus_cnt = -1 self.cruise_button_prev = 0 - self.frame = 0 + self.last_cancel_frame = 0 self.p = CarControllerParams(CP) self.packer = CANPacker(DBC[CP.carFingerprint]['pt']) @@ -67,9 +70,14 @@ class CarController: self.es_distance_cnt = CS.es_distance_msg["COUNTER"] else: - if self.es_distance_cnt != CS.es_distance_msg["COUNTER"]: - can_sends.append(subarucan.create_es_distance(self.packer, CS.es_distance_msg, pcm_cancel_cmd)) - self.es_distance_cnt = CS.es_distance_msg["COUNTER"] + if pcm_cancel_cmd and (self.frame - self.last_cancel_frame) > 0.2: + bus = 1 if self.CP.carFingerprint in GLOBAL_GEN2 else 0 + can_sends.append(subarucan.create_es_distance(self.packer, CS.es_distance_msg, bus, pcm_cancel_cmd)) + self.last_cancel_frame = self.frame + + if self.es_dashstatus_cnt != CS.es_dashstatus_msg["COUNTER"]: + can_sends.append(subarucan.create_es_dashstatus(self.packer, CS.es_dashstatus_msg)) + self.es_dashstatus_cnt = CS.es_dashstatus_msg["COUNTER"] if self.es_lkas_cnt != CS.es_lkas_msg["COUNTER"]: can_sends.append(subarucan.create_es_lkas(self.packer, CS.es_lkas_msg, CC.enabled, hud_control.visualAlert, diff --git a/selfdrive/car/subaru/carstate.py b/selfdrive/car/subaru/carstate.py index 9246cbde18..7b2580c92d 100644 --- a/selfdrive/car/subaru/carstate.py +++ b/selfdrive/car/subaru/carstate.py @@ -4,7 +4,7 @@ from opendbc.can.can_define import CANDefine from common.conversions import Conversions as CV from selfdrive.car.interfaces import CarStateBase from opendbc.can.parser import CANParser -from selfdrive.car.subaru.values import DBC, STEER_THRESHOLD, CAR, PREGLOBAL_CARS +from selfdrive.car.subaru.values import DBC, STEER_THRESHOLD, CAR, GLOBAL_GEN2, PREGLOBAL_CARS class CarState(CarStateBase): @@ -13,7 +13,7 @@ class CarState(CarStateBase): can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) self.shifter_values = can_define.dv["Transmission"]["Gear"] - def update(self, cp, cp_cam): + def update(self, cp, cp_cam, cp_body): ret = car.CarState.new_message() ret.gas = cp.vl["Throttle"]["Throttle_Pedal"] / 255. @@ -21,13 +21,15 @@ class CarState(CarStateBase): if self.car_fingerprint in PREGLOBAL_CARS: ret.brakePressed = cp.vl["Brake_Pedal"]["Brake_Pedal"] > 2 else: - ret.brakePressed = cp.vl["Brake_Status"]["Brake"] == 1 + cp_brakes = cp_body if self.car_fingerprint in GLOBAL_GEN2 else cp + ret.brakePressed = cp_brakes.vl["Brake_Status"]["Brake"] == 1 + cp_wheels = cp_body if self.car_fingerprint in GLOBAL_GEN2 else cp ret.wheelSpeeds = self.get_wheel_speeds( - cp.vl["Wheel_Speeds"]["FL"], - cp.vl["Wheel_Speeds"]["FR"], - cp.vl["Wheel_Speeds"]["RL"], - cp.vl["Wheel_Speeds"]["RR"], + cp_wheels.vl["Wheel_Speeds"]["FL"], + cp_wheels.vl["Wheel_Speeds"]["FR"], + cp_wheels.vl["Wheel_Speeds"]["RL"], + cp_wheels.vl["Wheel_Speeds"]["RR"], ) ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4. # Kalman filter, even though Subaru raw wheel speed is heaviliy filtered by default @@ -35,8 +37,8 @@ class CarState(CarStateBase): ret.standstill = ret.vEgoRaw < 0.01 # continuous blinker signals for assisted lane change - ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp( - 50, cp.vl["Dashlights"]["LEFT_BLINKER"], cp.vl["Dashlights"]["RIGHT_BLINKER"]) + ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["Dashlights"]["LEFT_BLINKER"], + cp.vl["Dashlights"]["RIGHT_BLINKER"]) if self.CP.enableBsm: ret.leftBlindspot = (cp.vl["BSD_RCTA"]["L_ADJACENT"] == 1) or (cp.vl["BSD_RCTA"]["L_APPROACHING"] == 1) @@ -50,8 +52,9 @@ class CarState(CarStateBase): ret.steeringTorqueEps = cp.vl["Steering_Torque"]["Steer_Torque_Output"] ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD[self.car_fingerprint] - ret.cruiseState.enabled = cp.vl["CruiseControl"]["Cruise_Activated"] != 0 - ret.cruiseState.available = cp.vl["CruiseControl"]["Cruise_On"] != 0 + cp_cruise = cp_body if self.car_fingerprint in GLOBAL_GEN2 else cp + ret.cruiseState.enabled = cp_cruise.vl["CruiseControl"]["Cruise_Activated"] != 0 + ret.cruiseState.available = cp_cruise.vl["CruiseControl"]["Cruise_On"] != 0 ret.cruiseState.speed = cp_cam.vl["ES_DashStatus"]["Cruise_Set_Speed"] * CV.KPH_TO_MS if (self.car_fingerprint in PREGLOBAL_CARS and cp.vl["Dash_State2"]["UNITS"] == 1) or \ @@ -72,10 +75,59 @@ class CarState(CarStateBase): ret.steerFaultTemporary = cp.vl["Steering_Torque"]["Steer_Warning"] == 1 ret.cruiseState.nonAdaptive = cp_cam.vl["ES_DashStatus"]["Conventional_Cruise"] == 1 self.es_lkas_msg = copy.copy(cp_cam.vl["ES_LKAS_State"]) - self.es_distance_msg = copy.copy(cp_cam.vl["ES_Distance"]) + + cp_es_distance = cp_body if self.car_fingerprint in GLOBAL_GEN2 else cp_cam + self.es_distance_msg = copy.copy(cp_es_distance.vl["ES_Distance"]) + self.es_dashstatus_msg = copy.copy(cp_cam.vl["ES_DashStatus"]) return ret + @staticmethod + def get_common_global_signals(): + signals = [ + ("Cruise_On", "CruiseControl"), + ("Cruise_Activated", "CruiseControl"), + ("FL", "Wheel_Speeds"), + ("FR", "Wheel_Speeds"), + ("RL", "Wheel_Speeds"), + ("RR", "Wheel_Speeds"), + ("Brake", "Brake_Status"), + ] + checks = [ + ("CruiseControl", 20), + ("Wheel_Speeds", 50), + ("Brake_Status", 50), + ] + + return signals, checks + + @staticmethod + def get_global_es_distance_signals(): + signals = [ + ("COUNTER", "ES_Distance"), + ("Signal1", "ES_Distance"), + ("Cruise_Fault", "ES_Distance"), + ("Cruise_Throttle", "ES_Distance"), + ("Signal2", "ES_Distance"), + ("Car_Follow", "ES_Distance"), + ("Signal3", "ES_Distance"), + ("Cruise_Brake_Active", "ES_Distance"), + ("Distance_Swap", "ES_Distance"), + ("Cruise_EPB", "ES_Distance"), + ("Signal4", "ES_Distance"), + ("Close_Distance", "ES_Distance"), + ("Signal5", "ES_Distance"), + ("Cruise_Cancel", "ES_Distance"), + ("Cruise_Set", "ES_Distance"), + ("Cruise_Resume", "ES_Distance"), + ("Signal6", "ES_Distance"), + ] + checks = [ + ("ES_Distance", 20), + ] + + return signals, checks + @staticmethod def get_can_parser(CP): signals = [ @@ -84,17 +136,11 @@ class CarState(CarStateBase): ("Steer_Torque_Output", "Steering_Torque"), ("Steering_Angle", "Steering_Torque"), ("Steer_Error_1", "Steering_Torque"), - ("Cruise_On", "CruiseControl"), - ("Cruise_Activated", "CruiseControl"), ("Brake_Pedal", "Brake_Pedal"), ("Throttle_Pedal", "Throttle"), ("LEFT_BLINKER", "Dashlights"), ("RIGHT_BLINKER", "Dashlights"), ("SEATBELT_FL", "Dashlights"), - ("FL", "Wheel_Speeds"), - ("FR", "Wheel_Speeds"), - ("RL", "Wheel_Speeds"), - ("RR", "Wheel_Speeds"), ("DOOR_OPEN_FR", "BodyInfo"), ("DOOR_OPEN_FL", "BodyInfo"), ("DOOR_OPEN_RR", "BodyInfo"), @@ -107,7 +153,6 @@ class CarState(CarStateBase): ("Throttle", 100), ("Dashlights", 10), ("Brake_Pedal", 50), - ("Wheel_Speeds", 50), ("Transmission", 100), ("Steering_Torque", 50), ("BodyInfo", 1), @@ -123,36 +168,47 @@ class CarState(CarStateBase): checks.append(("BSD_RCTA", 17)) if CP.carFingerprint not in PREGLOBAL_CARS: + if CP.carFingerprint not in GLOBAL_GEN2: + signals += CarState.get_common_global_signals()[0] + checks += CarState.get_common_global_signals()[1] + signals += [ ("Steer_Warning", "Steering_Torque"), - ("Brake", "Brake_Status"), ("UNITS", "Dashlights"), ] checks += [ ("Dashlights", 10), ("BodyInfo", 10), - ("Brake_Status", 50), - ("CruiseControl", 20), ] else: - signals.append(("UNITS", "Dash_State2")) - - checks.append(("Dash_State2", 1)) - - if CP.carFingerprint == CAR.FORESTER_PREGLOBAL: - checks += [ - ("Dashlights", 20), - ("BodyInfo", 1), - ("CruiseControl", 50), + signals += [ + ("FL", "Wheel_Speeds"), + ("FR", "Wheel_Speeds"), + ("RL", "Wheel_Speeds"), + ("RR", "Wheel_Speeds"), + ("UNITS", "Dash_State2"), + ("Cruise_On", "CruiseControl"), + ("Cruise_Activated", "CruiseControl"), ] - - if CP.carFingerprint in (CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018): checks += [ - ("Dashlights", 10), - ("CruiseControl", 50), + ("Wheel_Speeds", 50), + ("Dash_State2", 1), ] + if CP.carFingerprint == CAR.FORESTER_PREGLOBAL: + checks += [ + ("Dashlights", 20), + ("BodyInfo", 1), + ("CruiseControl", 50), + ] + + if CP.carFingerprint in (CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018): + checks += [ + ("Dashlights", 10), + ("CruiseControl", 50), + ] + return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 0) @staticmethod @@ -187,26 +243,32 @@ class CarState(CarStateBase): ] else: signals = [ - ("Cruise_Set_Speed", "ES_DashStatus"), + ("Counter", "ES_DashStatus"), + ("PCB_Off", "ES_DashStatus"), + ("LDW_Off", "ES_DashStatus"), + ("Signal1", "ES_DashStatus"), + ("Cruise_State_Msg", "ES_DashStatus"), + ("LKAS_State_Msg", "ES_DashStatus"), + ("Signal2", "ES_DashStatus"), + ("Cruise_Soft_Disable", "ES_DashStatus"), + ("EyeSight_Status_Msg", "ES_DashStatus"), + ("Signal3", "ES_DashStatus"), + ("Cruise_Distance", "ES_DashStatus"), + ("Signal4", "ES_DashStatus"), ("Conventional_Cruise", "ES_DashStatus"), - - ("COUNTER", "ES_Distance"), - ("Signal1", "ES_Distance"), - ("Cruise_Fault", "ES_Distance"), - ("Cruise_Throttle", "ES_Distance"), - ("Signal2", "ES_Distance"), - ("Car_Follow", "ES_Distance"), - ("Signal3", "ES_Distance"), - ("Cruise_Brake_Active", "ES_Distance"), - ("Distance_Swap", "ES_Distance"), - ("Cruise_EPB", "ES_Distance"), - ("Signal4", "ES_Distance"), - ("Close_Distance", "ES_Distance"), - ("Signal5", "ES_Distance"), - ("Cruise_Cancel", "ES_Distance"), - ("Cruise_Set", "ES_Distance"), - ("Cruise_Resume", "ES_Distance"), - ("Signal6", "ES_Distance"), + ("Signal5", "ES_DashStatus"), + ("Cruise_Disengaged", "ES_DashStatus"), + ("Cruise_Activated", "ES_DashStatus"), + ("Signal6", "ES_DashStatus"), + ("Cruise_Set_Speed", "ES_DashStatus"), + ("Cruise_Fault", "ES_DashStatus"), + ("Cruise_On", "ES_DashStatus"), + ("Display_Own_Car", "ES_DashStatus"), + ("Brake_Lights", "ES_DashStatus"), + ("Car_Follow", "ES_DashStatus"), + ("Signal7", "ES_DashStatus"), + ("Far_Distance", "ES_DashStatus"), + ("Cruise_State", "ES_DashStatus"), ("COUNTER", "ES_LKAS_State"), ("LKAS_Alert_Msg", "ES_LKAS_State"), @@ -227,8 +289,21 @@ class CarState(CarStateBase): checks = [ ("ES_DashStatus", 10), - ("ES_Distance", 20), ("ES_LKAS_State", 10), ] + if CP.carFingerprint not in GLOBAL_GEN2: + signals += CarState.get_global_es_distance_signals()[0] + checks += CarState.get_global_es_distance_signals()[1] + return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 2) + + @staticmethod + def get_body_can_parser(CP): + if CP.carFingerprint in GLOBAL_GEN2: + signals, checks = CarState.get_common_global_signals() + signals += CarState.get_global_es_distance_signals()[0] + checks += CarState.get_global_es_distance_signals()[1] + return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 1) + + return None \ No newline at end of file diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index d246ab2022..049da10a16 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 from cereal import car +from panda import Panda from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase -from selfdrive.car.subaru.values import CAR, PREGLOBAL_CARS +from selfdrive.car.subaru.values import CAR, GLOBAL_GEN2, PREGLOBAL_CARS class CarInterface(CarInterfaceBase): @@ -16,11 +17,13 @@ class CarInterface(CarInterfaceBase): ret.dashcamOnly = candidate in PREGLOBAL_CARS if candidate in PREGLOBAL_CARS: - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.subaruLegacy)] ret.enableBsm = 0x25c in fingerprint[0] + ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.subaruLegacy)] else: - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.subaru)] ret.enableBsm = 0x228 in fingerprint[0] + ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.subaru)] + if candidate in GLOBAL_GEN2: + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_SUBARU_GEN2 ret.steerLimitTimer = 0.4 ret.steerActuatorDelay = 0.1 @@ -68,6 +71,14 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.065, 0.2], [0.001, 0.015, 0.025]] + elif candidate == CAR.OUTBACK: + ret.mass = 1568. + STD_CARGO_KG + ret.wheelbase = 2.67 + ret.centerToFront = ret.wheelbase * 0.5 + ret.steerRatio = 17 + ret.steerActuatorDelay = 0.1 + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + elif candidate in (CAR.FORESTER_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018): ret.safetyConfigs[0].safetyParam = 1 # Outback 2018-2019 and Forester have reversed driver torque signal ret.mass = 1568 + STD_CARGO_KG @@ -88,6 +99,9 @@ class CarInterface(CarInterfaceBase): ret.centerToFront = ret.wheelbase * 0.5 ret.steerRatio = 20 # learned, 14 stock + else: + raise ValueError(f"unknown car: {candidate}") + # TODO: get actual value, for now starting with reasonable value for # civic and scaling by mass and wheelbase ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) @@ -101,7 +115,7 @@ class CarInterface(CarInterfaceBase): # returns a car.CarState def _update(self, c): - ret = self.CS.update(self.cp, self.cp_cam) + ret = self.CS.update(self.cp, self.cp_cam, self.cp_body) ret.events = self.create_common_events(ret).to_msg() diff --git a/selfdrive/car/subaru/subarucan.py b/selfdrive/car/subaru/subarucan.py index 5f2233be9d..d83b639a41 100644 --- a/selfdrive/car/subaru/subarucan.py +++ b/selfdrive/car/subaru/subarucan.py @@ -14,13 +14,12 @@ def create_steering_control(packer, apply_steer): def create_steering_status(packer): return packer.make_can_msg("ES_LKAS_State", 0, {}) -def create_es_distance(packer, es_distance_msg, pcm_cancel_cmd): - +def create_es_distance(packer, es_distance_msg, bus, pcm_cancel_cmd): values = copy.copy(es_distance_msg) + values["COUNTER"] = (values["COUNTER"] + 1) % 0x10 if pcm_cancel_cmd: values["Cruise_Cancel"] = 1 - - return packer.make_can_msg("ES_Distance", 0, values) + return packer.make_can_msg("ES_Distance", bus, values) def create_es_lkas(packer, es_lkas_msg, enabled, visual_alert, left_line, right_line, left_lane_depart, right_lane_depart): @@ -34,6 +33,18 @@ def create_es_lkas(packer, es_lkas_msg, enabled, visual_alert, left_line, right_ if values["LKAS_Alert"] == 27: values["LKAS_Alert"] = 0 + # Filter the stock LKAS sending an audible alert when "Keep hands on wheel" alert is active (2020+ models) + if values["LKAS_Alert"] == 28 and values["LKAS_Alert_Msg"] == 7: + values["LKAS_Alert"] = 0 + + # Filter the stock LKAS sending an audible alert when "Keep hands on wheel OFF" alert is active (2020+ models) + if values["LKAS_Alert"] == 30: + values["LKAS_Alert"] = 0 + + # Filter the stock LKAS sending "Keep hands on wheel OFF" alert (2020+ models) + if values["LKAS_Alert_Msg"] == 7: + values["LKAS_Alert_Msg"] = 0 + # Show Keep hands on wheel alert for openpilot steerRequired alert if visual_alert == VisualAlert.steerRequired: values["LKAS_Alert_Msg"] = 1 @@ -56,6 +67,15 @@ def create_es_lkas(packer, es_lkas_msg, enabled, visual_alert, left_line, right_ return packer.make_can_msg("ES_LKAS_State", 0, values) +def create_es_dashstatus(packer, dashstatus_msg): + values = copy.copy(dashstatus_msg) + + # Filter stock LKAS disabled and Keep hands on steering wheel OFF alerts + if values["LKAS_State_Msg"] in [2, 3]: + values["LKAS_State_Msg"] = 0 + + return packer.make_can_msg("ES_DashStatus", 0, values) + # *** Subaru Pre-global *** def subaru_preglobal_checksum(packer, values, addr): diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 362e9ccd6a..e242ba321a 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -11,23 +11,32 @@ Ecu = car.CarParams.Ecu class CarControllerParams: def __init__(self, CP): - if CP.carFingerprint == CAR.IMPREZA_2020: - self.STEER_MAX = 1439 - else: - self.STEER_MAX = 2047 self.STEER_STEP = 2 # how often we update the steer cmd self.STEER_DELTA_UP = 50 # torque increase per refresh, 0.8s to max self.STEER_DELTA_DOWN = 70 # torque decrease per refresh self.STEER_DRIVER_ALLOWANCE = 60 # allowed driver torque before start limiting - self.STEER_DRIVER_MULTIPLIER = 10 # weight driver torque heavily + self.STEER_DRIVER_MULTIPLIER = 50 # weight driver torque heavily self.STEER_DRIVER_FACTOR = 1 # from dbc + if CP.carFingerprint in GLOBAL_GEN2: + self.STEER_MAX = 1000 + self.STEER_DELTA_UP = 40 + self.STEER_DELTA_DOWN = 40 + elif CP.carFingerprint == CAR.IMPREZA_2020: + self.STEER_MAX = 1439 + else: + self.STEER_MAX = 2047 + class CAR: + # Global platform ASCENT = "SUBARU ASCENT LIMITED 2019" IMPREZA = "SUBARU IMPREZA LIMITED 2019" IMPREZA_2020 = "SUBARU IMPREZA SPORT 2020" FORESTER = "SUBARU FORESTER 2019" + OUTBACK = "SUBARU OUTBACK 6TH GEN" + + # Pre-global FORESTER_PREGLOBAL = "SUBARU FORESTER 2017 - 2018" LEGACY_PREGLOBAL = "SUBARU LEGACY 2015 - 2018" OUTBACK_PREGLOBAL = "SUBARU OUTBACK 2015 - 2017" @@ -42,6 +51,7 @@ class SubaruCarInfo(CarInfo): CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = { CAR.ASCENT: SubaruCarInfo("Subaru Ascent 2019-21", "All"), + CAR.OUTBACK: SubaruCarInfo("Subaru Outback 2020-22", "All"), CAR.IMPREZA: [ SubaruCarInfo("Subaru Impreza 2017-19"), SubaruCarInfo("Subaru Crosstrek 2018-19", video_link="https://youtu.be/Agww7oE1k-s?t=26"), @@ -396,6 +406,47 @@ FW_VERSIONS = { b'\xbb\xfb\xe0`\000', ], }, + CAR.OUTBACK: { + (Ecu.esp, 0x7b0, None): [ + b'\xa1 \x06\x01', + b'\xa1 \a\x00', + b'\xa1 \b\001', + b'\xa1 \x06\x00', + b'\xa1 "\t\x01', + b'\xa1 \x08\x02', + b'\xa1 \x06\x02', + b'\xa1 \x08\x00', + ], + (Ecu.eps, 0x746, None): [ + b'\x9b\xc0\x10\x00', + b'\x9b\xc0\x20\x00', + b'\x1b\xc0\x10\x00', + ], + (Ecu.fwdCamera, 0x787, None): [ + b'\x00\x00eJ\x00\x1f@ \x19\x00', + b'\000\000e\x80\000\037@ \031\000', + b'\x00\x00e\x9a\x00\x1f@ 1\x00', + b'\x00\x00eJ\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x7e0, None): [ + b'\xbc,\xa0q\x07', + b'\xbc\"`@\a', + b'\xde"`0\a', + b'\xf1\x82\xbc,\xa0q\a', + b'\xf1\x82\xe3,\xa0@\x07', + b'\xe2"`p\x07', + b'\xf1\x82\xe2,\xa0@\x07', + b'\xbc"`q\x07', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xa5\xfe\xf7@\x00', + b'\xa5\xf6D@\x00', + b'\xa5\xfe\xf6@\x00', + b'\xa7\x8e\xf40\x00', + b'\xf1\x82\xa7\xf6D@\x00', + b'\xa7\xfe\xf4@\x00', + ], + }, } STEER_THRESHOLD = { @@ -403,6 +454,7 @@ STEER_THRESHOLD = { CAR.IMPREZA: 80, CAR.IMPREZA_2020: 80, CAR.FORESTER: 80, + CAR.OUTBACK: 80, CAR.FORESTER_PREGLOBAL: 75, CAR.LEGACY_PREGLOBAL: 75, CAR.OUTBACK_PREGLOBAL: 75, @@ -414,10 +466,12 @@ DBC = { CAR.IMPREZA: dbc_dict('subaru_global_2017_generated', None), CAR.IMPREZA_2020: dbc_dict('subaru_global_2017_generated', None), CAR.FORESTER: dbc_dict('subaru_global_2017_generated', None), + CAR.OUTBACK: dbc_dict('subaru_global_2017_generated', None), CAR.FORESTER_PREGLOBAL: dbc_dict('subaru_forester_2017_generated', None), CAR.LEGACY_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None), CAR.OUTBACK_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None), CAR.OUTBACK_PREGLOBAL_2018: dbc_dict('subaru_outback_2019_generated', None), } -PREGLOBAL_CARS = [CAR.FORESTER_PREGLOBAL, CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018] +GLOBAL_GEN2 = (CAR.OUTBACK, ) +PREGLOBAL_CARS = (CAR.FORESTER_PREGLOBAL, CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018) \ No newline at end of file diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 96eb5f67b9..626f2a987a 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -187,13 +187,11 @@ routes = [ TestRoute("c321c6b697c5a5ff|2020-06-23--11-04-33", SUBARU.FORESTER), TestRoute("791340bc01ed993d|2019-03-10--16-28-08", SUBARU.IMPREZA), TestRoute("8bf7e79a3ce64055|2021-05-24--09-36-27", SUBARU.IMPREZA_2020), - # Dashcam + TestRoute("1bbe6bf2d62f58a8|2022-07-14--17-11-43", SUBARU.OUTBACK, segment=3), + # Pre-global, dashcam TestRoute("95441c38ae8c130e|2020-06-08--12-10-17", SUBARU.FORESTER_PREGLOBAL), - # Dashcam TestRoute("df5ca7660000fba8|2020-06-16--17-37-19", SUBARU.LEGACY_PREGLOBAL), - # Dashcam TestRoute("5ab784f361e19b78|2020-06-08--16-30-41", SUBARU.OUTBACK_PREGLOBAL), - # Dashcam TestRoute("e19eb5d5353b1ac1|2020-08-09--14-37-56", SUBARU.OUTBACK_PREGLOBAL_2018), TestRoute("fbbfa6af821552b9|2020-03-03--08-09-43", NISSAN.XTRAIL), diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 8e6f62c4e7..27a8c26fd6 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -22,6 +22,7 @@ COMMA BODY: [.nan, 1000, .nan] # Totally new cars KIA EV6 2022: [3.5, 2.5, 0.0] RAM 1500 5TH GEN: [2.0, 2.0, 0.0] +SUBARU OUTBACK 6TH GEN: [2.3, 2.3, 0.11] # Dashcam or fallback configured as ideal car mock: [10.0, 10, 0.0] diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 35226a30eb..80f5980fb6 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -912413daa4c36a788cf2c801fc49829d46ae3072 \ No newline at end of file +01e23eec1394b07d2c537f0e28493b10e05923c2 \ No newline at end of file