Skip to content

Add Pirate Go2 vision-guided object interaction hackathon submission#2290

Open
0xmandy wants to merge 4 commits into
dimensionalOS:mainfrom
0xmandy:real-go2-smoke-test
Open

Add Pirate Go2 vision-guided object interaction hackathon submission#2290
0xmandy wants to merge 4 commits into
dimensionalOS:mainfrom
0xmandy:real-go2-smoke-test

Conversation

@0xmandy
Copy link
Copy Markdown

@0xmandy 0xmandy commented May 28, 2026

Summary

  • Add hackathon submission pointer for Pirate — YOLO vision-guided Go2 object interaction
  • Link project repo, decision traces, sensor stream profile, and demo video
  • Document DimOS boundary: DimOS observes and executes; vision-servoing and trace layer live in external repo
  • No DimOS core files modified by this submission

Submission Links

What it demonstrates

  • YOLO visual servoing on real Unitree Go2: detect bottle/ball → bearing control → closed-loop approach
  • Yaw-gate realign: if yaw error > 8° at standoff, back off and re-approach before push
  • Full gesture sequence: approach → push → Hello (api_id=1016) → backup → Scrape (api_id=1029)
  • MuJoCo sim proof: ball freejoint physics, push displacement 0.118–0.196 m confirmed
  • Real hardware sensor validation: odom ~19 Hz, camera ~10–12 Hz, lidar ~7–8 Hz

Current results

  • Push displacement (valid runs): +0.118 m / +0.196 m vs 0.05 m threshold
  • Vision approach success rate: 100% (2/2 valid runs)
  • Premature contact abort rate: ~33% (1/3); known fix: offset approach target_y by −0.15 m
  • Confirmed gestures on hardware: Hello ✅ Scrape ✅

Validation

  • make check — all scripts compile
  • make sim-run — MuJoCo sim push succeeds with ball displacement confirmed
  • Real hardware smoke test passed: odom/camera/lidar streams verified, Hello+Scrape motion confirmed

Notes

This PR intentionally does not vendor the full external project into DimOS. The full
implementation, artifacts, decision traces, and demo video live in the project repo above.

bogwi and others added 4 commits May 25, 2026 13:46
Add hackathon/pirate/README.md linking the Go2 vision-guided object
interaction project. DimOS core files are not modified by this submission.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 28, 2026

Greptile Summary

This PR pairs a hackathon README for the Pirate YOLO vision-servoing project with five core DimOS infrastructure changes needed to support SHM-based high-bandwidth streaming for the Go2 robot.

  • Transport pickling fix (dimos/core/transport.py): __reduce__ now returns a 3-tuple and __setstate__ restores sizing kwargs so default_capacity survives RPC/worker boundaries. Unpickling first calls __init__ (creating a throw-away SHM object) before __setstate__ overwrites it; JpegShmTransport.__setstate__ also implicitly depends on self.quality being set by the prior __init__ call.
  • Go2 blueprint expansion (dimos/robot/unitree/go2/blueprints/basic/unitree_go2_basic.py): The Mac-only SHM override is replaced with always-on SHM for all large streams; topics normalized to leading-slash format consistent with other blueprints.
  • Rerun bridge + coordinator wiring (dimos/visualization/rerun/bridge.py, dimos/core/coordination/module_coordinator.py): A new helper wires resolved SHM transports to the bridge after stream wiring completes; the bridge gains set_visual_transports and deduplicates subscriptions by topic.

Confidence Score: 4/5

Safe to merge; no data-loss or crash paths introduced. The transport-pickling change is functionally correct and the Rerun wiring follows the established lifecycle.

The transport and bridge changes are functionally correct. The redundant SHM object created during unpickling is an inefficiency rather than a runtime failure, and the implicit self.quality dependency in JpegShmTransport.setstate holds under standard pickle but could silently break under atypical reconstruction paths. The coordinator deferred import of RerunBridgeModule couples core coordination to the visualization layer but is guarded at runtime.

dimos/core/transport.py — the setstate / reduce interaction warrants a second look for the implicit quality dependency and the double-construction pattern.

Important Files Changed

Filename Overview
dimos/constants.py Adds DEFAULT_CAPACITY_POINTCLOUD (64 MiB) and DEFAULT_CAPACITY_OCCUPANCY_GRID (16 MiB) constants alongside existing image capacity constants.
dimos/core/transport.py Adds setstate to all three SHM transport classes and extends reduce to a 3-tuple. Redundant SHM instantiation on unpickling and an implicit self.quality dependency in JpegShmTransport.setstate are noted concerns.
dimos/core/coordination/module_coordinator.py Adds _configure_rerun_bridge_visual_transports() at the tail of _connect_streams to wire SHM transports to the Rerun bridge, introducing a layering dependency from core coordination into the visualization layer.
dimos/robot/unitree/go2/blueprints/basic/unitree_go2_basic.py Expands SHM transports from color_image-only (Mac-only) to lidar/pointcloud/map streams on all platforms; topics normalized to leading-slash format.
dimos/visualization/rerun/bridge.py Adds visual_transports config field and set_visual_transports RPC method; _subscribe_visual_transports correctly deduplicates by topic and handles partial-start failures safely.
hackathon/pirate/README.md New hackathon submission README. Documentation only, no executable code added.

Sequence Diagram

sequenceDiagram
    participant B as ModuleCoordinator.build()
    participant D as _deploy_all_modules
    participant W as _connect_streams
    participant C as _configure_rerun_bridge_visual_transports
    participant R as RerunBridgeModule
    participant S as SHMTransport

    B->>D: deploy all modules incl. RerunBridgeModule
    B->>W: wire streams populate _transport_registry
    W->>C: called at end of _connect_streams
    C->>C: filter _transport_registry for SHM transports
    C->>R: set_visual_transports(transports) RPC
    R->>R: store in config.visual_transports
    B->>R: build_all_modules / start_all_modules
    R->>R: "start() sets _started=True"
    R->>R: _subscribe_visual_transports()
    R->>S: transport.start()
    R->>S: transport.subscribe(on_visual_message)
    S-->>R: unsub callable registered as disposable
    S-->>R: on_visual_message(msg, transport_topic)
    R->>R: _on_message to _get_entity_path to rr.log
Loading

Reviews (1): Last reviewed commit: "feat: add Pirate hackathon submission po..." | Re-trigger Greptile

Comment thread dimos/core/transport.py
Comment on lines 175 to +182
def __reduce__(self): # type: ignore[no-untyped-def]
return (pSHMTransport, (self.topic,))
# Preserve sizing options such as default_capacity when the coordinator
# sends this transport to workers or to Rerun.
return (pSHMTransport, (self.topic,), self._kwargs)

def __setstate__(self, state: dict[str, Any]) -> None:
self._kwargs = state
self.shm = PickleSharedMemory(**state)
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.

P2 Redundant SHM object created during unpickling. When pickle reconstructs a pSHMTransport it first calls pSHMTransport(topic) (which runs __init__ and creates PickleSharedMemory() with the default 3.5 MiB capacity), then immediately calls __setstate__ which creates a second PickleSharedMemory(**state) with the correct capacity and replaces self.shm. The first object is abandoned and GC'd. While no OS-level shared memory is allocated until .start(), the unnecessary construction can be avoided by having __reduce__ return a factory callable that bypasses __init__.

Suggested change
def __reduce__(self): # type: ignore[no-untyped-def]
return (pSHMTransport, (self.topic,))
# Preserve sizing options such as default_capacity when the coordinator
# sends this transport to workers or to Rerun.
return (pSHMTransport, (self.topic,), self._kwargs)
def __setstate__(self, state: dict[str, Any]) -> None:
self._kwargs = state
self.shm = PickleSharedMemory(**state)
def __reduce__(self): # type: ignore[no-untyped-def]
# Preserve sizing options such as default_capacity when the coordinator
# sends this transport to workers or to Rerun.
return (_rebuild_pshm, (self.topic, self._kwargs))
def __setstate__(self, state: dict[str, Any]) -> None:
self._kwargs = state
self.shm = PickleSharedMemory(**state)
def _rebuild_pshm(topic: str, kwargs: dict) -> "pSHMTransport":
"""Pickle helper that constructs pSHMTransport without a double-init."""
obj = object.__new__(pSHMTransport)
pSHMTransport.__init__(obj, topic, **kwargs)
return obj

Comment thread dimos/core/transport.py
Comment on lines +262 to +268
def __setstate__(self, state: dict[str, Any]) -> None:
from dimos.protocol.pubsub.impl.jpeg_shm import (
JpegSharedMemory,
) # deferred to avoid pulling in Image/cv2/rerun

self._kwargs = state
self.shm = JpegSharedMemory(quality=self.quality, **state)
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.

P2 self.quality is implicitly required before __setstate__ runs. __setstate__ references self.quality (line 268), which is only guaranteed to be set because pickle always calls __init__ (via the args tuple in __reduce__) before calling __setstate__. If the reconstruction path ever changes (e.g., __new__ + __setstate__ directly, as in some frameworks), this would raise AttributeError. Storing quality in the state dict alongside _kwargs would make the dependency explicit and the reconstruction self-contained.

Comment on lines +597 to +619
def _configure_rerun_bridge_visual_transports(coordinator: ModuleCoordinator) -> None:
"""Send resolved SHM transports to an active Rerun bridge.

RerunBridgeModule subscribes to configured pubsubs directly. For SHM
streams, the coordinator forwards the concrete transport objects after
stream wiring has selected them.
"""
from dimos.visualization.rerun.bridge import RerunBridgeModule

if RerunBridgeModule not in coordinator._deployed_modules:
return

# LCM transports are already visible through RerunBridgeModule.config.pubsubs.
transports = [
transport
for transport in coordinator._transport_registry.values()
if isinstance(transport, SHMTransport | pSHMTransport | JpegShmTransport)
]
if not transports:
return

bridge = coordinator.get_instance(RerunBridgeModule)
bridge.set_visual_transports(transports)
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.

P2 Visualization-layer import inside core coordination. _configure_rerun_bridge_visual_transports does a deferred from dimos.visualization.rerun.bridge import RerunBridgeModule inside the core coordinator module. This creates a layering dependency: the coordination layer now has knowledge of—and a runtime dependency on—the visualization layer. The runtime guard (if RerunBridgeModule not in coordinator._deployed_modules) keeps headless deployments safe, but the right long-term home for this wiring is likely a post-wire hook registered by the bridge itself, keeping core coordination decoupled from visualization concerns.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@leshy leshy added the hackaton label May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants