From 640463aa174e6b905b68f715df3c882e088c7b0a Mon Sep 17 00:00:00 2001 From: rakadu1 Date: Tue, 31 Mar 2026 14:00:30 +0530 Subject: [PATCH] refactor: extend ScenarioBase with weather, max_frames, and ego_spawn_point props - Added ego_spawn_point for deterministic scenario starts - Implemented apply_parameters() for CLI parameter injection - Moved weather mapping logic to centralized src/utils.py - Emptied scenarios/__init__.py to prevent side-effect imports during discovery --- scenarios/__init__.py | 2 +- scenarios/base.py | 57 ++++++++++++++++++++++++++++++++++++++++--- src/utils.py | 29 ++++++++++++++++++++++ 3 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 src/utils.py diff --git a/scenarios/__init__.py b/scenarios/__init__.py index 077eb30..ac57287 100644 --- a/scenarios/__init__.py +++ b/scenarios/__init__.py @@ -1,2 +1,2 @@ # scenarios package -from .showcase import ShowcaseScenario +# This file is intentionally empty to avoid side-effects when discovering modules. diff --git a/scenarios/base.py b/scenarios/base.py index c6eebd8..48176df 100644 --- a/scenarios/base.py +++ b/scenarios/base.py @@ -10,8 +10,10 @@ Every scenario must subclass ScenarioBase and implement: - name (property) Optional overrides: - - on_ego_spawned() - - get_scenario_metadata() + - on_ego_spawned() + - get_scenario_metadata() + - weather (property) + - max_frames (property) """ 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: """ Called immediately after the ego vehicle is spawned. @@ -104,6 +133,28 @@ class ScenarioBase(ABC): """ 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 # ------------------------------------------------------------------ diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..aaeedec --- /dev/null +++ b/src/utils.py @@ -0,0 +1,29 @@ +import carla + +def get_weather_preset(name: str): + """ + Map names (case-insensitive, partial matching) to carla.WeatherParameters. + """ + weather_presets = { + "Clear": carla.WeatherParameters.ClearNoon, + "Cloudy": carla.WeatherParameters.CloudyNoon, + "Wet": carla.WeatherParameters.WetNoon, + "SoftRain": carla.WeatherParameters.SoftRainNoon, + "Rain": carla.WeatherParameters.HardRainNoon, + "Sunset": carla.WeatherParameters.ClearSunset, + "Night": carla.WeatherParameters( + sun_altitude_angle=-90.0, + cloudiness=0.0, + precipitation=10.0, + precipitation_deposits=10.0, + wind_intensity=0.0, + fog_density=0.0, + fog_distance=0.0, + wetness=0.0 + ) + } + + for k, v in weather_presets.items(): + if k.lower() in name.lower(): + return v + return carla.WeatherParameters.ClearNoon