POMDPPlanners.environments.carla_pomdp package
CARLA POMDP environment module.
This module provides a forward-only adapter exposing the CARLA autonomous-driving simulator as a ground-truth world for the POMDPPlanners episode loop, plus the planner-side generative-model interface paired with it and a concrete reference model.
- Classes:
CarlaPOMDP: Forward-only adapter exposing a CARLA session as a world Environment. CarlaModelPOMDP: Abstract generative-model interface over the CARLA schema. FactoredCarlaModelPOMDP: Concrete CARLA model with a factored observation model. DreamerCarlaModelPOMDP: Concrete CARLA model backed by a Dreamer world model. PerceivedAgentsBelief: Particle belief that stamps the perception pipeline’s agent block. CarlaPerceptionPipeline: Standalone, swappable perception + prediction stage. CarlaServerPool: Context manager owning N headless CARLA servers for parallel episodes. CarlaServerLease: Connection endpoints of one leased pool server.
- class POMDPPlanners.environments.carla_pomdp.CarlaModelPOMDP(discount_factor, action_presets=None, max_tracked_agents=5, observation_models=None, name=None)[source]
Bases:
DiscreteActionsEnvironmentAbstract generative-model interface paired with the forward-only CARLA world.
Concrete subclasses supply the dynamics —
sample_next_state(),transition_log_probability(),reward(),is_terminal(), and the initial-distribution hooks — while this base owns the fixed CARLA schema shared by every model (the ego + agent-slot state layout, the discrete action set, and the observation-dict hashing/equality) and the observation model. The observation is factored by channel: this base holds a{channel: CarlaObservationModel}map (observation_models) and composes it —sample_observation()perceives each channel of the clean observation built from the state,observation_log_probability()sums the per-channel densities, andencode_observation()(the single raw-observation seam) perceives each channel of the forward-only world’s raw reading into the same perceived space, so the belief filter and planner search operate on one consistent (encoded) observation. Two models differ in their observation only by the channel models they hold; a model that scores observations for a belief update needs every channel to provide a density (supports_density). A subclass whose observation is not a per-channel clean transform (e.g. a learned latent decoder) may instead overridesample_observation(),observation_log_probability()andencode_observation()directly.- Parameters:
- action_presets
Discrete
(throttle, steer, brake)control triples; the discrete action set is the indices into this list.
- max_tracked_agents
Number of fixed agent slots in the state/observation.
- observation_models
The per-channel
{channel: CarlaObservationModel}map composed to produce the observation, orNonefor a subclass that overrides the observation methods directly.
Note
This is an abstract base class and cannot be instantiated directly. See
FactoredCarlaModelPOMDPfor a concrete reference implementation.- encode_observation(observation)[source]
Perceive the world’s raw observation into the belief/planner observation space.
The forward-only world emits a raw, fully-detected observation; each channel model degrades its channel (per-slot detection gating, occlusion, additive noise) into the perceived observation the belief filter and planner search operate in. This is the single raw-observation seam — every other observation method works in the perceived (encoded) space. A subclass without channel models (
observation_models is None, e.g. a learned latent model) inherits the identity default.
- hash_action(action)[source]
Return a hashable key consistent with action equality.
Used by tree-search planners to index action children of a belief node in O(1). The returned key MUST satisfy:
action_a == action_b (per env's notion of equality) ==> hash_action(action_a) == hash_action(action_b)
Subclasses with non-hashable actions (e.g.
np.ndarray) must override to return a hashable surrogate (tobytes()is the standard choice for ndarray actions, which mirrors thenp.array_equalsemantics used by the linear-scan fallback).
- hash_observation(observation)[source]
Return a hashable key consistent with
is_equal_observation().Used by tree-search planners to index belief children by observation in O(1). The returned key MUST satisfy the contract:
is_equal_observation(a, b) implies hash_observation(a) == hash_observation(b)
- Parameters:
observation (
Any) – Observation to hash.- Returns:
the observation itself when it is already hashable).
- Return type:
- Raises:
NotImplementedError – If the observation is not hashable and the subclass has not provided an override. Subclasses with non-hashable observations (e.g.
np.ndarray) MUST override.
- is_equal_observation(observation1, observation2)[source]
Check if two observations are equal.
- Parameters:
- Return type:
- Returns:
True if observations are considered equal, False otherwise
Note
Subclasses must implement this method to define observation equality. This is particularly important for discrete observation spaces.
- observation_log_probability(next_state, action, observations)[source]
Log-density of
observationsunder the per-channel perception givennext_state.
- abstractmethod sample_next_state(state, action, n_samples=1)[source]
Sample
n_samplesnext states for(state, action).
- class POMDPPlanners.environments.carla_pomdp.CarlaPOMDP(discount_factor, host='localhost', port=2000, town='Town03', sensor_config=None, action_presets=None, record_camera=False, camera_config=None, include_camera=True, include_lidar=True, include_traffic_light=True, observation_camera_config=None, lidar_config=None, fixed_delta_seconds=0.05, collision_penalty=100.0, desired_speed=8.0, out_lane_thresh=2.0, destination=None, goal_radius=5.0, min_route_length=100.0, success_reward=100.0, num_vehicles=30, num_walkers=10, max_tracked_agents=5, traffic_manager_port=8000, server_pool_dir=None, randomize_spawn=True, observation_extractor=None, vehicle_filter='vehicle.tesla.model3', timeout=10.0, seed=None, name=None, reward_range=None, output_dir=None, debug=False, use_queue_logger=False)[source]
Bases:
EnvironmentForward-only adapter exposing a CARLA session as a world POMDP.
The wrapper drives a CARLA server as the ground-truth world of an episode. It ticks the simulator exactly once per real interaction and serves the resulting next state, observation and reward from a small cache, because the POMDPPlanners episode loop requests those three quantities through separate method calls while CARLA produces them atomically. The state is the ego vehicle’s ground-truth kinematics; the observation is a native CARLA sensor payload (GNSS by default), so the world is genuinely partially observed. See the module docstring for the exact state and observation variables, units, and frames.
Note
This is a world environment, not a generative model. It cannot sample a transition from an arbitrary state, so belief particle propagation and density queries are unsupported and raise
NotImplementedError/RuntimeError. Pair it with a generative model environment on the planner (policy.environment).- Parameters:
discount_factor (float)
host (str)
port (int)
town (str)
action_presets (Sequence[Tuple[float, float, float]] | None)
record_camera (bool)
include_camera (bool)
include_lidar (bool)
include_traffic_light (bool)
fixed_delta_seconds (float)
collision_penalty (float)
desired_speed (float)
out_lane_thresh (float)
goal_radius (float)
min_route_length (float)
success_reward (float)
num_vehicles (int)
num_walkers (int)
max_tracked_agents (int)
traffic_manager_port (int)
randomize_spawn (bool)
observation_extractor (Callable[[Dict[str, ndarray]], Any] | None)
vehicle_filter (str)
timeout (float)
seed (int | None)
name (str | None)
output_dir (Path | None)
debug (bool)
use_queue_logger (bool)
- host
CARLA server host.
- port
CARLA server RPC port.
- town
CARLA map name loaded on reset.
- sensor_config
GNSS blueprint attributes (e.g. noise stddev) forwarded to the sensor; measurement noise, if any, is CARLA’s own.
- action_presets
Discrete
(throttle, steer, brake)control triples.
- seed
Optional seed applied to the first
resetfor reproducibility.
Example
The environment is used as the forward-only world of an
EpisodeRunner, paired with a separate generative model on the planner. It requires a running CARLA server, so this snippet is illustrative rather than executed:env = CarlaPOMDP(discount_factor=0.95, town="Town03") state = env.initial_state_dist().sample()[0] next_state, observation, reward = env.sample_next_step(state, 0) # state is [ego(7), nearest-agent slots...]; observation is a # gnss/agents/camera/lidar dict hiding out-of-range / occluded agents.
- cache_visualization(history, output_dir, episode_index)[source]
Save the episode as CARLA’s own chase-camera MP4 footage.
The episode
historyis unused: the video is the native camera rendering buffered live while the world was stepped, not a plot reconstructed from the step data. The environment must have been constructed withrecord_camera=True.
- compute_metrics(histories)[source]
Compute CARLA driving-quality metrics from episode histories.
- Parameters:
- Return type:
- Returns:
A list of
MetricValuewith 95% confidence bounds across episodes:collision_rate: fraction of episodes that ended in a terminal state without reaching the destination (i.e. in a collision).success_rate: fraction of episodes whose final state is withingoal_radiusof the episode destination.route_completion: mean over episodes of the fraction of the planned route’s arc length covered by the end of the episode.average_progress: mean per-episode ground distance travelled by the ego, in metres.average_speed: mean ego speed over the driven trajectory, in m/s.red_light_violation_rate: fraction of functioning-light stop-line crossings taken while the light was red (averaged over episodes that crossed at least one working light).red_light_violation_count: mean number of red-light crossings per episode.traffic_light_malfunction_count: mean number of crossings per episode where the light was off / unknown — recorded separately and never counted as a violation, since the light was not operating.near_miss_count: mean number of near-miss events per episode (a run within_NEAR_MISS_DISTANCEof another vehicle that did not become a collision).min_vehicle_distance: mean over episodes of the closest the ego came to any vehicle, in metres (a safety-margin metric; episodes that saw no vehicle are excluded).
- hash_action(action)[source]
Return a hashable key consistent with action equality.
Used by tree-search planners to index action children of a belief node in O(1). The returned key MUST satisfy:
action_a == action_b (per env's notion of equality) ==> hash_action(action_a) == hash_action(action_b)
Subclasses with non-hashable actions (e.g.
np.ndarray) must override to return a hashable surrogate (tobytes()is the standard choice for ndarray actions, which mirrors thenp.array_equalsemantics used by the linear-scan fallback).
- hash_observation(observation)[source]
Return a hashable key consistent with
is_equal_observation().Used by tree-search planners to index belief children by observation in O(1). The returned key MUST satisfy the contract:
is_equal_observation(a, b) implies hash_observation(a) == hash_observation(b)
- Parameters:
observation (
Any) – Observation to hash.- Returns:
the observation itself when it is already hashable).
- Return type:
- Raises:
NotImplementedError – If the observation is not hashable and the subclass has not provided an override. Subclasses with non-hashable observations (e.g.
np.ndarray) MUST override.
- initial_observation_dist()[source]
Get the initial observation distribution.
- Return type:
- Returns:
Distribution over initial observations
Note
Subclasses must implement this method to define initial observations.
- initial_state_dist()[source]
Get the initial state distribution.
- Return type:
- Returns:
Distribution over initial states
Note
Subclasses must implement this method to define the starting distribution.
- is_equal_observation(observation1, observation2)[source]
Check if two observations are equal.
- Parameters:
- Return type:
- Returns:
True if observations are considered equal, False otherwise
Note
Subclasses must implement this method to define observation equality. This is particularly important for discrete observation spaces.
- is_terminal(state)[source]
Check if a state is terminal.
- Parameters:
state (
Any) – State to check for terminal condition- Return type:
- Returns:
True if the state is terminal, False otherwise
Note
Subclasses must implement this method to define terminal conditions.
- observation_log_probability(next_state, action, observations)[source]
Log-probability of each candidate observation under
(next_state, action).Returns
np.ndarrayof shape(N,)where N is the number of candidate observations. Subclasses must implement.
- reward(state, action, next_state=None)[source]
Calculate the immediate reward for a state-action(-next_state) tuple.
next_stateis the realised post-transition state when known (e.g. threaded bysample_next_step()), allowing rewards that depend on stochastic transition outcomes to use the same draw as the trajectory instead of resampling. Subclasses whose reward is a pure function of(state, action)may ignore it; subclasses whose reward depends on the realised next state (collision penalties, win bonuses) should consume it when provided and fall back to drawing/computing one whenNone.- Parameters:
- Return type:
- Returns:
Immediate reward value.
Note
Subclasses must implement this method to define reward structure.
- sample_next_state(state, action, n_samples=1)[source]
Sample one or more next states for
(state, action).Hot-path entry point used by MCTS planners and particle filters. Subclasses must implement.
- sample_observation(next_state, action, n_samples=1)[source]
Sample one or more observations for
(next_state, action).Hot-path entry point used by MCTS planners and particle filters. Subclasses must implement.
- save_camera_video(cache_path, fps=20)[source]
Write CARLA’s own chase-camera footage to an MP4 video.
This is the native CARLA rendering (an RGB camera following the ego), not a reconstructed plot. Frames are captured live while the world is stepped, so the environment must have been constructed with
record_camera=Trueand driven for at least one tick before calling this.- Parameters:
- Raises:
RuntimeError – If camera recording is disabled or no frames were captured.
- Return type:
- class POMDPPlanners.environments.carla_pomdp.CarlaPerceptionPipeline(max_tracked_agents=5, perception=None, tracker=None, sensor_fusion=True, stop_for_traffic_lights=True, obstacle_detection_range=30.0, dt=0.05, lidar_corridor_halfwidth=1.5, tracks=None)[source]
Bases:
objectStandalone perception + prediction stage: raw observation -> agent slots + obstacle.
Composes a
PerceptionModel(single-frame) and aMotionTracker(temporal), owns the tracker state, and produces the ego-frame agent block a belief stamps onto its particles plus a fused forward-obstacle distance. Immutable:process()returns aPerceptionOutputcarrying a successor pipeline with the advanced tracks.It is a whole-observation sensor-fusion stage (fusing lidar/camera into the agent block), not a per-channel
CarlaObservationModel: it perceives a whole observation and exposes no observation density. The world threads its tracker state forward viaprocess(); theperceive()convenience method returns a single perceived observation without carrying the advanced tracks, for callers that only need one reading.- Parameters:
max_tracked_agents (int)
perception (PerceptionModel | None)
tracker (MotionTracker | None)
sensor_fusion (bool)
stop_for_traffic_lights (bool)
obstacle_detection_range (float)
dt (float)
lidar_corridor_halfwidth (float)
tracks (ndarray | None)
- max_tracked_agents
Number of agent slots produced in the agent block.
- perception
The single-frame
PerceptionModel.
- tracker
The temporal
MotionTracker.
- sensor_fusion
Whether the fused lidar/camera forward obstacle is reported.
- stop_for_traffic_lights
Whether a red/amber light is reported as a forward obstacle.
- obstacle_detection_range
Only obstacles nearer than this (m) are reported.
- dt
Tracker time step (s).
Example
>>> import numpy as np >>> pipeline = CarlaPerceptionPipeline(max_tracked_agents=1) >>> obs = {"lidar": np.zeros((0, 4)), "camera": np.zeros((8, 8, 3), dtype=np.uint8)} >>> output = pipeline.process(obs) >>> output.agent_rows.shape (1, 5)
- perceive(clean_observation)[source]
Perceive one observation, replacing its
agentsblock with tracked slots.Unlike
process()this discards the advanced tracker state: it yields a single perceived observation for callers that only need one reading. Useprocess()when the successor pipeline (advanced tracks) must be threaded forward.
- process(observation)[source]
Perceive and track one observation into an agent block and forward obstacle.
- class POMDPPlanners.environments.carla_pomdp.CarlaServerLease(host, rpc_port, traffic_manager_port)[source]
Bases:
objectConnection endpoints of one leased pool server.
- host
Hostname the pool’s servers listen on.
- rpc_port
CARLA RPC port of the leased server.
- traffic_manager_port
Client-side Traffic Manager port reserved for the lease holder (unique per server so parallel clients never collide).
- class POMDPPlanners.environments.carla_pomdp.CarlaServerPool(n_servers, pool_dir=None, carla_root=None, rpc_port_base=2000, tm_port_base=8000, gpu_indices=None, extra_args=None, ready_timeout=120.0, command_factory=None)[source]
Bases:
objectContext manager owning N headless CARLA servers plus their lease directory.
On
start()(orwithentry) it spawnsn_serversheadless CARLA servers — RPC portsrpc_port_base + RPC_PORT_STRIDE * i, Traffic Manager portstm_port_base + i— writes the pool spec and lease files intopool_dir, and waits for every server to accept connections. Onshutdown()(orwithexit, or interpreter exit) it terminates them.Worker processes claim a server with
acquire_pool_lease(), or transparently by constructingCarlaPOMDPwithserver_pool_dir=pool.pool_dir. Run at mostn_serversworkers (e.g.JoblibConfig(n_jobs=n_servers)— the defaultn_jobs=-1uses all cores and will exhaust the pool).- Parameters:
- n_servers
Number of servers the pool launches.
- handles
Live
CarlaServerHandleobjects (empty until started).
Example
Illustrative — requires a CARLA installation at
$CARLA_ROOT:with CarlaServerPool(n_servers=2, gpu_indices=[0, 1]) as pool: env = CarlaPOMDP(discount_factor=0.95, server_pool_dir=pool.pool_dir)
- handles: List[CarlaServerHandle]
- property pool_dir: Path
The pool directory holding the spec, lease, and log files.
- Raises:
RuntimeError – If accessed before
start()and no explicitpool_dirwas configured.
- start()[source]
Launch all servers, write the pool spec, and wait until every one is ready.
Launches every server first so their (slow) startups overlap, then blocks on readiness. On any failure the already-launched servers are terminated before the error propagates.
- Return type:
- Returns:
This pool, for chaining.
- Raises:
RuntimeError – If a server process exits before becoming ready.
TimeoutError – If a server is not ready within
ready_timeout.
- class POMDPPlanners.environments.carla_pomdp.DreamerCarlaModelPOMDP(world_model, discount_factor, action_presets=None, max_tracked_agents=5, continue_threshold=0.5, initial_observation=None, name=None)[source]
Bases:
CarlaModelPOMDPConcrete CARLA generative model whose dynamics are a trained Dreamer world model.
The planner-side state is the Dreamer latent; transitions, observations, reward, and termination are served by the injected
DreamerWorldModel. The belief is seeded by encoding the world’s initial observation with the posterior.- Parameters:
- world_model
The trained Dreamer RSSM backing every dynamic quantity.
- continue_threshold
Termination fires when the continue head’s probability drops below this value.
Note
Reward comes from the world model’s learned reward head, not the analytic
driving_quality_reward(); a Dreamer model predicts reward directly from its latent.Example
>>> import numpy as np >>> >>> class _IdentityWorldModel: ... latent_dim = 4 ... def encode(self, observation): ... return np.zeros(self.latent_dim) ... def imagine(self, latents, controls): ... return np.asarray(latents, dtype=float) ... def decode(self, latents): ... batch = np.asarray(latents).shape[0] ... return {"gnss": np.zeros((batch, 3)), "agents": np.zeros((batch, 25))} ... def decode_log_prob(self, latents, observation): ... return np.zeros(np.asarray(latents).shape[0]) ... def reward(self, latents): ... return np.zeros(np.asarray(latents).shape[0]) ... def continue_prob(self, latents): ... return np.ones(np.asarray(latents).shape[0]) >>> >>> obs = {"gnss": np.zeros(3), "agents": np.zeros(25)} >>> env = DreamerCarlaModelPOMDP( ... _IdentityWorldModel(), discount_factor=0.95, initial_observation=obs) >>> >>> state = env.initial_state_dist().sample()[0] >>> action = env.get_actions()[0] >>> next_state, observation, reward = env.sample_next_step(state, action) >>> sorted(observation) ['agents', 'gnss'] >>> env.is_terminal(state) False
- initial_observation_dist()[source]
Get the initial observation distribution.
- Return type:
- Returns:
Distribution over initial observations
Note
Subclasses must implement this method to define initial observations.
- initial_state_dist()[source]
Get the initial state distribution.
- Return type:
- Returns:
Distribution over initial states
Note
Subclasses must implement this method to define the starting distribution.
- is_terminal(state)[source]
Check if a state is terminal.
- Parameters:
state (
Any) – State to check for terminal condition- Return type:
- Returns:
True if the state is terminal, False otherwise
Note
Subclasses must implement this method to define terminal conditions.
- observation_log_probability(next_state, action, observations)[source]
Log-density of
observationsunder the per-channel perception givennext_state.
- observation_log_probability_per_state(next_states, action, observation)[source]
Log-probability of one observation under each candidate next-state.
Used by particle filters: given N candidate next-states and ONE observation, return N log-likelihoods.
The default implementation falls back to a per-state Python loop delegating to
observation_log_probability(). Native-backed envs (those whose observation kernel exposesbatch_log_likelihood(next_states_array, observation_array)) should override to avoid the loop.
- reward(state, action, next_state=None)[source]
Calculate the immediate reward for a state-action(-next_state) tuple.
next_stateis the realised post-transition state when known (e.g. threaded bysample_next_step()), allowing rewards that depend on stochastic transition outcomes to use the same draw as the trajectory instead of resampling. Subclasses whose reward is a pure function of(state, action)may ignore it; subclasses whose reward depends on the realised next state (collision penalties, win bonuses) should consume it when provided and fall back to drawing/computing one whenNone.- Parameters:
- Return type:
- Returns:
Immediate reward value.
Note
Subclasses must implement this method to define reward structure.
- sample_next_state(state, action, n_samples=1)[source]
Sample
n_samplesnext states for(state, action).
- sample_next_state_batch(states, action)[source]
Sample one next state per input state, all under the same action.
Used by particle filters: given N current particles and one action, draw N next states (one per particle) in a single vectorized call.
The default implementation falls back to a per-state Python loop delegating to
sample_next_state(). Native-backed envs (those whose state-transition kernel exposesbatch_sample(states_array)) should override to avoid the loop.
- class POMDPPlanners.environments.carla_pomdp.FactoredCarlaModelPOMDP(discount_factor, action_presets=None, max_tracked_agents=5, perception_range=50.0, occlusion_radius=1.5, pose_std=0.5, gnss_std=1e-05, detect_prob=0.95, desired_speed=8.0, out_lane_thresh=2.0, collision_penalty=100.0, observation=None, name=None)[source]
Bases:
CarlaModelPOMDPConcrete CARLA generative model pairing placeholder dynamics with factored perception.
The observation is composed per channel (held as
self.observation_models): aFactoredAgentObservationModelonagents(detection gated by perception range and geometric occlusion, additive Gaussian pose noise) and aGnssObservationModelongnss. The reward is the shared gym-carla driving-quality reward. The transition is a documented identity placeholder to be replaced with real dynamics per study.- Parameters:
discount_factor (float)
action_presets (Sequence[Tuple[float, float, float]] | None)
max_tracked_agents (int)
perception_range (float | None)
occlusion_radius (float)
pose_std (float)
gnss_std (float)
detect_prob (float)
desired_speed (float)
out_lane_thresh (float)
collision_penalty (float)
name (str | None)
- observation_models
The per-channel
{channel: CarlaObservationModel}map carrying the observation parameters (perception_range,occlusion_radius,pose_std,gnss_std,detect_prob).
- desired_speed
Target longitudinal speed (m/s) used by the reward.
- out_lane_thresh
Lateral offset (m) beyond which the reward penalises out-of-lane.
- collision_penalty
Penalty scale applied on a terminal collision in the reward.
Example
>>> import numpy as np >>> np.random.seed(42) # For reproducible results >>> >>> from POMDPPlanners.environments.carla_pomdp.carla_pomdp import ( ... AGENT_SLOT_WIDTH, EGO_STATE_WIDTH) >>> env = FactoredCarlaModelPOMDP(discount_factor=0.95) >>> >>> width = EGO_STATE_WIDTH + env.max_tracked_agents * AGENT_SLOT_WIDTH >>> state = np.zeros(width) >>> action = env.get_actions()[0] >>> >>> next_state, observation, reward = env.sample_next_step(state, action) >>> sorted(observation) ['agents', 'gnss'] >>> env.is_terminal(state) False
- initial_observation_dist()[source]
Get the initial observation distribution.
- Return type:
- Returns:
Distribution over initial observations
Note
Subclasses must implement this method to define initial observations.
- initial_state_dist()[source]
Get the initial state distribution.
- Return type:
- Returns:
Distribution over initial states
Note
Subclasses must implement this method to define the starting distribution.
- is_terminal(state)[source]
Check if a state is terminal.
- Parameters:
state (
Any) – State to check for terminal condition- Return type:
- Returns:
True if the state is terminal, False otherwise
Note
Subclasses must implement this method to define terminal conditions.
- reward(state, action, next_state=None)[source]
Calculate the immediate reward for a state-action(-next_state) tuple.
next_stateis the realised post-transition state when known (e.g. threaded bysample_next_step()), allowing rewards that depend on stochastic transition outcomes to use the same draw as the trajectory instead of resampling. Subclasses whose reward is a pure function of(state, action)may ignore it; subclasses whose reward depends on the realised next state (collision penalties, win bonuses) should consume it when provided and fall back to drawing/computing one whenNone.- Parameters:
- Return type:
- Returns:
Immediate reward value.
Note
Subclasses must implement this method to define reward structure.
- class POMDPPlanners.environments.carla_pomdp.LidarCameraPerceptionModel(lidar_corridor_halfwidth=1.5, traffic_light_source='camera')[source]
Bases:
PerceptionModelDefault CARLA perception: lidar vehicle clustering + camera obstacle/traffic-light cues.
Vehicles are clustered from the lidar cloud, the forward obstacle fuses the lidar corridor clearance with the camera looming cue, and the traffic light is inferred from the camera image (no ground-truth channel is consulted) unless
traffic_light_source='channel'.- lidar_corridor_halfwidth
Half-width (m) of the forward corridor scanned for an obstacle.
- traffic_light_source
'camera'infers the light from the RGB image;'channel'reads it from the observation’straffic_lightkey.
Example
>>> import numpy as np >>> model = LidarCameraPerceptionModel() >>> obs = {"lidar": np.zeros((0, 4)), "camera": np.zeros((8, 8, 3), dtype=np.uint8)} >>> model.detect(obs).vehicle_positions.shape (0, 3)
- detect(observation)[source]
Perceive vehicles, a forward obstacle, and a traffic light from one observation.
- class POMDPPlanners.environments.carla_pomdp.MotionTracker[source]
Bases:
ABCAbstract temporal prediction interface: prior tracks + detections -> tracks with velocity.
Note
This is an abstract base class and cannot be instantiated directly.
- class POMDPPlanners.environments.carla_pomdp.OracleAgentPerceptionModel(max_tracked_agents=5, lidar_corridor_halfwidth=1.5)[source]
Bases:
PerceptionModelGround-truth-agent perception for studies/tests: vehicles from the
agentschannel.Reads the observation’s ground-truth
agentsrows as vehicle detections (position with confidence1.0), still fusing lidar/camera for the forward obstacle and reading the light from thetraffic_lightchannel. Use when a study wants exact agent positions rather than inferred ones; the tracker then re-estimates velocity from the position stream.- max_tracked_agents
Number of fixed agent slots in the ground-truth
agentschannel.
- lidar_corridor_halfwidth
Half-width (m) of the forward obstacle corridor.
Example
>>> import numpy as np >>> model = OracleAgentPerceptionModel(max_tracked_agents=1) >>> obs = {"agents": np.array([1.0, 8.0, 0.0, 0.0, 5.0])} >>> model.detect(obs).vehicle_positions.shape (1, 3)
- detect(observation)[source]
Perceive vehicles, a forward obstacle, and a traffic light from one observation.
- class POMDPPlanners.environments.carla_pomdp.PerceivedAgentsBelief(particles, log_weights, max_tracked_agents=5, agent_pose_jitter=0.3, resampling=True, ess_factor=0.5)[source]
Bases:
WeightedParticleBeliefReinvigorationWeighted particle belief that stamps the observation’s agent block onto every particle.
After the standard particle-filter weight update and resample, the reinvigoration step writes the current observation’s
agentsblock into every particle’s agent slots (plus optional per-particle jitter), leaving the ego block to the filter. The belief holds no perception state — perception is the planner model’s, applied upstream byencode_observation— so a plain observation with a perceivedagentsblock is all it needs.- Parameters:
- max_tracked_agents
Number of fixed agent slots carried in each particle.
- agent_pose_jitter
Std of Gaussian noise added to each stamped agent’s
[rel_x, rel_y, rel_yaw, rel_speed]pose, for particle diversity.
Example
>>> import numpy as np >>> np.random.seed(0) >>> from POMDPPlanners.environments.carla_pomdp.carla_pomdp import ( ... AGENT_SLOT_WIDTH, EGO_STATE_WIDTH) >>> width = EGO_STATE_WIDTH + 1 * AGENT_SLOT_WIDTH >>> particles = [np.zeros(width) for _ in range(4)] >>> belief = PerceivedAgentsBelief( ... particles=particles, ... log_weights=np.log(np.ones(4) / 4), ... max_tracked_agents=1, ... ) >>> observation = { # a perceived agent 8 m ahead ... "gnss": np.zeros(2), ... "agents": np.array([1.0, 8.0, 0.0, 0.0, 5.0]), ... } >>> base = WeightedParticleBelief(particles=particles, log_weights=belief.log_weights) >>> refreshed = belief.reinvigorate("noop", observation, None, base) >>> bool(np.asarray(refreshed.particles)[0, EGO_STATE_WIDTH] == 1.0) # slot now present True
- reinvigorate(action, observation, pomdp, belief)[source]
Stamp the observation’s perceived agent block onto every particle.
- Return type:
- Parameters:
action (Any)
observation (Any)
pomdp (Environment)
belief (WeightedParticleBelief)
- class POMDPPlanners.environments.carla_pomdp.PerceptionModel[source]
Bases:
ABCAbstract single-frame perception interface: raw sensor dict ->
Detections.Note
This is an abstract base class and cannot be instantiated directly.
- abstractmethod detect(observation)[source]
Perceive vehicles, a forward obstacle, and a traffic light from one observation.
- POMDPPlanners.environments.carla_pomdp.acquire_pool_lease(pool_dir)[source]
Claim one server from a
CarlaServerPoolfor the current process.The first call locks a free server’s lease file (exclusive non-blocking
flock) and caches the result; subsequent calls from the same process with the same pool directory return the cached lease. The lock is held for the process lifetime and released by the kernel when the process exits, so a recycled worker’s server returns to the pool automatically.- Parameters:
pool_dir (
Union[str,Path]) – Directory written byCarlaServerPool.start().- Return type:
- Returns:
The leased server’s connection endpoints.
- Raises:
FileNotFoundError – If
pool_dirdoes not contain a pool spec.RuntimeError – If every server in the pool is already leased by another process (run at most
n_serversworkers).
Subpackages
- POMDPPlanners.environments.carla_pomdp.carla_generative_models package
CarDreamerWorldModelCarlaModelPOMDPCarlaModelPOMDP.action_presetsCarlaModelPOMDP.max_tracked_agentsCarlaModelPOMDP.observation_modelsCarlaModelPOMDP.encode_observation()CarlaModelPOMDP.get_actions()CarlaModelPOMDP.hash_action()CarlaModelPOMDP.hash_observation()CarlaModelPOMDP.is_equal_observation()CarlaModelPOMDP.observation_log_probability()CarlaModelPOMDP.sample_next_state()CarlaModelPOMDP.sample_observation()CarlaModelPOMDP.transition_log_probability()
DreamerCarlaModelPOMDPDreamerCarlaModelPOMDP.world_modelDreamerCarlaModelPOMDP.continue_thresholdDreamerCarlaModelPOMDP.initial_observation_dist()DreamerCarlaModelPOMDP.initial_state_dist()DreamerCarlaModelPOMDP.is_terminal()DreamerCarlaModelPOMDP.observation_log_probability()DreamerCarlaModelPOMDP.observation_log_probability_per_state()DreamerCarlaModelPOMDP.reward()DreamerCarlaModelPOMDP.sample_next_state()DreamerCarlaModelPOMDP.sample_next_state_batch()DreamerCarlaModelPOMDP.sample_observation()DreamerCarlaModelPOMDP.transition_log_probability()
DreamerWorldModelFactoredCarlaModelPOMDPFactoredCarlaModelPOMDP.observation_modelsFactoredCarlaModelPOMDP.desired_speedFactoredCarlaModelPOMDP.out_lane_threshFactoredCarlaModelPOMDP.collision_penaltyFactoredCarlaModelPOMDP.initial_observation_dist()FactoredCarlaModelPOMDP.initial_state_dist()FactoredCarlaModelPOMDP.is_terminal()FactoredCarlaModelPOMDP.reward()FactoredCarlaModelPOMDP.sample_next_state()FactoredCarlaModelPOMDP.transition_log_probability()
KinematicCarlaModelPOMDPKinematicCarlaModelPOMDP.dtKinematicCarlaModelPOMDP.wheelbaseKinematicCarlaModelPOMDP.max_steer_angleKinematicCarlaModelPOMDP.accelKinematicCarlaModelPOMDP.brake_decelKinematicCarlaModelPOMDP.dragKinematicCarlaModelPOMDP.collision_gapKinematicCarlaModelPOMDP.collision_halfwidthKinematicCarlaModelPOMDP.safe_distanceKinematicCarlaModelPOMDP.stop_gapKinematicCarlaModelPOMDP.is_terminal()KinematicCarlaModelPOMDP.reward()KinematicCarlaModelPOMDP.sample_next_state()KinematicCarlaModelPOMDP.sample_next_state_batch()
build_cardreamer_model()- Submodules
- POMDPPlanners.environments.carla_pomdp.carla_generative_models.cardreamer_world_model module
- POMDPPlanners.environments.carla_pomdp.carla_generative_models.carla_dreamer_model_pomdp module
DreamerCarlaModelPOMDPDreamerCarlaModelPOMDP.world_modelDreamerCarlaModelPOMDP.continue_thresholdDreamerCarlaModelPOMDP.initial_observation_dist()DreamerCarlaModelPOMDP.initial_state_dist()DreamerCarlaModelPOMDP.is_terminal()DreamerCarlaModelPOMDP.observation_log_probability()DreamerCarlaModelPOMDP.observation_log_probability_per_state()DreamerCarlaModelPOMDP.reward()DreamerCarlaModelPOMDP.sample_next_state()DreamerCarlaModelPOMDP.sample_next_state_batch()DreamerCarlaModelPOMDP.sample_observation()DreamerCarlaModelPOMDP.transition_log_probability()
DreamerWorldModel
- POMDPPlanners.environments.carla_pomdp.carla_generative_models.carla_factored_model_pomdp module
FactoredCarlaModelPOMDPFactoredCarlaModelPOMDP.observation_modelsFactoredCarlaModelPOMDP.desired_speedFactoredCarlaModelPOMDP.out_lane_threshFactoredCarlaModelPOMDP.collision_penaltyFactoredCarlaModelPOMDP.initial_observation_dist()FactoredCarlaModelPOMDP.initial_state_dist()FactoredCarlaModelPOMDP.is_terminal()FactoredCarlaModelPOMDP.reward()FactoredCarlaModelPOMDP.sample_next_state()FactoredCarlaModelPOMDP.transition_log_probability()
- POMDPPlanners.environments.carla_pomdp.carla_generative_models.carla_kinematic_model_pomdp module
KinematicCarlaModelPOMDPKinematicCarlaModelPOMDP.dtKinematicCarlaModelPOMDP.wheelbaseKinematicCarlaModelPOMDP.max_steer_angleKinematicCarlaModelPOMDP.accelKinematicCarlaModelPOMDP.brake_decelKinematicCarlaModelPOMDP.dragKinematicCarlaModelPOMDP.collision_gapKinematicCarlaModelPOMDP.collision_halfwidthKinematicCarlaModelPOMDP.safe_distanceKinematicCarlaModelPOMDP.stop_gapKinematicCarlaModelPOMDP.is_terminal()KinematicCarlaModelPOMDP.reward()KinematicCarlaModelPOMDP.sample_next_state()KinematicCarlaModelPOMDP.sample_next_state_batch()
- POMDPPlanners.environments.carla_pomdp.carla_generative_models.carla_kinematic_vectorized_model module
CarlaKinematicVectorizedModelCarlaKinematicVectorizedModel.deviceCarlaKinematicVectorizedModel.dtypeCarlaKinematicVectorizedModel.num_actionsCarlaKinematicVectorizedModel.state_dimCarlaKinematicVectorizedModel.observation_dimCarlaKinematicVectorizedModel.action_keys()CarlaKinematicVectorizedModel.observation_keys()CarlaKinematicVectorizedModel.observation_log_probs()CarlaKinematicVectorizedModel.rewards()CarlaKinematicVectorizedModel.sample_next_states()CarlaKinematicVectorizedModel.sample_observations()CarlaKinematicVectorizedModel.terminal_mask()
- POMDPPlanners.environments.carla_pomdp.carla_generative_models.carla_model_pomdp module
CarlaModelPOMDPCarlaModelPOMDP.action_presetsCarlaModelPOMDP.max_tracked_agentsCarlaModelPOMDP.observation_modelsCarlaModelPOMDP.encode_observation()CarlaModelPOMDP.get_actions()CarlaModelPOMDP.hash_action()CarlaModelPOMDP.hash_observation()CarlaModelPOMDP.is_equal_observation()CarlaModelPOMDP.observation_log_probability()CarlaModelPOMDP.sample_next_state()CarlaModelPOMDP.sample_observation()CarlaModelPOMDP.transition_log_probability()
- POMDPPlanners.environments.carla_pomdp.carla_perception package
AlphaBetaTrackerCarlaObservationModelCarlaPerceptionPipelineCarlaPerceptionPipeline.max_tracked_agentsCarlaPerceptionPipeline.perceptionCarlaPerceptionPipeline.trackerCarlaPerceptionPipeline.sensor_fusionCarlaPerceptionPipeline.stop_for_traffic_lightsCarlaPerceptionPipeline.obstacle_detection_rangeCarlaPerceptionPipeline.dtCarlaPerceptionPipeline.perceive()CarlaPerceptionPipeline.process()
DetectionsFactoredAgentObservationModelFactoredAgentObservationModel.max_tracked_agentsFactoredAgentObservationModel.perception_rangeFactoredAgentObservationModel.occlusion_radiusFactoredAgentObservationModel.pose_stdFactoredAgentObservationModel.detect_probFactoredAgentObservationModel.channelFactoredAgentObservationModel.log_probability()FactoredAgentObservationModel.perceive()FactoredAgentObservationModel.render()FactoredAgentObservationModel.supports_density
GnssObservationModelLidarCameraPerceptionModelMotionTrackerOracleAgentPerceptionModelPerceptionModelPerceptionOutputavailable_observation_models()build_observation_model()camera_looming_cue()fuse_forward_obstacle()lidar_forward_clearance()lidar_vehicle_detections()register_observation_model()traffic_light_from_camera()traffic_light_stop_distance()update_tracks()- Subpackages
- POMDPPlanners.environments.carla_pomdp.carla_perception.observation_models package
FactoredAgentObservationModelGnssObservationModelavailable_observation_models()build_observation_model()register_observation_model()- Submodules
- POMDPPlanners.environments.carla_pomdp.carla_perception.observation_models.agent_models module
- POMDPPlanners.environments.carla_pomdp.carla_perception.observation_models.gnss_models module
- POMDPPlanners.environments.carla_pomdp.carla_perception.observation_models.image_models module
- POMDPPlanners.environments.carla_pomdp.carla_perception.observation_models.lidar_models module
- POMDPPlanners.environments.carla_pomdp.carla_perception.observation_models.registry module
- POMDPPlanners.environments.carla_pomdp.carla_perception.observation_models package
- Submodules
- POMDPPlanners.environments.carla_pomdp.carla_perception.carla_pipeline module
AlphaBetaTrackerCarlaPerceptionPipelineCarlaPerceptionPipeline.max_tracked_agentsCarlaPerceptionPipeline.perceptionCarlaPerceptionPipeline.trackerCarlaPerceptionPipeline.sensor_fusionCarlaPerceptionPipeline.stop_for_traffic_lightsCarlaPerceptionPipeline.obstacle_detection_rangeCarlaPerceptionPipeline.dtCarlaPerceptionPipeline.perceive()CarlaPerceptionPipeline.process()
DetectionsLidarCameraPerceptionModelMotionTrackerOracleAgentPerceptionModelPerceptionModelPerceptionOutput
- POMDPPlanners.environments.carla_pomdp.carla_perception.carla_sensors module
- POMDPPlanners.environments.carla_pomdp.carla_perception.carla_tracking module
- POMDPPlanners.environments.carla_pomdp.carla_perception.observation_model module
Submodules
POMDPPlanners.environments.carla_pomdp.carla_belief module
Plain particle belief that stamps the observed agent block onto its particles.
Perception lives on the planner’s generative model, not here and not in the world: the
forward-only CarlaPOMDP emits a raw,
ground-truth observation, and the model’s
encode_observation()
degrades it into the perceived observation the belief receives, so the agents channel the
belief sees is already the tracked object list. The belief therefore does no perception at all.
It still cannot be a bare particle filter, though: a weight-only update can reweight and
propagate the agents a particle was seeded with, but it can never acquire a vehicle that
appears mid-episode, and a slot seeded empty stays empty forever. PerceivedAgentsBelief
closes that gap in the minimal way — after the ordinary particle-filter weight update and
resample, it replaces every particle’s ego-frame agent block with the observation’s agents
block (plus optional per-particle pose jitter for diversity), leaving the ego block to the
filter. The perceived agents are the observation’s estimate, trusted rather than re-filtered as
a per-particle latent.
The returned belief is itself a PerceivedAgentsBelief, so the stamping repeats on every
step of the episode.
Note
The belief’s max_tracked_agents must match the width of the observation’s agents
block, since that block is written straight into each particle’s fixed agent slots.
- Classes:
PerceivedAgentsBelief: Particle belief that stamps the observed agent block onto particles.
- class POMDPPlanners.environments.carla_pomdp.carla_belief.PerceivedAgentsBelief(particles, log_weights, max_tracked_agents=5, agent_pose_jitter=0.3, resampling=True, ess_factor=0.5)[source]
Bases:
WeightedParticleBeliefReinvigorationWeighted particle belief that stamps the observation’s agent block onto every particle.
After the standard particle-filter weight update and resample, the reinvigoration step writes the current observation’s
agentsblock into every particle’s agent slots (plus optional per-particle jitter), leaving the ego block to the filter. The belief holds no perception state — perception is the planner model’s, applied upstream byencode_observation— so a plain observation with a perceivedagentsblock is all it needs.- Parameters:
- max_tracked_agents
Number of fixed agent slots carried in each particle.
- agent_pose_jitter
Std of Gaussian noise added to each stamped agent’s
[rel_x, rel_y, rel_yaw, rel_speed]pose, for particle diversity.
Example
>>> import numpy as np >>> np.random.seed(0) >>> from POMDPPlanners.environments.carla_pomdp.carla_pomdp import ( ... AGENT_SLOT_WIDTH, EGO_STATE_WIDTH) >>> width = EGO_STATE_WIDTH + 1 * AGENT_SLOT_WIDTH >>> particles = [np.zeros(width) for _ in range(4)] >>> belief = PerceivedAgentsBelief( ... particles=particles, ... log_weights=np.log(np.ones(4) / 4), ... max_tracked_agents=1, ... ) >>> observation = { # a perceived agent 8 m ahead ... "gnss": np.zeros(2), ... "agents": np.array([1.0, 8.0, 0.0, 0.0, 5.0]), ... } >>> base = WeightedParticleBelief(particles=particles, log_weights=belief.log_weights) >>> refreshed = belief.reinvigorate("noop", observation, None, base) >>> bool(np.asarray(refreshed.particles)[0, EGO_STATE_WIDTH] == 1.0) # slot now present True
- reinvigorate(action, observation, pomdp, belief)[source]
Stamp the observation’s perceived agent block onto every particle.
- Return type:
- Parameters:
action (Any)
observation (Any)
pomdp (Environment)
belief (WeightedParticleBelief)
POMDPPlanners.environments.carla_pomdp.carla_pomdp module
CARLA POMDP world environment.
This module adapts the CARLA autonomous-driving
simulator to the POMDPPlanners Environment
interface so it can serve as the ground-truth world in an
EpisodeRunner.
CARLA is forward-only: it is a live Unreal server driven over a Python client
that exposes reset/tick on a single true state and cannot be queried for
a transition/observation density nor re-run from an arbitrary injected state. It
therefore cannot act as a planner’s generative model. In the two-environment
episode design the planner keeps its own generative model (policy.environment)
and this wrapper only advances the single true state forward, one step per real
interaction. Consequently CarlaPOMDP.transition_log_probability() and
CarlaPOMDP.observation_log_probability() intentionally raise
NotImplementedError — in the intended world/model split they are never
called.
Unlike GymPOMDP (which is
fully observed: observation equals state), CARLA is genuinely partially observed.
The world is populated each reset with surrounding autopilot traffic and walking pedestrians (via CARLA’s Traffic Manager), so it poses a genuine multi-agent perception problem rather than an empty course.
The state is the ego vehicle’s ground-truth kinematics and lane pose,
[x, y, yaw, vx, vy, lat, heading_err], followed by fixed slots for the
``max_tracked_agents`` nearest other vehicles (ground truth). Each agent slot is
[present, rel_x, rel_y, rel_yaw, rel_speed] expressed in the ego frame
(rel_x forward, rel_y left, rel_yaw in radians, rel_speed in
m/s); present is 1 for a filled slot and 0 for padding. The ego part
is read straight from the simulator, where:
x,y: ego position in the CARLA map (world) frame, in metres, read from the actor transform’s location.yaw: ego heading about the world Z axis, in degrees (CARLA convention), read from the actor transform’s rotation.vx,vy: ego linear-velocity components in the world frame, in metres per second, read from the actor’s velocity vector.lat: signed lateral offset from the centre of the nearest driving lane, in metres (positive to the lane’s left), from the CARLA map’s lane geometry.heading_err: ego heading minus the lane direction, wrapped to[-pi, pi], in radians.
The state ends with one traffic-light slot,
[present, rel_x, rel_y, state_code, time_to_change] (ego frame; state_code is a
TRAFFIC_LIGHT_* code, time_to_change in seconds), carrying the light governing the
ego as ground truth (present == 0 when none affects it). It is always in the state — used
by the red-light-violation metrics — and is independent of whether the observation exposes
the light (include_traffic_light); a planner can thus be scored for running reds even when
it is given no light information.
(The vertical axis z and roll/pitch are intentionally omitted; the ego is
modelled on the ground plane.)
The lane-relative terms (lat, heading_err) drive a gym-carla-style
driving-quality reward: it rewards longitudinal progress along the lane while
penalising overspeed, drifting out of lane, and harsh / high-speed steering, plus
a per-step time cost and a terminal collision penalty. See
REWARD_SPEED_WEIGHT and the sibling weights for the fixed coefficients.
The observation is a multi-modal dict of native CARLA sensor payloads:
"gnss":[lat, lon, alt](always present) — latitude and longitude in degrees and altitude in metres, from asensor.other.gnssreading."agents"(always present): themax_tracked_agentsagent slots of the state flattened, reported raw at their true ego-frame poses. The world applies no perception, so this is the ground-truth channel; range-gating, occlusion and sensor noise are the planner model’s observation model, not the world’s."camera"(present iffinclude_camera): a front-facing RGB image,(H, W, 3)uint8, from asensor.camera.rgb."lidar"(present iffinclude_lidar): a point cloud,(N, 4)float32with rows[x, y, z, intensity]in the LiDAR sensor frame (metres;intensitynormalised to[0, 1]), from asensor.lidar.ray_cast.Nvaries per tick."traffic_light"(present iffinclude_traffic_light):[should_stop, distance_m]—should_stopis1.0when the ego is affected by a red or yellow light (else0.0) anddistance_mis the forward distance to that light’s stop line. This is a privileged ground-truth read (no noise), letting a planner treat a red light as a virtual obstacle to stop for; disable it to withhold the signal entirely.
Any measurement noise is CARLA’s own, configured through the sensor blueprint attributes — the wrapper adds none.
- Classes:
CarlaPOMDP: Forward-only adapter exposing a CARLA session as a world Environment.
- class POMDPPlanners.environments.carla_pomdp.carla_pomdp.CarlaPOMDP(discount_factor, host='localhost', port=2000, town='Town03', sensor_config=None, action_presets=None, record_camera=False, camera_config=None, include_camera=True, include_lidar=True, include_traffic_light=True, observation_camera_config=None, lidar_config=None, fixed_delta_seconds=0.05, collision_penalty=100.0, desired_speed=8.0, out_lane_thresh=2.0, destination=None, goal_radius=5.0, min_route_length=100.0, success_reward=100.0, num_vehicles=30, num_walkers=10, max_tracked_agents=5, traffic_manager_port=8000, server_pool_dir=None, randomize_spawn=True, observation_extractor=None, vehicle_filter='vehicle.tesla.model3', timeout=10.0, seed=None, name=None, reward_range=None, output_dir=None, debug=False, use_queue_logger=False)[source]
Bases:
EnvironmentForward-only adapter exposing a CARLA session as a world POMDP.
The wrapper drives a CARLA server as the ground-truth world of an episode. It ticks the simulator exactly once per real interaction and serves the resulting next state, observation and reward from a small cache, because the POMDPPlanners episode loop requests those three quantities through separate method calls while CARLA produces them atomically. The state is the ego vehicle’s ground-truth kinematics; the observation is a native CARLA sensor payload (GNSS by default), so the world is genuinely partially observed. See the module docstring for the exact state and observation variables, units, and frames.
Note
This is a world environment, not a generative model. It cannot sample a transition from an arbitrary state, so belief particle propagation and density queries are unsupported and raise
NotImplementedError/RuntimeError. Pair it with a generative model environment on the planner (policy.environment).- Parameters:
discount_factor (float)
host (str)
port (int)
town (str)
action_presets (Sequence[Tuple[float, float, float]] | None)
record_camera (bool)
include_camera (bool)
include_lidar (bool)
include_traffic_light (bool)
fixed_delta_seconds (float)
collision_penalty (float)
desired_speed (float)
out_lane_thresh (float)
goal_radius (float)
min_route_length (float)
success_reward (float)
num_vehicles (int)
num_walkers (int)
max_tracked_agents (int)
traffic_manager_port (int)
randomize_spawn (bool)
observation_extractor (Callable[[Dict[str, ndarray]], Any] | None)
vehicle_filter (str)
timeout (float)
seed (int | None)
name (str | None)
output_dir (Path | None)
debug (bool)
use_queue_logger (bool)
- host
CARLA server host.
- port
CARLA server RPC port.
- town
CARLA map name loaded on reset.
- sensor_config
GNSS blueprint attributes (e.g. noise stddev) forwarded to the sensor; measurement noise, if any, is CARLA’s own.
- action_presets
Discrete
(throttle, steer, brake)control triples.
- seed
Optional seed applied to the first
resetfor reproducibility.
Example
The environment is used as the forward-only world of an
EpisodeRunner, paired with a separate generative model on the planner. It requires a running CARLA server, so this snippet is illustrative rather than executed:env = CarlaPOMDP(discount_factor=0.95, town="Town03") state = env.initial_state_dist().sample()[0] next_state, observation, reward = env.sample_next_step(state, 0) # state is [ego(7), nearest-agent slots...]; observation is a # gnss/agents/camera/lidar dict hiding out-of-range / occluded agents.
- cache_visualization(history, output_dir, episode_index)[source]
Save the episode as CARLA’s own chase-camera MP4 footage.
The episode
historyis unused: the video is the native camera rendering buffered live while the world was stepped, not a plot reconstructed from the step data. The environment must have been constructed withrecord_camera=True.
- compute_metrics(histories)[source]
Compute CARLA driving-quality metrics from episode histories.
- Parameters:
- Return type:
- Returns:
A list of
MetricValuewith 95% confidence bounds across episodes:collision_rate: fraction of episodes that ended in a terminal state without reaching the destination (i.e. in a collision).success_rate: fraction of episodes whose final state is withingoal_radiusof the episode destination.route_completion: mean over episodes of the fraction of the planned route’s arc length covered by the end of the episode.average_progress: mean per-episode ground distance travelled by the ego, in metres.average_speed: mean ego speed over the driven trajectory, in m/s.red_light_violation_rate: fraction of functioning-light stop-line crossings taken while the light was red (averaged over episodes that crossed at least one working light).red_light_violation_count: mean number of red-light crossings per episode.traffic_light_malfunction_count: mean number of crossings per episode where the light was off / unknown — recorded separately and never counted as a violation, since the light was not operating.near_miss_count: mean number of near-miss events per episode (a run within_NEAR_MISS_DISTANCEof another vehicle that did not become a collision).min_vehicle_distance: mean over episodes of the closest the ego came to any vehicle, in metres (a safety-margin metric; episodes that saw no vehicle are excluded).
- hash_action(action)[source]
Return a hashable key consistent with action equality.
Used by tree-search planners to index action children of a belief node in O(1). The returned key MUST satisfy:
action_a == action_b (per env's notion of equality) ==> hash_action(action_a) == hash_action(action_b)
Subclasses with non-hashable actions (e.g.
np.ndarray) must override to return a hashable surrogate (tobytes()is the standard choice for ndarray actions, which mirrors thenp.array_equalsemantics used by the linear-scan fallback).
- hash_observation(observation)[source]
Return a hashable key consistent with
is_equal_observation().Used by tree-search planners to index belief children by observation in O(1). The returned key MUST satisfy the contract:
is_equal_observation(a, b) implies hash_observation(a) == hash_observation(b)
- Parameters:
observation (
Any) – Observation to hash.- Returns:
the observation itself when it is already hashable).
- Return type:
- Raises:
NotImplementedError – If the observation is not hashable and the subclass has not provided an override. Subclasses with non-hashable observations (e.g.
np.ndarray) MUST override.
- initial_observation_dist()[source]
Get the initial observation distribution.
- Return type:
- Returns:
Distribution over initial observations
Note
Subclasses must implement this method to define initial observations.
- initial_state_dist()[source]
Get the initial state distribution.
- Return type:
- Returns:
Distribution over initial states
Note
Subclasses must implement this method to define the starting distribution.
- is_equal_observation(observation1, observation2)[source]
Check if two observations are equal.
- Parameters:
- Return type:
- Returns:
True if observations are considered equal, False otherwise
Note
Subclasses must implement this method to define observation equality. This is particularly important for discrete observation spaces.
- is_terminal(state)[source]
Check if a state is terminal.
- Parameters:
state (
Any) – State to check for terminal condition- Return type:
- Returns:
True if the state is terminal, False otherwise
Note
Subclasses must implement this method to define terminal conditions.
- observation_log_probability(next_state, action, observations)[source]
Log-probability of each candidate observation under
(next_state, action).Returns
np.ndarrayof shape(N,)where N is the number of candidate observations. Subclasses must implement.
- reward(state, action, next_state=None)[source]
Calculate the immediate reward for a state-action(-next_state) tuple.
next_stateis the realised post-transition state when known (e.g. threaded bysample_next_step()), allowing rewards that depend on stochastic transition outcomes to use the same draw as the trajectory instead of resampling. Subclasses whose reward is a pure function of(state, action)may ignore it; subclasses whose reward depends on the realised next state (collision penalties, win bonuses) should consume it when provided and fall back to drawing/computing one whenNone.- Parameters:
- Return type:
- Returns:
Immediate reward value.
Note
Subclasses must implement this method to define reward structure.
- sample_next_state(state, action, n_samples=1)[source]
Sample one or more next states for
(state, action).Hot-path entry point used by MCTS planners and particle filters. Subclasses must implement.
- sample_observation(next_state, action, n_samples=1)[source]
Sample one or more observations for
(next_state, action).Hot-path entry point used by MCTS planners and particle filters. Subclasses must implement.
- save_camera_video(cache_path, fps=20)[source]
Write CARLA’s own chase-camera footage to an MP4 video.
This is the native CARLA rendering (an RGB camera following the ego), not a reconstructed plot. Frames are captured live while the world is stepped, so the environment must have been constructed with
record_camera=Trueand driven for at least one tick before calling this.- Parameters:
- Raises:
RuntimeError – If camera recording is disabled or no frames were captured.
- Return type:
- class POMDPPlanners.environments.carla_pomdp.carla_pomdp.CarlaPOMDPMetrics(*values)[source]
Bases:
EnumMetric names for the CARLA POMDP environment.
- AVERAGE_PROGRESS = 'average_progress'
- AVERAGE_SPEED = 'average_speed'
- COLLISION_RATE = 'collision_rate'
- MIN_VEHICLE_DISTANCE = 'min_vehicle_distance'
- NEAR_MISS_COUNT = 'near_miss_count'
- RED_LIGHT_VIOLATION_COUNT = 'red_light_violation_count'
- RED_LIGHT_VIOLATION_RATE = 'red_light_violation_rate'
- ROUTE_COMPLETION = 'route_completion'
- SUCCESS_RATE = 'success_rate'
- TRAFFIC_LIGHT_MALFUNCTION_COUNT = 'traffic_light_malfunction_count'
- POMDPPlanners.environments.carla_pomdp.carla_pomdp.driving_quality_reward(next_state, steer, collided, desired_speed, out_lane_thresh, collision_penalty, success=False, success_reward=0.0)[source]
Score a transition with a gym-carla-style driving-quality reward.
Rewards along-route progress and penalises overspeed, drifting off the route, harsh / high-speed steering, each elapsed step, and a terminal collision; reaching the destination earns a terminal success bonus. Shared by the
CarlaPOMDPworld and the planner-side factored model so the two score a transition identically by construction.- Parameters:
next_state (
ndarray) – Resulting ego state[x, y, yaw(deg), vx, vy, lat, heading_err].steer (
float) – Steering command applied on the transition (from the action preset).collided (
bool) – Whether the transition ended in a terminal collision.desired_speed (
float) – Target longitudinal speed (m/s); exceeding it is penalised.out_lane_thresh (
float) – Lateral offset (m) beyond which the ego is treated as off route.collision_penalty (
float) – Penalty scale applied on a terminal collision.success (
bool) – Whether the transition reached the destination. Defaults to False.success_reward (
float) – Bonus applied on a successful arrival. Defaults to 0.0.
- Return type:
- Returns:
The scalar reward for the transition.
POMDPPlanners.environments.carla_pomdp.carla_server_pool module
Headless CARLA server pool for parallel episode simulation.
A single CARLA server serves one client at a time, so parallel episode execution
(e.g. JoblibTaskManager
with n_jobs > 1) needs one server per worker process. This module provides:
CarlaServerPool— a context manager that launchesn_serversheadless CARLA servers (CarlaUE4.sh -RenderOffScreen -nosound -carla-rpc-port=<port>), each on its own RPC port, and terminates them on exit.acquire_pool_lease()— the worker-side counterpart: a process claims exactly one server from the pool via anflock-based lease and reuses it for the lifetime of the process.
Pool directory layout (written by CarlaServerPool.start()):
pool.json— the pool spec: host and per-serverrpc_port/traffic_manager_port/ lease-file name.server_<i>.lease— one lock file per server. A worker holds a server by holding an exclusiveflockon its lease file; the kernel releases the lock automatically when the worker process dies, so a recycled joblib worker frees its server for the replacement worker.server_<i>.log— each server’s combined stdout/stderr, for diagnosing startup failures.
Wiring into the episode loop is transparent: pass server_pool_dir=pool.pool_dir
to CarlaPOMDP and its
lazily-built session resolves its connection ports from the per-process lease
instead of the static host/port/traffic_manager_port.
Limitation: the lease is per process, so all CARLA environments in one worker process that share a pool directory share one server. This matches the simulator’s one-world-per-episode design.
- Classes:
CarlaServerLease: Connection endpoints of one leased pool server. CarlaServerHandle: One spawned headless CARLA server subprocess. CarlaServerPool: Context manager owning N headless CARLA servers.
Example
Launch four headless servers and run parallel episodes against them
(illustrative — requires a CARLA installation at $CARLA_ROOT):
from POMDPPlanners.environments.carla_pomdp import CarlaPOMDP, CarlaServerPool
with CarlaServerPool(n_servers=4) as pool:
env = CarlaPOMDP(discount_factor=0.95, server_pool_dir=pool.pool_dir)
# Hand ``env`` to POMDPSimulator with JoblibConfig(n_jobs=4); each
# joblib worker process leases its own server on first connection.
Or manage a long-lived pool manually from the command line:
python -m POMDPPlanners.environments.carla_pomdp.carla_server_pool --n-servers 4
- class POMDPPlanners.environments.carla_pomdp.carla_server_pool.CarlaServerHandle(process, rpc_port, traffic_manager_port, log_path, gpu_index=None)[source]
Bases:
objectOne spawned headless CARLA server subprocess.
Owns the process for its lifetime: readiness polling on the RPC port and process-group termination. Instances are created by
CarlaServerPool.- Parameters:
- process
The spawned server subprocess (its own session/process group).
- rpc_port
RPC port the server was asked to listen on.
- traffic_manager_port
Traffic Manager port reserved for this server’s client.
- log_path
File receiving the server’s combined stdout/stderr.
- gpu_index
GPU the server was pinned to, or
None.
- terminate(grace_seconds=10.0)[source]
Terminate the server’s process group (SIGTERM, then SIGKILL).
- wait_until_ready(timeout=120.0)[source]
Block until the server accepts TCP connections on its RPC port.
- Parameters:
timeout (
float) – Maximum seconds to wait.- Raises:
RuntimeError – If the server process exits before becoming ready.
TimeoutError – If the port is not accepting connections within
timeout.
- Return type:
- class POMDPPlanners.environments.carla_pomdp.carla_server_pool.CarlaServerLease(host, rpc_port, traffic_manager_port)[source]
Bases:
objectConnection endpoints of one leased pool server.
- host
Hostname the pool’s servers listen on.
- rpc_port
CARLA RPC port of the leased server.
- traffic_manager_port
Client-side Traffic Manager port reserved for the lease holder (unique per server so parallel clients never collide).
- class POMDPPlanners.environments.carla_pomdp.carla_server_pool.CarlaServerPool(n_servers, pool_dir=None, carla_root=None, rpc_port_base=2000, tm_port_base=8000, gpu_indices=None, extra_args=None, ready_timeout=120.0, command_factory=None)[source]
Bases:
objectContext manager owning N headless CARLA servers plus their lease directory.
On
start()(orwithentry) it spawnsn_serversheadless CARLA servers — RPC portsrpc_port_base + RPC_PORT_STRIDE * i, Traffic Manager portstm_port_base + i— writes the pool spec and lease files intopool_dir, and waits for every server to accept connections. Onshutdown()(orwithexit, or interpreter exit) it terminates them.Worker processes claim a server with
acquire_pool_lease(), or transparently by constructingCarlaPOMDPwithserver_pool_dir=pool.pool_dir. Run at mostn_serversworkers (e.g.JoblibConfig(n_jobs=n_servers)— the defaultn_jobs=-1uses all cores and will exhaust the pool).- Parameters:
- n_servers
Number of servers the pool launches.
- handles
Live
CarlaServerHandleobjects (empty until started).
Example
Illustrative — requires a CARLA installation at
$CARLA_ROOT:with CarlaServerPool(n_servers=2, gpu_indices=[0, 1]) as pool: env = CarlaPOMDP(discount_factor=0.95, server_pool_dir=pool.pool_dir)
- handles: List[CarlaServerHandle]
- property pool_dir: Path
The pool directory holding the spec, lease, and log files.
- Raises:
RuntimeError – If accessed before
start()and no explicitpool_dirwas configured.
- start()[source]
Launch all servers, write the pool spec, and wait until every one is ready.
Launches every server first so their (slow) startups overlap, then blocks on readiness. On any failure the already-launched servers are terminated before the error propagates.
- Return type:
- Returns:
This pool, for chaining.
- Raises:
RuntimeError – If a server process exits before becoming ready.
TimeoutError – If a server is not ready within
ready_timeout.
- POMDPPlanners.environments.carla_pomdp.carla_server_pool.acquire_pool_lease(pool_dir)[source]
Claim one server from a
CarlaServerPoolfor the current process.The first call locks a free server’s lease file (exclusive non-blocking
flock) and caches the result; subsequent calls from the same process with the same pool directory return the cached lease. The lock is held for the process lifetime and released by the kernel when the process exits, so a recycled worker’s server returns to the pool automatically.- Parameters:
pool_dir (
Union[str,Path]) – Directory written byCarlaServerPool.start().- Return type:
- Returns:
The leased server’s connection endpoints.
- Raises:
FileNotFoundError – If
pool_dirdoes not contain a pool spec.RuntimeError – If every server in the pool is already leased by another process (run at most
n_serversworkers).
POMDPPlanners.environments.carla_pomdp.carla_video module
Encode CARLA RGB camera frames as an MP4 video.
CarlaPOMDP can attach
a chase RGB camera to the ego vehicle and buffer one rendered frame per simulator
tick. This module turns that buffer of (H, W, 3) uint8 frames into an H.264
MP4 by piping the raw RGB bytes straight to an ffmpeg subprocess. Streaming
the pixels to ffmpeg avoids matplotlib’s per-frame figure re-render, so the saved
footage is CARLA’s own rendering and encoding it is roughly 2-3x faster than the
previous matplotlib writer.
- Functions:
write_frames_to_mp4: Encode a list of RGB frames as an MP4 video.
- POMDPPlanners.environments.carla_pomdp.carla_video.write_frames_to_mp4(frames, cache_path, fps=20)[source]
Encode buffered CARLA chase-camera frames as an MP4 video.
The frames are streamed as raw
rgb24bytes to anffmpegsubprocess, which encodes them to an H.264 MP4. This is CARLA’s own rendering, not a reconstructed plot.- Parameters:
- Raises:
TypeError – If
cache_pathis not a Path object.ValueError – If
framesis empty orcache_pathdoes not end in.mp4.RuntimeError – If
ffmpegis not on PATH or the encode fails.
- Return type: