Files
StarPilot/selfdrive/selfdrived/tests/test_blindspot_alerts.py
firestar5683 b945d4c021 Add vision adjacent spot monitoring
Integrate V-ASM from PR #75 with Galaxy-only configuration, stale-state safety, conditional SLV coexistence, and OpenCV inference.

Originally contributed by @prabhaavp in #75.

Co-authored-by: Prabhaav Pillai <143428353+prabhaavp@users.noreply.github.com>
2026-07-23 00:05:43 -05:00

105 lines
4.4 KiB
Python

from types import SimpleNamespace
from cereal import custom, log
from openpilot.selfdrive.selfdrived.alertmanager import AlertManager
from openpilot.selfdrive.selfdrived.events import ET, Events
from openpilot.selfdrive.selfdrived.selfdrived import get_starpilot_alert_filters, should_loud_blindspot_alert_without_lateral
LaneChangeState = log.LaneChangeState
LaneChangeDirection = log.LaneChangeDirection
StarPilotEventName = custom.StarPilotOnroadEvent.EventName
def _car_state(left_blinker=False, right_blinker=False, left_blindspot=False, right_blindspot=False):
return SimpleNamespace(
leftBlinker=left_blinker,
rightBlinker=right_blinker,
leftBlindspot=left_blindspot,
rightBlindspot=right_blindspot,
)
def _sm(lane_change_state=LaneChangeState.off, lane_change_direction=LaneChangeDirection.none,
lat_active=False, lateral_check=False, pause_lateral=False):
return {
"modelV2": SimpleNamespace(meta=SimpleNamespace(laneChangeState=lane_change_state, laneChangeDirection=lane_change_direction)),
"carControl": SimpleNamespace(latActive=lat_active),
"starpilotPlan": SimpleNamespace(lateralCheck=lateral_check),
"starpilotCarState": SimpleNamespace(pauseLateral=pause_lateral),
}
def _toggles(enabled=True):
return SimpleNamespace(
loud_blindspot_alert=True,
loud_blindspot_alert_when_disengaged=enabled,
)
def test_loud_blindspot_alert_without_lateral_for_matching_signal():
CS = _car_state(left_blinker=True, left_blindspot=True)
assert should_loud_blindspot_alert_without_lateral(CS, _sm(lat_active=False), _toggles())
assert should_loud_blindspot_alert_without_lateral(CS, _sm(lat_active=True, lateral_check=False), _toggles())
assert should_loud_blindspot_alert_without_lateral(CS, _sm(lat_active=True, lateral_check=True, pause_lateral=True), _toggles())
def test_loud_blindspot_alert_accepts_combined_vision_state():
CS = _car_state(left_blinker=True)
assert should_loud_blindspot_alert_without_lateral(
CS, _sm(lat_active=False), _toggles(), combined_left_bsm=True,
)
def test_loud_blindspot_alert_without_lateral_ignores_active_lateral():
CS = _car_state(right_blinker=True, right_blindspot=True)
assert not should_loud_blindspot_alert_without_lateral(CS, _sm(lat_active=True, lateral_check=True), _toggles())
def test_loud_blindspot_alert_without_lateral_requires_matching_side_and_toggle():
assert not should_loud_blindspot_alert_without_lateral(_car_state(left_blinker=True, right_blindspot=True), _sm(), _toggles())
assert not should_loud_blindspot_alert_without_lateral(_car_state(left_blinker=True, right_blinker=True, left_blindspot=True), _sm(), _toggles())
assert not should_loud_blindspot_alert_without_lateral(_car_state(left_blinker=True, left_blindspot=True), _sm(), _toggles(enabled=False))
def test_loud_blindspot_alert_without_lateral_skips_normal_lane_change_alert_path():
CS = _car_state(left_blinker=True, left_blindspot=True)
assert not should_loud_blindspot_alert_without_lateral(CS, _sm(lane_change_state=LaneChangeState.preLaneChange,
lane_change_direction=LaneChangeDirection.left), _toggles())
def test_loud_blindspot_alert_without_lateral_handles_paused_pre_lane_change_without_direction():
CS = _car_state(left_blinker=True, left_blindspot=True)
sm = _sm(lane_change_state=LaneChangeState.preLaneChange, lat_active=True, lateral_check=True, pause_lateral=True)
assert should_loud_blindspot_alert_without_lateral(CS, sm, _toggles())
def test_loud_blindspot_alert_survives_disabled_warning_filter():
events = Events(starpilot=True)
events.add(StarPilotEventName.laneChangeBlockedLoud)
alert_types, clear_event_types = get_starpilot_alert_filters([ET.PERMANENT], {ET.WARNING}, events)
alerts = events.create_alerts(alert_types)
alert_manager = AlertManager()
alert_manager.add_many(0, alerts)
alert_manager.process_alerts(0, clear_event_types)
assert alert_manager.current_alert.alert_type == "laneChangeBlockedLoud/warning"
def test_disabled_starpilot_warnings_stay_filtered_without_blindspot_event():
events = Events(starpilot=True)
events.add(StarPilotEventName.noLaneAvailable)
alert_types, clear_event_types = get_starpilot_alert_filters([ET.PERMANENT], {ET.WARNING}, events)
assert ET.WARNING not in alert_types
assert ET.WARNING in clear_event_types
assert events.create_alerts(alert_types) == []