Add SAM3 perception and persistent placed-box obstacles to hangar_sim ML Move Boxes#746
Conversation
📝 WalkthroughWalkthroughThis PR adds a SAM3 mask calibration tree, changes the top-level loading loop to use drained-state control, and updates the waypoint subtree to use SAM3 exemplar segmentation, revised ports, forced-down grasp orientation, JTC lift execution, and placement-state tracking. ChangesBehavior tree updates
Possibly related issues
Possibly related PRs
Suggested reviewers: Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (1 error)
✅ Passed checks (3 passed)
Comment |
|
fad7d97 to
47b1269
Compare
|
bccd327 to
68e8c2a
Compare
|
|
68e8c2a to
0eecc95
Compare
|
0eecc95 to
9594f91
Compare
|
Replace the CLIPSeg text-query + SAM2 point-refine perception chain with SAM3 (GetMasks2DFromExemplar), which produces high-quality per-detection masks directly from a text prompt. Restructure the outer loop to a drain-aware Fallback so it exits SUCCESS when the scene is cleared and surfaces real pick errors as FAILURE (fixes the #19112 infinite loop). Adds an area-based SAM3 mask false-positive filter, discards noisy box-yaw from grasps with max_ik_solutions=16, and ships a calibrate_sam3_mask_areas diagnostic Objective. Carries forward the #732 grasp-cup offset and the SetupMTCSetCollisionRule migration from main.
After each box is released at the loading zone, add a persistent collision object at the world-frame place_pose (dropped to floor height) under a unique id (placed_box_N), so the whole-body base+arm planner avoids every already-placed box on later picks instead of driving over them (#19973). ResetPlanningSceneObjects at objective start clears boxes from a previous run; a placed_count counter (ported across perception passes) keeps the ids unique. The obstacle is placed from place_pose, not the ICP target_pose: target_pose is base-relative but stamped world, so using it (with attach/detach) dropped the obstacles ~10 m off the robot. place_pose is built world-frame by the parent Objective, so the obstacle lands where the box was actually placed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9594f91 to
5fbbdd8
Compare
|
5fbbdd8 to
f4164b1
Compare
Lift each grasped box ~10 cm (Cartesian, grasp_link -Z) before transiting so it clears the surface and does not drag along the ground. Tune the pick for speed and consistency: drop num_orientation_samples 20->8 and max_ik_solutions 16->8 (fewer candidates, the pose IK is the bottleneck). Skip the new Calibrate SAM3 Mask Areas diagnostic in the CI integration test: the CI image does not ship the moveit_pro_sam3 model package, so GetMasks2DFromExemplar cannot resolve its encoder model path there (same ML-inference skip class as ML Move Boxes to Loading Zone). The base-yaw pirouette this objective used to trigger is addressed separately: controller-level mitigation in moveit_pro_example_ws#753 (JTC angle_wraparound) and the core representation-splice fix tracked in moveit_pro#20250. This PR is standalone-mergeable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
f4164b1 to
06dded7
Compare
|
|
|
[written by AI] @marioprats @JWhitleyWork — review requested from you both, but either one's approval is sufficient; whoever gets to it first. The description carries the full story: a sped-up video of the complete objective run, behavior-tree renderings, and the live retest evidence. |
marioprats
left a comment
There was a problem hiding this comment.
Looks good to me! nice improvement.
I haven't tested it myself, from the PR description it looks like it has been thoroughly tested already
[written by AI]
Problem
Two issues in hangar_sim's
ML Move Boxes to Loading Zone: (1) perception used the CLIPSeg+SAM2 pipeline with an unboundedRetryUntilSuccessful(1000)loop that never terminated and hid real errors (moveit_pro#19112); (2) already-placed boxes were invisible to planning, so the base could drive over them and the arm could sweep through them (part of moveit_pro#19973).Full objective run, sped up ~13× (7.6 min real time → 35 s) — every scattered box picked off the hangar floor and placed in the loading zone, objective terminating with SUCCESS via the new drain detection. Higher-quality 720p: pr746_full_run.mp4 (1.6 MB).
Changes
GetMasks2DFromExemplar(single text-prompted segmenter, replaces CLIPSeg+SAM2 pair), addFilterMasks2DByArea, and restructure the loop to be drain-aware:RepeatUnlessFailureEachTick+ adrainedscript flag, so the objective terminates SUCCESS when the scene is empty and FAILURE on real pick errors instead of retrying forever. Includes acalibrate_sam3_mask_areasdiagnostic objective.placed_box_N,AddCollisionMeshwithoverwrite), pose dropped to floor height via a body-frameTransformPose;ResetPlanningSceneObjectsat objective start clears stale objects from prior runs. Subsequent base/arm plans route around placed boxes.ForEach→OverridePoseOrientation→ rebuilt vector) before MTC planning, discarding noisy segmentation yaw. Note this makes the wrist-orientation samples duplicates of each other (see tuning below).grasp_link−Z (world up) before transit so the box clears the surface;num_orientation_samples20→8 andmax_ik_solutions16→8 (pose IK is the cycle-time bottleneck; with leveling the orientation samples collapse anyway — a follow-up may reduce to 1).Behavior-tree renderings (MoveIt Pro editor)
Top-level Objective — drain-aware loop: init scripts, then
Fallback[RepeatUnlessFailureEachTick → ScriptCondition(drained)]alternating the two view-waypoint SubTree calls (second gated by_skipIf: picked_at_wp1):Pick subtree — full shape at a glance, then readable sections left to right:
Annotated structure diagrams (green = new in this PR vs. gray = pre-existing, derived from the diff — shows what changed structurally, which the editor view can't)
Structural changes worth a reviewer's attention: the pick-resilience retry loop moved from iterating 2D masks (with per-mask SAM2 refinement, now removed) to iterating post-3D-extraction
graspable_objects; the_skipIf: mask_count == 0on the outerInverteris what lets a "scanned, found nothing" pass exit SUCCESS withpicked_box=false, which the parent's drain logic depends on.Images live on the
assets/pr746-bt-diagramsbranch. UI renderings captured from the live editor; annotated diagrams generated programmatically from the XML.Scope note (2026-07-02 rescope)
An earlier revision of this PR carried
cost_joint_names/cost_joint_weightsyaw-bias ports that depended on core PR moveit_pro#20073; that PR and example_ws#736 are closed and the ports are removed — this PR is standalone-mergeable on currentmain. The base-yaw pirouette those ports partially mitigated is fixed properly elsewhere: controller-level mitigation in #753 (angle_wraparoundon the yaw JTC gain, validated 14 runs / 0 spins) and the core representation-splice fix tracked in moveit_pro#20250.Verification
placed_box_*obstacles present in the planning scene, placed boxes landing in a clean line in the loading zone.placed_box_0..7world collision objects verified via/get_planning_scene. (Object count was 8 rather than the expected 7, most likely carryover from a preceding hung attempt on the same backend session — the persistence mechanism itself is working; noting for transparency.)Release notes
ML Move Boxes to Loading ZoneObjective to SAM3 perception with drain-aware looping, so it finishes when the boxes are gone and reports real failures instead of retrying forever.