Skip to content

Refactor viser into panel-based ViserApp architecture#5

Draft
TToTMooN wants to merge 6 commits into
mainfrom
claude/viser-panel-refactor-PR5
Draft

Refactor viser into panel-based ViserApp architecture#5
TToTMooN wants to merge 6 commits into
mainfrom
claude/viser-panel-refactor-PR5

Conversation

@TToTMooN

Copy link
Copy Markdown
Owner

Summary

  • Replace monolithic ViserMonitor with composable ViserApp + panel system
  • Each concern is a small, independent panel (~30-150 lines) that registers via app.add_panel()
  • Adding new visualizations (3D points, policy status, intervention) is now a single-file addition + one line in launch.py

Architecture

ViserApp (single server owner)
├── add_panel(name, panel)  →  panel.attach(server)
├── update(obs)             →  fans out to ObservablePanels
├── close()                 →  detach all
│
├── CameraPanel         — sidebar image thumbnails
├── URDFPanel           — 3D robot visualization
├── RecordingPanel      — Start/Stop recording button
├── SessionPanel        — data collection controls + TriggerSource
└── LoopStatusPanel     — Hz/step count

Key changes

  • limb/visualization/app.py — ViserApp coordinator + ViserPanel/ObservablePanel protocols
  • limb/visualization/panels/ — 5 focused panel classes split from ViserMonitor
  • limb/envs/launch.py — declarative panel registration replaces conditional ViserMonitor wiring
  • limb/agents/teleoperation/yam_viser_agent.py — uses CameraPanel directly
  • limb/visualization/viser_monitor.py — kept as backward-compat wrapper

Test plan

  • Teleop with viser agent: uv run limb/envs/launch.py --config_path configs/yam_viser_bimanual.yaml
  • Teleop with GELLO: camera feeds + URDF + recording button in viser sidebar
  • Data collection: session panel buttons + keyboard trigger both work
  • Verify ViserMonitor backward compat (any code creating ViserMonitor directly still works)

Note: This PR depends on PR #4 — rebase after PR4 merges.

https://claude.ai/code/session_01BNWyGBKJRszYAY7db6eYMB

claude added 6 commits March 25, 2026 04:15
Inspired by comparing with Raiden's data collection toolkit:
- Unified `limb` CLI entry point with subcommands (teleop, record,
  devices, replay, convert, visualize) — replaces remembering
  individual script paths
- Device discovery (`limb devices`) enumerates RealSense, ZED,
  CAN interfaces, Dynamixel serial, foot pedals, and SpaceMouse
- Motion replay (`limb replay`) streams recorded joint commands
  back to hardware for verifying recording quality before conversion
- Incomplete episode detection: RECORDING_IN_PROGRESS marker tracks
  in-flight recordings; auto-cleaned on next startup
- Depth recording: EpisodeRecorder now captures depth video when
  cameras provide depth data
- Converter skips incomplete/corrupted episodes automatically

https://claude.ai/code/session_01BNWyGBKJRszYAY7db6eYMB
- Fix P1: episode cleanup race condition — marker now stores PID,
  only removes episodes whose owner process is dead
- Fix P1: move convert/visualize logic into limb.data package so
  CLI imports work in wheel installs (scripts become thin wrappers)
- Fix P2: validate empty timestamps in replay before accessing indices
- Add limb.data.convert_webdataset — WebDataset .tar shard export
  with Welford online stats, configurable image resize/quality
- Add limb.data.upload — S3/GCS/HuggingFace upload with URI scheme
  (s3://, gs://, hf://) and ~/.config/limb/storage.yaml config
- Add shared limb.data.episode_utils for episode discovery/loading
- Update CLI: convert-lerobot, convert-webdataset, upload subcommands

https://claude.ai/code/session_01BNWyGBKJRszYAY7db6eYMB
Replaces the Rich terminal TUI (StatusDisplay) when a ViserMonitor is
active. Renders session status and interactive buttons in the viser
sidebar instead of fighting with terminal output.

- ViserSessionPanel implements both display interface (update_loop,
  update_session) and TriggerSource protocol (get_signal) so GUI
  buttons feed signals into the session alongside keyboard/pedal
- Buttons: Start/Stop, Mark Success, Discard, Quit Session
- Composed with existing trigger via CompositeTrigger (first wins)
- launch.py auto-selects viser panel vs Rich TUI based on monitor
- For YamViserAgent + collection, creates lightweight standalone
  monitor (no URDF) so session panel has a viser server to attach to

https://claude.ai/code/session_01BNWyGBKJRszYAY7db6eYMB
Replace monolithic ViserMonitor with a composable panel system:

- ViserApp: central coordinator that owns a ViserServer and provides
  add_panel()/update()/close() API for declarative panel registration
- ViserPanel protocol: attach(server)/detach() interface for panels
- ObservablePanel protocol: adds update(obs) for control loop data

Split ViserMonitor into focused panels:
- CameraPanel: camera feed thumbnails in sidebar (~40 lines)
- URDFPanel: 3D robot visualization in viewport (~80 lines)
- RecordingPanel: Start/Stop recording button (~90 lines)
- SessionPanel: data collection controls + TriggerSource (~150 lines)
- LoopStatusPanel: Hz/step count display (~30 lines)

Update launch.py to declarative panel registration:
  app = ViserApp()
  app.add_panel("cameras", CameraPanel())
  app.add_panel("urdf", URDFPanel(bimanual=True))
  if session: app.add_panel("session", SessionPanel())

Keep ViserMonitor as backward-compat wrapper for external code.
Update YamViserAgent to use CameraPanel directly.

Adding new panels (3D points, policy viz, intervention) is now a
single-file addition + one line in launch.py.

https://claude.ai/code/session_01BNWyGBKJRszYAY7db6eYMB
- Document threading model in ViserApp docstring: main thread calls
  update(), viser server thread fires on_click callbacks
- RecordingPanel now implements ObservablePanel (update(obs)) instead
  of requiring a get_latest_rgb callback — extracts RGB from obs
  directly, fixing the bug where frames were never written in the
  direct-panel path
- RecordingPanel.update() uses double-checked locking: fast path
  skips when not recording, extracts RGB outside lock, then writes
  inside lock
- Panel registration order matters: CameraPanel before RecordingPanel
  ensures RGB is extracted before frames are written
- Remove unused Callable import and stale get_latest_rgb coupling
- Simplify ViserMonitor backward-compat wrapper

https://claude.ai/code/session_01BNWyGBKJRszYAY7db6eYMB
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