Files
sunnypilot-byd/openpilot/sunnypilot/selfdrive/car/tests/test_custom_cruise.py
T
github-actions[bot] de77c89cf6 sunnypilot v2026.002.000
version: sunnypilot v2026.002.000 (staging)
date: 2026-07-21T07:44:02
master commit: 2c334ede443d7391d27575af8c854a095ba702a8
2026-07-21 07:44:02 +00:00

151 lines
6.4 KiB
Python

import pytest
from opendbc.car.structs import car
from openpilot.common.constants import CV
from openpilot.common.parameterized import parameterized_class
from openpilot.common.params import Params
from openpilot.selfdrive.car.cruise import V_CRUISE_INITIAL
from openpilot.selfdrive.car.tests.test_cruise_speed import TestVCruiseHelper
ButtonEvent = car.CarState.ButtonEvent
ButtonType = car.CarState.ButtonEvent.Type
# TODO: test pcmCruise and pcmCruiseSpeed
@parameterized_class(('pcm_cruise', 'pcm_cruise_speed'), [(False, True)])
class TestCustomAccIncrements(TestVCruiseHelper):
def setup_method(self):
TestVCruiseHelper.setup_method(self)
self.params = Params()
self.reset_custom_params()
def reset_custom_params(self) -> None:
"""Reset to default custom ACC parameters"""
self.params.put_bool("CustomAccIncrementsEnabled", False, block=True)
self.params.put("CustomAccShortPressIncrement", 1, block=True)
self.params.put("CustomAccLongPressIncrement", 5, block=True)
self.v_cruise_helper.read_custom_set_speed_params()
def press_button_short(self, button_type: car.CarState.ButtonEvent.Type) -> None:
"""Simulate a short button press (press + release)"""
CS = car.CarState(cruiseState={"available": True})
CS.buttonEvents = [ButtonEvent(type=button_type, pressed=True)]
self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=True)
CS.buttonEvents = [ButtonEvent(type=button_type, pressed=False)]
self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=True)
def press_button_long(self, button_type: car.CarState.ButtonEvent.Type) -> None:
"""Simulate a long button press (50+ frames)"""
CS = car.CarState(cruiseState={"available": True})
CS.buttonEvents = [ButtonEvent(type=button_type, pressed=True)]
self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=True)
# Hold for 50 frames to trigger long press
CS.buttonEvents = []
for _ in range(50):
self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=True)
CS.buttonEvents = [ButtonEvent(type=button_type, pressed=False)]
self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=True)
def set_custom_increments(self, enabled: bool, short_inc: int, long_inc: int) -> None:
"""Set custom ACC increment parameters"""
self.params.put_bool("CustomAccIncrementsEnabled", enabled, block=True)
self.params.put("CustomAccShortPressIncrement", short_inc, block=True)
self.params.put("CustomAccLongPressIncrement", long_inc, block=True)
self.v_cruise_helper.read_custom_set_speed_params()
def test_default_behavior_when_disabled(self):
"""Test that default increments are used when custom ACC is disabled"""
self.set_custom_increments(enabled=False, short_inc=5, long_inc=10)
self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False, False)
initial_speed = self.v_cruise_helper.v_cruise_kph
# Short press should increment by 1 (default)
self.press_button_short(ButtonType.accelCruise)
assert self.v_cruise_helper.v_cruise_kph == initial_speed + 1
@pytest.mark.parametrize("increment", (1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
def test_custom_short_press_increments(self, increment):
"""Test custom short press increments (1-10)"""
self.set_custom_increments(enabled=True, short_inc=increment, long_inc=5)
self.enable(50 * CV.KPH_TO_MS, False, False)
initial_speed = self.v_cruise_helper.v_cruise_kph
self.press_button_short(ButtonType.accelCruise)
if increment in (5, 10):
# Should round to nearest increment
expected_speed = ((initial_speed // increment) + 1) * increment
else:
expected_speed = initial_speed + increment
assert self.v_cruise_helper.v_cruise_kph == expected_speed
@pytest.mark.parametrize("increment", (1, 5, 10))
def test_custom_long_press_increments(self, increment):
"""Test custom long press increments (1, 5, 10)"""
self.set_custom_increments(enabled=True, short_inc=1, long_inc=increment)
self.enable(50 * CV.KPH_TO_MS, False, False)
initial_speed = self.v_cruise_helper.v_cruise_kph
self.press_button_long(ButtonType.accelCruise)
if increment in (5, 10):
# Should round to nearest increment
expected_speed = ((initial_speed // increment) + 1) * increment
else:
expected_speed = initial_speed + increment
assert self.v_cruise_helper.v_cruise_kph == expected_speed
@pytest.mark.parametrize("button_type", [ButtonType.accelCruise, ButtonType.decelCruise])
def test_accel_decel_symmetry(self, button_type):
"""Test that acceleration and deceleration work symmetrically"""
self.set_custom_increments(enabled=True, short_inc=3, long_inc=5)
self.enable(50 * CV.KPH_TO_MS, False, False)
initial_speed = self.v_cruise_helper.v_cruise_kph
self.press_button_short(button_type)
expected_change = 3 if button_type == ButtonType.accelCruise else -3
assert self.v_cruise_helper.v_cruise_kph == initial_speed + expected_change
def test_rounding_behavior(self):
"""Test rounding behavior for 5 and 10 increments"""
test_cases = [
(47, 5, 50), # 47 -> 50 (round up to next 5)
(45, 5, 50), # 45 -> 50 (already at 5, increment by 5)
(43, 10, 50), # 43 -> 50 (round up to next 10)
(40, 10, 50), # 40 -> 50 (already at 10, increment by 10)
]
for initial, increment, expected in test_cases:
self.set_custom_increments(enabled=True, short_inc=increment, long_inc=increment)
self.reset_cruise_speed_state()
self.enable(initial * CV.KPH_TO_MS, False, False)
self.press_button_short(ButtonType.accelCruise)
assert self.v_cruise_helper.v_cruise_kph == expected
def test_invalid_values_fallback(self):
"""Test that invalid values fallback to safe defaults"""
# Test invalid short increment
self.set_custom_increments(enabled=True, short_inc=-1, long_inc=5)
self.enable(50 * CV.KPH_TO_MS, False, False)
initial_speed = self.v_cruise_helper.v_cruise_kph
self.press_button_short(ButtonType.accelCruise)
assert self.v_cruise_helper.v_cruise_kph == initial_speed + 1 # Should fallback to 1
# Test invalid long increment
self.reset_cruise_speed_state()
self.set_custom_increments(enabled=True, short_inc=1, long_inc=99)
self.enable(50 * CV.KPH_TO_MS, False, False)
initial_speed = self.v_cruise_helper.v_cruise_kph
self.press_button_long(ButtonType.accelCruise)
assert self.v_cruise_helper.v_cruise_kph == initial_speed + 10 # Should fallback to 10