""" scenarios/obstacle.py --------------------- Static Obstacle Scenario. A traffic cone (or configurable static prop) is placed on the ego lane ahead of the vehicle. The ego autopilot must detect and react to the obstruction. No per-frame logic is needed — this is a purely static scene. """ import sys import os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from scenarios.base import ScenarioBase class ObstacleScenario(ScenarioBase): """ Scenario: Static obstacle on the ego lane. A prop is spawned on the road ahead. The ego continues under autopilot and must navigate around or brake for the obstacle. """ OBSTACLE_DISTANCE_M = 30 # metres ahead of ego for static prop # CARLA blueprint name for the static prop PROP_BLUEPRINT = "static.prop.trafficcone01" def __init__(self): super().__init__() self._obstacle = None # ------------------------------------------------------------------ # ScenarioBase interface # ------------------------------------------------------------------ @property def name(self) -> str: return "obstacle" @property def ego_spawn_point(self): # Working Town10 intersection point (Southbound) import carla return carla.Transform(carla.Location(x=107.412, y=45.309, z=0.5), carla.Rotation(yaw=-87.7)) def setup(self, world, ego_vehicle, traffic_manager) -> None: self._world = world self._ego = ego_vehicle self._tm = traffic_manager bp_lib = world.get_blueprint_library() # Locate prop blueprint prop_bps = bp_lib.filter(self.PROP_BLUEPRINT) if not prop_bps: # Fallback to any traffic cone available prop_bps = bp_lib.filter("static.prop.trafficcone*") if not prop_bps: raise RuntimeError( f"[ObstacleScenario] Blueprint '{self.PROP_BLUEPRINT}' not found. " "Check CARLA content pack." ) prop_bp = prop_bps[0] # Place obstacle on the ego lane ahead spawn_wp = self._get_waypoint_ahead(self.OBSTACLE_DISTANCE_M, lane_offset=0) if spawn_wp is None: raise RuntimeError( "[ObstacleScenario] Could not find waypoint ahead — " "ensure ego is on a driveable road." ) # Offset slightly to lane centre to avoid collision with road mesh obstacle_transform = spawn_wp.transform obstacle_transform.location.z += 0.1 # tiny Z lift avoids clipping self._obstacle = world.try_spawn_actor(prop_bp, obstacle_transform) if self._obstacle is None: raise RuntimeError( "[ObstacleScenario] Failed to spawn obstacle at " f"{obstacle_transform.location}." ) self._actors.append(self._obstacle) print( f"[{self.name}] '{self.PROP_BLUEPRINT}' placed " f"{self.OBSTACLE_DISTANCE_M} m ahead of ego." ) def step(self, frame_count: int, ego_vehicle, pbar=None) -> None: # Static scenario — no per-frame logic required pass def cleanup(self) -> None: self._destroy_actors() print(f"[{self.name}] Cleanup complete.") # ------------------------------------------------------------------ # Optional overrides # ------------------------------------------------------------------ def get_scenario_metadata(self) -> dict: return { "scenario": self.name, "obstacle_prop": self.PROP_BLUEPRINT, "obstacle_distance_m": self.OBSTACLE_DISTANCE_M, }