|
|
@ -12,6 +12,8 @@ Every scenario must subclass ScenarioBase and implement: |
|
|
Optional overrides: |
|
|
Optional overrides: |
|
|
- on_ego_spawned() |
|
|
- on_ego_spawned() |
|
|
- get_scenario_metadata() |
|
|
- get_scenario_metadata() |
|
|
|
|
|
- weather (property) |
|
|
|
|
|
- max_frames (property) |
|
|
""" |
|
|
""" |
|
|
|
|
|
|
|
|
from abc import ABC, abstractmethod |
|
|
from abc import ABC, abstractmethod |
|
|
@ -85,9 +87,36 @@ class ScenarioBase(ABC): |
|
|
""" |
|
|
""" |
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------ |
|
|
# ------------------------------------------------------------------ |
|
|
# Optional hooks (default no-ops — override as needed) |
|
|
|
|
|
|
|
|
# Optional hooks & Properties (default no-ops — override as needed) |
|
|
# ------------------------------------------------------------------ |
|
|
# ------------------------------------------------------------------ |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def weather(self) -> str: |
|
|
|
|
|
""" |
|
|
|
|
|
Override to request a specific weather preset for this scenario. |
|
|
|
|
|
If None, the global config or CLI default will be used. |
|
|
|
|
|
""" |
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def max_frames(self) -> int: |
|
|
|
|
|
""" |
|
|
|
|
|
Override to request a specific duration for this scenario. |
|
|
|
|
|
If None, the global config or CLI default will be used. |
|
|
|
|
|
""" |
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
def ego_spawn_point(self): |
|
|
|
|
|
""" |
|
|
|
|
|
Override to request a specific spawn point for the ego vehicle. |
|
|
|
|
|
Returns: |
|
|
|
|
|
- int: index in the world's spawn points list. |
|
|
|
|
|
- carla.Transform: absolute spawn position and rotation. |
|
|
|
|
|
If None, the global config or CLI default index will be used. |
|
|
|
|
|
""" |
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
def on_ego_spawned(self, ego_vehicle) -> None: |
|
|
def on_ego_spawned(self, ego_vehicle) -> None: |
|
|
""" |
|
|
""" |
|
|
Called immediately after the ego vehicle is spawned. |
|
|
Called immediately after the ego vehicle is spawned. |
|
|
@ -104,6 +133,28 @@ class ScenarioBase(ABC): |
|
|
""" |
|
|
""" |
|
|
return {"scenario": self.name} |
|
|
return {"scenario": self.name} |
|
|
|
|
|
|
|
|
|
|
|
def apply_parameters(self, params: dict) -> None: |
|
|
|
|
|
""" |
|
|
|
|
|
Allow the orchestrator to inject parameters parsed from CLI. |
|
|
|
|
|
This maps keys in `params` to existing attributes on the scenario. |
|
|
|
|
|
Useful for non-code tuning. |
|
|
|
|
|
""" |
|
|
|
|
|
for key, value in params.items(): |
|
|
|
|
|
if hasattr(self, key): |
|
|
|
|
|
# Try to preserve type |
|
|
|
|
|
existing_val = getattr(self, key) |
|
|
|
|
|
try: |
|
|
|
|
|
if isinstance(existing_val, bool): |
|
|
|
|
|
typed_val = str(value).lower() in ("true", "1", "yes") |
|
|
|
|
|
else: |
|
|
|
|
|
typed_val = type(existing_val)(value) |
|
|
|
|
|
setattr(self, key, typed_val) |
|
|
|
|
|
print(f"[Scenario] Injected param: {key} = {typed_val}") |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
print(f"[WARN] Failed to inject param '{key}={value}': {e}") |
|
|
|
|
|
else: |
|
|
|
|
|
print(f"[WARN] Scenario '{self.name}' has no attribute '{key}'") |
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------ |
|
|
# ------------------------------------------------------------------ |
|
|
# Shared helpers for subclasses |
|
|
# Shared helpers for subclasses |
|
|
# ------------------------------------------------------------------ |
|
|
# ------------------------------------------------------------------ |
|
|
|