Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CARLA Scenario Editor

Draw multi-vehicle trajectories on a map in CARLA, save the whole thing as one JSON model, and run it end to end with one button.

This repo accompanies the paper CARLA Scenario Editor (MODELS Companion '26). On disk the package is seditor; the browser tool calls itself Scenario Editor.

Most CARLA tooling snaps routes to the road network. This editor doesn't: a drawn path can cut across medians, swerve late, or drive the wrong way, which is exactly what you need to stress a safety framework like RSS. Three things set it apart:

  • Direct trajectory editing. Drag multi-vehicle paths on the real map instead of typing coordinates.
  • Freedom from the road network. A drawn path isn't constrained to lane geometry.
  • One workflow. A single model drives everything, and one button launches the server, the scenario, and the drivable ego.

Contents


Architecture

Everything hangs off one declarative scenario model. That model is the only authoritative artifact. The py_trees behavior tree and the ScenarioRunner XML are both generated from it, which is what lets a multi-vehicle scenario run from a single press. See the paper for the full treatment.

Layer Package Responsibility
Authoring seditor/backend/static Browser editor: SVG map canvas, actor and step panels, run cockpit.
Schema seditor/schema The scenario model, the parameter catalog, and validation.
Runtime seditor/runtime Turns the model into a py_trees behavior tree.
Orchestration seditor/orchestrator One-action startup and teardown, plus process supervision.
Execution seditor/srunner, seditor/rss ScenarioRunner scenario, path follower, and the RSS ego client.
flowchart LR
    subgraph create["1 - Author (this tool)"]
        editor["Browser editor"]
        json[("scenario.json")]
        editor -->|save| json
    end
    subgraph exec["2 - Execute"]
        orch["Orchestrator"]
        runner["ScenarioRunner client"]
        ego["Ego client (RSS)"]
        server["CARLA server"]
        orch --> runner --> server
        orch --> ego --> server
    end
    json -->|Run| orch
Loading

The one piece worth calling out: a custom PathFollower and PID controller let a vehicle steer toward any point, not just on-lane waypoints, so a maneuver is a drawn path instead of a stack of atomic behaviors.


Requirements

Linux only. The tool launches CarlaUE4.sh and tears runs down by process group.

  • CARLA 0.9.14, the RSS-enabled build (for the RSS ego client)
  • ScenarioRunner 0.9.13
  • A Python env with CARLA importable, plus py_trees and pygame. Defaults expect a conda env named carla_0.9.14.

The backend and UI are pure standard library and a browser. No build step, no npm.


Setup

Point the tool at your installs with three environment variables (drop them in ~/.bashrc):

export CARLA_ROOT=/home/user/Documents/CARLA_0.9.14_RSS/
export SCENARIO_RUNNER_ROOT=/home/user/Documents/scenario_runner-0.9.13/
export SCENARIO_EDITOR_ROOT=/home/user/Documents/scenario_editor/

Then sanity check the paths:

python -m seditor doctor

doctor prints the resolved interpreter and roots and flags anything missing.


Run it

python -m seditor up          # opens the editor at http://localhost:8123

In the browser: pick a Town and click Load map, add vehicles and drag their spawn markers, draw paths, give each actor a sequence of steps, then Save (Ctrl+S). Hit Run.

Run needs no second terminal. It starts CARLA if the RPC port is closed (otherwise it connects to what's already there), launches the ScenarioRunner client, then opens the drivable ego window, with live logs streaming into the right panel. The editor and the CLI drive the same Orchestrator, so a headless seditor run does the identical thing.


Command reference

python -m seditor run <scenario.json>   # run a scenario end to end
python -m seditor stop                  # stop a running simulation
python -m seditor restart [<scenario>]  # restart runner + ego, keep the server warm
python -m seditor status                # server + last-run status
python -m seditor validate <scenario>   # validate a file, report issues
python -m seditor doctor                # check paths and configuration
python -m seditor up                    # launch the editor + backend
Flag Commands Effect
--host, --port run, restart, status, doctor, up CARLA RPC host and port (default 127.0.0.1:2000)
--keep-server run, stop leave CARLA running on exit
--quality Low|Epic run, restart quality level when the tool launches the server (default Epic)
--nvidia-offload run, restart force the discrete NVIDIA GPU via PRIME offload
--ui-port, --no-browser up editor port (default 8123) / don't auto-open a browser

The scenario model

One JSON file (SCHEMA_VERSION = 3). Distances and coordinates are meters, speeds m/s, times seconds. The UI may show km/h, but disk and runtime are always m/s.

{
  "version": 3,
  "name": "cut_in_town02",
  "map": "Town02",
  "timeout_s": 120.0,
  "criteria": { "collision_test": true },

  "ego": {
    "model": "vehicle.lincoln.mkz_2020",
    "spawn": { "point": [28.32, 187.95], "yaw_deg": 0.0 },
    "path":  { "frame": "world", "points": [[28.32, 187.95], [159.76, 187.73]] },
    "target_speed_ms": 10.0
  },

  "vehicles": [
    {
      "id": "other1",
      "model": "vehicle.dodge.charger_2020",
      "spawn": { "point": [131.86, 191.5], "yaw_deg": 0.0 },
      "steps": [ /* see below */ ]
    }
  ],

  "paths": {}
}
  • Spawn (every actor, ego included): a { point: [x, y], yaw_deg } pose in world coordinates, the single source of truth for where an actor starts. Yaw is CARLA's convention (clockwise positive from +x).
  • Ego: driven by hand in the pygame window. Its path is an optional reference for hands off assist, with no steps and no triggers.
  • Vehicle: a non-ego actor with an ordered list of steps.
  • Step: { wait_for?, action, until?, name? }. The wait_for trigger gates the start, the action runs, the until trigger interrupts it.
  • Path: 2D points in the world frame (absolute) or the local frame (relative to the actor's live transform when the action starts). A local path may carry an anchor pose, which is authoring metadata the runtime ignores.
  • Path library: paths holds named paths a follow_path action can reuse by path_ref.

Each step compiles to a py_trees subtree:

wait_for + action + until  ->  Sequence(wait_for, Parallel_ONE(action, until))
wait_for + action          ->  Sequence(wait_for, action)
action   + until           ->  Parallel_ONE(action, until)
action                     ->  action

A vehicle's steps become a Sequence, and all vehicles run under one Parallel.


Triggers and actions

Both are stored as a type plus a parameter dict, which keeps the model off ScenarioRunner's class signatures. The catalog lives in one file (seditor/schema/specs.py) that drives validation, the UI forms, and the runtime adapters at once, so adding one is a catalog entry plus a factory.

Triggers (usable as wait_for or until, each concerning the step's own actor unless it names a reference):

Type Parameters Fires when
in_distance_to_vehicle reference, distance_m within distance_m of another actor
in_distance_to_location location, distance_m within distance_m of a fixed point
velocity_above / velocity_below speed_ms speed crosses the threshold
time_to_arrival_vehicle reference, time_s time to collision with an actor drops below time_s
time_to_arrival_location location, time_s time to reach a location drops below time_s
stand_still duration_s (near) stationary for duration_s
drive_distance distance_m driven distance_m since the trigger started
timer duration_s duration_s seconds elapsed

Actions:

Type Parameters Behavior
follow_path path or path_ref, target_speed_ms drive a drawn path (the star primitive: off-lane allowed)
keep_velocity speed_ms, duration_s?, distance_m? hold a speed; ends on duration, distance, or until
follow_lane speed_ms?, avoid_collision? follow real lanes until until fires
lane_change direction, speed_ms, distance_other_lane_m? change one lane along road geometry
stop brake brake to a stop (brake in (0, 1])
idle duration_s? do nothing, optionally for a fixed time

The rule: free-form paths for the interesting moves, atomics for the boring ones. follow_lane and lane_change lean on CARLA's waypoint API, while a drawn follow_path obeys nothing but the points.


Worked example: an offramp cut-in

The paper's demo (scenarios/cut_in_town02.json): other1 waits until the ego closes to 15 m, then follows a drawn path that cuts in front of it toward an offramp. The ego runs the RSS layer and brakes early, because RSS clamps its acceleration in response. The whole actor is one step:

{
  "action": {
    "type": "follow_path",
    "path": {
      "frame": "world",
      "points": [[131.86, 191.5], [145, 190], [155, 188], [170, 187.8]]
    },
    "target_speed_ms": 12
  },
  "name": "wait then cut in",
  "wait_for": { "type": "in_distance_to_vehicle", "reference": "ego", "distance_m": 15 }
}
python -m seditor validate scenarios/cut_in_town02.json
python -m seditor run scenarios/cut_in_town02.json

With the RSS ego selected, the brake indicator lights up early as other1 cuts in, showing RSS force a safe response the ego's own navigation wouldn't have.


Configuration

Settings resolve defaults → environment variables → a JSON file ($SEDITOR_SETTINGS, or ~/.config/seditor/settings.json) → CLI flags, in that order. Paths always come from the environment, so a stale file can't clobber a working setup. The ones you'll actually touch:

Setting Default Notes
host, port 127.0.0.1, 2000 CARLA RPC connection
ego_client rss rss (safety sensor + visualization) or plain (lighter, no RSS)
carla_quality Epic Low segfaults camera sensors, so the tool forces it back to Epic
force_nvidia_offload false PRIME offload for hybrid-graphics laptops

Towns: Town01–Town07 and Town10HD. The tiled maps (Town11–Town13) are separate CARLA downloads and aren't listed by default. Tests run without CARLA: pytest tests/.


Repository layout

seditor/
  backend/          HTTP app, session, and the static browser editor
  schema/           scenario model, catalog (specs), validation, JSON I/O
  runtime/          behavior-tree builder, action + trigger factories
  orchestrator/     CLI, core orchestrator, settings, supervisor, XML gen
  srunner/          the custom ScenarioRunner scenario (main_scenario.py)
  rss/              ego clients (RSS and plain) + RSS sensor
  helpers/          probe.py (server health), extract_geometry.py
  PathFollower.py   custom path follower behavior
scenarios/          example scenarios
tests/              headless tests (no CARLA required)

Citation

@inproceedings{carla_scenario_editor_2026,
  title     = {CARLA Scenario Editor},
  author    = {Bozkurt, Emre and Chang, Kehang and Gowland, Ryan and
               Ramdhan, Stefan and Dagenais, Kyanna and Pantelic, Vera and
               Paige, Richard and Lawford, Mark},
  booktitle = {Proceedings of the ACM/IEEE 29th International Conference on
               Model Driven Engineering Languages and Systems (MODELS Companion '26)},
  year      = {2026},
  address   = {Malaga, Spain},
  publisher = {ACM}
}

Built at the McMaster Centre for Software Certification (McSCert) with Stellantis, on CARLA, ScenarioRunner, py_trees, pygame, and ad-rss-lib.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages