Closed-loop CAN and CARLA

Drive a CARLA ego from Safety Island control over classic CAN while Autoware plans against the simulator. Design: CAN and CARLA integration.

This is a host demo. GitHub Actions never starts CARLA or Open AD Kit.

Two repositories

  • Open AD Kit PR #146 deployments/safety-island-carla-simulation/: CARLA, domain-bridge, sensors-only autoware_carla_interface and its deployment configuration. Autoware’s follower stays running for Auto/Engage but does not actuate CARLA.

  • This repository: freertos-posix CAN_ONLY, vcan0, and demo/can_carla_bridge.

Open AD Kit’s deployment and sensors-only overlay are maintained in PR #146.

Host loop

GPU host, Docker NVIDIA runtime, and the vcan kernel module. Open AD Kit also needs large UDP buffers; see that project’s CARLA simulation docs.

  1. Start Open AD Kit (no --drive):

    $ cd /path/to/openadkit
    $ git fetch origin pull/146/head
    $ git checkout FETCH_HEAD
    $ ./openadkit run safety-island-carla-simulation --gpu
    

    Do not start carla-simulation first and recreate carla-interface. That leaves a second ego in CARLA and breaks NDT.

  2. From this repository:

    $ sudo ip link add vcan0 type vcan
    $ sudo ip link set up vcan0
    $ ./build.sh --platform freertos-posix -d build/freertos-posix \
        --control-output CAN_ONLY --dds-interface lo
    $ SAFETY_ISLAND_CAN_IFACE=vcan0 ./build/freertos-posix/actuation_freertos
    $ python3 demo/can_carla_bridge/bridge.py --interface vcan0 --ego-role ego_vehicle
    
  3. In RViz: set a goal, engage. candump vcan0 should show 0x100 / 0x101 / 0x102 (0x103 in CAN-FD mode).

Confirm Autoware is not applying VehicleControl to the ego. The overlay skips apply_control(); the CAN bridge applies VehicleAckermannControl. Autoware Auto/Engage is required so SI sees AUTONOMOUS; it does not mean Autoware drives CARLA.

CAN-FD (optional)

freertos-posix can send one 24-byte 0x103 frame instead of the classic three. Everything else is unchanged:

$ SAFETY_ISLAND_CAN_FORMAT=fd SAFETY_ISLAND_CAN_IFACE=vcan0 ./build/freertos-posix/actuation_freertos
$ python3 demo/can_carla_bridge/bridge.py --interface vcan0 --can-format fd --ego-role ego_vehicle

See CAN-FD.

DDS

Open AD Kit pins domain 1 to loopback. Its closed-loop deployment’s cyclonedds.xml pins domains 1 and 2 to lo. Build the Safety Island with --dds-interface lo. The domain-bridge forwards the five controller inputs 1 → 2 and does not forward control_cmd (CAN_ONLY). The SI subscribes to /planning/trajectory, the trajectory Autoware 2.0’s own follower reads, so Autoware 2.0 needs no remap. Another Autoware needs a remap from the topic its follower reads to /planning/trajectory in the bridge (DDS topics). /system/operation_mode/state is bridged with transient_local durability so a late-joining SI still sees AUTONOMOUS.

Pins

Open AD Kit’s deployments/safety-island-carla-simulation/config.env pins CARLA and component images by digest. Record git rev-parse HEAD in the Open AD Kit checkout alongside the Safety Island commit when you run the demo so a later rerun can use the same pair.

Tests

Privilege-free (no CARLA):

$ python3 demo/can_carla_bridge/test_decoder.py
$ python3 demo/can_carla_bridge/test_bridge.py
$ python3 demo/can_tunnel_bridge/test_datagram.py

The deployment contract test lives in Open AD Kit:

$ python3 deployments/safety-island-carla-simulation/test_contract.py

Zephyr FVP TAP

Same open-loop and closed-loop host demos, with Safety Island on zephyr-fvp --network tap instead of freertos-posix. Frames still land on vcan0. Native FVP CAN stays loopback-only.

$ sudo ip tuntap add dev tap0 mode tap user "$(id -un)" 2>/dev/null || true
$ sudo ip addr replace 192.168.10.1/24 dev tap0
$ sudo ip link set dev tap0 up
$ sudo ip link add vcan0 type vcan
$ sudo ip link set up vcan0
$ python3 demo/can_tunnel_bridge/gateway.py --bind 192.168.10.1 --port 5555
$ ./build.sh --platform zephyr-fvp --network tap --control-output CAN_ONLY \
    -d build/zephyr-fvp-tap-can
$ west build -d build/zephyr-fvp-tap-can --target run
$ python3 demo/can_carla_bridge/bridge.py --interface vcan0 --timeout 5 \
    --ego-role ego_vehicle

FVP is not real-time; use a larger --timeout than the 0.5 s POSIX default. Closed-loop still starts Open AD Kit safety-island-carla-simulation first. Apply its docker-compose.fvp.yaml overlay so the domain-bridge’s domain 2 binds to tap0.