Skip to content

Add physical-style xArm6 WorldBelief replay blueprint - #3273

Draft
jhengyilin wants to merge 10 commits into
mainfrom
agent/xarm6-worldbelief-replay
Draft

Add physical-style xArm6 WorldBelief replay blueprint#3273
jhengyilin wants to merge 10 commits into
mainfrom
agent/xarm6-worldbelief-replay

Conversation

@jhengyilin

Copy link
Copy Markdown
Contributor

Summary

Adds hardware-free xArm6 WorldBelief replay blueprints that replace only the physical camera/TF source while keeping the same live pipeline:

recorded RGB-D + TF (timed replay)
    -> normal pubsub streams
    -> WorldBeliefRecorder (fresh timestamped session DB)
    -> WorldBeliefModule scan / recall
    -> Rerun + MCP

This is intentionally not global --replay mode. The source recording is played into the ordinary live Recorder, so scan only sees evidence that has reached the replay cursor, just as it only sees evidence recorded so far on the physical robot.

Blueprints

  • xarm6-worldbelief-replay-kitchen
  • xarm6-worldbelief-replay-stationery
  • xarm6-worldbelief-replay for a custom recording supplied through --replay-db

The two named variants resolve/download the PR #3255 Git LFS datasets automatically.

Direct test

# Starts Rerun, Recorder, WorldBelief, MCP, and 1x timed playback in the background.
uv run dimos run xarm6-worldbelief-replay-kitchen -d

uv run dimos mcp call replay_status
uv run dimos mcp call scan \
  -a prompt='["coke can", "water bottle", "banana", "orange", "green tea bottle", "tissue paper"]'
uv run dimos mcp call recall -a text="coke can"

uv run dimos stop

Stationery:

uv run dimos run xarm6-worldbelief-replay-stationery -d
uv run dimos mcp call scan \
  -a prompt='["red marker", "post it", "black pen", "book", "black tape"]'

Custom recording:

uv run dimos --replay-db /absolute/path/to/session.db \
  run xarm6-worldbelief-replay -d

Playback controls:

uv run dimos mcp call replay_pause
uv run dimos mcp call replay_status
uv run dimos mcp call replay_resume

Optional startup controls use the replay source instance config:

uv run dimos run xarm6-worldbelief-replay-kitchen -d \
  -o worldbelief_replay_source.speed=2.0 \
  -o worldbelief_replay_source.seek=165.0

Higher speeds trade fidelity for turnaround because RGB-D decoding, TF publication, Rerun, and re-recording still happen live.

Fidelity to the physical blueprint

Kept identical:

  • WorldBeliefRecorder and its fresh timestamped session DB
  • WorldBeliefModule models and sampling configuration
  • scan/recall MCP skills
  • persistent DINO gallery and CLIP history DB behavior
  • raw RGB/depth/TF Rerun feed
  • established detections and aggregate point cloud after scan

Replaced:

  • RealSense and xArm TF publication are replaced by their recorded streams
  • manipulation hardware/coordinator are omitted

Playback starts from on_system_modules, after Recorder, WorldBelief model warmup, Rerun, and MCP are ready, so startup does not consume the beginning of the recording while models load.

Validation

  • Python syntax/compile checks pass for the changed Python files.
  • Added unit coverage for explicit DB and named-dataset-directory resolution.
  • Full GPU/LFS end-to-end playback was not run in this execution environment.

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
3674 1 3673 92
View the full list of 1 ❄️ flaky test(s)
dimos.e2e_tests.test_dimsim_spatial_memory::test_go_to_the_bed

Flake rate in main: 16.90% (Passed 118 times, Failed 24 times)

Stack Traces | 382s run time
lcm_spy = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x76f9108dff20>
start_blueprint = <function start_blueprint.<locals>.set_name_and_start at 0x76f9bd3e68e0>
human_input = <function human_input.<locals>.send_human_input at 0x76f9bd3e72e0>
dim_sim = <dimos.e2e_tests.dim_sim_client.DimSimClient object at 0x76f9bd68ac00>
explore_house = <function explore_house.<locals>.explore at 0x76f9bd3e7920>

    @pytest.mark.self_hosted_large
    def test_go_to_the_bed(lcm_spy, start_blueprint, human_input, dim_sim, explore_house) -> None:
        start_blueprint(
            "run",
            "unitree-go2-agentic",
            simulator="dimsim",
        )
        lcm_spy.save_topic(".../McpClient/on_system_modules/res")
        lcm_spy.wait_for_saved_topic(".../McpClient/on_system_modules/res", timeout=1200.0)
    
        explore_house()
    
        human_input("go to the bed")
    
>       lcm_spy.wait_until_odom_position(-3.567, -1.332, threshold=2, timeout=180)

dim_sim    = <dimos.e2e_tests.dim_sim_client.DimSimClient object at 0x76f9bd68ac00>
explore_house = <function explore_house.<locals>.explore at 0x76f9bd3e7920>
human_input = <function human_input.<locals>.send_human_input at 0x76f9bd3e72e0>
lcm_spy    = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x76f9108dff20>
start_blueprint = <function start_blueprint.<locals>.set_name_and_start at 0x76f9bd3e68e0>

dimos/e2e_tests/test_dimsim_spatial_memory.py:32: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
dimos/e2e_tests/lcm_spy.py:167: in wait_until_odom_position
    self.wait_for_message_result(
        predicate  = <function LcmSpy.wait_until_odom_position.<locals>.predicate at 0x76f9bd3e7ce0>
        self       = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x76f9108dff20>
        threshold  = 2
        timeout    = 180
        x          = -3.567
        y          = -1.332
dimos/e2e_tests/lcm_spy.py:153: in wait_for_message_result
    wait_until(
        event      = <threading.Event at 0x76f9bd668740: unset>
        fail_message = 'Failed to get to position x=-3.567, y=-1.332'
        listener   = <function LcmSpy.wait_for_message_result.<locals>.listener at 0x76f9bd3e7b00>
        predicate  = <function LcmSpy.wait_until_odom_position.<locals>.predicate at 0x76f9bd3e7ce0>
        self       = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x76f9108dff20>
        timeout    = 180
        topic      = '/odom#geometry_msgs.PoseStamped'
        type       = <class 'dimos.msgs.geometry_msgs.PoseStamped.PoseStamped'>
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

predicate = <bound method Event.is_set of <threading.Event at 0x76f9bd668740: unset>>

    def wait_until(
        predicate: Callable[[], bool],
        *,
        timeout: float,
        interval: float = 0.1,
        message: str | None = None,
    ) -> None:
        """Poll ``predicate`` until it returns truthy or ``timeout`` elapses."""
        deadline = time.monotonic() + timeout
        while time.monotonic() < deadline:
            if predicate():
                return
            time.sleep(interval)
>       raise TimeoutError(message or f"Timed out after {timeout}s waiting for condition")
E       TimeoutError: Failed to get to position x=-3.567, y=-1.332

deadline   = 1816837.145042045
interval   = 0.1
message    = 'Failed to get to position x=-3.567, y=-1.332'
predicate  = <bound method Event.is_set of <threading.Event at 0x76f9bd668740: unset>>
timeout    = 180

.../utils/testing/waiting.py:35: TimeoutError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

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