Tesla AP2 port (#20074)
* squashed the PR * remove AP passthrough * disengage on steer override * bump panda * add test routes * bump panda * tesla is still dashcam only * dashcam only * rerun CI * add to release filespull/21385/head
parent
7e6a9ce9a5
commit
cdfba105ed
11 changed files with 410 additions and 2 deletions
@ -1 +1 @@ |
||||
Subproject commit d7b3ae02824fe67f88ee408e0d7540c1ec5bceab |
||||
Subproject commit d8385413c3ecc59799f0909c7384f385a71c4431 |
@ -0,0 +1,53 @@ |
||||
from common.numpy_fast import clip, interp |
||||
from selfdrive.car.tesla.teslacan import TeslaCAN |
||||
from opendbc.can.packer import CANPacker |
||||
from selfdrive.car.tesla.values import CANBUS, CarControllerParams |
||||
|
||||
class CarController(): |
||||
def __init__(self, dbc_name, CP, VM): |
||||
self.CP = CP |
||||
self.last_angle = 0 |
||||
self.packer = CANPacker(dbc_name) |
||||
self.tesla_can = TeslaCAN(dbc_name, self.packer) |
||||
|
||||
def update(self, enabled, CS, frame, actuators, cruise_cancel): |
||||
can_sends = [] |
||||
|
||||
# Temp disable steering on a hands_on_fault, and allow for user override |
||||
hands_on_fault = (CS.steer_warning == "EAC_ERROR_HANDS_ON" and CS.hands_on_level >= 3) |
||||
lkas_enabled = enabled and (not hands_on_fault) |
||||
|
||||
if lkas_enabled: |
||||
apply_angle = actuators.steeringAngleDeg |
||||
|
||||
# Angular rate limit based on speed |
||||
steer_up = (self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(self.last_angle)) |
||||
rate_limit = CarControllerParams.RATE_LIMIT_UP if steer_up else CarControllerParams.RATE_LIMIT_DOWN |
||||
max_angle_diff = interp(CS.out.vEgo, rate_limit.speed_points, rate_limit.max_angle_diff_points) |
||||
apply_angle = clip(apply_angle, (self.last_angle - max_angle_diff), (self.last_angle + max_angle_diff)) |
||||
|
||||
# To not fault the EPS |
||||
apply_angle = clip(apply_angle, (CS.out.steeringAngleDeg - 20), (CS.out.steeringAngleDeg + 20)) |
||||
else: |
||||
apply_angle = CS.out.steeringAngleDeg |
||||
|
||||
self.last_angle = apply_angle |
||||
can_sends.append(self.tesla_can.create_steering_control(apply_angle, lkas_enabled, frame)) |
||||
|
||||
# Cancel on user steering override, since there is no steering torque blending |
||||
if hands_on_fault: |
||||
cruise_cancel = True |
||||
|
||||
# Cancel when openpilot is not enabled anymore |
||||
if not enabled and bool(CS.out.cruiseState.enabled): |
||||
cruise_cancel = True |
||||
|
||||
if ((frame % 10) == 0 and cruise_cancel): |
||||
# Spam every possible counter value, otherwise it might not be accepted |
||||
for counter in range(16): |
||||
can_sends.append(self.tesla_can.create_action_request(CS.msg_stw_actn_req, cruise_cancel, CANBUS.chassis, counter)) |
||||
can_sends.append(self.tesla_can.create_action_request(CS.msg_stw_actn_req, cruise_cancel, CANBUS.autopilot, counter)) |
||||
|
||||
# TODO: HUD control |
||||
|
||||
return can_sends |
@ -0,0 +1,181 @@ |
||||
import copy |
||||
from cereal import car |
||||
from selfdrive.car.tesla.values import DBC, CANBUS, GEAR_MAP, DOORS, BUTTONS |
||||
from selfdrive.car.interfaces import CarStateBase |
||||
from opendbc.can.parser import CANParser |
||||
from opendbc.can.can_define import CANDefine |
||||
from selfdrive.config import Conversions as CV |
||||
|
||||
class CarState(CarStateBase): |
||||
def __init__(self, CP): |
||||
super().__init__(CP) |
||||
self.button_states = {button.event_type: False for button in BUTTONS} |
||||
self.can_define = CANDefine(DBC[CP.carFingerprint]['chassis']) |
||||
|
||||
# Needed by carcontroller |
||||
self.msg_stw_actn_req = None |
||||
self.hands_on_level = 0 |
||||
self.steer_warning = None |
||||
|
||||
def update(self, cp, cp_cam): |
||||
ret = car.CarState.new_message() |
||||
|
||||
# Vehicle speed |
||||
ret.vEgoRaw = cp.vl["ESP_B"]["ESP_vehicleSpeed"] * CV.KPH_TO_MS |
||||
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) |
||||
ret.standstill = (ret.vEgo < 0.1) |
||||
|
||||
# Gas pedal |
||||
ret.gas = cp.vl["DI_torque1"]["DI_pedalPos"] / 100.0 |
||||
ret.gasPressed = (ret.gas > 0) |
||||
|
||||
# Brake pedal |
||||
ret.brake = 0 |
||||
ret.brakePressed = bool(cp.vl["BrakeMessage"]["driverBrakeStatus"] != 1) |
||||
|
||||
# Steering wheel |
||||
self.hands_on_level = cp.vl["EPAS_sysStatus"]["EPAS_handsOnLevel"] |
||||
self.steer_warning = self.can_define.dv["EPAS_sysStatus"]["EPAS_eacErrorCode"].get(int(cp.vl["EPAS_sysStatus"]["EPAS_eacErrorCode"]), None) |
||||
steer_status = self.can_define.dv["EPAS_sysStatus"]["EPAS_eacStatus"].get(int(cp.vl["EPAS_sysStatus"]["EPAS_eacStatus"]), None) |
||||
|
||||
ret.steeringAngleDeg = -cp.vl["EPAS_sysStatus"]["EPAS_internalSAS"] |
||||
ret.steeringRateDeg = -cp.vl["STW_ANGLHP_STAT"]["StW_AnglHP_Spd"] # This is from a different angle sensor, and at different rate |
||||
ret.steeringTorque = -cp.vl["EPAS_sysStatus"]["EPAS_torsionBarTorque"] |
||||
ret.steeringPressed = (self.hands_on_level > 0) |
||||
ret.steerError = steer_status in ["EAC_FAULT", "EAC_INHIBITED"] |
||||
ret.steerWarning = self.steer_warning in ["EAC_ERROR_MAX_SPEED", "EAC_ERROR_MIN_SPEED", "EAC_ERROR_TMP_FAULT", "SNA"] # TODO: not sure if this list is complete |
||||
|
||||
# Cruise state |
||||
cruise_state = self.can_define.dv["DI_state"]["DI_cruiseState"].get(int(cp.vl["DI_state"]["DI_cruiseState"]), None) |
||||
speed_units = self.can_define.dv["DI_state"]["DI_speedUnits"].get(int(cp.vl["DI_state"]["DI_speedUnits"]), None) |
||||
|
||||
acc_enabled = (cruise_state in ["ENABLED", "STANDSTILL", "OVERRIDE", "PRE_FAULT", "PRE_CANCEL"]) |
||||
|
||||
ret.cruiseState.enabled = acc_enabled |
||||
if speed_units == "KPH": |
||||
ret.cruiseState.speed = cp.vl["DI_state"]["DI_digitalSpeed"] * CV.KPH_TO_MS |
||||
elif speed_units == "MPH": |
||||
ret.cruiseState.speed = cp.vl["DI_state"]["DI_digitalSpeed"] * CV.MPH_TO_MS |
||||
ret.cruiseState.available = ((cruise_state == "STANDBY") or ret.cruiseState.enabled) |
||||
ret.cruiseState.standstill = (cruise_state == "STANDSTILL") |
||||
|
||||
# Gear |
||||
ret.gearShifter = GEAR_MAP[self.can_define.dv["DI_torque2"]["DI_gear"].get(int(cp.vl["DI_torque2"]["DI_gear"]), "DI_GEAR_INVALID")] |
||||
|
||||
# Buttons |
||||
buttonEvents = [] |
||||
for button in BUTTONS: |
||||
state = (cp.vl[button.can_addr][button.can_msg] in button.values) |
||||
if self.button_states[button.event_type] != state: |
||||
event = car.CarState.ButtonEvent.new_message() |
||||
event.type = button.event_type |
||||
event.pressed = state |
||||
buttonEvents.append(event) |
||||
self.button_states[button.event_type] = state |
||||
ret.buttonEvents = buttonEvents |
||||
|
||||
# Doors |
||||
ret.doorOpen = any([(self.can_define.dv["GTW_carState"][door].get(int(cp.vl["GTW_carState"][door]), "OPEN") == "OPEN") for door in DOORS]) |
||||
|
||||
# Blinkers |
||||
ret.leftBlinker = (cp.vl["GTW_carState"]["BC_indicatorLStatus"] == 1) |
||||
ret.rightBlinker = (cp.vl["GTW_carState"]["BC_indicatorRStatus"] == 1) |
||||
|
||||
# Seatbelt |
||||
ret.seatbeltUnlatched = (cp.vl["SDM1"]["SDM_bcklDrivStatus"] != 1) |
||||
|
||||
# TODO: blindspot |
||||
|
||||
# Messages needed by carcontroller |
||||
self.msg_stw_actn_req = copy.copy(cp.vl["STW_ACTN_RQ"]) |
||||
|
||||
return ret |
||||
|
||||
@staticmethod |
||||
def get_can_parser(CP): |
||||
signals = [ |
||||
# sig_name, sig_address, default |
||||
("ESP_vehicleSpeed", "ESP_B", 0), |
||||
("DI_pedalPos", "DI_torque1", 0), |
||||
("DI_brakePedal", "DI_torque2", 0), |
||||
("StW_AnglHP", "STW_ANGLHP_STAT", 0), |
||||
("StW_AnglHP_Spd", "STW_ANGLHP_STAT", 0), |
||||
("EPAS_handsOnLevel", "EPAS_sysStatus", 0), |
||||
("EPAS_torsionBarTorque", "EPAS_sysStatus", 0), |
||||
("EPAS_internalSAS", "EPAS_sysStatus", 0), |
||||
("EPAS_eacStatus", "EPAS_sysStatus", 1), |
||||
("EPAS_eacErrorCode", "EPAS_sysStatus", 0), |
||||
("DI_cruiseState", "DI_state", 0), |
||||
("DI_digitalSpeed", "DI_state", 0), |
||||
("DI_speedUnits", "DI_state", 0), |
||||
("DI_gear", "DI_torque2", 0), |
||||
("DOOR_STATE_FL", "GTW_carState", 1), |
||||
("DOOR_STATE_FR", "GTW_carState", 1), |
||||
("DOOR_STATE_RL", "GTW_carState", 1), |
||||
("DOOR_STATE_RR", "GTW_carState", 1), |
||||
("DOOR_STATE_FrontTrunk", "GTW_carState", 1), |
||||
("BOOT_STATE", "GTW_carState", 1), |
||||
("BC_indicatorLStatus", "GTW_carState", 1), |
||||
("BC_indicatorRStatus", "GTW_carState", 1), |
||||
("SDM_bcklDrivStatus", "SDM1", 0), |
||||
("driverBrakeStatus", "BrakeMessage", 0), |
||||
|
||||
# We copy this whole message when spamming cancel |
||||
("SpdCtrlLvr_Stat", "STW_ACTN_RQ", 0), |
||||
("VSL_Enbl_Rq", "STW_ACTN_RQ", 0), |
||||
("SpdCtrlLvrStat_Inv", "STW_ACTN_RQ", 0), |
||||
("DTR_Dist_Rq", "STW_ACTN_RQ", 0), |
||||
("TurnIndLvr_Stat", "STW_ACTN_RQ", 0), |
||||
("HiBmLvr_Stat", "STW_ACTN_RQ", 0), |
||||
("WprWashSw_Psd", "STW_ACTN_RQ", 0), |
||||
("WprWash_R_Sw_Posn_V2", "STW_ACTN_RQ", 0), |
||||
("StW_Lvr_Stat", "STW_ACTN_RQ", 0), |
||||
("StW_Cond_Flt", "STW_ACTN_RQ", 0), |
||||
("StW_Cond_Psd", "STW_ACTN_RQ", 0), |
||||
("HrnSw_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw00_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw01_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw02_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw03_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw04_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw05_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw06_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw07_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw08_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw09_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw10_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw11_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw12_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw13_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw14_Psd", "STW_ACTN_RQ", 0), |
||||
("StW_Sw15_Psd", "STW_ACTN_RQ", 0), |
||||
("WprSw6Posn", "STW_ACTN_RQ", 0), |
||||
("MC_STW_ACTN_RQ", "STW_ACTN_RQ", 0), |
||||
("CRC_STW_ACTN_RQ", "STW_ACTN_RQ", 0), |
||||
] |
||||
|
||||
checks = [ |
||||
# sig_address, frequency |
||||
("ESP_B", 50), |
||||
("DI_torque1", 100), |
||||
("DI_torque2", 100), |
||||
("STW_ANGLHP_STAT", 100), |
||||
("EPAS_sysStatus", 25), |
||||
("DI_state", 10), |
||||
("STW_ACTN_RQ", 10), |
||||
("GTW_carState", 10), |
||||
("SDM1", 10), |
||||
("BrakeMessage", 50), |
||||
] |
||||
|
||||
return CANParser(DBC[CP.carFingerprint]['chassis'], signals, checks, CANBUS.chassis) |
||||
|
||||
@staticmethod |
||||
def get_cam_can_parser(CP): |
||||
signals = [ |
||||
# sig_name, sig_address, default |
||||
] |
||||
checks = [ |
||||
# sig_address, frequency |
||||
] |
||||
return CANParser(DBC[CP.carFingerprint]['chassis'], signals, checks, CANBUS.autopilot) |
@ -0,0 +1,62 @@ |
||||
#!/usr/bin/env python3 |
||||
from cereal import car |
||||
from selfdrive.car.tesla.values import CAR |
||||
from selfdrive.car import STD_CARGO_KG, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness |
||||
from selfdrive.car.interfaces import CarInterfaceBase |
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase): |
||||
@staticmethod |
||||
def compute_gb(accel, speed): |
||||
# TODO: is this correct? |
||||
return accel |
||||
|
||||
@staticmethod |
||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None): |
||||
ret = CarInterfaceBase.get_std_params(candidate, fingerprint) |
||||
ret.carName = "tesla" |
||||
ret.safetyModel = car.CarParams.SafetyModel.tesla |
||||
|
||||
# There is no safe way to do steer blending with user torque, |
||||
# so the steering behaves like autopilot. This is not |
||||
# how openpilot should be, hence dashcamOnly |
||||
ret.dashcamOnly = True |
||||
|
||||
ret.steerControlType = car.CarParams.SteerControlType.angle |
||||
ret.enableCamera = True |
||||
ret.openpilotLongitudinalControl = False |
||||
ret.communityFeature = True |
||||
|
||||
ret.steerActuatorDelay = 0.1 |
||||
ret.steerRateCost = 0.5 |
||||
|
||||
if candidate == CAR.AP2_MODELS: |
||||
ret.mass = 2100. + STD_CARGO_KG |
||||
ret.wheelbase = 2.959 |
||||
ret.centerToFront = ret.wheelbase * 0.5 |
||||
ret.steerRatio = 13.5 |
||||
else: |
||||
raise ValueError(f"Unsupported car: {candidate}") |
||||
|
||||
ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) |
||||
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) |
||||
|
||||
return ret |
||||
|
||||
def update(self, c, can_strings): |
||||
self.cp.update_strings(can_strings) |
||||
self.cp_cam.update_strings(can_strings) |
||||
|
||||
ret = self.CS.update(self.cp, self.cp_cam) |
||||
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid |
||||
|
||||
events = self.create_common_events(ret) |
||||
|
||||
ret.events = events.to_msg() |
||||
self.CS.out = ret.as_reader() |
||||
return self.CS.out |
||||
|
||||
def apply(self, c): |
||||
can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators, c.cruiseControl.cancel) |
||||
self.frame += 1 |
||||
return can_sends |
@ -0,0 +1,5 @@ |
||||
#!/usr/bin/env python3 |
||||
from selfdrive.car.interfaces import RadarInterfaceBase |
||||
|
||||
class RadarInterface(RadarInterfaceBase): |
||||
pass |
@ -0,0 +1,41 @@ |
||||
import copy |
||||
import crcmod |
||||
from opendbc.can.can_define import CANDefine |
||||
from selfdrive.car.tesla.values import CANBUS |
||||
|
||||
|
||||
class TeslaCAN: |
||||
def __init__(self, dbc_name, packer): |
||||
self.can_define = CANDefine(dbc_name) |
||||
self.packer = packer |
||||
self.crc = crcmod.mkCrcFun(0x11d, initCrc=0x00, rev=False, xorOut=0xff) |
||||
|
||||
@staticmethod |
||||
def checksum(msg_id, dat): |
||||
# TODO: get message ID from name instead |
||||
ret = (msg_id & 0xFF) + ((msg_id >> 8) & 0xFF) |
||||
ret += sum(dat) |
||||
return ret & 0xFF |
||||
|
||||
def create_steering_control(self, angle, enabled, frame): |
||||
values = { |
||||
"DAS_steeringAngleRequest": -angle, |
||||
"DAS_steeringHapticRequest": 0, |
||||
"DAS_steeringControlType": 1 if enabled else 0, |
||||
"DAS_steeringControlCounter": (frame % 16), |
||||
} |
||||
|
||||
data = self.packer.make_can_msg("DAS_steeringControl", CANBUS.chassis, values)[2] |
||||
values["DAS_steeringControlChecksum"] = self.checksum(0x488, data[:3]) |
||||
return self.packer.make_can_msg("DAS_steeringControl", CANBUS.chassis, values) |
||||
|
||||
def create_action_request(self, msg_stw_actn_req, cancel, bus, counter): |
||||
values = copy.copy(msg_stw_actn_req) |
||||
|
||||
if cancel: |
||||
values["SpdCtrlLvr_Stat"] = 1 |
||||
values["MC_STW_ACTN_RQ"] = counter |
||||
|
||||
data = self.packer.make_can_msg("STW_ACTN_RQ", bus, values)[2] |
||||
values["CRC_STW_ACTN_RQ"] = self.crc(data[:7]) |
||||
return self.packer.make_can_msg("STW_ACTN_RQ", bus, values) |
@ -0,0 +1,53 @@ |
||||
# flake8: noqa |
||||
|
||||
from collections import namedtuple |
||||
from selfdrive.car import dbc_dict |
||||
from cereal import car |
||||
|
||||
Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) |
||||
AngleRateLimit = namedtuple('AngleRateLimit', ['speed_points', 'max_angle_diff_points']) |
||||
|
||||
class CAR: |
||||
AP2_MODELS = 'TESLA AP2 MODEL S' |
||||
|
||||
FINGERPRINTS = { |
||||
CAR.AP2_MODELS: [ |
||||
{ |
||||
1: 8, 3: 8, 14: 8, 21: 4, 69: 8, 109: 4, 257: 3, 264: 8, 277: 6, 280: 6, 293: 4, 296: 4, 309: 5, 325: 8, 328: 5, 336: 8, 341: 8, 360: 7, 373: 8, 389: 8, 415: 8, 513: 5, 516: 8, 518: 8, 520: 4, 522: 8, 524: 8, 526: 8, 532: 3, 536: 8, 537: 3, 542: 8, 551: 5, 552: 2, 556: 8, 558: 8, 568: 8, 569: 8, 574: 8, 577: 8, 582: 5, 583: 8, 584: 4, 585: 8, 590: 8, 601: 8, 606: 8, 608: 1, 622: 8, 627: 6, 638: 8, 641: 8, 643: 8, 692: 8, 693: 8, 695: 8, 696: 8, 697: 8, 699: 8, 700: 8, 701: 8, 702: 8, 703: 8, 704: 8, 708: 8, 709: 8, 710: 8, 711: 8, 712: 8, 728: 8, 744: 8, 760: 8, 772: 8, 775: 8, 776: 8, 777: 8, 778: 8, 782: 8, 788: 8, 791: 8, 792: 8, 796: 2, 797: 8, 798: 6, 799: 8, 804: 8, 805: 8, 807: 8, 808: 1, 811: 8, 812: 8, 813: 8, 814: 5, 815: 8, 820: 8, 823: 8, 824: 8, 829: 8, 830: 5, 836: 8, 840: 8, 845: 8, 846: 5, 848: 8, 852: 8, 853: 8, 856: 4, 857: 6, 861: 8, 862: 5, 872: 8, 876: 8, 877: 8, 879: 8, 880: 8, 882: 8, 884: 8, 888: 8, 893: 8, 894: 8, 901: 6, 904: 3, 905: 8, 906: 8, 908: 2, 909: 8, 910: 8, 912: 8, 920: 8, 921: 8, 925: 4, 926: 6, 936: 8, 941: 8, 949: 8, 952: 8, 953: 6, 968: 8, 969: 6, 970: 8, 971: 8, 977: 8, 984: 8, 987: 8, 990: 8, 1000: 8, 1001: 8, 1006: 8, 1007: 8, 1008: 8, 1010: 6, 1014: 1, 1015: 8, 1016: 8, 1017: 8, 1018: 8, 1020: 8, 1026: 8, 1028: 8, 1029: 8, 1030: 8, 1032: 1, 1033: 1, 1034: 8, 1048: 1, 1049: 8, 1061: 8, 1064: 8, 1065: 8, 1070: 8, 1080: 8, 1081: 8, 1097: 8, 1113: 8, 1129: 8, 1145: 8, 1160: 4, 1177: 8, 1281: 8, 1328: 8, 1329: 8, 1332: 8, 1335: 8, 1337: 8, 1353: 8, 1368: 8, 1412: 8, 1436: 8, 1476: 8, 1481: 8, 1497: 8, 1513: 8, 1519: 8, 1601: 8, 1605: 8, 1617: 8, 1621: 8, 1800: 4, 1804: 8, 1812: 8, 1815: 8, 1816: 8, 1824: 8, 1828: 8, 1831: 8, 1832: 8, 1864: 8, 1880: 8, 1892: 8, 1896: 8, 1912: 8, 1960: 8, 1992: 8, 2008: 3, 2043: 5, 2045: 4 |
||||
}, |
||||
], |
||||
} |
||||
|
||||
DBC = { |
||||
CAR.AP2_MODELS: dbc_dict(None, 'tesla_radar', chassis_dbc='tesla_can'), |
||||
} |
||||
|
||||
class CANBUS: |
||||
chassis = 0 |
||||
autopilot = 2 |
||||
radar = 1 |
||||
|
||||
GEAR_MAP = { |
||||
"DI_GEAR_INVALID": car.CarState.GearShifter.unknown, |
||||
"DI_GEAR_P": car.CarState.GearShifter.park, |
||||
"DI_GEAR_R": car.CarState.GearShifter.reverse, |
||||
"DI_GEAR_N": car.CarState.GearShifter.neutral, |
||||
"DI_GEAR_D": car.CarState.GearShifter.drive, |
||||
"DI_GEAR_SNA": car.CarState.GearShifter.unknown, |
||||
} |
||||
|
||||
DOORS = ["DOOR_STATE_FL", "DOOR_STATE_FR", "DOOR_STATE_RL", "DOOR_STATE_RR", "DOOR_STATE_FrontTrunk", "BOOT_STATE"] |
||||
|
||||
# Make sure the message and addr is also in the CAN parser! |
||||
BUTTONS = [ |
||||
Button(car.CarState.ButtonEvent.Type.leftBlinker, "STW_ACTN_RQ", "TurnIndLvr_Stat", [1]), |
||||
Button(car.CarState.ButtonEvent.Type.rightBlinker, "STW_ACTN_RQ", "TurnIndLvr_Stat", [2]), |
||||
Button(car.CarState.ButtonEvent.Type.accelCruise, "STW_ACTN_RQ", "SpdCtrlLvr_Stat", [4, 16]), |
||||
Button(car.CarState.ButtonEvent.Type.decelCruise, "STW_ACTN_RQ", "SpdCtrlLvr_Stat", [8, 32]), |
||||
Button(car.CarState.ButtonEvent.Type.cancel, "STW_ACTN_RQ", "SpdCtrlLvr_Stat", [2]), |
||||
Button(car.CarState.ButtonEvent.Type.resumeCruise, "STW_ACTN_RQ", "SpdCtrlLvr_Stat", [1]), |
||||
] |
||||
|
||||
class CarControllerParams: |
||||
RATE_LIMIT_UP = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., .8, .15]) |
||||
RATE_LIMIT_DOWN = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., 3.5, 0.4]) |
Loading…
Reference in new issue