[Sim Theme F] Gazebo native web visualization (gzweb)#27
Conversation
- Changed default Gazebo render engine reference from Jetty to Ionic in documentation. - Updated Dockerfile for ROS service to set default ROS_DISTRO to Kilted. - Modified DDS discovery configuration to reflect Kilted changes. - Adjusted simulator Dockerfile to set GZ_RELEASE to Ionic and added ROS_DISTRO as an argument. - Revised Copilot instructions and agent expectations to align with Kilted and Ionic. - Added new Business Requirements Document (BRD) for UbeROS Simulation and Visualization, outlining the need for a pluggable simulator framework and native web visualization for Gazebo.
…tion - Introduced a comprehensive PRD outlining the goals, requirements, and architecture for the UbeROS simulation and visualization framework. - Defined the context, core opportunity, and user personas to clarify the project's objectives. - Detailed functional and non-functional requirements, including a pluggable simulator framework, launch menu, and ROS 2 integration. - Specified the solution architecture, including component models and discovery systems. - Included operational considerations, risks, and rollout phases to guide implementation.
All open questions resolved (gzweb spike, kilted/ionic pairing, configurable autostart, drop ros-gz from ros image). Status -> Approved.
…ata-driven menu (FR-A1..A4)
…turtlesim/novnc route (FR-C1..C4)
7d6acca to
4dfb12f
Compare
…t behind proxy; retire Gazebo VNC (FR-F1..F5)
🤖 Automated PR reviewRetires the Gazebo VNC sidecar ( Findings
✅ Recommendation: Approve once the partial-FR-F3 scope is confirmed. |
jmservera
left a comment
There was a problem hiding this comment.
🤖 Automated line-anchored review — see the summary comment for the full findings table.
There was a problem hiding this comment.
Pull request overview
Replaces the retired Gazebo GUI pixel-streaming stack (Xvfb + x11vnc/noVNC) with a headless Gazebo service that exposes scene-state over a WebSocket, plus a self-hosted minimal gzweb client served through the existing single-origin Nginx proxy.
Changes:
- Retire the
simulator+vncservices and introduce a newgazeboservice runninggz sim -splus a gz-launchWebsocketServeron:9002. - Add
/gzweb/(static client) and/gzweb/ws/(WebSocket proxy) routes in Nginx and point the frontend “Simulator” panel to/gzweb/. - Update compose GPU overlays and CI shellcheck discovery to match the new service layout.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| services/vnc/openbox-rc.xml | Removed legacy Openbox config used for the VNC pixel-stream pipeline. |
| services/vnc/entrypoint.sh | Removed legacy VNC sidecar entrypoint (x11vnc + websockify). |
| services/vnc/Dockerfile | Removed legacy VNC sidecar image build. |
| services/simulator/entrypoint.sh | Removed legacy Xvfb + GUI gz sim entrypoint. |
| services/simulator/Dockerfile | Removed legacy simulator image build (Xvfb/Mesa + ros-gz install). |
| services/simulator/config/fuel.yaml | Removed legacy Fuel-disable config (moved under new gazebo service). |
| services/proxy/nginx.conf | Adds /gzweb/ static client + /gzweb/ws/ WebSocket proxy; removes Gazebo /novnc route. |
| services/gazebo/entrypoint.sh | New headless Gazebo entrypoint that starts gz sim -s and gz launch WebsocketServer. |
| services/gazebo/Dockerfile | New Gazebo image definition for Theme F (headless + websocket). |
| services/gazebo/config/websocket.gzlaunch | New gz-launch file enabling the WebsocketServer plugin on port 9002. |
| services/gazebo/config/fuel.yaml | New Fuel-disable config for the gazebo container. |
| services/gazebo/client/index.html | New minimal gzweb client page served under /gzweb/. |
| services/gazebo/client/config.js | New config injection for same-origin /gzweb/ws/ WebSocket URL. |
| services/gazebo/client/app.js | New minimal client logic (handshake + frame header logging; no protobuf decode/render yet). |
| services/frontend/src/lib/panels.js | Routes the built-in simulator panel to /gzweb/ and documents the new transport. |
| services/control/server.js | Updates default service restart allowlist to include gazebo instead of simulator/vnc. |
| docs/specs/01-Init-research.md | Adjusts ROS lifecycle footnote text (currently introduces an internal inconsistency). |
| docs/plans/sim-theme-f-gzweb.md | Adds a Theme F plan stub documenting scope and likely file touchpoints. |
| docs/decisions/ADR-001-ros-distro.md | Updates ADR text (currently contains a typo for the Jazzy fallback). |
| compose.yaml | Replaces simulator+vnc with gazebo, adds gzweb client mount to proxy, updates service allowlist. |
| compose.override.wsl.yaml | Renames overlay target from simulator to gazebo and updates commentary for scene-state streaming. |
| compose.override.intel.yaml | Renames overlay target from simulator to gazebo and updates intent (server compute vs display). |
| compose.override.gpu.yaml | Renames overlay target from simulator to gazebo. |
| .github/workflows/ci.yml | Expands shellcheck to discover all *.sh under services/ and tests/. |
| - Longest support horizon if SPIKE-A passes. | ||
| - If SPIKE-A P2/P4 fail, either install the missing packages from source or set | ||
| `ROS_DISTRO=jazzy` and `GZ_RELEASE=harmonic`. | ||
| `ROS_DISTRO=ionic` and `GZ_RELEASE=harmonic`. |
| [^gz-eol]: Gazebo version and EOL table: <https://raw.githubusercontent.com/gazebosim/docs/master/tools/versions.md>, fetched 2026-07-17. It records Gazebo Classic 11 EOL on 2025-01-25, Gazebo Ionic (`gz-sim10`) stable through 2031-05, and Gazebo Harmonic (`gz-sim8`) stable through 2029-05. | ||
|
|
||
| [^ros-eol]: ROS 2 lifecycle schedule: <https://endoflife.date/ros-2>, last updated 2026-06-01 and accessed 2026-07-17. It records Iron EOL in November 2024, Humble in May 2027, Jazzy in May 2029, Kilted in November 2026, and Lyrical ending in approximately May 2031. REP-2000 had no Lyrical section at the research date. | ||
| [^ros-eol]: ROS 2 lifecycle schedule: <https://endoflife.date/ros-2>, last updated 2026-06-01 and accessed 2026-07-17. It records Iron EOL in November 2024, Humble in May 2027, Jazzy in May 2029, Kilted in November 2026, and Kilted ending in approximately May 2031. REP-2000 had no Kilted section at the research date. |
| # (FR-F5). Under the `simulators` profile so it launches on demand (like | ||
| # turtlesim); the proxy therefore must not hard-depend on it, and /gzweb/ws/ | ||
| # resolves gazebo lazily. On ros_net (DDS discovery, for the Theme E bridge) | ||
| # and web_net (proxy). No host-published ports (INV-04, WP-13). | ||
| gazebo: |
| // Gazebo now streams SCENE STATE to the self-hosted gzweb client (Theme F); | ||
| // the retired noVNC pixel stream is gone. The client connects to the | ||
| // WebsocketServer through the proxy at /gzweb/ws/ (see the gazebo registry | ||
| // entry's panelRoute + transport `gzweb`). | ||
| url: '/gzweb/', |
| This is the minimal UbeROS gzweb client: it establishes the | ||
| WebsocketServer connection through the proxy (<code>/gzweb/ws/</code>) | ||
| and confirms live scene-state frames are flowing. Full Three.js 3D | ||
| rendering is a documented follow-up (see services/gazebo/client/app.js). | ||
| </p> |
- Update CI workflow to install Playwright browsers and dependencies. - Modify acceptance tests to validate gzweb scene-state delivery. - Enhance README with instructions for browser installation. - Introduce script to ensure Playwright browser is installed. - Adjust smoke tests and helper functions for new gzweb endpoints.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 35 out of 35 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (3)
compose.yaml:90
- The Gazebo service comment says it is “Under the
simulatorsprofile” but the service definition has noprofiles:stanza, so it will start unconditionally. This mismatch is confusing for operators and also conflicts with the proxy comment that treats gazebo as on-demand.
# (FR-F5). Under the `simulators` profile so it launches on demand (like
# turtlesim); the proxy therefore must not hard-depend on it, and /gzweb/ws/
# resolves gazebo lazily. On ros_net (DDS discovery, for the Theme E bridge)
docs/decisions/ADR-001-ros-distro.md:36
- The fallback guidance here appears to swap ROS and Gazebo variables:
ROS_DISTROshould be a ROS 2 distro (e.g.jazzy), whileionicis a Gazebo release used byGZ_RELEASE. As written,ROS_DISTRO=ionicis not a valid ROS distro and would break builds.
- If SPIKE-A P2/P4 fail, either install the missing packages from source or set
`ROS_DISTRO=ionic` and `GZ_RELEASE=harmonic`.
docs/specs/01-Init-research.md:1686
- This footnote now claims “REP-2000 had no Kilted section,” but the very next footnote ([^rep2000]) says REP-2000 covered Kilted. It also repeats “Kilted” where the prior text referred to Lyrical, which reads like an accidental edit and makes the lifecycle summary internally inconsistent.
[^ros-eol]: ROS 2 lifecycle schedule: <https://endoflife.date/ros-2>, last updated 2026-06-01 and accessed 2026-07-17. It records Iron EOL in November 2024, Humble in May 2027, Jazzy in May 2029, Kilted in November 2026, and Kilted ending in approximately May 2031. REP-2000 had no Kilted section at the research date.
| 'ros', | ||
| 'simulator', | ||
| 'vnc', | ||
| 'gazebo', | ||
| 'turtlesim', | ||
| 'editor', |
| | Criterion | Spec intent | Machine-testable check | File | | ||
| |-----------|-------------|------------------------|------| | ||
| | S1 | `docker compose up` starts all services without error | The S1 health assertion checks 7 runtime services (`discovery-server`, `ros`, `simulator`, `vnc`, `editor`, `frontend`, `proxy`) report `healthy`; `/healthz` returns `200 "ok"` | `acceptance/s1-stack-health.spec.js` | | ||
| | S1 | `docker compose up` starts all services without error | The S1 health assertion checks 7 runtime services (`discovery-server`, `ros`, `gazebo`, `turtlesim`, `editor`, `frontend`, `proxy`) report `healthy`; `/healthz` returns `200 "ok"` | `acceptance/s1-stack-health.spec.js` | |
| # NOTE: gazebo is deliberately NOT declared as a static upstream. It is an | ||
| # on-demand service (compose `simulators` profile) that may be stopped when the | ||
| # proxy starts. A static `upstream { server gazebo:9002; }` is resolved at |
| # procps provides pgrep for the health check. The gz-launch websocket server | ||
| # plugin is already present in the `-full` image; installed defensively in case | ||
| # a slimmer base is pinned later (the package is a no-op if already satisfied). |
Implements Theme F of the Simulation & Visualization PRD (FR-F1..F5). Lane 2 (Gazebo backend), highest risk (R-1). Headless gz sim -s + WebsocketServer (:9002) streaming scene state; self-hosted minimal gzweb client behind /gzweb/ + /gzweb/ws/; retire Gazebo VNC; target lag < 300ms. Spike-confirmed for Ionic. Plan: docs/plans/sim-theme-f-gzweb.md. Draft.