mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-07 21:13:41 +08:00
460 lines
22 KiB
Python
460 lines
22 KiB
Python
"""Validated saved longitudinal profiles resolved for the native planner."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
from dataclasses import astuple, dataclass
|
|
|
|
from openpilot.common.constants import CV
|
|
from opendbc.car.structs import car
|
|
from opendbc.car.interfaces import ACCEL_MIN, ACCEL_MAX
|
|
from openpilot.starpilot.longitudinal.accel_profile import A_CRUISE_MAX_VALS_TRAFFIC_ALL, interpolate_accel_profile
|
|
from openpilot.starpilot.longitudinal.profile_document import (
|
|
DEFAULT_DECELERATION_PROFILE, active_personality_id, interpolate_category_curve, is_truck_fingerprint,
|
|
)
|
|
from openpilot.starpilot.longitudinal.profile_preferences import (
|
|
FOLLOW_MIN_SECONDS, FOLLOW_MAX_SECONDS, NAMES, SCALARS, TRAFFIC_JERK_SUFFIXES,
|
|
read_document_value, read_master_value, read_profile_health, read_traffic_health,
|
|
)
|
|
|
|
JERK_MIN = 0.25
|
|
JERK_MAX = 2.0
|
|
LEGACY_FOLLOW_BP = (45.0 * CV.MPH_TO_MS, 70.0 * CV.MPH_TO_MS)
|
|
TRAFFIC_BP = (0.0, 25.0) # m/s, not mph.
|
|
TRAFFIC_CRUISE_BRAKE_MAGNITUDE = 1.2 * 0.35 # Magnitude of A_CRUISE_MIN * 0.35.
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ProfileSettings:
|
|
document: dict | None
|
|
profile_enabled: dict[str, bool]
|
|
follow: dict[str, tuple[float, float]]
|
|
jerk: dict[str, tuple[float, float, float, float, float]]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class TrafficSettings:
|
|
valid: bool
|
|
reason: str
|
|
document: dict | None
|
|
profile_enabled: bool
|
|
follow: tuple[float, float]
|
|
jerk: tuple[tuple[float, float], ...]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ProfileTuning:
|
|
personality_id: str
|
|
follow_seconds: float
|
|
acceleration_jerk: float
|
|
deceleration_jerk: float
|
|
speed_jerk: float
|
|
speed_decrease_jerk: float
|
|
danger_jerk: float
|
|
acceleration_max: float | None = None
|
|
cruise_brake_magnitude: float | None = None
|
|
traffic_braking_custom: bool = False
|
|
custom_acceleration: bool = False
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AppliedProfile:
|
|
follow_seconds: float
|
|
acceleration_max: float
|
|
cruise_brake_magnitude: float
|
|
acceleration_jerk: float
|
|
deceleration_jerk: float
|
|
speed_jerk: float
|
|
speed_decrease_jerk: float
|
|
danger_jerk: float
|
|
|
|
|
|
def _move(current: float, target: float, step: float) -> float:
|
|
return min(max(target, current - step), current + step)
|
|
|
|
|
|
class ProfileSmoother:
|
|
"""Bound live setting/personality changes and fade invalid input to stock."""
|
|
def __init__(self):
|
|
self.applied: AppliedProfile | None = None
|
|
|
|
def sample(self, target: ProfileTuning | None, personality, dt: float, *, traffic_mode: bool | None = False) -> AppliedProfile | None:
|
|
if type(dt) not in (int, float) or not math.isfinite(dt) or not 0.0 < dt <= 0.25:
|
|
self.applied = None
|
|
return None
|
|
if type(traffic_mode) is not bool:
|
|
self.applied = None
|
|
return None
|
|
personality_id = active_personality_id(traffic_mode, personality)
|
|
if personality_id not in ('traffic', 'aggressive', 'standard', 'relaxed'):
|
|
self.applied = None
|
|
return None
|
|
if target is not None:
|
|
values = (target.follow_seconds, target.acceleration_jerk, target.deceleration_jerk,
|
|
target.speed_jerk, target.speed_decrease_jerk, target.danger_jerk)
|
|
valid = (target.personality_id == personality_id and
|
|
type(target.traffic_braking_custom) is bool and
|
|
all(type(value) in (int, float) and math.isfinite(value) for value in values) and
|
|
FOLLOW_MIN_SECONDS <= target.follow_seconds <= FOLLOW_MAX_SECONDS and
|
|
all(JERK_MIN <= value <= JERK_MAX for value in values[1:]) and
|
|
(target.acceleration_max is None or
|
|
(type(target.acceleration_max) in (int, float) and math.isfinite(target.acceleration_max) and
|
|
0.0 <= target.acceleration_max <= ACCEL_MAX)) and
|
|
(target.cruise_brake_magnitude is None or
|
|
(type(target.cruise_brake_magnitude) in (int, float) and math.isfinite(target.cruise_brake_magnitude) and
|
|
(0.35 if traffic_mode else 0.5) <= target.cruise_brake_magnitude <= abs(ACCEL_MIN))))
|
|
if not valid:
|
|
target = None
|
|
if traffic_mode and target is None:
|
|
self.applied = None
|
|
return None
|
|
default_follow = {'traffic': 0.75, 'aggressive': 1.25, 'standard': 1.45, 'relaxed': 1.75}[personality_id]
|
|
default_jerk = 0.5 if personality_id == 'aggressive' else 1.0
|
|
default = AppliedProfile(default_follow, ACCEL_MAX, 1.2, default_jerk, default_jerk,
|
|
default_jerk, default_jerk, 1.0)
|
|
if target is None and self.applied is None:
|
|
return None
|
|
if target is None:
|
|
desired = default
|
|
else:
|
|
desired = AppliedProfile(target.follow_seconds,
|
|
min(target.acceleration_max if target.acceleration_max is not None else ACCEL_MAX, ACCEL_MAX),
|
|
min(target.cruise_brake_magnitude if target.cruise_brake_magnitude is not None else 1.2,
|
|
abs(ACCEL_MIN)),
|
|
target.acceleration_jerk, target.deceleration_jerk,
|
|
target.speed_jerk, target.speed_decrease_jerk, target.danger_jerk)
|
|
if self.applied is None and traffic_mode:
|
|
# The first Traffic frame fades from the ordinary native personality,
|
|
# not from Traffic's low-speed endpoint (which may be below this target).
|
|
ordinary_id = active_personality_id(False, personality)
|
|
ordinary_follow = {'aggressive': 1.25, 'standard': 1.45, 'relaxed': 1.75}.get(ordinary_id)
|
|
if ordinary_follow is None:
|
|
return None
|
|
ordinary_jerk = 0.5 if ordinary_id == 'aggressive' else 1.0
|
|
previous = AppliedProfile(ordinary_follow, ACCEL_MAX, 1.2, ordinary_jerk, ordinary_jerk,
|
|
ordinary_jerk, ordinary_jerk, 1.0)
|
|
else:
|
|
previous = self.applied or default
|
|
follow_step = max(dt, 0.0) * 1.0
|
|
accel_step = max(dt, 0.0) * 2.0
|
|
jerk_step = max(dt, 0.0) * 2.0
|
|
self.applied = AppliedProfile(
|
|
_move(previous.follow_seconds, desired.follow_seconds, follow_step),
|
|
_move(previous.acceleration_max, desired.acceleration_max, accel_step),
|
|
_move(previous.cruise_brake_magnitude, desired.cruise_brake_magnitude, accel_step),
|
|
_move(previous.acceleration_jerk, desired.acceleration_jerk, jerk_step),
|
|
_move(previous.deceleration_jerk, desired.deceleration_jerk, jerk_step),
|
|
_move(previous.speed_jerk, desired.speed_jerk, jerk_step),
|
|
_move(previous.speed_decrease_jerk, desired.speed_decrease_jerk, jerk_step),
|
|
_move(previous.danger_jerk, desired.danger_jerk, jerk_step),
|
|
)
|
|
if target is None and all(abs(a - b) < 1e-8 for a, b in zip(astuple(self.applied), astuple(default), strict=True)):
|
|
self.applied = None
|
|
return self.applied
|
|
|
|
|
|
def read_settings(params) -> ProfileSettings | None:
|
|
"""A saved preference is inert unless the host explicitly opts into this runtime."""
|
|
master = read_master_value(params)
|
|
if not master.valid or master.value is not True:
|
|
return None
|
|
health = read_profile_health(params, master=master)
|
|
if not health.dependencies_valid:
|
|
return None
|
|
try:
|
|
profile_enabled = dict.fromkeys(NAMES, True)
|
|
follow = {name: (health.number(SCALARS[name][0]), health.number(SCALARS[name][1])) for name in NAMES}
|
|
jerk = {name: (health.number(SCALARS[name][2]) / 100.0, health.number(SCALARS[name][3]) / 100.0,
|
|
health.number(SCALARS[name][4]) / 100.0, health.number(SCALARS[name][5]) / 100.0,
|
|
health.number(SCALARS[name][6]) / 100.0) for name in NAMES}
|
|
return ProfileSettings(health.document, profile_enabled, follow, jerk)
|
|
except ValueError:
|
|
return None
|
|
|
|
|
|
def read_traffic_settings(params) -> TrafficSettings:
|
|
health = read_traffic_health(params)
|
|
if not health.valid:
|
|
return TrafficSettings(False, health.reason, None, False, (0.75, 1.6), ())
|
|
follow = (health.number('TrafficFollow'), health.number('RelaxedFollow'))
|
|
jerk = tuple((health.number('Traffic' + suffix) / 100.0,
|
|
health.number('Relaxed' + suffix) / 100.0) for suffix in TRAFFIC_JERK_SUFFIXES)
|
|
return TrafficSettings(True, 'valid', health.document if health.master_on else None,
|
|
health.profile_enabled if health.master_on else False, follow, jerk)
|
|
|
|
|
|
def _traffic_value(points: tuple[float, float], speed: float) -> float:
|
|
ratio = min(max((speed - TRAFFIC_BP[0]) / (TRAFFIC_BP[1] - TRAFFIC_BP[0]), 0.0), 1.0)
|
|
return float(points[0] + (points[1] - points[0]) * ratio)
|
|
|
|
|
|
def resolve(settings: ProfileSettings | TrafficSettings | None, personality, v_ego: float, CP,
|
|
*, traffic_mode: bool | None = False) -> ProfileTuning | None:
|
|
if settings is None or type(traffic_mode) is not bool or not math.isfinite(v_ego) or v_ego < 0:
|
|
return None
|
|
personality_id = active_personality_id(traffic_mode, personality)
|
|
if traffic_mode:
|
|
if not isinstance(settings, TrafficSettings) or not settings.valid or len(settings.jerk) != 5:
|
|
return None
|
|
follow = _traffic_value(settings.follow, v_ego)
|
|
acceleration_max = interpolate_accel_profile(v_ego, A_CRUISE_MAX_VALS_TRAFFIC_ALL)
|
|
cruise_brake_magnitude = TRAFFIC_CRUISE_BRAKE_MAGNITUDE
|
|
traffic_braking_custom = False
|
|
document = settings.document
|
|
if document is not None and document['enabled'] and settings.profile_enabled:
|
|
categories = document['profiles']['traffic']
|
|
ev_tuning = CP.transmissionType == car.CarParams.TransmissionType.direct
|
|
truck_tuning = is_truck_fingerprint(str(CP.carFingerprint)) and not ev_tuning
|
|
for category in ('following', 'acceleration', 'braking'):
|
|
config = categories[category]
|
|
if config['preset'] in ('dom_default', 'selected_profile') or (category != 'following' and not config.get('legacyActivation', False)):
|
|
continue
|
|
value = interpolate_category_curve(category, v_ego, config, ev_tuning, truck_tuning)
|
|
if category == 'following':
|
|
follow = value
|
|
elif category == 'acceleration':
|
|
acceleration_max = value
|
|
else:
|
|
cruise_brake_magnitude = value
|
|
traffic_braking_custom = True
|
|
if (not all(math.isfinite(value) for value in (follow, acceleration_max, cruise_brake_magnitude)) or
|
|
not FOLLOW_MIN_SECONDS <= follow <= FOLLOW_MAX_SECONDS or
|
|
acceleration_max < 0.0 or not 0.35 <= cruise_brake_magnitude <= abs(ACCEL_MIN)):
|
|
return None
|
|
acceleration, deceleration, speed, speed_decrease, danger = (
|
|
_traffic_value(points, v_ego) for points in settings.jerk
|
|
)
|
|
return ProfileTuning('traffic', follow, acceleration, deceleration, speed, speed_decrease, danger,
|
|
min(acceleration_max, ACCEL_MAX), cruise_brake_magnitude,
|
|
traffic_braking_custom=traffic_braking_custom)
|
|
if not isinstance(settings, ProfileSettings):
|
|
return None
|
|
if personality_id not in settings.follow:
|
|
return None
|
|
low, high = settings.follow[personality_id]
|
|
follow = float(low + (high - low) * min(max((v_ego - LEGACY_FOLLOW_BP[0]) /
|
|
(LEGACY_FOLLOW_BP[1] - LEGACY_FOLLOW_BP[0]), 0.0), 1.0))
|
|
acceleration_max = None
|
|
cruise_brake_magnitude = None
|
|
custom_acceleration = False
|
|
document = settings.document
|
|
if document is not None and document['enabled'] and settings.profile_enabled[personality_id]:
|
|
categories = document['profiles'][personality_id]
|
|
ev_tuning = CP.transmissionType == car.CarParams.TransmissionType.direct
|
|
truck_tuning = is_truck_fingerprint(str(CP.carFingerprint)) and not ev_tuning
|
|
for category in ('following', 'acceleration', 'braking'):
|
|
config = categories[category]
|
|
if config['preset'] in ('dom_default', 'selected_profile') or (category != 'following' and not config.get('legacyActivation', False)):
|
|
continue
|
|
value = interpolate_category_curve(category, v_ego, config, ev_tuning, truck_tuning)
|
|
if not math.isfinite(value):
|
|
return None
|
|
if category == 'following':
|
|
follow = value
|
|
elif category == 'acceleration':
|
|
custom_acceleration = config['preset'] == 'custom'
|
|
acceleration_max = min(max(value, 0.0), ACCEL_MAX)
|
|
else:
|
|
cruise_brake_magnitude = min(max(value, 0.5), abs(ACCEL_MIN))
|
|
acceleration_jerk, deceleration_jerk, speed_jerk, speed_decrease_jerk, danger_jerk = settings.jerk[personality_id]
|
|
return ProfileTuning(personality_id, min(max(follow, FOLLOW_MIN_SECONDS), FOLLOW_MAX_SECONDS),
|
|
acceleration_jerk, deceleration_jerk, speed_jerk, speed_decrease_jerk, danger_jerk,
|
|
acceleration_max, cruise_brake_magnitude, custom_acceleration=custom_acceleration)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class SelectedProfileTuning:
|
|
acceleration_max: float | None = None
|
|
cruise_brake_magnitude: float | None = None
|
|
braking_style: str = 'standard'
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class GlobalPowertrainPreset:
|
|
ev: bool
|
|
truck: bool
|
|
|
|
|
|
def read_global_powertrain_preset(params, CP) -> GlobalPowertrainPreset | None:
|
|
from opendbc.car.gm.feature_capabilities import longitudinal_supported
|
|
from opendbc.car.gm.truck_longitudinal import truck_tuning_supported
|
|
from openpilot.starpilot.saved_source import read_saved
|
|
if not longitudinal_supported(CP):
|
|
return None
|
|
try:
|
|
ev, ev_readable = read_saved(params, 'EVTuning', 8)
|
|
truck, truck_readable = read_saved(params, 'TruckTuning', 8)
|
|
if not ev_readable or not truck_readable or ev not in (None, b'0', b'1') or truck not in (None, b'0', b'1'):
|
|
return None
|
|
if not truck_tuning_supported(CP):
|
|
truck = None # A saved choice from another truck cannot activate this owner.
|
|
if ev is None and truck is None:
|
|
return None # Absence preserves the existing final-CP response.
|
|
truck_selected = truck == b'1' and truck_tuning_supported(CP)
|
|
return GlobalPowertrainPreset((CP.transmissionType == car.CarParams.TransmissionType.direct if ev is None else ev == b'1') and not truck_selected,
|
|
truck_selected)
|
|
except (OSError, RuntimeError, TypeError, ValueError):
|
|
return None
|
|
|
|
|
|
def selected_profiles_requested(document: dict | None) -> bool:
|
|
if document is None:
|
|
return False
|
|
if document['selectedAccelerationProfile'] != 'dom_default' or document['selectedDecelerationProfile'] != 'dom_default':
|
|
return True
|
|
return any(config['preset'] not in ('dom_default', 'selected_profile') and not config.get('legacyActivation', False)
|
|
for profile in document['profiles'].values() for category, config in profile.items() if category != 'following')
|
|
|
|
|
|
def resolve_selected_profiles(document: dict | None, personality, v_ego: float, CP, *, traffic_mode: bool | None = False,
|
|
legacy: ProfileTuning | None = None, global_powertrain: GlobalPowertrainPreset | None = None) -> SelectedProfileTuning | None:
|
|
"""Resolve only acceleration/braking; never enable following or jerk tuning.
|
|
|
|
Migration provenance preserves the former master/curve gates until the user
|
|
explicitly selects inheritance or an override. Global deceleration retains
|
|
the historical response scale; explicit personality curves retain theirs.
|
|
"""
|
|
identity = active_personality_id(traffic_mode, personality)
|
|
if document is None or identity is None or not math.isfinite(v_ego) or v_ego < 0:
|
|
return None
|
|
ev = CP.transmissionType == car.CarParams.TransmissionType.direct
|
|
truck = is_truck_fingerprint(str(CP.carFingerprint)) and not ev
|
|
acceleration = braking = None
|
|
style = 'standard'
|
|
for category in ('acceleration', 'braking'):
|
|
config = document['profiles'][identity][category]
|
|
preset = config['preset']
|
|
inherited = preset == 'selected_profile'
|
|
if config.get('legacyActivation', False):
|
|
# Old active overrides are already applied by the original smoother.
|
|
active_value = getattr(legacy, 'acceleration_max' if category == 'acceleration' else 'cruise_brake_magnitude', None)
|
|
if active_value is not None or category == 'acceleration' or traffic_mode is True:
|
|
continue
|
|
inherited = True # Old global response was ordinary-cruise-only.
|
|
if inherited:
|
|
preset = document['selectedAccelerationProfile' if category == 'acceleration' else 'selectedDecelerationProfile']
|
|
if preset == 'dom_default':
|
|
if category == 'acceleration' and inherited and traffic_mode is False and global_powertrain is not None:
|
|
preset = 'standard' # Original explicit EV/Truck choice owns the global Standard fallback.
|
|
else:
|
|
continue
|
|
if category == 'braking' and inherited:
|
|
value = {'standard': 1.2, 'eco': 0.6, 'sport': 2.4}[preset]
|
|
else:
|
|
selected_ev, selected_truck = ev, truck
|
|
if category == 'acceleration' and inherited and traffic_mode is False and global_powertrain is not None:
|
|
selected_ev, selected_truck = global_powertrain.ev, global_powertrain.truck
|
|
value = interpolate_category_curve(category, v_ego,
|
|
{'preset': preset, 'curve': []} if inherited else config, selected_ev, selected_truck)
|
|
if not math.isfinite(value):
|
|
return None
|
|
if category == 'acceleration':
|
|
acceleration = min(max(value, 0.0), ACCEL_MAX)
|
|
else:
|
|
braking = min(max(value, 0.35 if traffic_mode else 0.5), abs(ACCEL_MIN))
|
|
style = preset if preset in ('eco', 'sport') else 'standard'
|
|
return SelectedProfileTuning(acceleration, braking, style)
|
|
|
|
|
|
class ProfileHost:
|
|
"""Bounded local Params refresh; a failed read expires the previous tuning."""
|
|
REFRESH_NS = 1_000_000_000
|
|
MAX_AGE_NS = 2_000_000_000
|
|
|
|
def __init__(self, params):
|
|
self.params = params
|
|
self.disabled = False
|
|
self.selected_document: dict | None = None
|
|
self.selected_powertrain: GlobalPowertrainPreset | None = None
|
|
self.selected_attempt_ns = -self.REFRESH_NS
|
|
self.selected_success_ns = -1
|
|
self.settings: ProfileSettings | TrafficSettings | None = None
|
|
self.last_attempt_ns = -self.REFRESH_NS
|
|
self.last_success_ns = -1
|
|
|
|
self.last_mode: bool | None = None
|
|
self.global_braking_response: str | None = None
|
|
self.global_last_attempt_ns = -self.REFRESH_NS
|
|
self.global_last_success_ns = -1
|
|
|
|
def sample_selected(self, now_ns: int, personality, v_ego: float, CP, *, traffic_mode: bool | None = False,
|
|
legacy: ProfileTuning | None = None) -> SelectedProfileTuning | None:
|
|
if now_ns < 0 or now_ns < self.selected_attempt_ns:
|
|
self.selected_document = None
|
|
self.selected_powertrain = None
|
|
self.selected_attempt_ns = now_ns - self.REFRESH_NS
|
|
self.selected_success_ns = -1
|
|
if now_ns - self.selected_attempt_ns >= self.REFRESH_NS:
|
|
self.selected_attempt_ns = now_ns
|
|
try:
|
|
saved = read_document_value(self.params)
|
|
self.selected_document = saved.value if saved.valid and isinstance(saved.value, dict) else None
|
|
self.selected_powertrain = read_global_powertrain_preset(self.params, CP)
|
|
self.selected_success_ns = now_ns if saved.valid else -1
|
|
except (OSError, RuntimeError, ValueError, TypeError, KeyError):
|
|
self.selected_document = None
|
|
self.selected_powertrain = None
|
|
self.selected_success_ns = -1
|
|
if self.selected_success_ns < 0 or now_ns - self.selected_success_ns > self.MAX_AGE_NS:
|
|
return None
|
|
return resolve_selected_profiles(self.selected_document, personality, v_ego, CP,
|
|
traffic_mode=traffic_mode, legacy=legacy, global_powertrain=self.selected_powertrain)
|
|
|
|
def sample_global_braking(self, now_ns: int) -> str | None:
|
|
if now_ns < 0 or now_ns < self.global_last_attempt_ns:
|
|
self.global_braking_response = None
|
|
self.global_last_attempt_ns = now_ns - self.REFRESH_NS
|
|
self.global_last_success_ns = -1
|
|
if now_ns - self.global_last_attempt_ns >= self.REFRESH_NS:
|
|
self.global_last_attempt_ns = now_ns
|
|
try:
|
|
saved = read_document_value(self.params)
|
|
if saved.valid and saved.value is None:
|
|
self.global_braking_response = DEFAULT_DECELERATION_PROFILE
|
|
elif saved.valid and isinstance(saved.value, dict):
|
|
response = saved.value.get("selectedDecelerationProfile")
|
|
self.global_braking_response = response if isinstance(response, str) else None
|
|
else:
|
|
self.global_braking_response = None
|
|
self.global_last_success_ns = now_ns if self.global_braking_response is not None else -1
|
|
except (OSError, RuntimeError, ValueError, TypeError, KeyError):
|
|
self.global_braking_response = None
|
|
self.global_last_success_ns = -1
|
|
if self.global_last_success_ns < 0 or now_ns - self.global_last_success_ns > self.MAX_AGE_NS:
|
|
return None
|
|
return self.global_braking_response
|
|
|
|
def sample(self, now_ns: int, personality, v_ego: float, CP, *, traffic_mode: bool | None = False) -> ProfileTuning | None:
|
|
if type(traffic_mode) is not bool:
|
|
self.disabled = False
|
|
self.settings = None
|
|
self.last_attempt_ns = now_ns - self.REFRESH_NS
|
|
self.last_success_ns = -1
|
|
self.last_mode = None
|
|
return None
|
|
if self.last_mode is not traffic_mode:
|
|
self.settings = None
|
|
self.last_attempt_ns = now_ns - self.REFRESH_NS
|
|
self.last_success_ns = -1
|
|
self.last_mode = traffic_mode
|
|
if now_ns < 0 or now_ns < self.last_attempt_ns:
|
|
self.disabled = False
|
|
self.settings = None
|
|
self.last_attempt_ns = now_ns - self.REFRESH_NS
|
|
self.last_success_ns = -1
|
|
if now_ns - self.last_attempt_ns >= self.REFRESH_NS:
|
|
self.last_attempt_ns = now_ns
|
|
try:
|
|
master = read_master_value(self.params)
|
|
self.disabled = (not traffic_mode and master.valid and master.value is False and
|
|
read_document_value(self.params).valid)
|
|
self.settings = read_traffic_settings(self.params) if traffic_mode else read_settings(self.params)
|
|
self.last_success_ns = now_ns
|
|
except (OSError, RuntimeError, ValueError, TypeError):
|
|
self.disabled = False
|
|
self.settings = None
|
|
if self.last_success_ns < 0 or now_ns - self.last_success_ns > self.MAX_AGE_NS:
|
|
self.disabled = False
|
|
return None
|
|
return resolve(self.settings, personality, v_ego, CP, traffic_mode=traffic_mode)
|