-
Notifications
You must be signed in to change notification settings - Fork 10
Integrate graspgen in manipulationmodule as a service #1234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
Adds a generate_grasps RPC method to ManipulationModule that lazily starts a GraspGen Docker container (GPU) on first call and returns ranked grasp poses (PoseArray) for a given point cloud. - Config: graspgen_docker_image, gripper_type, num_grasps, topk - _get_graspgen(): lazy DockerModule init with LFS checkpoint pull - Cleanup in stop() to tear down Docker container - GPU integration test with synthetic cube point cloud
Adds a generate_grasps RPC method to ManipulationModule that lazily starts a GraspGen Docker container (GPU) on first call and returns ranked grasp poses (PoseArray) for a given point cloud. - Config: graspgen_docker_image, gripper_type, num_grasps, topk - _get_graspgen(): lazy DockerModule init with LFS checkpoint pull - Cleanup in stop() to tear down Docker container
Greptile OverviewGreptile SummaryAdds GraspGen grasp generation capability to Key Changes:
Issues Found:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant ManipulationModule
participant DockerModule
participant GraspGenModule
Client->>ManipulationModule: generate_grasps(pointcloud, scene_pointcloud)
ManipulationModule->>ManipulationModule: _get_graspgen()
alt First call (lazy init)
ManipulationModule->>ManipulationModule: get_data("models_graspgen")
ManipulationModule->>DockerModule: new DockerModule(GraspGenModule, ...)
ManipulationModule->>DockerModule: start()
DockerModule-->>ManipulationModule: started
else Subsequent calls
Note over ManipulationModule: Return cached _graspgen
end
ManipulationModule->>GraspGenModule: generate_grasps(pointcloud, scene_pointcloud)
GraspGenModule->>GraspGenModule: Run inference
GraspGenModule-->>ManipulationModule: PoseArray
ManipulationModule-->>Client: PoseArray
Client->>ManipulationModule: stop()
ManipulationModule->>DockerModule: stop()
DockerModule-->>ManipulationModule: stopped
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 files reviewed, 2 comments
| def _get_graspgen(self) -> DockerModule | None: | ||
| """Get or create GraspGen Docker module (lazy init).""" | ||
| if self._graspgen is not None: | ||
| return self._graspgen | ||
|
|
||
| from dimos.core.docker_runner import DockerModule | ||
| from dimos.manipulation.grasping.graspgen_module import GraspGenModule | ||
| from dimos.utils.data import get_data | ||
| from dimos.utils.path_utils import get_project_root | ||
|
|
||
| # Ensure GraspGen model checkpoints are pulled from LFS | ||
| get_data("models_graspgen") | ||
|
|
||
| project_root = get_project_root() | ||
| docker_file = ( | ||
| project_root / "dimos" / "manipulation" / "grasping" / "docker_context" / "Dockerfile" | ||
| ) | ||
| self._graspgen = DockerModule( | ||
| GraspGenModule, | ||
| docker_file=docker_file, | ||
| docker_build_context=project_root, | ||
| docker_image=self.config.graspgen_docker_image, | ||
| docker_env={"CI": "1"}, # skip interactive system config prompt in container | ||
| gripper_type=self.config.graspgen_gripper_type, | ||
| num_grasps=self.config.graspgen_num_grasps, | ||
| topk_num_grasps=self.config.graspgen_topk_num_grasps, | ||
| grasp_threshold=self.config.graspgen_grasp_threshold, | ||
| filter_collisions=self.config.graspgen_filter_collisions, | ||
| save_visualization_data=self.config.graspgen_save_visualization_data, | ||
| visualization_output_path=self.config.graspgen_visualization_output_path, | ||
| ) | ||
| self._graspgen.start() | ||
| return self._graspgen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing error handling - if get_data(), get_project_root(), DockerModule(), or .start() raise exceptions, _graspgen remains None but no error is logged or raised.
| def _get_graspgen(self) -> DockerModule | None: | |
| """Get or create GraspGen Docker module (lazy init).""" | |
| if self._graspgen is not None: | |
| return self._graspgen | |
| from dimos.core.docker_runner import DockerModule | |
| from dimos.manipulation.grasping.graspgen_module import GraspGenModule | |
| from dimos.utils.data import get_data | |
| from dimos.utils.path_utils import get_project_root | |
| # Ensure GraspGen model checkpoints are pulled from LFS | |
| get_data("models_graspgen") | |
| project_root = get_project_root() | |
| docker_file = ( | |
| project_root / "dimos" / "manipulation" / "grasping" / "docker_context" / "Dockerfile" | |
| ) | |
| self._graspgen = DockerModule( | |
| GraspGenModule, | |
| docker_file=docker_file, | |
| docker_build_context=project_root, | |
| docker_image=self.config.graspgen_docker_image, | |
| docker_env={"CI": "1"}, # skip interactive system config prompt in container | |
| gripper_type=self.config.graspgen_gripper_type, | |
| num_grasps=self.config.graspgen_num_grasps, | |
| topk_num_grasps=self.config.graspgen_topk_num_grasps, | |
| grasp_threshold=self.config.graspgen_grasp_threshold, | |
| filter_collisions=self.config.graspgen_filter_collisions, | |
| save_visualization_data=self.config.graspgen_save_visualization_data, | |
| visualization_output_path=self.config.graspgen_visualization_output_path, | |
| ) | |
| self._graspgen.start() | |
| return self._graspgen | |
| def _get_graspgen(self) -> DockerModule | None: | |
| """Get or create GraspGen Docker module (lazy init).""" | |
| if self._graspgen is not None: | |
| return self._graspgen | |
| try: | |
| from dimos.core.docker_runner import DockerModule | |
| from dimos.manipulation.grasping.graspgen_module import GraspGenModule | |
| from dimos.utils.data import get_data | |
| from dimos.utils.path_utils import get_project_root | |
| # Ensure GraspGen model checkpoints are pulled from LFS | |
| get_data("models_graspgen") | |
| project_root = get_project_root() | |
| docker_file = ( | |
| project_root / "dimos" / "manipulation" / "grasping" / "docker_context" / "Dockerfile" | |
| ) | |
| self._graspgen = DockerModule( | |
| GraspGenModule, | |
| docker_file=docker_file, | |
| docker_build_context=project_root, | |
| docker_image=self.config.graspgen_docker_image, | |
| docker_env={"CI": "1"}, # skip interactive system config prompt in container | |
| gripper_type=self.config.graspgen_gripper_type, | |
| num_grasps=self.config.graspgen_num_grasps, | |
| topk_num_grasps=self.config.graspgen_topk_num_grasps, | |
| grasp_threshold=self.config.graspgen_grasp_threshold, | |
| filter_collisions=self.config.graspgen_filter_collisions, | |
| save_visualization_data=self.config.graspgen_save_visualization_data, | |
| visualization_output_path=self.config.graspgen_visualization_output_path, | |
| ) | |
| self._graspgen.start() | |
| return self._graspgen | |
| except Exception as e: | |
| logger.error(f"Failed to initialize GraspGen Docker module: {e}") | |
| return None |
| @rpc | ||
| def generate_grasps( | ||
| self, | ||
| pointcloud: PointCloud2, | ||
| scene_pointcloud: PointCloud2 | None = None, | ||
| ) -> PoseArray | None: | ||
| graspgen = self._get_graspgen() | ||
| if graspgen is None: | ||
| return None | ||
| return graspgen.generate_grasps(pointcloud, scene_pointcloud) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No error logging when _get_graspgen() returns None - the RPC call silently returns None without informing the caller why it failed
| @rpc | |
| def generate_grasps( | |
| self, | |
| pointcloud: PointCloud2, | |
| scene_pointcloud: PointCloud2 | None = None, | |
| ) -> PoseArray | None: | |
| graspgen = self._get_graspgen() | |
| if graspgen is None: | |
| return None | |
| return graspgen.generate_grasps(pointcloud, scene_pointcloud) | |
| @rpc | |
| def generate_grasps( | |
| self, | |
| pointcloud: PointCloud2, | |
| scene_pointcloud: PointCloud2 | None = None, | |
| ) -> PoseArray | None: | |
| graspgen = self._get_graspgen() | |
| if graspgen is None: | |
| logger.error("GraspGen Docker module not available") | |
| return None | |
| return graspgen.generate_grasps(pointcloud, scene_pointcloud) |
Summary
Adds
@rpc generate_grasps(pointcloud, scene_pointcloud)->PoseArraytoManipulationModulethat lazily spins up aDockerModule(GraspGenModule)on first call, managing the full DockerlifecycleHow it works
ManipulationModule lazily creates and starts a GraspGen Docker container on first
generate_grasps()call, to the point cloud to GraspGenModule via LCMRPC, and returns ranked grasp poses as PoseArray.Changes
dimos/manipulation/manipulation_module.pyCloses #1130 DIM-390