Controls - Always On Lateral - Control Via LKAS Button

Enable or disable 'Always On Lateral' by clicking your 'LKAS' button.
This commit is contained in:
FrogAi 2024-07-23 00:12:48 -07:00
parent de55a3ebb0
commit ea23fc4fd7
26 changed files with 126 additions and 13 deletions

View File

@ -312,6 +312,7 @@ BO_ 764 ACCEL_RELATED_2FC: 8 XXX
BO_ 816 TRACTION_BUTTON: 8 XXX
SG_ TRACTION_OFF : 19|1@0+ (1,0) [0|3] "" XXX
SG_ TOGGLE_PARKSENSE : 52|1@0+ (1,0) [0|3] "" XXX
SG_ TOGGLE_LKAS : 53|1@0+ (1,0) [0|1] "" XXX
BO_ 878 ACCEL_RELATED_36E: 8 XXX
SG_ ACCEL_OR_RPM_2 : 15|8@0+ (1,0) [0|255] "" XXX

View File

@ -221,3 +221,9 @@ BO_ 630 LKAS_COMMAND: 8 XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 650 Center_Stack_2: 8 XXX
SG_ LKAS_Button : 57|1@1+ (1,0) [0|0] "" XXX
BO_ 816 Center_Stack_1: 8 XXX
SG_ LKAS_Button : 53|1@1+ (1,0) [0|0] "" XXX
SG_ Traction_Button : 54|1@0+ (1,0) [0|1] "" XXX

View File

@ -316,7 +316,7 @@ BO_ 441 CAM_0x1b9: 32 CAMERA
BO_ 463 CRUISE_BUTTONS: 8 XXX
SG_ _CHECKSUM : 0|8@1+ (1,0) [0|65535] "" XXX
SG_ LKAS_BTN : 23|1@1+ (1,0) [0|1] "" XXX
SG_ LFA_BTN : 23|1@1+ (1,0) [0|1] "" XXX
SG_ SET_ME_1 : 29|1@1+ (1,0) [0|1] "" XXX
SG_ ADAPTIVE_CRUISE_MAIN_BTN : 19|1@1+ (1,0) [0|1] "" XXX
SG_ NORMAL_CRUISE_MAIN_BTN : 21|1@1+ (1,0) [0|1] "" XXX

View File

@ -209,6 +209,7 @@ class Panda:
FLAG_HYUNDAI_CANFD_ALT_BUTTONS = 32
FLAG_HYUNDAI_ALT_LIMITS = 64
FLAG_HYUNDAI_CANFD_HDA2_ALT_STEERING = 128
FLAG_HYUNDAI_LFA_BTN = 256
FLAG_TESLA_POWERTRAIN = 1
FLAG_TESLA_LONG_CONTROL = 2

View File

@ -103,6 +103,13 @@ class CarState(CarStateBase):
self.lkas_car_model = cp_cam.vl["DAS_6"]["CAR_MODEL"]
self.button_counter = cp.vl[self.button_message]["COUNTER"]
# FrogPilot CarState functions
self.lkas_previously_enabled = self.lkas_enabled
if self.CP.carFingerprint in RAM_CARS:
self.lkas_enabled = cp.vl["Center_Stack_2"]["LKAS_Button"] or cp.vl["Center_Stack_1"]["LKAS_Button"]
else:
self.lkas_enabled = cp.vl["TRACTION_BUTTON"]["TOGGLE_LKAS"] == 1
return ret, fp_ret
@staticmethod
@ -137,11 +144,14 @@ class CarState(CarStateBase):
("ESP_8", 50),
("EPS_3", 50),
("Transmission_Status", 50),
("Center_Stack_1", 1),
("Center_Stack_2", 1),
]
else:
messages += [
("GEAR", 50),
("SPEED_1", 100),
("TRACTION_BUTTON", 1),
]
messages += CarState.get_cruise_messages()

View File

@ -6,6 +6,7 @@ from openpilot.selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CAR
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
ButtonType = car.CarState.ButtonEvent.Type
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
class CarInterface(CarInterfaceBase):
@ -88,7 +89,10 @@ class CarInterface(CarInterfaceBase):
def _update(self, c, frogpilot_toggles):
ret, fp_ret = self.CS.update(self.cp, self.cp_cam, frogpilot_toggles)
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
ret.buttonEvents = [
*create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}),
*create_button_events(self.CS.lkas_enabled, self.CS.lkas_previously_enabled, {1: FrogPilotButtonType.lkas}),
]
# events
events = self.create_common_events(ret, extra_gears=[car.CarState.GearShifter.low])

View File

@ -108,6 +108,10 @@ class CarState(CarStateBase):
self.acc_tja_status_stock_values = cp_cam.vl["ACCDATA_3"]
self.lkas_status_stock_values = cp_cam.vl["IPMA_Data"]
# FrogPilot CarState functions
self.lkas_previously_enabled = self.lkas_enabled
self.lkas_enabled = ret.genericToggle
return ret, fp_ret
@staticmethod

View File

@ -7,6 +7,7 @@ from openpilot.selfdrive.car.ford.values import Ecu, FordFlags
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
ButtonType = car.CarState.ButtonEvent.Type
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
TransmissionType = car.CarParams.TransmissionType
GearShifter = car.CarState.GearShifter
@ -70,7 +71,10 @@ class CarInterface(CarInterfaceBase):
def _update(self, c, frogpilot_toggles):
ret, fp_ret = self.CS.update(self.cp, self.cp_cam, frogpilot_toggles)
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
ret.buttonEvents = [
*create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}),
*create_button_events(self.CS.lkas_enabled, self.CS.lkas_previously_enabled, {1: FrogPilotButtonType.lkas}),
]
events = self.create_common_events(ret, extra_gears=[GearShifter.manumatic])
if not self.CS.vehicle_sensors_valid:

View File

@ -172,6 +172,12 @@ class CarState(CarStateBase):
# FrogPilot CarState functions
fp_ret.hasMenu = not (self.CP.flags & GMFlags.NO_CAMERA.value or self.CP.carFingerprint in CC_ONLY_CAR)
self.lkas_previously_enabled = self.lkas_enabled
if self.CP.carFingerprint in SDGM_CAR:
self.lkas_enabled = cam_cp.vl["ASCMSteeringButton"]["LKAButton"]
else:
self.lkas_enabled = pt_cp.vl["ASCMSteeringButton"]["LKAButton"]
self.pcm_acc_status = pt_cp.vl["AcceleratorPedal2"]["CruiseState"]
return ret, fp_ret

View File

@ -13,6 +13,7 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLater
from openpilot.selfdrive.controls.lib.drive_helpers import get_friction
ButtonType = car.CarState.ButtonEvent.Type
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
GearShifter = car.CarState.GearShifter
TransmissionType = car.CarParams.TransmissionType
@ -317,7 +318,9 @@ class CarInterface(CarInterfaceBase):
*create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT,
unpressed_btn=CruiseButtons.UNPRESS),
*create_button_events(self.CS.distance_button, self.CS.prev_distance_button,
{1: ButtonType.gapAdjustCruise})
{1: ButtonType.gapAdjustCruise}),
*create_button_events(self.CS.lkas_enabled, self.CS.lkas_previously_enabled,
{1: FrogPilotButtonType.lkas}),
]
# The ECM allows enabling on falling edge of set, but only rising edge of resume

View File

@ -273,6 +273,10 @@ class CarState(CarStateBase):
ret.leftBlindspot = cp_body.vl["BSM_STATUS_LEFT"]["BSM_ALERT"] == 1
ret.rightBlindspot = cp_body.vl["BSM_STATUS_RIGHT"]["BSM_ALERT"] == 1
# FrogPilot CarState functions
self.lkas_previously_enabled = self.lkas_enabled
self.lkas_enabled = self.cruise_setting == 1
return ret, fp_ret
def get_can_parser(self, CP):

View File

@ -12,6 +12,7 @@ from openpilot.selfdrive.car.disable_ecu import disable_ecu
ButtonType = car.CarState.ButtonEvent.Type
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
TransmissionType = car.CarParams.TransmissionType
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
@ -253,6 +254,7 @@ class CarInterface(CarInterfaceBase):
ret.buttonEvents = [
*create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT),
*create_button_events(self.CS.cruise_setting, self.CS.prev_cruise_setting, SETTINGS_BUTTONS_DICT),
*create_button_events(self.CS.lkas_enabled, self.CS.lkas_previously_enabled, {1: FrogPilotButtonType.lkas}),
]
# events

View File

@ -172,6 +172,11 @@ class CarState(CarStateBase):
if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
self.main_enabled = not self.main_enabled
# FrogPilot CarState functions
self.lkas_previously_enabled = self.lkas_enabled
if self.CP.flags & HyundaiFlags.CAN_LFA_BTN:
self.lkas_enabled = cp.vl["BCM_PO_11"]["LFA_Pressed"]
return ret, fp_ret
def update_canfd(self, cp, cp_cam, frogpilot_toggles):
@ -258,6 +263,10 @@ class CarState(CarStateBase):
self.hda2_lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING
else cp_cam.vl["CAM_0x2a4"])
# FrogPilot CarState functions
self.lkas_previously_enabled = self.lkas_enabled
self.lkas_enabled = cp.vl[self.cruise_btns_msg_canfd]["LFA_BTN"]
return ret, fp_ret
def get_can_parser(self, CP):
@ -308,6 +317,9 @@ class CarState(CarStateBase):
else:
messages.append(("LVR12", 100))
if CP.flags & HyundaiFlags.CAN_LFA_BTN:
messages.append(("BCM_PO_11", 50))
return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0)
@staticmethod

View File

@ -11,6 +11,7 @@ from openpilot.selfdrive.car.disable_ecu import disable_ecu
Ecu = car.CarParams.Ecu
ButtonType = car.CarState.ButtonEvent.Type
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
GearShifter = car.CarState.GearShifter
ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
@ -124,6 +125,10 @@ class CarInterface(CarInterfaceBase):
if candidate in CAMERA_SCC_CAR:
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC
if 0x391 in fingerprint[0]:
ret.flags |= HyundaiFlags.CAN_LFA_BTN.value
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_HYUNDAI_LFA_BTN
if ret.openpilotLongitudinalControl:
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_LONG
if ret.flags & HyundaiFlags.HYBRID:
@ -155,7 +160,10 @@ class CarInterface(CarInterfaceBase):
ret, fp_ret = self.CS.update(self.cp, self.cp_cam, frogpilot_toggles)
if self.CS.CP.openpilotLongitudinalControl:
ret.buttonEvents = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)
ret.buttonEvents = [
*create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT),
*create_button_events(self.CS.lkas_enabled, self.CS.lkas_previously_enabled, {1: FrogPilotButtonType.lkas}),
]
# On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
# To avoid re-engaging when openpilot cancels, check user engagement intention via buttons

View File

@ -95,6 +95,8 @@ class HyundaiFlags(IntFlag):
MIN_STEER_32_MPH = 2 ** 23
# FrogPilot HKG flags
CAN_LFA_BTN = 2 ** 24
class Footnote(Enum):
CANFD = CarFootnote(

View File

@ -8,7 +8,7 @@ from typing import Any, NamedTuple
from collections.abc import Callable
from functools import cache
from cereal import car
from cereal import car, custom
from openpilot.common.basedir import BASEDIR
from openpilot.common.conversions import Conversions as CV
from openpilot.common.simple_kalman import KF1D, get_kalman_gain
@ -22,6 +22,7 @@ from openpilot.selfdrive.controls.lib.events import Events
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
ButtonType = car.CarState.ButtonEvent.Type
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
GearShifter = car.CarState.GearShifter
EventName = car.CarEvent.EventName
@ -115,6 +116,7 @@ class CarInterfaceBase(ABC):
self.params = Params()
self.params_memory = Params("/dev/shm/params")
self.always_on_lateral_disabled = False
self.belowSteerSpeed_shown = False
self.disable_belowSteerSpeed = False
self.disable_resumeRequired = False
@ -266,6 +268,9 @@ class CarInterfaceBase(ABC):
if ret.cruiseState.speedCluster == 0:
ret.cruiseState.speedCluster = ret.cruiseState.speed
# Add any additional frogpilotCarStates
fp_ret.alwaysOnLateralDisabled = self.always_on_lateral_disabled
# copy back for next iteration
if self.CS is not None:
self.CS.out = ret.as_reader()
@ -320,6 +325,10 @@ class CarInterfaceBase(ABC):
if b.type == ButtonType.cancel:
events.add(EventName.buttonCancel)
# FrogPilot button presses
if b.type == FrogPilotButtonType.lkas and b.pressed:
self.always_on_lateral_disabled = not self.always_on_lateral_disabled
# Handle permanent and temporary steering faults
self.steering_unpressed = 0 if cs_out.steeringPressed else self.steering_unpressed + 1
if cs_out.steerFaultTemporary:
@ -389,6 +398,9 @@ class CarStateBase(ABC):
K = get_kalman_gain(DT_CTRL, np.array(A), np.array(C), np.array(Q), R)
self.v_ego_kf = KF1D(x0=x0, A=A, C=C[0], K=K)
# FrogPilot variables
self.lkas_enabled = False
def update_speed_kf(self, v_ego_raw):
if abs(v_ego_raw - self.v_ego_kf.x[0][0]) > 2.0: # Prevent large accelerations when car starts at non zero speed
self.v_ego_kf.set_x([[v_ego_raw], [0.0]])

View File

@ -111,6 +111,10 @@ class CarState(CarStateBase):
self.cam_laneinfo = cp_cam.vl["CAM_LANEINFO"]
ret.steerFaultPermanent = cp_cam.vl["CAM_LKAS"]["ERR_BIT_1"] == 1
# FrogPilot CarState functions
self.lkas_previously_enabled = self.lkas_enabled
self.lkas_enabled = not self.lkas_disabled
return ret, fp_ret
@staticmethod

View File

@ -6,6 +6,7 @@ from openpilot.selfdrive.car import create_button_events, get_safety_config
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
ButtonType = car.CarState.ButtonEvent.Type
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
class CarInterface(CarInterfaceBase):
@ -33,7 +34,10 @@ class CarInterface(CarInterfaceBase):
ret, fp_ret = self.CS.update(self.cp, self.cp_cam, frogpilot_toggles)
# TODO: add button types for inc and dec
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
ret.buttonEvents = [
*create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}),
*create_button_events(self.CS.lkas_enabled, self.CS.lkas_previously_enabled, {1: FrogPilotButtonType.lkas}),
]
# events
events = self.create_common_events(ret)

View File

@ -108,6 +108,7 @@ class CarState(CarStateBase):
can_gear = int(cp.vl["GEARBOX"]["GEAR_SHIFTER"])
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None))
self.lkas_previously_enabled = self.lkas_enabled
if self.CP.carFingerprint == CAR.NISSAN_ALTIMA:
self.lkas_enabled = bool(cp.vl["LKAS_SETTINGS"]["LKAS_ENABLED"])
else:

View File

@ -5,6 +5,7 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.nissan.values import CAR
ButtonType = car.CarState.ButtonEvent.Type
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
class CarInterface(CarInterfaceBase):
@ -32,7 +33,10 @@ class CarInterface(CarInterfaceBase):
def _update(self, c, frogpilot_toggles):
ret, fp_ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam, frogpilot_toggles)
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
ret.buttonEvents = [
*create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}),
*create_button_events(self.CS.lkas_enabled, self.CS.lkas_previously_enabled, {1: FrogPilotButtonType.lkas}),
]
events = self.create_common_events(ret, extra_gears=[car.CarState.GearShifter.brake])

View File

@ -4,7 +4,7 @@ from opendbc.can.can_define import CANDefine
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.subaru.values import DBC, CanBus, SubaruFlags
from openpilot.selfdrive.car.subaru.values import DBC, CanBus, PREGLOBAL_CARS, SubaruFlags
from openpilot.selfdrive.car import CanSignalRateCalculator
@ -126,6 +126,11 @@ class CarState(CarStateBase):
if self.CP.flags & SubaruFlags.SEND_INFOTAINMENT:
self.es_infotainment_msg = copy.copy(cp_cam.vl["ES_Infotainment"])
# FrogPilot CarState functions
self.lkas_previously_enabled = self.lkas_enabled
if self.car_fingerprint not in PREGLOBAL_CARS:
self.lkas_enabled = cp_cam.vl["ES_LKAS_State"]["LKAS_Dash_State"]
return ret, fp_ret
@staticmethod

View File

@ -1,10 +1,11 @@
from cereal import car, custom
from panda import Panda
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car import create_button_events, get_safety_config
from openpilot.selfdrive.car.disable_ecu import disable_ecu
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.subaru.values import CAR, GLOBAL_ES_ADDR, SubaruFlags
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
class CarInterface(CarInterfaceBase):
@ -101,6 +102,10 @@ class CarInterface(CarInterfaceBase):
ret, fp_ret = self.CS.update(self.cp, self.cp_cam, self.cp_body, frogpilot_toggles)
ret.buttonEvents = [
*create_button_events(self.CS.lkas_enabled, self.CS.lkas_previously_enabled, {1: FrogPilotButtonType.lkas}),
]
ret.events = self.create_common_events(ret).to_msg()
return ret, fp_ret

View File

@ -209,6 +209,8 @@ class CAR(Platforms):
)
PREGLOBAL_CARS = {CAR.SUBARU_FORESTER_PREGLOBAL, CAR.SUBARU_LEGACY_PREGLOBAL, CAR.SUBARU_OUTBACK_PREGLOBAL, CAR.SUBARU_OUTBACK_PREGLOBAL_2018}
SUBARU_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_DATA_IDENTIFICATION)
SUBARU_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \

View File

@ -191,6 +191,10 @@ class CarState(CarStateBase):
self.distance_button = cp.vl["SDSU"]["FD_BUTTON"]
# FrogPilot CarState functions
if self.CP.carFingerprint != CAR.TOYOTA_PRIUS_V:
self.lkas_previously_enabled = self.lkas_enabled
message_keys = ["LDA_ON_MESSAGE", "SET_ME_X02"]
self.lkas_enabled = any(self.lkas_hud.get(key) == 1 for key in message_keys)
# ZSS Support - Credit goes to the DragonPilot team!
if self.CP.flags & ToyotaFlags.ZSS and self.zss_threshold_count < ZSS_THRESHOLD_COUNT:

View File

@ -8,6 +8,7 @@ from openpilot.selfdrive.car.disable_ecu import disable_ecu
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
ButtonType = car.CarState.ButtonEvent.Type
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
SteerControlType = car.CarParams.SteerControlType
@ -156,7 +157,10 @@ class CarInterface(CarInterfaceBase):
ret, fp_ret = self.CS.update(self.cp, self.cp_cam, frogpilot_toggles)
if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR) or (self.CP.flags & ToyotaFlags.SMART_DSU and not self.CP.flags & ToyotaFlags.RADAR_CAN_FILTER):
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
ret.buttonEvents = [
*create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}),
*create_button_events(self.CS.lkas_enabled, self.CS.lkas_previously_enabled, {1: FrogPilotButtonType.lkas}),
]
# events
events = self.create_common_events(ret)

View File

@ -680,7 +680,7 @@ class Controls:
self.display_timer -= 1
FPCC = self.update_frogpilot_variables(CS)
FPCC = self.update_frogpilot_variables(CS, self.sm['frogpilotCarState'])
return CC, lac_log, FPCC
@ -892,12 +892,13 @@ class Controls:
self.events.add(EventName.openpilotCrashed)
self.openpilot_crashed_triggered = True
def update_frogpilot_variables(self, CS):
def update_frogpilot_variables(self, CS, frogpilotCarState):
driving_gear = CS.gearShifter not in (GearShifter.neutral, GearShifter.park, GearShifter.reverse, GearShifter.unknown)
self.always_on_lateral_active |= self.frogpilot_toggles.always_on_lateral_main or CS.cruiseState.enabled
self.always_on_lateral_active &= self.frogpilot_toggles.always_on_lateral and CS.cruiseState.available
self.always_on_lateral_active &= driving_gear
self.always_on_lateral_active &= not (self.frogpilot_toggles.always_on_lateral_lkas and frogpilotCarState.alwaysOnLateralDisabled)
self.always_on_lateral_active &= not (CS.brakePressed and CS.vEgo < self.frogpilot_toggles.always_on_lateral_pause_speed) or CS.standstill
self.drive_distance += CS.vEgo * DT_CTRL