This guide covers architecture, configuration details, API reference, and advanced usage for developers.
- Architecture Overview
- Configuration System
- API Reference
- Advanced Usage
- Extending the Toolkit
- Development Workflow
carla_dataset_tools/
├── config/ # Configuration management
│ ├── config_manager.py # YAML config loader and validator
│ └── profiles/ # Pre-configured profiles
│ ├── default.yaml # Default configuration
│ ├── kitti.yaml # KITTI dataset style
│ ├── argoverse.yaml # Argoverse dataset style
│ ├── simple.yaml # Simple testing config
│ └── route_example.yaml # Route configuration example
├── label_tools/ # Labeling scripts
│ ├── kitti_objects_label.py # KITTI format labeling
│ ├── yolo_label.py # YOLOv5 format labeling
│ └── kitti_object/ # KITTI utilities
├── recorder/ # Core recording modules
│ ├── actor_tree.py # Actor hierarchy management
│ ├── actor_factory.py # Actor and sensor spawning
│ ├── vehicle.py # Vehicle recording with route following
│ ├── sensor.py # Base sensor class
│ ├── camera.py # Camera sensors
│ ├── lidar.py # LiDAR sensors
│ ├── radar.py # Radar sensor
│ └── agents/ # Autopilot and navigation agents
│ ├── navigation/ # Navigation components
│ │ └── global_route_planner.py # Topology-aware path planning
│ └── ...
├── routes/ # Vehicle route definitions
│ ├── README.md # Route system documentation
│ └── *.yaml, *.pkl # Route files (YAML + pickle)
├── core/ # Core shared modules
│ ├── geometry.py # Geometric types (Vector3d, Location, Transform, etc.)
│ ├── types.py # Label and object types
│ ├── transform.py # Coordinate transformations
│ ├── converters.py # Data format converters
│ └── logger.py # Unified logging system
├── tools/ # CLI utility scripts
│ ├── viz_lidar.py # Point cloud visualization
│ ├── viz_map.py # Map visualization
│ ├── viz_actor_tree.py # Actor tree visualization (pre-recording)
│ ├── editor_route.py # Interactive route creation tool
│ ├── data_generate_imageset.py # Dataset file list generation
│ ├── config_convert.py # JSON to YAML converter
│ ├── config_list.py # List available profiles
│ ├── config_validate.py # Config validation tool
│ └── debug_info.py # Debug information display
├── data_recorder.py # Main recording script
└── param.py # Global parameters
Centralized configuration management with validation:
class ConfigManager:
"""
Manages YAML configuration loading and validation
Features:
- Profile-based configuration
- CARLA 0.9.16 API validation
- Map and weather preset validation
- Security: 10MB file size limit
"""Hierarchical management of actors and sensors:
class ActorTree:
"""
Manages actor hierarchy and data recording
Structure:
World
├── Vehicle_1
│ ├── Camera_1
│ ├── LiDAR_1
│ └── ...
├── Vehicle_2
└── Infrastructure_1
"""Spawns and configures actors and sensors:
class ActorFactory:
"""
Factory pattern for creating CARLA actors
Responsibilities:
- Spawn vehicles and infrastructure
- Attach sensors to parent actors
- Configure autopilot and traffic manager
"""Base sensor class with specific implementations:
class Sensor:
"""Base sensor class with callback handling"""
class Camera(Sensor):
"""RGB, depth, semantic segmentation cameras"""
class Lidar(Sensor):
"""Ray-cast and semantic LiDAR"""
class Radar(Sensor):
"""Radar sensor"""Configuration files use YAML format with the following sections:
# Recording settings
recording:
frame_total: 12000 # Total frames to record
frame_step: 3 # Save every N frames
map: Town02 # CARLA map name
weather: ClearNoon # Weather preset (optional)
# Spectator camera position
spectator:
x: 100.0
y: -150.0
z: 150.0
pitch: 60.0
yaw: -90.0
roll: 0.0
# World physics settings
world_settings:
synchronous_mode: true
fixed_delta_seconds: 0.1
substepping: true
max_substep_delta_time: 0.01
max_substeps: 16
# Traffic light timings
traffic_lights:
red_time: 2.0
green_time: 2.0
yellow_time: 0.01
# Sensor templates (YAML anchors for reuse)
sensor_templates:
rgb_camera: &rgb_camera
type: sensor.camera.rgb
image_size_x: 800
image_size_y: 600
fov: 90.0
# Vehicle and sensor actors
actors:
- type: vehicle.tesla.model3
name: ego_vehicle
spawn_point: 73
sensors:
- <<: *rgb_camera # Reuse template
name: front_camera
spawn_point:
x: 2.0
y: 0.0
z: 2.0
roll: 0.0
pitch: 0.0
yaw: 0.0
# Background traffic
other_vehicles:
count: 50
spawn_points: [44, 55, 64]Town Maps:
Town01,Town01_Opt- Simple town with basic road networkTown02,Town02_Opt- Small town with various intersectionsTown03,Town03_Opt- Larger urban area with roundaboutTown04,Town04_Opt- Small town with highwayTown05,Town05_Opt- Urban area with bridge and tunnelTown06,Town06_Opt- Urban area with multiple lane highwayTown07,Town07_Opt- Rural environment with narrow roadsTown10HD,Town10HD_Opt- High-definition urban areaTown11,Town12,Town13,Town15- Additional urban variations
Special Maps:
AnnotationColorLandscape- Testing environment
Note: _Opt versions have optimized geometry for better performance.
Control environmental conditions with weather presets:
Clear Weather:
ClearNoon,ClearSunset,ClearNight- Clear sky conditions
Cloudy Weather:
CloudyNoon,CloudySunset,CloudyNight- Overcast conditions
Wet Weather:
WetNoon,WetSunset,WetNight- Wet roads, no rainWetCloudyNoon,WetCloudySunset,WetCloudyNight- Wet and cloudy
Rainy Weather:
SoftRainNoon,SoftRainSunset,SoftRainNight- Light rainMidRainyNoon,MidRainSunset,MidRainyNight- Moderate rainHardRainNoon,HardRainSunset,HardRainNight- Heavy rain
Extreme Weather:
DustStorm- Desert dust storm conditions
Default:
Default- CARLA's default weather
sensor.camera.rgb- RGB Camerasensor.camera.depth- Depth Camerasensor.camera.semantic_segmentation- Semantic Segmentation Camerasensor.lidar.ray_cast- LiDARsensor.lidar.ray_cast_semantic- Semantic LiDARsensor.other.radar- Radar
Vehicles can be configured to follow predefined routes using topology-aware path planning:
actors:
- type: vehicle.tesla.model3
name: ego_vehicle
spawn_point: 73
route:
# Option 1: Load from file
from_file: routes/Town02_my_route.yaml
# Option 2: Inline waypoints
mode: strict # strict | disabled
loop: true # Optional: for circular routes
waypoints:
- {x: 107.5, y: -133.2, z: 0.3}
- {x: 150.0, y: -130.5, z: 0.3}
- {x: 200.3, y: -128.8, z: 0.3}
sensors: [...]Route files (YAML) contain waypoint definitions:
# routes/Town02_my_route.yaml
mode: strict
loop: false
waypoints:
- {x: 107.5, y: -133.2, z: 0.3}
- {x: 150.0, y: -130.5, z: 0.3}
- {x: 200.3, y: -128.8, z: 0.3}
- {x: 250.8, y: -125.1, z: 0.3}Corresponding pickle files (.pkl) are automatically generated for internal use.
-
strict: Vehicle follows waypoints using GlobalRoutePlanner- Waypoints are expanded into complete road-topology-aware paths
- Respects lanes, intersections, and road structure
- Example: 8 user waypoints → 450+ road waypoints
-
disabled: Route is ignored, uses default autopilot -
No route specified: Default autopilot behavior (backward compatible)
Use the interactive route editor:
python3 tools/editor_route.py --map Town02 --name my_routeFeatures:
- Visual waypoint selection on map
- Real-time topology-aware path preview using GlobalRoutePlanner
- Auto-detect loop routes (first and last waypoints within 5m)
- Undo support (Ctrl+Z)
- Saves both YAML (human-readable) and PKL (internal) formats
Controls:
- Left click: Add waypoint
- Right click on circle: Delete waypoint
- Ctrl+Z: Undo
- Enter: Save and exit
- Escape: Cancel
Path Planning Process:
- User Input: Define 3-8 key waypoints in route editor or YAML
- GlobalRoutePlanner: Calculates complete road paths between waypoints
- Uses CARLA's road topology graph
- Respects lane markings, turn restrictions, intersections
- Route Expansion: Waypoints expanded to 100s of road waypoints
- BasicAgent: Navigates vehicle along the complete path
- Uses LocalPlanner for trajectory control
- PID controllers for steering, throttle, brake
Validation Rules:
- Minimum 2 waypoints required
- Each waypoint must have x, y, z coordinates
- Route files validated during configuration loading
- Invalid route files trigger ConfigValidationError
The ConfigManager validates:
- File size: Maximum 10MB (security)
- YAML syntax: Valid YAML structure
- Required fields: All mandatory fields present
- Sensor types: Match CARLA 0.9.16 API
- Maps: Valid map names
- Weather: Valid weather presets
- Physics constraints:
fixed_delta_seconds <= max_substep_delta_time * max_substeps
Reuse configurations with YAML anchors:
sensor_templates:
# Define template with anchor
base_camera: &base_camera
type: sensor.camera.rgb
image_size_x: 800
image_size_y: 600
fov: 90.0
actors:
- type: vehicle.tesla.model3
sensors:
# Reuse template and override specific fields
- <<: *base_camera
name: front_camera
spawn_point: {x: 2.0, y: 0.0, z: 2.0}
- <<: *base_camera
name: rear_camera
spawn_point: {x: -2.0, y: 0.0, z: 2.0, yaw: 180.0}YAML supports inline and block comments:
recording:
frame_total: 12000 # Total frames to record
frame_step: 3 # Save every 3rd framefrom config.config_manager import ConfigManager, ConfigValidationError
# Initialize
config_manager = ConfigManager(config_root="/path/to/config")
# Load profile
config = config_manager.load_profile("kitti")
# Load custom config file
config = config_manager.load_config("/path/to/config.yaml")
# List available profiles
profiles = config_manager.list_profiles()
# Validate configuration
try:
config = config_manager.load_profile("my_profile")
except ConfigValidationError as e:
print(f"Validation error: {e}")from recorder.actor_tree import ActorTree
# Initialize with world and configuration
actor_tree = ActorTree(world, config, save_dir)
actor_tree.init()
# Tick controller (update autopilot)
actor_tree.tick_controller()
# Save data for current frame
actor_tree.tick_data_saving(frame_id, timestamp)
# Cleanup
actor_tree.destroy()from recorder.camera import Camera
from recorder.lidar import Lidar
from recorder.radar import Radar
# Create sensor instance
camera = Camera(world, sensor_config, parent_actor, save_dir)
# Sensors automatically register callbacks
# Data is saved when tick_data_saving() is called
# Access sensor attributes
sensor_transform = camera.get_transform()from core.transform import Transform, Location, Rotation
from core.transform import transform_to_carla_transform
# Create transform
transform = Transform(
Location(x=10.0, y=5.0, z=2.0),
Rotation(pitch=0.0, yaw=90.0, roll=0.0)
)
# Convert to CARLA transform
carla_transform = transform_to_carla_transform(transform)
# Apply to actor
actor.set_transform(carla_transform)Find spawn points in a map:
import carla
client = carla.Client('localhost', 2000)
world = client.get_world()
spawn_points = world.get_map().get_spawn_points()
for i, point in enumerate(spawn_points):
print(f"Spawn point {i}: {point.location}")Infrastructure actors represent static roadside units (RSUs) for V2X (Vehicle-to-Everything) communication scenarios. Infrastructure actors are virtual (not spawned as CARLA actors) but can have sensors attached.
actors:
- type: infrastructure
name: rsu_intersection_1
spawn_point:
x: 41
y: -240
z: 15.0
sensors:
- type: sensor.camera.rgb
name: infra_camera
spawn_point: {x: 0.0, y: 0.0, z: 0.0}Infrastructure supports V2X Custom sensors for one-way message broadcasting:
actors:
- type: infrastructure
name: rsu_highway_1
spawn_point:
x: 100.0
y: -200.0
z: 10.0
sensors:
- type: sensor.other.v2x_custom
name: v2x_broadcast
spawn_point: {x: 0.0, y: 0.0, z: 5.0}
transmit_power: 30.0
receiver_sensitivity: -99.0
frequency_ghz: 5.9
filter_distance: 500
path_loss_model: geometric
scenario: urbanImportant Limitations:
- Infrastructure does NOT support
sensor.other.v2x(V2X CAM) sensors - V2X CAM requires vehicle dynamics (speed, acceleration) which Infrastructure cannot provide
- Only
sensor.other.v2x_customis supported for Infrastructure - Infrastructure V2X is one-way only (can send but not receive messages)
1. V2X CAM (sensor.other.v2x)
- ETSI standard Cooperative Awareness Message sensor
- Automatically generates messages based on vehicle dynamics
- Requires: speed, acceleration, yaw rate (vehicles only)
- Use case: Standard V2V communication following ETSI protocols
2. V2X Custom (sensor.other.v2x_custom)
- Custom message sensor for arbitrary string messages
- Manual message sending via
send()API - Supports both vehicles and infrastructure
- Use case: Custom V2X protocols, infrastructure broadcasting
V2V (Vehicle-to-Vehicle):
actors:
- type: vehicle.tesla.model3
name: vehicle_01
spawn_point: 60
sensors:
- type: sensor.other.v2x_custom
name: v2x_custom
spawn_point: {x: 0.0, y: 0.0, z: 2.0}
- type: vehicle.audi.a2
name: vehicle_02
spawn_point: 76
sensors:
- type: sensor.other.v2x_custom
name: v2x_custom
spawn_point: {x: 0.0, y: 0.0, z: 2.0}V2I/I2V (Vehicle-Infrastructure):
actors:
- type: infrastructure
name: rsu_intersection
spawn_point: {x: 100.0, y: -200.0, z: 10.0}
sensors:
- type: sensor.other.v2x_custom
name: v2x_broadcast
spawn_point: {x: 0.0, y: 0.0, z: 5.0}
- type: vehicle.tesla.model3
name: ego_vehicle
spawn_point: 73
sensors:
- type: sensor.other.v2x_custom
name: v2x_receiver
spawn_point: {x: 0.0, y: 0.0, z: 2.0}Infrastructure generates JSON messages automatically:
{
"type": "RSU",
"name": "rsu_intersection_1",
"location": {
"x": 100.0,
"y": -200.0,
"z": 10.0
}
}Vehicles generate similar messages with vehicle position:
{
"type": "VEHICLE",
"name": "vehicle_01",
"location": {
"x": 92.0,
"y": 188.0,
"z": 0.3
}
}Generate bird's-eye view (BEV) maps of entire CARLA maps:
# Capture BEV map with default settings
python3 tools/capture_map_bev.py --map Town02 --output ./bev_output
# Custom parameters
python3 tools/capture_map_bev.py \
--map Town01 \
--output ./bev_output \
--height 150 \
--fov 60 \
--overlap 0.15 \
--resolution 2000Parameters:
--map: CARLA map name (Town01, Town02, etc.)--output: Output directory path--height: Camera height in meters (default: 120)--fov: Field of view in degrees (default: 60, lower = less distortion)--overlap: Overlap ratio between camera tiles (default: 0.15)--resolution: Camera resolution in pixels (default: 2000)
Output:
{map_name}_rgb.png: RGB BEV image{map_name}_depth.png: Depth BEV image{map_name}_depth_normalized.png: Normalized depth grayscale{map_name}_semantic.png: Semantic segmentation BEV imagemetadata.json: Capture parameters and grid information
Configure multiple vehicles with different sensor setups:
actors:
- type: vehicle.tesla.model3
name: ego_vehicle
spawn_point: 73
sensors: [...]
- type: vehicle.audi.a2
name: following_vehicle
spawn_point: 76
sensors: [...]All vehicles are synchronized using CARLA's synchronous mode.
Configure vehicles to follow specific paths for reproducible data collection:
# Start CARLA server
cd $CARLA_ROOT && ./CarlaUE4.sh
# Create route using interactive editor
python3 tools/editor_route.py --map Town02 --name highway_loop
# Click waypoints on the map following your desired path
# Press Enter to saveMethod 1: Load from file
actors:
- type: vehicle.tesla.model3
name: ego_vehicle
spawn_point: 73
route:
from_file: routes/Town02_highway_loop.yaml
sensors:
- type: sensor.camera.rgb
name: front_camera
spawn_point: {x: 2.0, y: 0.0, z: 2.0}
- type: sensor.lidar.ray_cast
name: lidar
spawn_point: {x: 0.0, y: 0.0, z: 2.5}Method 2: Inline waypoints
actors:
- type: vehicle.tesla.model3
name: ego_vehicle
spawn_point: 73
route:
mode: strict
loop: true
waypoints:
- {x: 107.5, y: -133.2, z: 0.3}
- {x: 150.0, y: -130.5, z: 0.3}
- {x: 200.3, y: -128.8, z: 0.3}
- {x: 180.5, y: -170.8, z: 0.3}
sensors: [...]When route is configured with mode: strict:
-
At Startup: GlobalRoutePlanner calculates complete road path
- Input: User's 8 waypoints
- Output: 450+ road waypoints following topology
- Console:
Vehicle 'ego_vehicle' configured with route: 8 waypoints expanded to 453 road waypoints (LOOP)
-
During Recording: BasicAgent follows the path
- Maintains lane discipline
- Respects traffic lights (optional)
- Handles intersections properly
- Loops back to start if
loop: true
-
Data Collection: Vehicle follows same path every recording
- Reproducible dataset collection
- Consistent lighting/weather conditions
- Same viewpoints for multi-session comparison
# config/profiles/continuous_loop.yaml
recording:
frame_total: 50000 # Long recording
frame_step: 1
map: Town02
weather: ClearNoon
actors:
- type: vehicle.tesla.model3
name: ego_vehicle
spawn_point: 73
route:
from_file: routes/Town02_continuous_loop.yaml
sensors:
- type: sensor.camera.rgb
name: front_camera
spawn_point: {x: 2.0, y: 0.0, z: 2.0}
image_size_x: 1920
image_size_y: 1080Run with:
python3 data_recorder.py --config config/profiles/continuous_loop.yamlVehicle will loop continuously collecting data until frame_total is reached.
Apply custom weather parameters programmatically:
import carla
world = client.get_world()
weather = carla.WeatherParameters(
cloudiness=80.0,
precipitation=30.0,
sun_altitude_angle=70.0
)
world.set_weather(weather)Configure traffic behavior:
tm = client.get_trafficmanager()
tm.set_synchronous_mode(True)
tm.set_global_distance_to_leading_vehicle(2.5)
tm.set_respawn_dormant_vehicles(True)
tm.set_hybrid_physics_mode(True) # Optimize distant vehicles- Create sensor class in
recorder/:
from recorder.sensor import Sensor
class MySensor(Sensor):
def __init__(self, world, sensor_info, parent_actor, save_dir):
super().__init__(world, sensor_info, parent_actor, save_dir)
self._init_sensor()
def _init_sensor(self):
blueprint = self.world.get_blueprint_library().find(self.sensor_type)
# Configure blueprint attributes
self.sensor = self.world.spawn_actor(
blueprint, self.transform, attach_to=self.parent_actor
)
self.sensor.listen(self._on_data)
def _on_data(self, data):
# Process and save sensor data
pass- Register in ActorFactory (
recorder/actor_factory.py):
from recorder.my_sensor import MySensor
class ActorFactory:
def create_sensor_node(self, sensor_info, parent_node):
if sensor_type == "sensor.my.type":
return MySensor(self.world, sensor_info, parent_actor, save_dir)- Update ConfigManager validation:
VALID_SENSOR_TYPES = {
'sensor.my.type',
# ... existing types
}- Create labeling script in
label_tools/:
# label_tools/my_format_label.py
def convert_to_my_format(raw_data_path, output_path):
# Load raw data
# Transform to dataset format
# Write output files
pass-
Follow existing patterns from
kitti_objects_label.pyoryolo_label.py -
Add documentation to USER_GUIDE.md
Create specialized profiles for specific scenarios:
# config/profiles/urban_night.yaml
recording:
map: Town03
weather: ClearNight
frame_total: 5000
# High-sensitivity night camera
sensor_templates:
night_camera: &night_camera
type: sensor.camera.rgb
image_size_x: 1920
image_size_y: 1080
fov: 90.0
exposure_mode: manual
exposure_compensation: 0.5# Clone repository
git clone https://github.com/KevinLADLee/carla_dataset_tools.git
cd carla_dataset_tools
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Install development tools
pip install pytest black flake8# Validate all profiles
python3 tools/config_validate.py --all
# Test configuration loading
python3 -c "from config.config_manager import ConfigManager; \
cm = ConfigManager('config'); \
config = cm.load_profile('default'); \
print('Success!')"Follow PEP 8 guidelines:
# Format code
black data_recorder.py
# Check style
flake8 recorder/ --max-line-length=100# Create feature branch
git checkout -b feature/my-new-feature
# Make changes and commit
git add .
git commit -m "Add: My new feature"
# Push to remote
git push origin feature/my-new-feature- Enable CARLA logging:
import logging
logging.basicConfig(level=logging.DEBUG)- Check sensor callbacks:
def _on_data(self, data):
print(f"Received data: {data.frame} at {data.timestamp}")
# Process data- Verify spawn points:
python3 tools/debug_info.py --map Town02- Monitor performance:
import time
start = time.time()
# ... operation ...
print(f"Operation took {time.time() - start:.3f}s")Contributions are welcome! Areas for contribution:
- Additional dataset format support (nuScenes, Waymo, etc.)
- Enhanced documentation and examples
- Bug fixes and performance improvements
- New sensor types or features
Please submit pull requests to the main repository.