Skip to content

feat(viser): add scan-from-here and saved viewpoints - #3836

Draft
mustafab0 wants to merge 1 commit into
mainfrom
feat/grasp-demo-viser-scan-viewpoints
Draft

feat(viser): add scan-from-here and saved viewpoints#3836
mustafab0 wants to merge 1 commit into
mainfrom
feat/grasp-demo-viser-scan-viewpoints

Conversation

@mustafab0

@mustafab0 mustafab0 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add per-client named Viser camera viewpoints with save and jump controls
  • route debounced scan-from-here requests through ManipulationOperator and typed module-to-OSR request/response streams
  • refresh planner obstacles after each completed scan and show detection/total counts in the panel
  • enable both controls for xarm-room-sim

@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.12069% with 67 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 58.25% 37 Missing and 6 partials ⚠️
dimos/manipulation/manipulation_module.py 56.00% 19 Missing and 3 partials ⚠️
...rception/experimental/object_scene_registration.py 66.66% 2 Missing ⚠️
@@            Coverage Diff             @@
##             main    #3836      +/-   ##
==========================================
- Coverage   77.58%   77.57%   -0.02%     
==========================================
  Files        1315     1315              
  Lines      124697   124929     +232     
  Branches    10867    10882      +15     
==========================================
+ Hits        96748    96915     +167     
- Misses      24816    24873      +57     
- Partials     3133     3141       +8     
Flag Coverage Δ
OS-ubuntu-24.04-arm 74.20% <47.28%> (-0.03%) ⬇️
OS-ubuntu-latest 74.77% <71.12%> (-0.01%) ⬇️
Py-3.10 74.77% <71.12%> (-0.01%) ⬇️
Py-3.11 74.77% <71.12%> (-0.01%) ⬇️
Py-3.12 74.77% <71.12%> (-0.01%) ⬇️
Py-3.13 74.77% <71.12%> (-0.01%) ⬇️
Py-3.14 74.78% <71.12%> (-0.01%) ⬇️
Py-3.14t 74.77% <71.12%> (-0.01%) ⬇️
SelfHosted-Large 30.20% <17.67%> (-0.02%) ⬇️
SelfHosted-Linux 34.71% <17.67%> (-0.04%) ⬇️

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

Files with missing lines Coverage Δ
dimos/manipulation/conftest.py 100.00% <100.00%> (ø)
dimos/manipulation/test_manipulation_unit.py 99.61% <100.00%> (+0.01%) ⬆️
dimos/manipulation/visualization/operator.py 77.72% <100.00%> (+0.22%) ⬆️
dimos/manipulation/visualization/test_operator.py 100.00% <100.00%> (ø)
dimos/manipulation/visualization/viser/config.py 100.00% <100.00%> (ø)
dimos/manipulation/visualization/viser/test_gui.py 98.58% <100.00%> (+0.26%) ⬆️
...s/robot/manipulators/xarm/blueprints/simulation.py 100.00% <ø> (ø)
...rception/experimental/object_scene_registration.py 63.63% <66.66%> (+0.06%) ⬆️
dimos/manipulation/manipulation_module.py 67.53% <56.00%> (-0.70%) ⬇️
dimos/manipulation/visualization/viser/gui.py 34.28% <58.25%> (+2.82%) ⬆️

... and 3 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.

@greptile-apps

greptile-apps Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This change adds scan-from-here controls, planner obstacle refreshes from scan results, and saved camera viewpoints in the Viser panel.

A delayed result from a timed-out scan can be applied to a later scan and refresh the planning world using an earlier camera pose. Saved viewpoints are shared across connected clients, allowing one client to overwrite a name and cause another client to restore that camera position. The scan timeout path can also permit the backend operation to continue beyond the panel timeout, potentially refreshing obstacles after the panel enters a failed state and prevents retries.

T-Rex validation blocked

The late-completion timing path for the scan timeout mismatch could not be conclusively executed because the available validation tool execution capacity was exhausted after a scheduler-sensitive timing attempt. Category: tool. Missing item: additional validation execution capacity.

Confidence Score: 2/5

The change should not merge until scan responses are correlated, scan completion is bounded by one operation deadline or cancellation mechanism, and saved viewpoints are isolated per client.

Two failures were reproduced with executable harnesses against the reviewed behavior. The remaining timeout lifecycle failure is supported by the independent backend and UI time budgets, but its exact late-refresh timing could not be conclusively executed.

Files Needing Attention: dimos/manipulation/manipulation_module.py needs request correlation and a single end-to-end scan deadline; dimos/manipulation/visualization/viser/gui.py needs client-scoped viewpoint state and timeout recovery.

T-Rex T-Rex Logs

What T-Rex did

  • Ran a focused executable stale-scan reproduction script to validate a P1 finding, and captured logs showing a timed-out first scan, followed by delayed response queueing, and a later scan that consumed the old-pose response to refresh obstacles.
  • Executed two-client viewpoint reproducer and collected outputs to verify cross-client interaction and the reproducibility of the observed behavior.
  • General contract validation identified that the late-result scan timeout scenario could not be conclusively completed due to validation execution capacity being exhausted, and noted the need for additional validation capacity.
  • Documented the scan result flow in code and GUI: how the queue entry is replaced, how the drain/publish sequence works, and how cross-client viewpoint repro saved and restored a shared entry.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (2)

  1. General comment

    P1 Timed-out scan response can satisfy a later scan request

    • Bug
      • scan_from_here uses a shared one-entry response queue without a request ID, timestamp cutoff, or generation counter. A response from a scan that has already timed out can arrive after the next call drains the queue and publishes its request; the next call accepts it as its own response and refreshes planning obstacles.
    • Cause
      • Lines 1367-1375 only clear the queue before publishing and then take the next arriving response. handle_scan_results at lines 1337-1344 retains only the latest incoming response but has no way to associate it with a specific published request.
    • Fix
      • Add end-to-end scan correlation (for example, a monotonically increasing request ID included in both request and response) and wait only for the matching response. If protocol changes are not possible, record a request generation/monotonic dispatch cutoff atomically with publication and reject responses not demonstrably produced after that dispatch; correlation IDs remain the robust fix.

    T-Rex Ran code and verified through T-Rex

  2. General comment

    P1 Scan operation has a two-timeout backend budget but only a one-timeout GUI budget

    • Bug
      • The synchronous scan first waits up to timeout for a result and, after a result arrives, waits up to another timeout for planning objects. The Viser GUI permits only scan_timeout + 1.0 seconds. When the result arrives late and planning objects arrive during the second backend wait, the GUI worker can time out and set the panel to FAILED while the backend operation continues and refreshes obstacles afterward. FAILED fails the scan-submission guard (action_status != IDLE), blocking retry scans and plans until recovery.
    • Cause
      • At manipulation_module.py:1379, _wait_for_scan_objects is passed a fresh time.monotonic() + timeout rather than a deadline derived from the original scan start. At gui.py:511, the operation timeout assumes a single scan timeout. At state.py:354-359, the timeout does not cancel the operation thread, permitting late state-changing completion.
    • Fix
      • Use one end-to-end deadline in scan_from_here (capture it before publishing, and pass that same deadline to both waits), or increase and document the GUI timeout to cover the full backend contract. Prefer cooperative cancellation/token propagation so a GUI timeout prevents late refresh_obstacles; ensure a timed-out scan cannot leave the panel permanently FAILED or provide an explicit retry/reset transition.

    T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "feat(viser): add scans and saved viewpoi..." | Re-trigger Greptile

Comment on lines +1373 to +1375
self.scan_requests.publish(normalized)
try:
result = self._scan_result_queue.get(timeout=timeout)

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.

P1 Scan responses lack correlation

If a timed-out scan responds after a later scan drains the shared queue, the later call accepts that stale response without checking request identity or timestamp, causing planner obstacles to be refreshed from the earlier camera pose.

Artifacts

Focused executable stale scan response reproduction script

  • This script AST-loads and executes the current target method bodies, simulates a timeout and delayed callback, and proves that the later scan accepts the earlier response.

Timed-out first scan followed by delayed response queueing

  • The executed before run shows the first scan timing out and its delayed old-pose response subsequently occupying the shared queue.

Later scan accepts stale old-pose response and refreshes obstacles

  • The executed after run shows the new-pose request accepting `old-pose-response` without a fresh response and performing one obstacle refresh, proving the bug.

View artifacts

T-Rex Ran code and verified through T-Rex

except queue.Empty as error:
raise TimeoutError(f"Scan timed out after {timeout:.1f}s") from error
expected_ids = {str(detection.id) for detection in result.detections if detection.id}
self._wait_for_scan_objects(expected_ids, time.monotonic() + timeout)

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.

P1 Scan timeout leaves detached work

When the result consumes most of scan_timeout and object propagation takes over one additional second, the GUI times out while this fresh timeout remains active; its uncancelled operation can later refresh the planning world after the panel reports failure, while the panel remains in FAILED and blocks further scans and plans.

Comment on lines +443 to +451
self._viewpoints[name] = CameraViewpoint(
position=self._camera_vector(camera.position),
look_at=self._camera_vector(camera.look_at),
up_direction=self._camera_vector(camera.up_direction),
fov=float(camera.fov),
)
choices = self._handles.get("viewpoint_choices")
self._set_optional_handle_attr(choices, "options", list(self._viewpoints))
self._set_optional_handle_attr(choices, "value", name)

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.

P1 Viewpoints cross client boundaries

If multiple clients use this panel, saving writes one client's camera into the shared _viewpoints dictionary and shared dropdown, so another client can overwrite or restore that entry and have its camera jump to a viewpoint it did not save.

Artifacts

Executed two-client viewpoint reproducer source

  • This Python harness imports the production GUI class and invokes its save and restore callbacks for two distinct clients using the same viewpoint name, demonstrating the client-crossing path; takeaway.

Executed two-client viewpoint reproducer output

  • This command output records a successful execution where client B overwrote `shared-entry` and client A restored B’s camera position with `cross_client_jump_reproduced= True`; takeaway.

View artifacts

T-Rex Ran code and verified through T-Rex

@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Aug 31, 2026
@mustafab0
mustafab0 force-pushed the feat/grasp-demo-viser-scan-viewpoints branch from a60a617 to 058d935 Compare August 31, 2026 21:00
@github-actions github-actions Bot removed the ready-to-merge Required CI checks have passed on this PR label Aug 31, 2026
@mustafab0
mustafab0 changed the base branch from feat/grasp-demo-viser-ground-truth to main August 31, 2026 21:00
@mustafab0
mustafab0 marked this pull request as draft August 31, 2026 21:03
@mustafab0 mustafab0 closed this Aug 31, 2026
@mustafab0 mustafab0 reopened this Aug 31, 2026
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.

1 participant