Skip to content

feat(manipulation): add heuristic grasp provider - #3709

Draft
ruthwikdasyam wants to merge 3 commits into
mainfrom
ruthwik/feat/heuristic-grasp
Draft

feat(manipulation): add heuristic grasp provider#3709
ruthwikdasyam wants to merge 3 commits into
mainfrom
ruthwik/feat/heuristic-grasp

Conversation

@ruthwikdasyam

Copy link
Copy Markdown
Contributor

Contribution path

  • Small, focused change extracted from the pick-and-place exploration work.

Problem

Pick-and-place needs a lightweight grasp provider that does not require the optional GraspGenX runtime.

Solution

  • Add HeuristicGraspModule, implementing the existing GraspGenSpec.
  • Produce one deterministic top-down parallel-jaw proposal from a segmented object point cloud.
  • Validate point-cloud metadata and geometry.
  • Register the module and add focused unit coverage.

How to Test

TMPDIR=/dev/shm uv run --no-sync pytest dimos/manipulation/grasping/test_heuristic_grasp.py dimos/robot/test_all_blueprints_generation.py -q
TMPDIR=/dev/shm uv run --no-sync mypy dimos/manipulation/grasping/heuristic_grasp.py
TMPDIR=/dev/shm uv run --no-sync ruff format --check dimos/manipulation/grasping/heuristic_grasp.py dimos/manipulation/grasping/test_heuristic_grasp.py
TMPDIR=/dev/shm uv run --no-sync ruff check dimos/manipulation/grasping/heuristic_grasp.py dimos/manipulation/grasping/test_heuristic_grasp.py

AI assistance

OpenCode with gpt-5.6-terra assisted with implementation and validation. The author will review the public method descriptions before they are added.

Checklist

  • I have read and approved the CLA.

@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
4817 2 4815 87
View the top 1 failed test(s) by shortest run time
dimos.e2e_tests.test_manipulation_planning_groups::test_dual_arm_plans_and_dispatches_both_arms_through_control_coordinator
Stack Traces | 120s run time
lcm_spy = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x758352ac7f20>
start_blueprint = <function start_blueprint.<locals>.set_name_and_start at 0x758350717100>

    def test_dual_arm_plans_and_dispatches_both_arms_through_control_coordinator(
        lcm_spy: LcmSpy,
        start_blueprint: Callable[..., DimosCliCall],
    ) -> None:
        """Plan one generated plan over both arms and dispatch through one trajectory task."""
>       _start_openarm_mock_planner(start_blueprint, lcm_spy)

lcm_spy    = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x758352ac7f20>
start_blueprint = <function start_blueprint.<locals>.set_name_and_start at 0x758350717100>

dimos/e2e_tests/test_manipulation_planning_groups.py:190: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
dimos/e2e_tests/test_manipulation_planning_groups.py:151: in _start_openarm_mock_planner
    lcm_spy.wait_for_saved_topic(JOINT_STATE_TOPIC, timeout=120.0)
        lcm_spy    = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x758352ac7f20>
        start_blueprint = <function start_blueprint.<locals>.set_name_and_start at 0x758350717100>
dimos/e2e_tests/lcm_spy.py:97: in wait_for_saved_topic
    wait_until(
        condition  = <function LcmSpy.wait_for_saved_topic.<locals>.condition at 0x758350717a60>
        self       = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x758352ac7f20>
        timeout    = 120.0
        topic      = '/coordinator_joint_state#sensor_msgs.JointState'
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

predicate = <function LcmSpy.wait_for_saved_topic.<locals>.condition at 0x758350717a60>

    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: Timeout waiting for topic /coordinator_joint_state#sensor_msgs.JointState

deadline   = 4268088.689404055
interval   = 0.1
message    = 'Timeout waiting for topic /coordinator_joint_state#sensor_msgs.JointState'
predicate  = <function LcmSpy.wait_for_saved_topic.<locals>.condition at 0x758350717a60>
timeout    = 120.0

.../utils/testing/waiting.py:35: TimeoutError
View the full list of 1 ❄️ flaky test(s)
dimos.e2e_tests.test_manipulation_planning_groups::test_single_arm_plans_and_executes_through_control_coordinator

Flake rate in main: 7.69% (Passed 12 times, Failed 1 times)

Stack Traces | 120s run time
lcm_spy = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x7583526115e0>
start_blueprint = <function start_blueprint.<locals>.set_name_and_start at 0x758350716b60>

    def test_single_arm_plans_and_executes_through_control_coordinator(
        lcm_spy: LcmSpy,
        start_blueprint: Callable[..., DimosCliCall],
    ) -> None:
        """Plan with one arm and execute through its trajectory task."""
>       _start_openarm_mock_planner(start_blueprint, lcm_spy)

lcm_spy    = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x7583526115e0>
start_blueprint = <function start_blueprint.<locals>.set_name_and_start at 0x758350716b60>

dimos/e2e_tests/test_manipulation_planning_groups.py:159: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
dimos/e2e_tests/test_manipulation_planning_groups.py:151: in _start_openarm_mock_planner
    lcm_spy.wait_for_saved_topic(JOINT_STATE_TOPIC, timeout=120.0)
        lcm_spy    = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x7583526115e0>
        start_blueprint = <function start_blueprint.<locals>.set_name_and_start at 0x758350716b60>
dimos/e2e_tests/lcm_spy.py:97: in wait_for_saved_topic
    wait_until(
        condition  = <function LcmSpy.wait_for_saved_topic.<locals>.condition at 0x758350715260>
        self       = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x7583526115e0>
        timeout    = 120.0
        topic      = '/coordinator_joint_state#sensor_msgs.JointState'
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

predicate = <function LcmSpy.wait_for_saved_topic.<locals>.condition at 0x758350715260>

    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: Timeout waiting for topic /coordinator_joint_state#sensor_msgs.JointState

deadline   = 4267968.487287269
interval   = 0.1
message    = 'Timeout waiting for topic /coordinator_joint_state#sensor_msgs.JointState'
predicate  = <function LcmSpy.wait_for_saved_topic.<locals>.condition at 0x758350715260>
timeout    = 120.0

.../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.

@greptile-apps

greptile-apps Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This change adds a deterministic, PCA-based heuristic grasp provider, focused proposal tests, and generated catalog registration. The rectangular-fixture test checks that the gripper approaches from above but does not check its yaw, so a rotation that places the jaws across the fixture's wide dimension can remain undetected.

T-Rex validation blocked

The focused test could not start because the Python package tqdm is missing. A narrowly scoped yaw-regression harness then could not import the grasp provider because the Python package zenoh is missing.

Confidence Score: 4/5

The provider's yaw behavior should receive explicit regression coverage before it is relied on for rectangular-object grasp planning.

The remaining finding is limited to test coverage: the current assertion constrains the downward approach direction but not the yaw-dependent jaw direction.

Files Needing Attention: dimos/manipulation/grasping/test_heuristic_grasp.py needs a jaw-axis assertion for the non-square rectangular fixture.

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex completed the requested verification, but its local artifact references were not uploaded.
  • T-Rex produced proof for a posted P2 finding, and the reviewer comment contains the finding details.
  • Validation was blocked before the relevant behavior could execute due to missing tqdm and zenoh during imports, and the attempt record is preserved.

T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "feat(manipulation): add heuristic grasp ..." | Re-trigger Greptile

Comment thread dimos/manipulation/grasping/test_heuristic_grasp.py
@ruthwikdasyam
ruthwikdasyam marked this pull request as draft August 27, 2026 00:35
@ruthwikdasyam
ruthwikdasyam force-pushed the ruthwik/feat/heuristic-grasp branch from a1bf6c4 to 4a436c0 Compare August 27, 2026 02:26
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