Skip to content

feat: add viser as new manipulation vis backend#2475

Open
TomCC7 wants to merge 25 commits into
mainfrom
cc/feat/viser-vis-rework
Open

feat: add viser as new manipulation vis backend#2475
TomCC7 wants to merge 25 commits into
mainfrom
cc/feat/viser-vis-rework

Conversation

@TomCC7

@TomCC7 TomCC7 commented Jun 12, 2026

Copy link
Copy Markdown
Member

Closes #2412 and supersedes #2413

Adds Viser as a manipulation planning visualizer and rewires manipulation visualization config around a single validated visualization field. The new visualizer is more feature-rich than the original drake-bundled meshcat vis and provides a moveit style UI for plan/preview/execute.

image

Main changes:

  • Add in-process Viser manipulation visualization: runtime, scene rendering, GUI panel, adapter, animation, and tests.
  • Replace loose visualization_backend / visualization_options config with a Pydantic discriminated visualization config for none, meshcat, and viser.
  • Clean up spec creation so manipulation startup creates:
    1. WorldSpec
    2. PlanningSpecs
    3. optional VisualizationSpec
  • Keep Meshcat as an embedded Drake-world visualizer and create Viser as a separate visualization backend.
  • Sync planning-scene metadata to external visualizers so Viser can initialize robot visuals without Viser-specific hooks in WorldMonitor.
  • Include viser[urdf] in the manipulation extra and move Viser usage docs into the manipulation docs.

Notes

  • Viser panel execution is opt-in via allow_plan_execute.
  • The earlier set_planning_target / clear_planning_target VisualizationSpec API was reverted; target controls remain internal to the Viser GUI/scene.

How to Test

uv run dimos run xarm7-planner-coordinator \
  -o manipulationmodule.visualization.backend=viser \
  -o manipulationmodule.visualization.allow_plan_execute=true

Contributor License Agreement

  • I have read and approved the CLA.

@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.42439% with 545 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
dimos/manipulation/visualization/viser/gui.py 65.44% 150 Missing and 48 partials ⚠️
dimos/manipulation/visualization/viser/adapter.py 60.00% 64 Missing and 16 partials ⚠️
dimos/manipulation/visualization/viser/scene.py 78.12% 48 Missing and 15 partials ⚠️
...mos/manipulation/visualization/viser/visualizer.py 43.42% 39 Missing and 4 partials ⚠️
...anipulation/planning/monitor/test_world_monitor.py 71.54% 35 Missing ⚠️
dimos/manipulation/visualization/test_factory.py 70.09% 32 Missing ⚠️
dimos/manipulation/visualization/viser/state.py 87.71% 16 Missing and 12 partials ⚠️
dimos/manipulation/visualization/viser/runtime.py 42.55% 27 Missing ⚠️
...imos/manipulation/visualization/viser/animation.py 74.46% 6 Missing and 6 partials ⚠️
dimos/manipulation/visualization/viser/theme.py 87.09% 6 Missing and 2 partials ⚠️
... and 6 more
Flag Coverage Δ
OS-ubuntu-24.04-arm 64.27% <77.92%> (+0.42%) ⬆️
OS-ubuntu-latest 65.09% <77.92%> (+0.39%) ⬆️
Py-3.10 65.08% <77.92%> (+0.38%) ⬆️
Py-3.11 65.08% <77.92%> (+0.39%) ⬆️
Py-3.12 65.08% <77.92%> (+0.38%) ⬆️
Py-3.13 65.09% <77.92%> (+0.39%) ⬆️
Py-3.14 65.09% <77.92%> (+0.38%) ⬆️
Py-3.14t 65.08% <77.92%> (+0.38%) ⬆️
SelfHosted-Large 30.17% <26.59%> (?)
SelfHosted-Linux 37.87% <27.51%> (-0.41%) ⬇️
SelfHosted-macOS 36.68% <27.51%> (-0.37%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
dimos/manipulation/blueprints.py 100.00% <ø> (ø)
...mos/manipulation/planning/monitor/world_monitor.py 54.28% <100.00%> (+2.24%) ⬆️
dimos/manipulation/planning/spec/models.py 98.14% <100.00%> (+0.18%) ⬆️
dimos/manipulation/planning/spec/protocols.py 100.00% <100.00%> (ø)
dimos/manipulation/test_manipulation_module.py 98.62% <ø> (ø)
dimos/manipulation/test_manipulation_unit.py 100.00% <100.00%> (ø)
dimos/manipulation/visualization/config.py 100.00% <100.00%> (ø)
dimos/robot/manipulators/a750/blueprints.py 100.00% <ø> (ø)
dimos/robot/manipulators/openarm/blueprints.py 100.00% <ø> (ø)
dimos/robot/manipulators/piper/blueprints.py 100.00% <ø> (ø)
... and 17 more

... and 24 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@TomCC7 TomCC7 force-pushed the cc/feat/viser-vis-rework branch from 283a6da to 9087b4d Compare June 12, 2026 20:35
@TomCC7 TomCC7 changed the title WIP: feat/viser-manip-vis feat: add viser as new manipulation vis backend Jun 12, 2026
@TomCC7 TomCC7 mentioned this pull request Jun 12, 2026
1 task
@TomCC7 TomCC7 marked this pull request as ready for review June 12, 2026 20:51
@TomCC7 TomCC7 requested a review from mustafab0 as a code owner June 12, 2026 20:51
@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds Viser as a new manipulation visualization backend and replaces the old visualization_backend/visualization_options config pair with a single Pydantic-discriminated visualization field supporting none, meshcat, and viser.

  • New Viser backend: Adds ViserManipulationVisualizer with an in-process server, scene graph (current/target/preview ghosts), an operator control panel (Plan \u2192 Preview \u2192 Execute), and a TargetEvaluationWorker/OperationWorker threading model for non-blocking UI interactions.
  • Config refactor: ManipulationVisualizationConfig is now a discriminated union; all blueprints migrated from enable_viz=True to visualization={\"backend\": \"meshcat\"}; WorldMonitor is restructured to accept an externally-created WorldSpec and a late-bound VisualizationSpec.
  • Scene sync: A new PlanningSceneInfo snapshot and sync_visualization_scene() flow passes robot metadata to external visualizers (Viser) after world finalization, without requiring Viser-specific hooks in WorldMonitor.

Confidence Score: 5/5

Safe to merge; the only findings are cosmetic improvements to the fallback path of the adapter and a dead config field.

The new Viser backend is well-structured: server lifecycle, scene management, GUI panel, and threading model are cleanly separated. The initialization ordering is correct. Previously identified state-race issues in the GUI have been addressed. The only noteworthy items are a dead preview_request_timeout config field, a duplicate FK call in the fallback evaluation path, and a semantically misleading success=True for collision returns in the same fallback path, none of which affect the happy path.

dimos/manipulation/visualization/viser/adapter.py - the evaluate_joint_target fallback path has two minor issues worth cleaning up.

Important Files Changed

Filename Overview
dimos/manipulation/visualization/viser/adapter.py New in-process adapter bridging Viser callbacks to manipulation internals; two minor issues in the fallback evaluate_joint_target path (success=True for collisions, double get_ee_pose call).
dimos/manipulation/visualization/viser/gui.py New operator panel GUI; previously flagged issues with _finish_operation on the plan early-exit and the OperationWorker timeout have been addressed in this version.
dimos/manipulation/visualization/viser/state.py TargetEvaluationWorker and OperationWorker use a _submit_lock around the drain-then-put pattern, addressing the previously identified queue race; PanelState is mutated from multiple threads without locks but is mitigated by the GIL and sequence-ID checks.
dimos/manipulation/visualization/viser/config.py Viser config model; preview_request_timeout is defined but never consumed by OperationWorker, making it dead configuration.
dimos/manipulation/visualization/viser/visualizer.py Top-level Viser visualizer entry point; initialization, scene sync, and cleanup are well-structured with proper exception handling and resource cleanup.
dimos/manipulation/visualization/config.py New discriminated union config type for visualization backends; clean Pydantic model design.
dimos/manipulation/manipulation_module.py Migrated from enable_viz to the new visualization config; initialization sequence is correct.
dimos/manipulation/planning/monitor/world_monitor.py Refactored to accept an externally-created WorldSpec; adds planning_scene_info() and sync_visualization_scene() to push metadata to external visualizers without coupling WorldMonitor to Viser.
dimos/manipulation/planning/world/drake_world.py Adds a no-op initialize_scene() to satisfy the updated VisualizationSpec protocol; correct since Meshcat reads state directly from Drake.
dimos/manipulation/visualization/factory.py New visualization factory; cleanly dispatches on discriminated union type with a safe fallback assertion.

Sequence Diagram

sequenceDiagram
    participant MM as ManipulationModule
    participant WM as WorldMonitor
    participant VF as VisualizationFactory
    participant VV as ViserManipulationVisualizer
    participant GUI as ViserPanelGui
    participant ADP as InProcessViserAdapter

    MM->>WM: create_planning_specs()
    MM->>VF: create_manipulation_visualization(config, world, world_monitor, self)
    VF->>VV: ViserManipulationVisualizer(...)
    VV->>ADP: InProcessViserAdapter(world_monitor, manipulation_module)
    VV->>GUI: ViserPanelGui(server, adapter, config, scene)
    GUI->>GUI: start() - refresh() - WAITING_FOR_ROBOT
    VF-->>MM: visualization

    MM->>WM: add_robot(config) x N
    MM->>WM: finalize()
    MM->>WM: set_visualization(visualization)
    MM->>WM: sync_visualization_scene()
    WM->>VV: initialize_scene(PlanningSceneInfo)
    VV->>GUI: refresh() - READY

    Note over GUI,ADP: User interaction
    GUI->>ADP: evaluate_joint_target(joints, robot_name)
    ADP->>WM: is_state_valid(robot_id, target)
    ADP-->>GUI: result

    GUI->>ADP: plan_to_joints(target, robot_name)
    ADP->>MM: plan_to_joints(joints)
    MM-->>GUI: bool

    GUI->>ADP: preview_path(robot_name)
    ADP->>MM: preview_path()
    MM->>VV: animate_path(robot_id, path, duration)
    VV->>VV: PreviewAnimator.animate() blocking
Loading

Reviews (5): Last reviewed commit: "fix: make viser theme test tolerate fall..." | Re-trigger Greptile

Comment thread dimos/manipulation/visualization/viser/gui.py
Comment thread dimos/manipulation/visualization/viser/gui.py
Comment thread dimos/manipulation/visualization/viser/state.py Outdated
Comment thread dimos/manipulation/manipulation_module.py Outdated
@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Jun 12, 2026
@github-actions github-actions Bot removed the ready-to-merge Required CI checks have passed on this PR label Jun 12, 2026
@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Jun 12, 2026
@github-actions github-actions Bot removed the ready-to-merge Required CI checks have passed on this PR label Jun 15, 2026
@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Required CI checks have passed on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Viser Manipulation Control Panel

1 participant