Skip to content

[Sim Theme F] Gazebo native web visualization (gzweb)#27

Open
jmservera wants to merge 13 commits into
mainfrom
jmservera/sim-theme-f-gzweb
Open

[Sim Theme F] Gazebo native web visualization (gzweb)#27
jmservera wants to merge 13 commits into
mainfrom
jmservera/sim-theme-f-gzweb

Conversation

@jmservera

Copy link
Copy Markdown
Owner

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.

- 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.
@jmservera
jmservera force-pushed the jmservera/sim-theme-f-gzweb branch from 7d6acca to 4dfb12f Compare July 21, 2026 11:00
@jmservera
jmservera changed the base branch from jmservera/gazebo-ros-integration to jmservera/sim-theme-c-turtlesim July 21, 2026 11:00
…t behind proxy; retire Gazebo VNC (FR-F1..F5)
@jmservera

Copy link
Copy Markdown
Owner Author

🤖 Automated PR review

Retires the Gazebo VNC sidecar (services/simulator + services/vnc deleted) and adds a headless services/gazebo (gz sim -s + gz-launch WebsocketServer) with a client and /gzweb/ + /gzweb/ws/ proxy routes. Base: #24.

Findings

Severity Location Finding
🟡 Medium services/gazebo/client/app.js This PR ships a scene-state diagnostic client (connection + frame/throughput readout), not the Three.js 3D render FR-F3 implies. It's clearly documented as a follow-up (and #25 delivers the real Vite-bundled gzweb render). Please confirm with the PM that #27 is acceptable as a partial FR-F3, or fold the render into this PR's acceptance criteria.
🟢 Low services/gazebo/client/app.js (parseHeader) Only the first 256 bytes are decoded for the text header; a pathological topic name >256 bytes would mis-parse. Extremely unlikely, but note it.

entrypoint.sh signal handling is correct (trap + wait -n, no exec-after-trap). Proxy-only exposure, max_connections 10, Fuel disabled — good security posture. Lazy-DNS /gzweb/ws/ route mirrors the turtlesim pattern.

Recommendation: Approve once the partial-FR-F3 scope is confirmed.

@jmservera jmservera left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated line-anchored review — see the summary comment for the full findings table.

Comment thread services/gazebo/client/app.js
Base automatically changed from jmservera/sim-theme-c-turtlesim to main July 23, 2026 07:50
@jmservera
jmservera marked this pull request as ready for review July 23, 2026 09:31
Copilot AI review requested due to automatic review settings July 23, 2026 09:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 + vnc services and introduce a new gazebo service running gz sim -s plus a gz-launch WebsocketServer on :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.
Comment thread compose.yaml
Comment on lines +88 to +92
# (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:
Comment on lines +57 to +61
// 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/',
Comment on lines +91 to +95
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.
Copilot AI review requested due to automatic review settings July 23, 2026 10:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 simulators profile” but the service definition has no profiles: 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_DISTRO should be a ROS 2 distro (e.g. jazzy), while ionic is a Gazebo release used by GZ_RELEASE. As written, ROS_DISTRO=ionic is 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.

Comment thread tests/helpers/stack.js
Comment on lines 12 to 15
'ros',
'simulator',
'vnc',
'gazebo',
'turtlesim',
'editor',
Comment thread tests/README.md
| 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` |
Comment thread services/proxy/nginx.conf
Comment on lines +14 to +16
# 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
Comment on lines +23 to +25
# 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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants