mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-28 00:53:45 +08:00
Preserve stock HKG lateral ownership through delayed brake status
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import pytest
|
||||
|
||||
from opendbc.car.hyundai.canfd_stock_aol import STOCK_AOL_WORDS
|
||||
from opendbc.safety.tests import test_hyundai_shared_canfd_stock_aol as fixture
|
||||
|
||||
|
||||
def rx(case, name, bus, counter, values):
|
||||
maximum = 16 if name == 'CRUISE_BUTTONS' else 256
|
||||
frame = case.packer.make_can_msg(name, bus, dict(values, COUNTER=counter % maximum))
|
||||
assert case.safety.safety_rx_hook(case.packet(frame))
|
||||
|
||||
|
||||
def steering(case, word, counter):
|
||||
name = 'LKAS_ALT' if word & 0x80 else 'LKAS' if word & 0x10 else 'LFA'
|
||||
frame = case.packer.make_can_msg(name, 0, {'COUNTER': counter, 'StrTqReqVal': 1,
|
||||
'ActToiSta': 1, 'LKA_OptUsmSta': 2, 'Damping_Gain': 100})
|
||||
return case.packet(frame)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('word', sorted(STOCK_AOL_WORDS))
|
||||
@pytest.mark.parametrize('gesture', ['cancel', 'brake'])
|
||||
@pytest.mark.parametrize('veto', ['host_withdrawal', 'bad_source_checksum'])
|
||||
def test_actual_stock_torque_brake_and_cancel_keep_only_existing_lateral_permission(word, gesture, veto):
|
||||
case = fixture.TestHyundaiSharedCanfdStockAol(methodName='runTest')
|
||||
case.setUp()
|
||||
case.mode(word)
|
||||
case.healthy(word)
|
||||
case.safety.set_aol_test_heartbeat(True)
|
||||
case.safety.aol_set_host_request(1)
|
||||
assert not case.safety.get_controls_allowed()
|
||||
assert case.safety.aol_get_permission_mask() == 0
|
||||
assert not case.safety.safety_tx_hook(steering(case, word, 0))
|
||||
case.gesture(word)
|
||||
case.safety.aol_set_host_request(1)
|
||||
assert case.safety.aol_get_permission_mask() == 1
|
||||
pt = 1 if word & 0x10 else 0
|
||||
buttons = 'CRUISE_BUTTONS_ALT' if word & 0x20 else 'CRUISE_BUTTONS'
|
||||
for counter, values in ((9, {'ADAPTIVE_CRUISE_MAIN_BTN': 1}),
|
||||
(10, {}), (11, {'CRUISE_BUTTONS': 2}), (12, {})):
|
||||
rx(case, buttons, pt, counter, values)
|
||||
scc = 2 if word & 8 else pt
|
||||
rx(case, 'SCC_CONTROL', scc, 7, {'MainMode_ACC': 1, 'ACCMode': 1, 'VSetDis': 90})
|
||||
assert case.safety.get_controls_allowed()
|
||||
case.safety.aol_set_host_request(3)
|
||||
assert case.safety.aol_get_permission_mask() == 1
|
||||
case.safety.aol_set_host_request(1)
|
||||
if gesture == 'cancel':
|
||||
rx(case, buttons, pt, 13, {'CRUISE_BUTTONS': 4})
|
||||
else:
|
||||
rx(case, 'TCS', pt, 7, {'DriverBraking': 1})
|
||||
assert bool(case.safety.get_controls_allowed()) == (gesture == 'cancel')
|
||||
assert case.safety.aol_get_permission_mask() == 1
|
||||
assert case.safety.safety_tx_hook(steering(case, word, 1))
|
||||
rx(case, 'SCC_CONTROL', scc, 8, {'MainMode_ACC': 1, 'ACCMode': 0, 'VSetDis': 90})
|
||||
assert not case.safety.get_controls_allowed()
|
||||
assert case.safety.aol_get_permission_mask() == 1
|
||||
assert case.safety.safety_tx_hook(steering(case, word, 2))
|
||||
assert not case.safety.safety_tx_hook(case.packet(case.packer.make_can_msg('SCC_CONTROL', pt, {'COUNTER': 9})))
|
||||
if veto == 'host_withdrawal':
|
||||
case.safety.aol_set_host_request(0)
|
||||
else:
|
||||
address, raw, bus = case.packer.make_can_msg('TCS', pt, {'COUNTER': 8, 'DriverBraking': int(gesture == 'brake')})
|
||||
corrupt = bytearray(raw)
|
||||
corrupt[0] ^= 1
|
||||
assert not case.safety.safety_rx_hook(case.packet((address, bytes(corrupt), bus)))
|
||||
assert case.safety.aol_get_permission_mask() == 0
|
||||
assert not case.safety.safety_tx_hook(steering(case, word, 3))
|
||||
@@ -1268,8 +1268,11 @@ class SelfdriveD:
|
||||
user_disable = self.events.contains(ET.USER_DISABLE)
|
||||
if user_disable:
|
||||
from opendbc.car.hyundai.canfd_angle_aol import qualified as angle_qualified
|
||||
from opendbc.car.hyundai.canfd_stock_aol import qualified as stock_canfd_qualified
|
||||
|
||||
if angle_qualified(self.CP, marked_only=True):
|
||||
if (angle_qualified(self.CP, marked_only=True) or
|
||||
self.CP.brand == 'hyundai' and CS.brakePressed and len(self.CP.safetyConfigs) == 1 and
|
||||
stock_canfd_qualified(self.CP, marked_only=True)):
|
||||
native = current_native(self.sm, self.CP, now_ns=now_ns, axis_session_id=self.aol_session_id)
|
||||
if stock_lateral_role(self, CS, native, intent, allow_independent_cancel=True,
|
||||
allow_independent_brake=True, now_ns=now_ns):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Classify ordinary host source loss without granting commands or engagement."""
|
||||
from math import isfinite
|
||||
from opendbc.car.structs import car
|
||||
from openpilot.cereal import log
|
||||
from openpilot.selfdrive.selfdrived.events import ET
|
||||
@@ -26,12 +27,16 @@ def stock_lateral_role(self, CS, native, intent=None, *, allow_independent_cance
|
||||
brake_role = False
|
||||
if allow_independent_brake:
|
||||
from opendbc.car.hyundai.canfd_angle_aol import command_allowed
|
||||
from opendbc.car.hyundai.canfd_stock_aol import qualified as stock_canfd_qualified
|
||||
|
||||
settings = getattr(self, 'aol_settings', None)
|
||||
previous = getattr(self, 'aol_axis_decision', None)
|
||||
brake_role = bool(settings is not None and settings.enabled and CS.vEgo >= settings.pause_brake_mps and
|
||||
CS.brakePressed and not CS.regenBraking and previous is not None and previous.lateral_active and
|
||||
previous.native_acknowledged and not previous.longitudinal_active and command_allowed(self.CP, CS))
|
||||
brake_role = bool(settings is not None and settings.enabled and CS.brakePressed and not CS.regenBraking and
|
||||
previous is not None and previous.lateral_active and previous.native_acknowledged and not previous.longitudinal_active and
|
||||
(CS.vEgo >= settings.pause_brake_mps and command_allowed(self.CP, CS) or
|
||||
len(self.CP.safetyConfigs) == 1 and stock_canfd_qualified(self.CP, marked_only=True) and
|
||||
CS.gearShifter == car.CarState.GearShifter.drive and isfinite(CS.vEgoRaw) and isfinite(CS.vEgo) and
|
||||
(settings.pause_brake_mps <= 0 or CS.vEgo >= settings.pause_brake_mps or CS.standstill)))
|
||||
rules = self.events.event_rules
|
||||
stock_user = stock_lateral_user_event(self.CP)
|
||||
users = [name for name in self.events.names if ET.USER_DISABLE in rules.get(name, {})]
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
from contextlib import ExitStack, contextmanager
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from opendbc.car import gen_empty_fingerprint, structs
|
||||
from opendbc.car.hyundai.canfd_stock_aol import qualified
|
||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from opendbc.car.hyundai.interface import CarInterface
|
||||
from opendbc.car.hyundai.values import CAR, HyundaiFlags
|
||||
from openpilot.cereal import log
|
||||
from openpilot.cereal.services import SERVICE_LIST
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.starpilot.aol.intent import read_settings
|
||||
from openpilot.starpilot.aol.tests.stock_lateral_test_helpers import car_state, hkg_family_case
|
||||
|
||||
MODELS = [(CAR.GENESIS_GV70_1ST_GEN, False), (CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN, True), (CAR.KIA_EV6, True)]
|
||||
|
||||
|
||||
@contextmanager
|
||||
def configured_callers(identity, lka, guard, *, hybrid=False, lkas_action=9):
|
||||
with ExitStack() as cleanup:
|
||||
with OpenpilotPrefix():
|
||||
saved = Params()
|
||||
saved.put_bool('AlwaysOnLateral', True, block=True)
|
||||
saved.put('LKASButtonControl', lkas_action, block=True)
|
||||
saved.put('MainCruiseButtonControl', 9 if guard == 'mapped_main' else 0, block=True)
|
||||
for key in ('CancelButtonControl', 'LongCancelButtonControl', 'VeryLongCancelButtonControl'):
|
||||
saved.put(key, 3 if guard == 'configured_cancel' and key == 'CancelButtonControl' else 0, block=True)
|
||||
saved.put('AolBrakePauseSpeedMps', 20.0 if guard == 'brake_pause_speed' else 0.0, block=True)
|
||||
case = hkg_family_case('hkg_canfd', False)
|
||||
cleanup.callback(case.doCleanups)
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
if lka:
|
||||
fingerprint[CanBus(None, fingerprint).CAM][0x50] = 16
|
||||
if hybrid:
|
||||
fingerprint[CanBus(None, fingerprint, lka_steering=lka).ECAN][0xFA] = 32
|
||||
cp = CarInterface.get_params(identity, fingerprint, [], False, False, False)
|
||||
assert bool(cp.flags & HyundaiFlags.HYBRID) == hybrid
|
||||
assert qualified(cp) and not cp.openpilotLongitudinalControl and cp.pcmCruise
|
||||
case.family_cp = cp.as_reader()
|
||||
sd, _, step, card, receive = case.family_callers(False)
|
||||
sd.aol_settings = read_settings(saved)
|
||||
assert sd.aol_settings == card.aol_card_intent.settings
|
||||
released = car_state()
|
||||
released.buttonEvents = [structs.CarState.ButtonEvent(type='lkas', pressed=False)]
|
||||
card.aol_card_intent.update(released, now_ns=10_015_000_000)
|
||||
assert card.aol_card_intent.allowed_latch
|
||||
engaged = car_state()
|
||||
engaged.vEgoRaw = engaged.vEgo
|
||||
engaged.cruiseState.enabled = True
|
||||
axis, _, command = step(2, observed_state=engaged, panda_controls_allowed=True)
|
||||
assert sd.enabled and axis.lateralActive and command.latActive
|
||||
assert not axis.longitudinalActive and not command.longActive
|
||||
assert receive(10_020_000_000, state=engaged, axis=sd.pm.messages['aolAxisState'],
|
||||
event=sd.pm.messages['onroadEvents'])
|
||||
yield SimpleNamespace(sd=sd, step=step, card=card, receive=receive)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity,lka', MODELS)
|
||||
@pytest.mark.parametrize('guard', ['native_denied', 'native_long', 'native_invalid', 'native_no_request',
|
||||
'panda_fault', 'relay_fault', 'critical_event', 'uncalibrated',
|
||||
'invalid_can', 'reverse', 'brake_pause_speed', 'stale_source',
|
||||
'future_source', 'both_pedals', 'configured_cancel', 'mapped_main',
|
||||
'mapped_lkas', 'nonfinite_raw', 'regen', 'unmarked_cp', 'aol_disabled',
|
||||
'invalid_pause', 'negative_pause', 'excess_pause'])
|
||||
def test_late_brake_continuity_cannot_override_existing_stock_guards(identity, lka, guard):
|
||||
with configured_callers(identity, lka, guard) as context:
|
||||
sd, step, card = context.sd, context.step, context.card
|
||||
state = car_state(brake=True)
|
||||
state.vEgoRaw = state.vEgo
|
||||
state.cruiseState.enabled = True
|
||||
kwargs = {'panda_controls_allowed': False}
|
||||
if guard == 'native_denied':
|
||||
kwargs['allowed'] = False
|
||||
elif guard == 'native_long':
|
||||
kwargs['native_request_long'] = True
|
||||
kwargs['long_allowed'] = False
|
||||
elif guard == 'native_invalid':
|
||||
kwargs['native_valid'] = False
|
||||
elif guard == 'native_no_request':
|
||||
kwargs['native_request_lat'] = False
|
||||
kwargs['allowed'] = False
|
||||
elif guard == 'panda_fault':
|
||||
kwargs['panda_fault'] = True
|
||||
elif guard == 'relay_fault':
|
||||
kwargs['relay_fault'] = True
|
||||
elif guard == 'critical_event':
|
||||
kwargs['critical_event'] = log.OnroadEvent.EventName.controlsMismatch
|
||||
elif guard == 'uncalibrated':
|
||||
kwargs['calibrated'] = False
|
||||
elif guard == 'brake_pause_speed':
|
||||
assert sd.aol_settings.pause_brake_mps == 20.0
|
||||
state.vEgoRaw = state.vEgo = 19.0
|
||||
assert not state.standstill and state.vEgo < sd.aol_settings.pause_brake_mps
|
||||
elif guard == 'invalid_can':
|
||||
state.canValid = False
|
||||
elif guard == 'reverse':
|
||||
state.gearShifter = 'reverse'
|
||||
elif guard == 'stale_source':
|
||||
kwargs['state_stamp'] = 10_020_000_000
|
||||
elif guard == 'future_source':
|
||||
kwargs['state_stamp'] = 10_080_000_000
|
||||
elif guard == 'both_pedals':
|
||||
kwargs['gas'] = True
|
||||
elif guard in ('configured_cancel', 'mapped_main', 'mapped_lkas'):
|
||||
button = {'configured_cancel': 'cancel', 'mapped_main': 'mainCruise', 'mapped_lkas': 'lkas'}[guard]
|
||||
state.buttonEvents = [structs.CarState.ButtonEvent(type=button, pressed=True)]
|
||||
card.aol_card_intent.update(state, now_ns=10_070_000_000)
|
||||
assert not card.aol_card_intent.allowed_latch
|
||||
elif guard == 'nonfinite_raw':
|
||||
state.vEgoRaw = float('nan')
|
||||
elif guard == 'regen':
|
||||
state.regenBraking = True
|
||||
elif guard == 'aol_disabled':
|
||||
sd.params.put_bool('AlwaysOnLateral', False, block=True)
|
||||
sd.aol_settings = read_settings(sd.params)
|
||||
card.aol_card_intent.settings = sd.aol_settings
|
||||
card.aol_card_intent.update(state, now_ns=10_070_000_000)
|
||||
assert not sd.aol_settings.enabled and not card.aol_card_intent.allowed_latch
|
||||
elif guard in ('invalid_pause', 'negative_pause', 'excess_pause'):
|
||||
raw = {'invalid_pause': b'not-a-number', 'negative_pause': b'-1', 'excess_pause': b'101'}[guard]
|
||||
Path(sd.params.get_param_path('AolBrakePauseSpeedMps')).write_bytes(raw)
|
||||
sd.aol_settings = read_settings(sd.params)
|
||||
card.aol_card_intent.settings = sd.aol_settings
|
||||
card.aol_card_intent.update(state, now_ns=10_070_000_000)
|
||||
assert not sd.aol_settings.enabled and not card.aol_card_intent.allowed_latch
|
||||
elif guard == 'unmarked_cp':
|
||||
cp = sd.CP.as_builder()
|
||||
cp.safetyConfigs[0].safetyParam &= ~0x0800
|
||||
sd.CP = cp.as_reader()
|
||||
tick = 7
|
||||
if guard == 'uncalibrated':
|
||||
period = round(1e9 / min(SERVICE_LIST['extrinsicsCalibration'].frequency, 100))
|
||||
next_due = int(sd.sm.logMonoTime['extrinsicsCalibration']) + period
|
||||
tick = max(tick, (next_due - 10_000_000_000 + 9_999_999) // 10_000_000)
|
||||
axis, _, command = step(tick, observed_state=state, **kwargs)
|
||||
if guard == 'uncalibrated':
|
||||
assert int(sd.sm.logMonoTime['extrinsicsCalibration']) == 10_000_000_000 + tick * 10_000_000
|
||||
assert sd.sm['extrinsicsCalibration'].calStatus == log.ExtrinsicsCalibration.Status.uncalibrated
|
||||
assert not axis.lateralActive and not command.latActive
|
||||
assert not axis.longitudinalActive and not command.longActive
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity,lka', MODELS)
|
||||
@pytest.mark.parametrize('boundary', ['unmarked', 'longitudinal', 'unknown', 'passive', 'second_panda', 'no_brake_role'])
|
||||
def test_stock_brake_exception_does_not_expand_configuration_admission(identity, lka, boundary):
|
||||
from openpilot.starpilot.aol.transport_pause import stock_lateral_off
|
||||
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
if lka:
|
||||
fingerprint[CanBus(None, fingerprint).CAM][0x50] = 16
|
||||
cp = CarInterface.get_params(identity, fingerprint, [], False, False, False)
|
||||
cp.safetyConfigs[0].safetyParam |= 0x0800
|
||||
assert qualified(cp, marked_only=True)
|
||||
state = car_state(brake=True)
|
||||
state.vEgoRaw = state.vEgo
|
||||
state.cruiseState.enabled = True
|
||||
state.cruiseState.available = True
|
||||
native = SimpleNamespace(requestedLateral=True, lateralAllowed=True, requestedLongitudinal=False)
|
||||
assert stock_lateral_off(cp, state, native, allow_independent_brake=True)
|
||||
if boundary == 'unmarked':
|
||||
cp.safetyConfigs[0].safetyParam &= ~0x0800
|
||||
elif boundary == 'longitudinal':
|
||||
cp.openpilotLongitudinalControl = True
|
||||
cp.pcmCruise = False
|
||||
elif boundary == 'unknown':
|
||||
cp.carFingerprint = 'UNKNOWN_HYUNDAI'
|
||||
elif boundary == 'passive':
|
||||
cp.passive = True
|
||||
elif boundary == 'second_panda':
|
||||
word = cp.safetyConfigs[0].safetyParam
|
||||
configs = cp.init('safetyConfigs', 2)
|
||||
configs[0].safetyModel = 'noOutput'
|
||||
configs[1].safetyModel = 'hyundaiCanfd'
|
||||
configs[1].safetyParam = word
|
||||
from opendbc.car.hyundai.canfd_owner import config_index
|
||||
|
||||
assert config_index(cp) == (1 if lka else None)
|
||||
assert qualified(cp, marked_only=True) == lka
|
||||
assert not stock_lateral_off(cp, state, native, allow_independent_brake=boundary != 'no_brake_role')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('tick', [3, 7])
|
||||
@pytest.mark.parametrize('gesture', ['cancel', 'brake'])
|
||||
def test_source_selected_hybrid_stock_brake_continuity(tick, gesture):
|
||||
with configured_callers(CAR.HYUNDAI_TUCSON_4TH_GEN, False, 'baseline', hybrid=True) as context:
|
||||
sd, step, card, receive = context.sd, context.step, context.card, context.receive
|
||||
state = car_state(brake=gesture == 'brake')
|
||||
state.vEgoRaw = state.vEgo
|
||||
state.cruiseState.enabled = True
|
||||
if gesture == 'cancel':
|
||||
state.buttonEvents = [structs.CarState.ButtonEvent(type='cancel', pressed=True)]
|
||||
axis, _, command = step(tick, observed_state=state, panda_controls_allowed=gesture == 'cancel')
|
||||
assert axis.lateralActive and command.latActive
|
||||
assert not axis.longitudinalActive and not command.longActive
|
||||
assert receive(10_000_000_000 + tick * 10_000_000, state=state,
|
||||
axis=sd.pm.messages['aolAxisState'], event=sd.pm.messages['onroadEvents'])
|
||||
settled = car_state(brake=gesture == 'brake')
|
||||
settled.vEgoRaw = settled.vEgo
|
||||
axis, _, command = step(tick + 1, observed_state=settled)
|
||||
assert not sd.enabled and axis.lateralActive and command.latActive
|
||||
assert not axis.longitudinalActive and not command.longActive
|
||||
assert receive(10_000_000_000 + (tick + 1) * 10_000_000, state=settled,
|
||||
axis=sd.pm.messages['aolAxisState'], event=sd.pm.messages['onroadEvents'])
|
||||
assert card.aol_card_intent.allowed_latch
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity,lka', MODELS)
|
||||
@pytest.mark.parametrize('tick', [3, 7])
|
||||
@pytest.mark.parametrize('gesture', ['cancel', 'brake'])
|
||||
def test_default_button_mapping_keeps_its_existing_cancel_withdrawal(identity, lka, tick, gesture):
|
||||
with configured_callers(identity, lka, 'baseline', lkas_action=0) as context:
|
||||
sd, step, card, receive = context.sd, context.step, context.card, context.receive
|
||||
state = car_state(brake=gesture == 'brake')
|
||||
state.vEgoRaw = state.vEgo
|
||||
state.cruiseState.enabled = True
|
||||
if gesture == 'cancel':
|
||||
state.buttonEvents = [structs.CarState.ButtonEvent(type='cancel', pressed=True)]
|
||||
card.aol_card_intent.update(state, now_ns=10_000_000_000 + tick * 10_000_000)
|
||||
assert card.aol_card_intent.allowed_latch == (gesture == 'brake')
|
||||
axis, _, command = step(tick, observed_state=state, panda_controls_allowed=gesture == 'cancel')
|
||||
assert axis.lateralActive and command.latActive
|
||||
assert not axis.longitudinalActive and not command.longActive
|
||||
assert receive(10_000_000_000 + tick * 10_000_000, state=state,
|
||||
axis=sd.pm.messages['aolAxisState'], event=sd.pm.messages['onroadEvents']) == (gesture == 'brake')
|
||||
settled = car_state(brake=gesture == 'brake')
|
||||
settled.vEgoRaw = settled.vEgo
|
||||
axis, _, command = step(tick + 1, observed_state=settled)
|
||||
assert not sd.enabled
|
||||
assert bool(axis.lateralActive) == bool(command.latActive) == (gesture == 'brake')
|
||||
assert not axis.longitudinalActive and not command.longActive
|
||||
assert receive(10_000_000_000 + (tick + 1) * 10_000_000, state=settled,
|
||||
axis=sd.pm.messages['aolAxisState'], event=sd.pm.messages['onroadEvents']) == (gesture == 'brake')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity,lka', MODELS)
|
||||
@pytest.mark.parametrize('pause_mps', [0.0, 20.0])
|
||||
def test_existing_independent_brake_policy_keeps_standstill_exception(identity, lka, pause_mps):
|
||||
guard = 'brake_pause_speed' if pause_mps else 'baseline'
|
||||
with configured_callers(identity, lka, guard) as context:
|
||||
sd, step, card, receive = context.sd, context.step, context.card, context.receive
|
||||
assert sd.aol_settings.pause_brake_mps == pause_mps
|
||||
state = car_state(brake=True)
|
||||
state.vEgoRaw = state.vEgo = 0.0
|
||||
state.standstill = True
|
||||
state.cruiseState.enabled = True
|
||||
axis, _, command = step(7, observed_state=state, panda_controls_allowed=False)
|
||||
assert not sd.enabled and not sd.CP.steerAtStandstill
|
||||
assert axis.lateralActive and not command.latActive
|
||||
assert not axis.longitudinalActive and not command.longActive
|
||||
assert receive(10_070_000_000, state=state, axis=sd.pm.messages['aolAxisState'],
|
||||
event=sd.pm.messages['onroadEvents'])
|
||||
assert card.aol_card_intent.allowed_latch
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity,lka', MODELS)
|
||||
def test_existing_brake_pause_threshold_equality_remains_allowed(identity, lka):
|
||||
with configured_callers(identity, lka, 'brake_pause_speed') as context:
|
||||
sd, step = context.sd, context.step
|
||||
state = car_state(brake=True)
|
||||
state.vEgoRaw = state.vEgo = sd.aol_settings.pause_brake_mps
|
||||
state.cruiseState.enabled = True
|
||||
assert state.vEgo == 20.0 and not state.standstill
|
||||
axis, _, command = step(7, observed_state=state, panda_controls_allowed=False)
|
||||
assert not sd.enabled and axis.lateralActive and command.latActive
|
||||
assert not axis.longitudinalActive and not command.longActive
|
||||
@@ -0,0 +1,72 @@
|
||||
from contextlib import ExitStack
|
||||
|
||||
import pytest
|
||||
|
||||
from opendbc.car import gen_empty_fingerprint, structs
|
||||
from opendbc.car.hyundai.canfd_stock_aol import qualified
|
||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from opendbc.car.hyundai.interface import CarInterface
|
||||
from opendbc.car.hyundai.values import CAR
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.starpilot.aol.intent import read_settings
|
||||
from openpilot.starpilot.aol.tests.stock_lateral_test_helpers import car_state, hkg_family_case
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity,lka', [(CAR.GENESIS_GV70_1ST_GEN, False),
|
||||
(CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN, True),
|
||||
(CAR.KIA_EV6, True)])
|
||||
@pytest.mark.parametrize('tick', [3, 7])
|
||||
@pytest.mark.parametrize('gesture', ['cancel', 'brake'])
|
||||
def test_configured_torque_stock_lateral_survives_stock_cruise_transition(identity, lka, tick, gesture):
|
||||
with ExitStack() as cleanup:
|
||||
with OpenpilotPrefix():
|
||||
saved = Params()
|
||||
saved.put('LKASButtonControl', 9, block=True)
|
||||
saved.put('MainCruiseButtonControl', 0, block=True)
|
||||
for key in ('CancelButtonControl', 'LongCancelButtonControl', 'VeryLongCancelButtonControl'):
|
||||
saved.put(key, 0, block=True)
|
||||
case = hkg_family_case('hkg_canfd', False)
|
||||
cleanup.callback(case.doCleanups)
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
if lka:
|
||||
fingerprint[CanBus(None, fingerprint).CAM][0x50] = 16
|
||||
cp = CarInterface.get_params(identity, fingerprint, [], False, False, False)
|
||||
assert cp.steerControlType == structs.CarParams.SteerControlType.torque
|
||||
assert qualified(cp) and not cp.openpilotLongitudinalControl and cp.pcmCruise
|
||||
case.family_cp = cp.as_reader()
|
||||
sd, _, step, card, receive = case.family_callers(False)
|
||||
sd.aol_settings = read_settings(saved)
|
||||
assert sd.aol_settings == card.aol_card_intent.settings
|
||||
assert sd.aol_settings.pause_brake_mps == 0
|
||||
assert card.aol_card_intent.independent_cruise_buttons
|
||||
engaged = car_state()
|
||||
engaged.vEgoRaw = engaged.vEgo
|
||||
engaged.cruiseState.enabled = True
|
||||
axis, _, command = step(2, observed_state=engaged, panda_controls_allowed=True)
|
||||
assert sd.enabled and axis.lateralActive and command.latActive
|
||||
assert not axis.longitudinalActive and not command.longActive
|
||||
assert receive(10_020_000_000, state=engaged, axis=sd.pm.messages['aolAxisState'],
|
||||
event=sd.pm.messages['onroadEvents'])
|
||||
state = car_state()
|
||||
state.vEgoRaw = state.vEgo
|
||||
state.cruiseState.enabled = True
|
||||
if gesture == 'cancel':
|
||||
state.buttonEvents = [structs.CarState.ButtonEvent(type='cancel', pressed=True)]
|
||||
else:
|
||||
state.brakePressed = True
|
||||
axis, _, command = step(tick, observed_state=state, panda_controls_allowed=gesture == 'cancel')
|
||||
assert sd.enabled == (gesture == 'cancel')
|
||||
assert not axis.longitudinalActive and not command.longActive
|
||||
assert axis.lateralActive and command.latActive
|
||||
assert receive(10_000_000_000 + tick * 10_000_000, state=state, axis=sd.pm.messages['aolAxisState'],
|
||||
event=sd.pm.messages['onroadEvents'])
|
||||
assert card.aol_card_intent.allowed_latch
|
||||
settled = car_state(brake=gesture == 'brake')
|
||||
settled.vEgoRaw = settled.vEgo
|
||||
axis, _, command = step(tick + 1, observed_state=settled)
|
||||
assert not sd.enabled and not axis.longitudinalActive and not command.longActive
|
||||
assert axis.lateralActive and command.latActive
|
||||
assert receive(10_000_000_000 + (tick + 1) * 10_000_000, state=settled,
|
||||
axis=sd.pm.messages['aolAxisState'], event=sd.pm.messages['onroadEvents'])
|
||||
assert card.aol_card_intent.allowed_latch
|
||||
@@ -109,12 +109,16 @@ def stock_lateral_off(cp, cs, native, *, allow_independent_cancel=False, allow_i
|
||||
from openpilot.starpilot.nostalgia import physical_cancel
|
||||
from opendbc.car.hyundai.canfd_angle_aol import qualified as angle_qualified
|
||||
|
||||
from opendbc.car.hyundai.canfd_stock_aol import qualified as stock_canfd_qualified
|
||||
|
||||
independent_angle = angle_qualified(cp, marked_only=True)
|
||||
independent_brake = independent_angle or (allow_independent_brake and cp.brand == 'hyundai' and
|
||||
len(cp.safetyConfigs) == 1 and stock_canfd_qualified(cp, marked_only=True))
|
||||
return bool(cp.pcmCruise and cs.cruiseState.available and
|
||||
(not cs.cruiseState.enabled or independent_angle and allow_independent_brake and cs.brakePressed) and
|
||||
(not cs.cruiseState.enabled or independent_brake and allow_independent_brake and cs.brakePressed) and
|
||||
cs.canValid and not cs.canTimeout and not cs.steerFaultPermanent and not cs.steerFaultTemporary and
|
||||
not cs.accFaulted and not cs.doorOpen and not cs.seatbeltUnlatched and
|
||||
(not cs.brakePressed or independent_angle and allow_independent_brake) and
|
||||
(not cs.brakePressed or independent_brake and allow_independent_brake) and
|
||||
not cs.regenBraking and (not cs.gasPressed or independent_angle) and
|
||||
(not physical_cancel(cs, cp) or independent_angle and allow_independent_cancel) and
|
||||
native is not None and native.requestedLateral and native.lateralAllowed and not native.requestedLongitudinal)
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"protected_inventory_sha256": "5ac0862226ed39da17f48eedaf31f71216c3ba44557194020d15bb031bf2e284", "schema_version": 1}
|
||||
{"protected_inventory_sha256": "28c9d821cce63586b434f23ee52d427e27a4357a8b42dd53cecb22288f420032", "schema_version": 1}
|
||||
|
||||
@@ -33,6 +33,9 @@ DEBUG_SAFETY_CLASS_TARGETS = {
|
||||
|
||||
|
||||
RELEASE_TARGETS = (
|
||||
"openpilot/starpilot/aol/tests/test_torque_stock_cruise_transition.py",
|
||||
"openpilot/starpilot/aol/tests/test_torque_stock_brake_guards.py",
|
||||
"opendbc_repo/opendbc/safety/tests/test_hyundai_torque_stock_transition.py",
|
||||
"openpilot/starpilot/aol/tests/test_angle_stock_cruise_transition.py",
|
||||
"opendbc_repo/opendbc/safety/tests/test_hyundai_stock_cruise_transition.py",
|
||||
"opendbc_repo/opendbc/car/hyundai/tests/test_ioniq5pe_replacement_duplicates.py",
|
||||
|
||||
Reference in New Issue
Block a user