Camera sensor renders 0 frames on Apple Silicon (amd64 emulation) - Follow Line "No image available"

On an Apple Silicon Mac, the RoboticsBackend connects fine and the world loads, but camera-based exercises (e.g. Follow Line) never receive an image (“No image available”).

After digging into the container, the root cause is that the Gazebo camera sensor produces 0 frames: the Ogre2 render engine cannot initialize a working rendering context under x86 emulation, and its render thread stays stuck at Sensors.cc:337 Waiting for init.

The robot itself spawns correctly and all other topics work (odom, cmd_vel, laser, tf…).

Only the camera rendering is broken.


Environment

Host machine (not a low-end setup — the hardware is not the bottleneck):

| Item | Value |

|—|—|

| Model | MacBook Pro (Mac17,7) |

| Chip | Apple M5 Max (arm64) |

| CPU | 18 cores (6 efficiency + 12 performance) |

| GPU | Apple M5 Max, 40-core GPU, Metal 4 — present but not accessible to the Linux container |

| RAM | 128 GB |

| macOS | 26.4.1 (build 25E253) |

Docker / image:

| Item | Value |

|—|—|

| Docker | Docker Desktop 29.4.0 |

| Docker resources | 18 CPUs, 7.75 GiB RAM assigned (host has 128 GB) |

| Rosetta for amd64 | enabled |

| Image | jderobot/robotics-backend:latest (same digest as :4.10.2) |

| Image digest | sha256:d6a6c1fc4036bb4852127fcf6a89f3db1f080eb96973c9db1d7a21c140f06750 |

| Run flag | --platform linux/amd64 (x86 emulation) |

| Inside image | ROS 2 Humble · Gazebo Sim 8.14.0 · Robotics Application Manager 5.6.13 |

Notes:

  • :latest and :4.10.2 resolve to the same digest, so trying different tags makes no difference.
  • The Mac has a powerful 40-core GPU, but it is not exposed to the emulated Linux

container (no /dev/dri, and Metal is not usable from Linux/amd64 containers), so Gazebo

falls back to CPU/software rendering, which is where the camera sensor breaks.

Run command:


docker run --rm -d --name rb --platform linux/amd64 \

-p 6080:6080 -p 1108:1108 -p 7163:7163 \

jderobot/robotics-backend:4.10.2


Steps to reproduce

  1. Start the container as above on an Apple Silicon Mac.

  2. On unibotics.org, open Follow Line, click Connect → status shows

connected.

  1. Click “select world” → Simple Circuit.

  2. Result: the world loads but the camera panel stays on “No image available”.

The frontend often also shows a spurious disconnected (websocket timeout while Gazebo is booting under emulation).


What works vs what fails

Works — the robot spawns fully. ros2 topic list shows all expected topics:


/cam_f1_left/camera_info

/cam_f1_left/image_raw

/cam_f1_left/image_raw/compressed

/clock

/cmd_vel

/f1/laser/scan

/joint_states

/odom

/robot_description

/tf

/tf_static

Fails/cam_f1_left/image_raw publishes 0 frames, on both the ROS side and the

Gazebo side:


gz topic -e -t /cam_f1_left/image_raw # -> no messages, 0 frames

ros2 topic hz /cam_f1_left/image_raw # -> "does not appear to be published yet"


Root-cause logs (Gazebo, headless server gz sim -s)


[Dbg] [Sensors.cc:697] Configuring Sensors system

[Dbg] [SystemManager.cc:80] Loaded system [gz::sim::systems::Sensors] for entity [1]

[Dbg] [Sensors.cc:532] SensorsPrivate::RenderThread started

[Dbg] [Sensors.cc:337] Waiting for init

[Wrn] [Ogre2RenderEngine.cc:551] Unable to open display: :0. Trying to run in headless mode.

[Wrn] [Ogre2Camera.cc:423] Ogre2Camera::SetVisibilityMask: Mask bits c0000000 are set but will be ignored as they conflict with the reserved bits used internally by the ogre2 backend.

The render thread reaches Waiting for init and never completes initialization, so no camera frames are ever produced. /dev/dri is absent (expected on macOS), so there is no direct GPU access:


[ERROR] (my_app_logger) /dev/dri does not exist. No direct GPU access.

Non-fatal red herring

This error also appears in the log but is not the cause — the entity is still created:


[Err] [UserCommands.cc:957] Expected exactly one top-level <model>, <light> or <actor> on SDF.

...

[Dbg] [UserCommands.cc:1094] Created entity [12] named [f1]


Workarounds I already tried (none fixed the camera)

Launching the world + F1 robot directly inside the container (ros2 launch .../simple_circuit.launch.py then .../f1.launch.py mode:=holo sensor:=camera),

I tried forcing software / headless rendering. In all cases the render thread stayed at Sensors.cc:337 Waiting for init and the camera published 0 frames:

  1. Default (no GPU) — Unable to open display :0, 0 frames.

  2. Forced software GLLIBGL_ALWAYS_SOFTWARE=1, GALLIUM_DRIVER=llvmpipe, MESA_GL_VERSION_OVERRIDE=3.3 — 0 frames, still Waiting for init.

  3. Virtual X displayXvfb :0 -screen 0 1600x1200x24 + DISPLAY=:0 — the display warning disappears, but rendering still hangs at Waiting for init, 0 frames.

This points to the emulated (Rosetta / amd64) OpenGL stack itself, not to a missing display or a missing env var.

Questions for the maintainers

  1. Is there a supported way to get camera sensors rendering in the RoboticsBackend on Apple Silicon (amd64 emulation, no GPU passthrough)? A known env var, a --headless-rendering / EGL surfaceless configuration for the Sensors system, or a Mesa/llvmpipe setup that is known to work?

  2. Would an arm64-native image (avoiding Rosetta emulation entirely) make Ogre2 software rendering viable for the camera sensor?

  3. Is Apple Silicon simply not supported for camera-based exercises today? If so, could the docs / connection UI warn about it, so students don’t debug a dead end?

Happy to run any additional diagnostics or test a candidate image. Thanks for Unibotics!