From 34baae6168d55a6c6650494b85c73a829515e414 Mon Sep 17 00:00:00 2001 From: Ryohsuke Mitsudome Date: Wed, 27 May 2026 00:16:04 +0900 Subject: [PATCH 1/9] feat: add docker-compose demo for Carla Signed-off-by: Ryohsuke Mitsudome --- docker/examples/demos/carla/README.md | 140 +++++++++++++++ .../examples/demos/carla/docker-compose.yaml | 165 ++++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 docker/examples/demos/carla/README.md create mode 100644 docker/examples/demos/carla/docker-compose.yaml diff --git a/docker/examples/demos/carla/README.md b/docker/examples/demos/carla/README.md new file mode 100644 index 0000000000..816ccca6ef --- /dev/null +++ b/docker/examples/demos/carla/README.md @@ -0,0 +1,140 @@ +# CARLA + +Runs the [CARLA](https://carla.readthedocs.io/en/0.9.16/) simulator and the autoware-side bridge in a single Docker Compose stack, split into four services: + +- **`carla-simulator`** — `carlasim/carla:0.9.16`, runs `CarlaUE4.sh` and listens on `localhost:2000`. +- **`carla-interface`** — `autoware:universe-cuda-jazzy`, runs `autoware_carla_interface.launch.xml` standalone. This is the bridge that connects to CARLA on port 2000 and republishes sensor data onto the autoware ROS graph. Its healthcheck passes once the ego vehicle exists in the current CARLA episode. +- **`spectator-follow`** — `autoware:universe-cuda-jazzy`, runs `ros2 run autoware_carla_interface spectator_follow` so the CARLA spectator camera chases the ego vehicle instead of staying where the simulator window started. +- **`autoware`** — `autoware:universe-cuda-jazzy`, launches `e2e_simulator.launch.xml` with `simulator_type:=carla` but `launch_simulator_interface:=false`, since the interface runs in its own container. + +All four services use `network_mode: host` so the interface can reach the CARLA server on `localhost:2000` and DDS traffic flows between the interface and autoware nodes. + +The autoware image does not ship the CARLA Python API, so the two services that talk to the CARLA server directly (`carla-interface` and `spectator-follow`) fetch the matching wheel on first run. That snippet lives in the `x-carla-python-api` YAML anchor at the top of the compose file, which is where the CARLA version is pinned. + +Splitting the interface out makes it easier to restart just the bridge (e.g. when CARLA changes maps) without tearing down the autoware stack. + +## Prerequisites + +- NVIDIA GPU with the NVIDIA Container Toolkit installed +- CARLA Lanelet2 map (e.g. `Town01`) extracted to `~/autoware_data/maps/Town01` — see the [autoware_carla_interface README](../../../../src/universe/autoware_universe/simulator/autoware_carla_interface/README.md#map-setup) for the expected layout (`lanelet2_map.osm`, `pointcloud_map.pcd`, `map_projector_info.yaml`) +- Perception model data under `~/autoware_data/ml_models` +- Docker Compose v2 + +## Run + +```bash +xhost +local:docker + +cd docker/examples/demos/carla +HOST_UID=$(id -u) HOST_GID=$(id -g) docker compose up +``` + +Or, to drop into a shell on the autoware side after the launch exits: + +```bash +HOST_UID=$(id -u) HOST_GID=$(id -g) docker compose run --rm autoware +``` + +`docker compose run` starts the `carla-simulator` dependency automatically and waits for its healthcheck (a TCP probe of port `2000`) to pass before launching autoware, so the carla interface won't hit its 20 s connect timeout on a cold start. Note that `docker compose run autoware` only pulls in autoware's own dependencies — add `spectator-follow` explicitly (`docker compose up -d spectator-follow`) if you want the chase camera in that flow. + +To run everything except the chase camera and keep manual control of the CARLA spectator: + +```bash +HOST_UID=$(id -u) HOST_GID=$(id -g) docker compose up --scale spectator-follow=0 +``` + +To stop everything: + +```bash +docker compose down +``` + +The compose file defaults `HOST_UID`/`HOST_GID` to `1000`; drop the prefix if your host UID/GID are 1000. + +Once both sides are up: set the initial pose (Init by GNSS) in RViz, set a goal, wait for planning, then engage. + +## Customizing + +Edit the `command:` block in `docker-compose.yaml` to change launch arguments. + +**`carla-simulator`**: + +- **Headless / no rendering**: append `-RenderOffScreen` to the `command:` list to disable the spectator window. +- **Higher quality**: change `-quality-level=Low` to `-quality-level=Epic` (uses more GPU). + +**`carla-interface`**: + +- **Map**: change `map_path` (e.g. `Town10HD`) — the basename is forwarded to CARLA as the world to load. Keep this in sync with the `map_path` on the `autoware` service. +- **Light-weight sensors**: set `use_light_weight_sensor_mapping:=true` to use a single front camera at lower frequencies (lower GPU load). +- **Timeout**: `timeout:=60` is the CARLA client connect timeout in seconds. + +**`spectator-follow`**: + +- **Top-down view**: use `--distance 0 --height 30 --pitch -90`. +- **Chase distance / height / pitch**: `--distance 8.0`, `--height 4.0`, `--pitch -15.0` position the camera behind and above the ego. +- **Ego actor**: `--role ego_vehicle` must match `ego_vehicle_role_name` on the interface. +- **Update rate**: `--rate 30.0` Hz. Lower it if the extra RPC traffic bothers the server. + +It waits for `carla-interface` to report healthy before connecting. + +The camera has no effect if CARLA runs headless (`-RenderOffScreen`). + +**`autoware`**: + +- **Map**: change `map_path` to match the interface. +- **E2E planning (VAD)**: add `use_e2e_planning:=true`. + +The autoware, interface, and spectator services all use `universe-cuda-jazzy`; swap the `image:` tag to target a different ROS distro (e.g. `universe-cuda-humble`) or point at a locally built image. Keep them in sync — they need to be ABI-compatible on the ROS graph. + +`network_mode: host` is required on all four services; removing it will break the bridge. + +## Launch command reference + +The autoware image's entrypoint sources `/opt/autoware/setup.bash` (via `AUTOWARE_RUNTIME=1`). + +`carla-interface` runs: + +```bash +ros2 launch autoware_carla_interface autoware_carla_interface.launch.xml \ + map_path:=/home/aw/autoware_data/maps/Town01 \ + port:=2000 \ + timeout:=60 \ + use_light_weight_sensor_mapping:=false +``` + +`spectator-follow` runs: + +```bash +ros2 run autoware_carla_interface spectator_follow \ + --host localhost \ + --port 2000 \ + --timeout 60 \ + --role ego_vehicle \ + --distance 8.0 \ + --height 4.0 \ + --pitch -15.0 \ + --rate 30.0 +``` + +See the [autoware_carla_interface README](../../../../src/universe/autoware_universe/simulator/autoware_carla_interface/README.md#following-the-ego-vehicle-with-the-carla-spectator-camera) for the full flag list. + +`autoware` runs: + +```bash +ros2 launch autoware_launch e2e_simulator.launch.xml \ + vehicle_model:=sample_vehicle \ + sensor_model:=carla_sensor_kit \ + simulator_type:=carla \ + launch_simulator_interface:=false \ + map_path:=/home/aw/autoware_data/maps/Town01 +``` + +`launch_simulator_interface:=false` prevents the e2e launch from also starting `autoware_carla_interface` — that runs in its own container now. + +`map_path` points inside the container; it maps to `~/autoware_data/maps/Town01` on the host via the `volumes:` mount. The map directory name (`Town01`) is parsed out and used as the CARLA world name, so it must match an existing CARLA map. + +`carla-simulator` runs: + +```bash +./CarlaUE4.sh -prefernvidia -quality-level=Low -nosound +``` diff --git a/docker/examples/demos/carla/docker-compose.yaml b/docker/examples/demos/carla/docker-compose.yaml new file mode 100644 index 0000000000..a1be8d5812 --- /dev/null +++ b/docker/examples/demos/carla/docker-compose.yaml @@ -0,0 +1,165 @@ +# Installs the CARLA Python API into the user site-packages of the autoware image. +# Shared by every service that talks to the CARLA server. +x-carla-python-api: &carla-python-api | + CARLA_VERSION=0.9.16 + if ! python3 -c "import carla" 2>/dev/null; then + # install missing wheel package for Carla Python API + USER_SITE="$$(python3 -c 'import site; print(site.getusersitepackages())')" + TAG="$$(python3 -c 'import sys; print("cp%d%d" % sys.version_info[:2])')" + WHEEL_URL="$$(python3 -c "import json, urllib.request; m = json.load(urllib.request.urlopen('https://pypi.org/pypi/carla/$$CARLA_VERSION/json')); print(next(u['url'] for u in m['urls'] if u['filename'].startswith('carla-$$CARLA_VERSION-$$TAG-$$TAG-manylinux')))")" + mkdir -p "$$USER_SITE" + python3 -c "import urllib.request; urllib.request.urlretrieve('$$WHEEL_URL', '/tmp/carla.whl')" + python3 -m zipfile -e /tmp/carla.whl "$$USER_SITE" + rm /tmp/carla.whl + fi + +services: + carla-simulator: + image: carlasim/carla:0.9.16 + runtime: nvidia + network_mode: host + stdin_open: true + tty: true + environment: + - DISPLAY=${DISPLAY} + - SDL_AUDIODRIVER=dummy + - NVIDIA_DRIVER_CAPABILITIES=all + - NVIDIA_VISIBLE_DEVICES=all + volumes: + - /tmp/.X11-unix:/tmp/.X11-unix:rw + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] + command: + - ./CarlaUE4.sh + - -prefernvidia + - -quality-level=Low + - -nosound + healthcheck: + test: ["CMD-SHELL", "bash -c ' Date: Mon, 10 Aug 2026 09:06:18 +0000 Subject: [PATCH 2/9] style(pre-commit): autofix --- docker/examples/demos/carla/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/examples/demos/carla/README.md b/docker/examples/demos/carla/README.md index 816ccca6ef..d20bb7f628 100644 --- a/docker/examples/demos/carla/README.md +++ b/docker/examples/demos/carla/README.md @@ -1,4 +1,4 @@ -# CARLA +# CARLA Runs the [CARLA](https://carla.readthedocs.io/en/0.9.16/) simulator and the autoware-side bridge in a single Docker Compose stack, split into four services: From de56e6c2756e673acefe3338961d2487a80d1545 Mon Sep 17 00:00:00 2001 From: Ryohsuke Mitsudome Date: Mon, 10 Aug 2026 18:02:40 +0900 Subject: [PATCH 3/9] use lightweight sensor Signed-off-by: Ryohsuke Mitsudome --- docker/examples/demos/carla/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/examples/demos/carla/docker-compose.yaml b/docker/examples/demos/carla/docker-compose.yaml index a1be8d5812..f59802258c 100644 --- a/docker/examples/demos/carla/docker-compose.yaml +++ b/docker/examples/demos/carla/docker-compose.yaml @@ -70,7 +70,7 @@ services: map_path:=/home/aw/autoware_data/maps/Town01 \ port:=2000 \ timeout:=60 \ - use_light_weight_sensor_mapping:=false + use_light_weight_sensor_mapping:=true exec bash # Healthy once the ego exists in the current CARLA episode. healthcheck: From a9a3bf9f78e68c4c90c7e160579912baa0c585fd Mon Sep 17 00:00:00 2001 From: Ryohsuke Mitsudome Date: Mon, 10 Aug 2026 18:09:34 +0900 Subject: [PATCH 4/9] fix links in reamde Signed-off-by: Ryohsuke Mitsudome --- docker/examples/demos/carla/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/examples/demos/carla/README.md b/docker/examples/demos/carla/README.md index d20bb7f628..b79b228e71 100644 --- a/docker/examples/demos/carla/README.md +++ b/docker/examples/demos/carla/README.md @@ -16,7 +16,7 @@ Splitting the interface out makes it easier to restart just the bridge (e.g. whe ## Prerequisites - NVIDIA GPU with the NVIDIA Container Toolkit installed -- CARLA Lanelet2 map (e.g. `Town01`) extracted to `~/autoware_data/maps/Town01` — see the [autoware_carla_interface README](../../../../src/universe/autoware_universe/simulator/autoware_carla_interface/README.md#map-setup) for the expected layout (`lanelet2_map.osm`, `pointcloud_map.pcd`, `map_projector_info.yaml`) +- CARLA Lanelet2 map (e.g. `Town01`) extracted to `~/autoware_data/maps/Town01` — see the [autoware_carla_interface README](https://autowarefoundation.github.io/autoware_universe/main/simulator/autoware_carla_interface/#map-setup) for the expected layout (`lanelet2_map.osm`, `pointcloud_map.pcd`, `map_projector_info.yaml`) - Perception model data under `~/autoware_data/ml_models` - Docker Compose v2 @@ -116,7 +116,7 @@ ros2 run autoware_carla_interface spectator_follow \ --rate 30.0 ``` -See the [autoware_carla_interface README](../../../../src/universe/autoware_universe/simulator/autoware_carla_interface/README.md#following-the-ego-vehicle-with-the-carla-spectator-camera) for the full flag list. +See the [autoware_carla_interface README](https://autowarefoundation.github.io/autoware_universe/main/simulator/autoware_carla_interface/#following-the-ego-vehicle-with-the-carla-spectator-camera) for the full flag list. `autoware` runs: From 576c699f9a9ed3f5ae8dc016e908731ece5b1f13 Mon Sep 17 00:00:00 2001 From: Ryohsuke Mitsudome Date: Mon, 10 Aug 2026 18:11:29 +0900 Subject: [PATCH 5/9] fix pre-commit error Signed-off-by: Ryohsuke Mitsudome --- docker/examples/demos/carla/docker-compose.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker/examples/demos/carla/docker-compose.yaml b/docker/examples/demos/carla/docker-compose.yaml index f59802258c..07cf5ac3eb 100644 --- a/docker/examples/demos/carla/docker-compose.yaml +++ b/docker/examples/demos/carla/docker-compose.yaml @@ -40,7 +40,9 @@ services: - -quality-level=Low - -nosound healthcheck: - test: ["CMD-SHELL", "bash -c ' Date: Mon, 10 Aug 2026 18:18:50 +0900 Subject: [PATCH 6/9] add cpell:ignore Signed-off-by: Ryohsuke Mitsudome --- docker/examples/demos/carla/docker-compose.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/examples/demos/carla/docker-compose.yaml b/docker/examples/demos/carla/docker-compose.yaml index 07cf5ac3eb..841396eedd 100644 --- a/docker/examples/demos/carla/docker-compose.yaml +++ b/docker/examples/demos/carla/docker-compose.yaml @@ -1,3 +1,5 @@ +# cspell:ignore getusersitepackages urllib urlopen urlretrieve manylinux AUDIODRIVER nosound + # Installs the CARLA Python API into the user site-packages of the autoware image. # Shared by every service that talks to the CARLA server. x-carla-python-api: &carla-python-api | From 7b80d66731acd179641564c803fdc709529c63cb Mon Sep 17 00:00:00 2001 From: Ryohsuke Mitsudome <43976834+mitsudome-r@users.noreply.github.com> Date: Mon, 31 Aug 2026 17:03:30 +0900 Subject: [PATCH 7/9] update README according suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mete Fatih Cırıt --- docker/examples/demos/carla/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/examples/demos/carla/README.md b/docker/examples/demos/carla/README.md index b79b228e71..95c3ef7e14 100644 --- a/docker/examples/demos/carla/README.md +++ b/docker/examples/demos/carla/README.md @@ -35,7 +35,7 @@ Or, to drop into a shell on the autoware side after the launch exits: HOST_UID=$(id -u) HOST_GID=$(id -g) docker compose run --rm autoware ``` -`docker compose run` starts the `carla-simulator` dependency automatically and waits for its healthcheck (a TCP probe of port `2000`) to pass before launching autoware, so the carla interface won't hit its 20 s connect timeout on a cold start. Note that `docker compose run autoware` only pulls in autoware's own dependencies — add `spectator-follow` explicitly (`docker compose up -d spectator-follow`) if you want the chase camera in that flow. +`docker compose run` starts the full dependency chain automatically: `carla-simulator` (healthcheck: a TCP probe of port `2000`), then `carla-interface` (healthcheck: the ego vehicle exists in the episode), so autoware launches only after the bridge is healthy. Note that `docker compose run autoware` only pulls in autoware's own dependencies — add `spectator-follow` explicitly (`docker compose up -d spectator-follow`) if you want the chase camera in that flow. To run everything except the chase camera and keep manual control of the CARLA spectator: From d57d99cf59efee4b0bc921a95bb27e9a955e071a Mon Sep 17 00:00:00 2001 From: Ryohsuke Mitsudome <43976834+mitsudome-r@users.noreply.github.com> Date: Mon, 31 Aug 2026 17:04:05 +0900 Subject: [PATCH 8/9] set use_light_weight_sensor_mapping to true MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mete Fatih Cırıt --- docker/examples/demos/carla/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/examples/demos/carla/README.md b/docker/examples/demos/carla/README.md index 95c3ef7e14..9e9b975953 100644 --- a/docker/examples/demos/carla/README.md +++ b/docker/examples/demos/carla/README.md @@ -99,7 +99,7 @@ ros2 launch autoware_carla_interface autoware_carla_interface.launch.xml \ map_path:=/home/aw/autoware_data/maps/Town01 \ port:=2000 \ timeout:=60 \ - use_light_weight_sensor_mapping:=false + use_light_weight_sensor_mapping:=true ``` `spectator-follow` runs: From 2979c2647ec567b9c7c22c616c4f42992e61dca9 Mon Sep 17 00:00:00 2001 From: Ryohsuke Mitsudome <43976834+mitsudome-r@users.noreply.github.com> Date: Mon, 31 Aug 2026 17:04:41 +0900 Subject: [PATCH 9/9] fix exec command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mete Fatih Cırıt --- docker/examples/demos/carla/docker-compose.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docker/examples/demos/carla/docker-compose.yaml b/docker/examples/demos/carla/docker-compose.yaml index 841396eedd..873c01c7d0 100644 --- a/docker/examples/demos/carla/docker-compose.yaml +++ b/docker/examples/demos/carla/docker-compose.yaml @@ -70,12 +70,11 @@ services: - | set -e eval "$$CARLA_PYTHON_API_BOOTSTRAP" - ros2 launch autoware_carla_interface autoware_carla_interface.launch.xml \ + exec ros2 launch autoware_carla_interface autoware_carla_interface.launch.xml \ map_path:=/home/aw/autoware_data/maps/Town01 \ port:=2000 \ timeout:=60 \ use_light_weight_sensor_mapping:=true - exec bash # Healthy once the ego exists in the current CARLA episode. healthcheck: test: