fix(demos): run headless automatically when no display is available (macOS)#61
Conversation
The GUI run mode launched the Gazebo/RViz client even with no X server, which aborts the whole required launch on macOS Docker Desktop. Detect a missing DISPLAY and fall back to headless, printing what still works (REST API, Web UI). Covers turtlebot3 and moveit.
10ad688 to
bbf4eb9
Compare
There was a problem hiding this comment.
Pull request overview
Fixes the macOS quick-start failure where run-demo.sh would launch Gazebo/RViz GUI clients against a Docker Desktop container that has no X server, causing the required GUI process to die and tear down the whole stack. The runners now detect a missing DISPLAY and automatically switch to headless, while preserving the existing GUI-on-Linux flow and honoring explicit --headless/HEADLESS=true. As a side effect the previously-broken HEADLESS=true env var now actually works because the hardcoded default no longer overwrites it.
Changes:
- Add auto-headless fallback (with macOS-specific messaging) to
turtlebot3_integration/run-demo.sh,turtlebot3_integration/run-demo-debounce.sh, andmoveit_pick_place/run-demo.sh. - Gate X11 forwarding (and its cleanup) on the resolved headless mode in the TurtleBot3 runners, so
xhostonly runs when a GUI is actually going to be shown. - Initialize
HEADLESS_MODEfrom${HEADLESS:-false}so the documented env variable is respected. - Update the TurtleBot3 README and root README quick-start to document the macOS auto-headless behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| README.md | Note that the TurtleBot3 quick-start auto-falls back to headless on macOS/headless hosts. |
| demos/turtlebot3_integration/run-demo.sh | Initialize HEADLESS_MODE from env, add auto-headless fallback when DISPLAY is empty, and only run/cleanup xhost when GUI mode is active. |
| demos/turtlebot3_integration/run-demo-debounce.sh | Same auto-headless + gated X11 setup/cleanup pattern for the debounce variant. |
| demos/turtlebot3_integration/README.md | Update prerequisites and add a macOS section explaining the auto-headless fallback. |
| demos/moveit_pick_place/run-demo.sh | Initialize HEADLESS_MODE from env and add auto-headless fallback for the MoveIt runner (X11 setup block above remains unchanged). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Mirror the turtlebot3 README updates for the MoveIt demo: the runner now falls back to headless when no display is present, so the docs no longer tell macOS users to set up X11/XQuartz.
Problem
On macOS (Docker Desktop) the default
run-demo.shlaunches the Gazebo/RViz GUI client, but the container has no X server (DISPLAYis empty). The GUI process aborts:Because that GUI process is marked
required, its death tears down the entire stack (simulation, Nav2, gateway, web UI). The flagship quick-start therefore fails on macOS out of the box, even though the demo's value (REST API + Web UI diagnostics) needs no GUI.Fix
run-demo.shnow detects a missing display (macOS, or any headless host) and falls back to headless automatically, instead of launching a GUI that cannot open. An explicit--headless/HEADLESS=truestill wins, and the Linux-with-display path is unchanged - X11 forwarding now only runs when a GUI will actually be shown.When it falls back, it prints what is running so the user knows what works and what they can do:
Applied to the GUI-launching demos:
turtlebot3_integration/run-demo.sh,turtlebot3_integration/run-demo-debounce.sh,moveit_pick_place/run-demo.sh. The headless-only demos (sensor_diagnostics,multi_ecu_aggregation) were already fine. As a side effect the documentedHEADLESS=trueenvironment variable now actually works (it was previously overwritten by the hardcoded default).READMEs updated to document the macOS behavior.
Verification
shellcheck -S warningandbash -nclean on all three scripts.DISPLAYand headless Linux force headless and print the notice; Linux withDISPLAYkeeps the GUI and sets up X11; explicitHEADLESS=trueis respected with no auto-notice.