Skip to content

Task: Create base manipulation module#1364

Open
mustafab0 wants to merge 6 commits intodevfrom
task/mustafa-create-base-manipulation-module
Open

Task: Create base manipulation module#1364
mustafab0 wants to merge 6 commits intodevfrom
task/mustafa-create-base-manipulation-module

Conversation

@mustafab0
Copy link
Contributor

Problem

ManipulationModule is a 1600-line monolith mixing core planning infrastructure with pick/place behaviors, GraspGen integration, and perception subscriptions. This makes it impossible to use the planner without pulling in perception and grasp generation dependencies.

Additionally, _BlueprintAtom.create in blueprints.py fails to resolve In/Out port annotations for modules using from future import annotations with TYPE_CHECKING guards (e.g. RealSenseCamera), silently breaking autoconnect transport wiring.

Issue: DIM-451
Solution

Split ManipulationModule into a base class and a PickAndPlaceModule subclass:

ManipulationModule (base): Core planning infrastructure, motion execution, gripper control, state machine. Skills: move_to_pose, move_to_joints, go_home, go_init, get_robot_state, reset.
PickAndPlaceModule(ManipulationModule): Adds perception integration (objects port, obstacle monitor, scan_objects, get_scene_info), GraspGen, and long-horizon skills (pick, place, place_back, pick_and_place, clear_perception_obstacles).

PickAndPlaceModuleConfig extends ManipulationModuleConfig with GraspGen fields. Only xarm_perception and xarm_perception_agent blueprints switch to pick_and_place_module; all other blueprints use the base manipulation_module unchanged.

New blueprints: xarm7_planner_coordinator_agent for testing base module with an LLM agent.

Bug fixes:

move_to_pose now preserves current EE orientation when roll/pitch/yaw are omitted (previously forced identity quaternion).
reset changed from @rpc to @skill so agents can clear faults.
clear_perception_obstacles changed from @rpc to @skill for agent recovery from COLLISION_AT_START.
_BlueprintAtom.create now uses reversed-MRO namespace resolution for get_type_hints, fixing autoconnect transport wiring for all modules with from __future__ import annotations.

Breaking Changes

None. ManipulationModule retains all base skills and RPCs. PickAndPlaceModule is a drop-in replacement where perception/pick-place is needed. Both are exported from dimos.manipulation.
How to Test

Test base agent: dimos run coordinator-mock then dimos run xarm7-planner-coordinator-agent
Test perception agent: dimos run coordinator-mock then dimos run xarm-perception-agent

closes DIM-451

@mustafab0 mustafab0 self-assigned this Feb 25, 2026
@mustafab0 mustafab0 linked an issue Feb 25, 2026 that may be closed by this pull request
4 tasks
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 25, 2026

Greptile Summary

This PR successfully splits the monolithic ManipulationModule (1600+ lines) into a clean base class and a PickAndPlaceModule subclass, achieving separation of concerns between core planning infrastructure and perception-dependent pick/place behaviors.

Key changes:

  • Base ManipulationModule: Provides core planning infrastructure, motion execution, gripper control, and basic skills (move_to_pose, move_to_joints, go_home, go_init, get_robot_state, reset)
  • New PickAndPlaceModule: Extends base with perception integration (objects port, obstacle monitor), GraspGen integration, and long-horizon skills (pick, place, place_back, pick_and_place, scan_objects, get_scene_info, clear_perception_obstacles)
  • Blueprint annotation fix: Fixed _BlueprintAtom.create to resolve In/Out port annotations using reversed-MRO namespace resolution, fixing autoconnect transport wiring for modules using from __future__ import annotations with TYPE_CHECKING guards
  • API improvements: Changed reset and clear_perception_obstacles from @rpc to @skill for agent accessibility; move_to_pose now preserves current EE orientation when roll/pitch/yaw are omitted (previously forced identity quaternion)

The refactoring maintains backward compatibility—existing blueprints continue using the base module, while only perception-dependent blueprints (xarm_perception, xarm_perception_agent) switch to pick_and_place_module.

Issue found: The move_to_pose orientation preservation logic has a flaw when only some orientation parameters are specified (e.g., roll=0.5 but no pitch/yaw)—it will set unspecified angles to 0.0 instead of preserving the current orientation. See inline comment for details.

Confidence Score: 4/5

  • Safe to merge with one orientation handling bug that should be fixed
  • The refactoring is well-structured and maintains backward compatibility, but the partial orientation specification bug in move_to_pose could cause unexpected behavior
  • dimos/manipulation/manipulation_module.py - fix the move_to_pose orientation handling for partial angle specifications

Important Files Changed

Filename Overview
dimos/core/blueprints.py Fixed annotation resolution for In/Out ports with from __future__ import annotations by using reversed-MRO namespace resolution
dimos/manipulation/manipulation_module.py Refactored to base class: removed perception/GraspGen code, changed reset/clear_perception_obstacles to skills, fixed move_to_pose orientation preservation
dimos/manipulation/pick_and_place_module.py New subclass extending ManipulationModule with perception integration (objects port, obstacle monitor) and pick/place skills
dimos/manipulation/manipulation_blueprints.py Updated xarm_perception blueprints to use pick_and_place_module, added new xarm7_planner_coordinator_agent for testing base module

Class Diagram

%%{init: {'theme': 'neutral'}}%%
classDiagram
    class ManipulationModule {
        +In~JointState~ joint_state
        -_world_monitor: WorldMonitor
        -_planner: Planner
        -_kinematics: Kinematics
        +start()
        +reset() str
        +move_to_pose(x, y, z, roll, pitch, yaw) str
        +move_to_joints(joints) str
        +go_home() str
        +go_init() str
        +get_robot_state() str
        +open_gripper() str
        +close_gripper() str
        +plan_to_pose(pose) bool
        +plan_to_joints(joints) bool
        +execute() bool
        +add_obstacle(obstacle) bool
        +remove_obstacle(id) bool
    }

    class PickAndPlaceModule {
        +In~list~DetObject~~ objects
        -_graspgen: DockerRunner
        -_detection_snapshot: list~DetObject~
        -_last_pick_position: Vector3
        +start()
        +stop()
        +scan_objects(min_duration) str
        +get_scene_info() str
        +pick(object_name, object_id) str
        +place(x, y, z) str
        +place_back() str
        +pick_and_place(object_name, x, y, z) str
        +clear_perception_obstacles() str
        +generate_grasps(pointcloud) PoseArray
        +refresh_obstacles(min_duration) list
        -_on_objects(objects)
    }

    class ManipulationModuleConfig {
        +robots: list~RobotModelConfig~
        +planning_timeout: float
        +enable_viz: bool
        +planner_name: str
        +kinematics_name: str
    }

    class PickAndPlaceModuleConfig {
        +graspgen_docker_image: str
        +graspgen_gripper_type: str
        +graspgen_num_grasps: int
        +graspgen_topk_num_grasps: int
        +graspgen_grasp_threshold: float
    }

    PickAndPlaceModule --|> ManipulationModule : extends
    PickAndPlaceModuleConfig --|> ManipulationModuleConfig : extends
    ManipulationModule ..> ManipulationModuleConfig : uses
    PickAndPlaceModule ..> PickAndPlaceModuleConfig : uses

    note for ManipulationModule "Base class: Core planning,\nmotion execution,\ngripper control"
    note for PickAndPlaceModule "Subclass: Adds perception\nintegration, GraspGen,\nand pick/place skills"
Loading

Last reviewed commit: 0a87c29

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +66 to +73
# Resolve annotations using namespaces from the full MRO chain so that
# In/Out behind TYPE_CHECKING + `from __future__ import annotations` work.
# Iterate reversed MRO so the most specific class's namespace wins when
# parent modules shadow names (e.g. spec.perception.Image vs sensor_msgs.Image).
globalns: dict[str, Any] = {}
for c in reversed(module.__mro__):
if c.__module__ in sys.modules:
globalns.update(sys.modules[c.__module__].__dict__)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks quite hack-y. What is the issue? I thought I fixed from __future__ import annotations. Can you show an example where it fails?

Copy link
Contributor Author

@mustafab0 mustafab0 Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #1309 from Feb 20 added from future import annotations + TYPE_CHECKING guard for Out to the RealSenseCamera — to lazy-load pyrealsense2. That broke _BlueprintAtom.create because it couldn't resolve the camera's string annotations.

The fix I just applied makes _BlueprintAtom.create use MRO-based namespace resolution (with reversed order so the defining class wins).

The object scene registration module does not capture the camera image streams. Above quote is from Claude, after workaround was implemented.

It agree with it being hacky >.<

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.

Create base Manipulation Module

2 participants