From 2e32f18d064dcaf022277b46e5d1801da59145c9 Mon Sep 17 00:00:00 2001 From: Julian Pieles Date: Fri, 5 Feb 2021 20:04:45 +0100 Subject: [PATCH] support for Nissan Leaf with ADAS ECU in alt location (instrument cluster) (#19619) --- selfdrive/car/nissan/carcontroller.py | 2 +- selfdrive/car/nissan/carstate.py | 17 ++++++++++------- selfdrive/car/nissan/interface.py | 3 +-- selfdrive/car/nissan/values.py | 12 ++++++++++++ selfdrive/test/test_car_models.py | 4 ++++ 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py index 6e8dc3d579..2804ec86cb 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -71,7 +71,7 @@ class CarController(): # For some reason spamming the cancel button is unreliable on the Leaf # We now cancel by making propilot think the seatbelt is unlatched, # this generates a beep and a warning message every time you disengage - if self.CP.carFingerprint == CAR.LEAF and frame % 2 == 0: + if self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC] and frame % 2 == 0: can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg, cruise_cancel)) can_sends.append(nissancan.create_steering_control( diff --git a/selfdrive/car/nissan/carstate.py b/selfdrive/car/nissan/carstate.py index e3a418d3cf..fcaa878a01 100644 --- a/selfdrive/car/nissan/carstate.py +++ b/selfdrive/car/nissan/carstate.py @@ -22,14 +22,14 @@ class CarState(CarStateBase): if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]: ret.gas = cp.vl["GAS_PEDAL"]["GAS_PEDAL"] - elif self.CP.carFingerprint == CAR.LEAF: + elif self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]: ret.gas = cp.vl["CRUISE_THROTTLE"]["GAS_PEDAL"] ret.gasPressed = bool(ret.gas > 3) if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]: ret.brakePressed = bool(cp.vl["DOORS_LIGHTS"]["USER_BRAKE_PRESSED"]) - elif self.CP.carFingerprint == CAR.LEAF: + elif self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]: ret.brakePressed = bool(cp.vl["BRAKE_PEDAL"]["BRAKE_PEDAL"] > 3) if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]: @@ -49,13 +49,16 @@ class CarState(CarStateBase): if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]: ret.seatbeltUnlatched = cp.vl["HUD"]["SEATBELT_DRIVER_LATCHED"] == 0 ret.cruiseState.available = bool(cp_cam.vl["PRO_PILOT"]["CRUISE_ON"]) - elif self.CP.carFingerprint == CAR.LEAF: - ret.seatbeltUnlatched = cp.vl["SEATBELT"]["SEATBELT_DRIVER_LATCHED"] == 0 + elif self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]: + if self.CP.carFingerprint == CAR.LEAF: + ret.seatbeltUnlatched = cp.vl["SEATBELT"]["SEATBELT_DRIVER_LATCHED"] == 0 + elif self.CP.carFingerprint == CAR.LEAF_IC: + ret.seatbeltUnlatched = cp.vl["CANCEL_MSG"]["CANCEL_SEATBELT"] == 1 ret.cruiseState.available = bool(cp.vl["CRUISE_THROTTLE"]["CRUISE_AVAILABLE"]) speed = cp_adas.vl["PROPILOT_HUD"]["SET_SPEED"] if speed != 255: - if self.CP.carFingerprint == CAR.LEAF: + if self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]: conversion = CV.MPH_TO_MS if cp.vl["HUD_SETTINGS"]["SPEED_MPH"] else CV.KPH_TO_MS else: conversion = CV.MPH_TO_MS if cp.vl["HUD"]["SPEED_MPH"] else CV.KPH_TO_MS @@ -86,7 +89,7 @@ class CarState(CarStateBase): self.cruise_throttle_msg = copy.copy(cp.vl["CRUISE_THROTTLE"]) - if self.CP.carFingerprint == CAR.LEAF: + if self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]: self.cancel_msg = copy.copy(cp.vl["CANCEL_MSG"]) self.lkas_hud_msg = copy.copy(cp_adas.vl["PROPILOT_HUD"]) @@ -159,7 +162,7 @@ class CarState(CarStateBase): ("GAS_PEDAL", 50), ] - elif CP.carFingerprint == CAR.LEAF: + elif CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]: signals += [ ("BRAKE_PEDAL", "BRAKE_PEDAL", 0), diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index 1a003a8824..0a1593d7cd 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -4,7 +4,6 @@ from selfdrive.car.nissan.values import CAR from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase - class CarInterface(CarInterfaceBase): def __init__(self, CP, CarController, CarState): super().__init__(CP, CarController, CarState) @@ -40,7 +39,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.705 ret.centerToFront = ret.wheelbase * 0.44 ret.steerRatio = 17 - elif candidate == CAR.LEAF: + elif candidate in [CAR.LEAF, CAR.LEAF_IC]: ret.mass = 1610 + STD_CARGO_KG ret.wheelbase = 2.705 ret.centerToFront = ret.wheelbase * 0.44 diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index 8b5f77a746..bd80c0d225 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -13,6 +13,9 @@ class CarControllerParams: class CAR: XTRAIL = "NISSAN X-TRAIL 2017" LEAF = "NISSAN LEAF 2018" + # Leaf with ADAS ECU found behind instrument cluster instead of glovebox + # Currently the only known difference between them is the inverted seatbelt signal. + LEAF_IC = "NISSAN LEAF 2018 Instrument Cluster" ROGUE = "NISSAN ROGUE 2019" @@ -34,6 +37,14 @@ FINGERPRINTS = { 2: 5, 42: 8, 264: 3, 361: 8, 372: 8, 384: 8, 389: 8, 403: 8, 459: 7, 460: 4, 470: 8, 520: 1, 569: 8, 581: 8, 634: 7, 640: 8, 643: 5, 644: 8, 645: 8, 646: 5, 658: 8, 682: 8, 683: 8, 689: 8, 724: 6, 758: 3, 761: 2, 772: 8, 773: 6, 774: 7, 775: 8, 776: 6, 777: 7, 778: 6, 783: 3, 852: 8, 853: 8, 856: 8, 861: 8, 943: 8, 944: 1, 976: 6, 1008: 7, 1009: 8, 1010: 8, 1011: 7, 1012: 8, 1013: 8, 1019: 8, 1020: 8, 1021: 8, 1022: 8, 1057: 3, 1227: 8, 1228: 8, 1261: 5, 1342: 1, 1354: 8, 1361: 8, 1402: 8, 1459: 8, 1477: 8, 1497: 3, 1549: 8, 1573: 6, 1821: 8, 1837: 8 }, ], + CAR.LEAF_IC: [ + { + 2: 5, 42: 6, 264: 3, 361: 8, 372: 8, 384: 8, 389: 8, 403: 8, 459: 7, 460: 4, 470: 8, 520: 1, 569: 8, 581: 8, 634: 7, 640: 8, 643: 5, 644: 8, 645: 8, 646: 5, 658: 8, 682: 8, 683: 8, 689: 8, 724: 6, 758: 3, 761: 2, 783: 3, 852: 8, 853: 8, 856: 8, 861: 8, 943: 8, 944: 1, 976: 6, 1001: 6, 1008: 7, 1011: 7, 1057: 3, 1227: 8, 1228: 8, 1229: 8, 1261: 5, 1342: 1, 1354: 8, 1361: 8, 1402: 8, 1459: 8, 1477: 8, 1497: 3, 1514: 6, 1549: 8, 1573: 6 + }, + { + 2: 5, 42: 6, 264: 3, 282: 8, 361: 8, 372: 8, 384: 8, 389: 8, 403: 8, 459: 7, 460: 4, 470: 8, 520: 1, 569: 8, 581: 8, 634: 7, 640: 8, 643: 5, 644: 8, 645: 8, 646: 5, 658: 8, 682: 8, 683: 8, 689: 8, 756: 5, 758: 3, 761: 2, 783: 3, 830: 2, 852: 8, 853: 8, 856: 8, 861: 8, 943: 8, 944: 1, 1001: 6, 1057: 3, 1227: 8, 1228: 8, 1229: 8, 1342: 1, 1354: 8, 1361: 8, 1459: 8, 1477: 8, 1497: 3, 1514: 6, 1549: 8, 1573: 6, 1821: 8, 1822: 8, 1837: 8, 1838: 8 + }, + ], CAR.ROGUE: [ { 2: 5, 42: 6, 346: 6, 347: 5, 348: 8, 349: 7, 361: 8, 386: 8, 389: 8, 397: 8, 398: 8, 403: 8, 520: 2, 523: 6, 548: 8, 634: 7, 643: 5, 645: 8, 658: 8, 665: 8, 666: 8, 674: 2, 682: 8, 683: 8, 689: 8, 723: 8, 758: 3, 772: 8, 773: 6, 774: 7, 775: 8, 776: 6, 777: 7, 778: 6, 783: 3, 851: 8, 855: 8, 1041: 8, 1042: 8, 1055: 2, 1104: 4, 1105: 6, 1107: 4, 1108: 8, 1110: 7, 1111: 7, 1227: 8, 1228: 8, 1247: 4, 1266: 8, 1273: 7, 1342: 1, 1376: 6, 1401: 8, 1474: 2, 1497: 3, 1534: 7, 1792: 8, 1821: 8, 1823: 8, 1837: 8, 1839: 8, 1872: 8, 1937: 8, 1953: 8, 1968: 8, 1988: 8, 2000: 8, 2001: 8, 2004: 8, 2005: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 @@ -44,5 +55,6 @@ FINGERPRINTS = { DBC = { CAR.XTRAIL: dbc_dict('nissan_x_trail_2017', None), CAR.LEAF: dbc_dict('nissan_leaf_2018', None), + CAR.LEAF_IC: dbc_dict('nissan_leaf_2018', None), CAR.ROGUE: dbc_dict('nissan_x_trail_2017', None), } diff --git a/selfdrive/test/test_car_models.py b/selfdrive/test/test_car_models.py index dcf1d96b46..37b3726f28 100755 --- a/selfdrive/test/test_car_models.py +++ b/selfdrive/test/test_car_models.py @@ -477,6 +477,10 @@ routes = { 'carFingerprint': NISSAN.LEAF, 'enableCamera': True, }, + "22c3dcce2dd627eb|2020-12-30--16-38-48": { + 'carFingerprint': NISSAN.LEAF_IC, + 'enableCamera': True, + }, "059ab9162e23198e|2020-05-30--09-41-01": { 'carFingerprint': NISSAN.ROGUE, 'enableCamera': True,