|
25 | 25 | from predicators.spot_utils.perception.object_detection import \ |
26 | 26 | AprilTagObjectDetectionID, KnownStaticObjectDetectionID, \ |
27 | 27 | LanguageObjectDetectionID, ObjectDetectionID, _query_detic_sam, \ |
28 | | - detect_objects, visualize_all_artifacts |
| 28 | + _query_vlm, detect_objects, visualize_all_artifacts |
29 | 29 | from predicators.spot_utils.perception.object_specific_grasp_selection import \ |
30 | 30 | brush_prompt, bucket_prompt, football_prompt, train_toy_prompt |
31 | 31 | from predicators.spot_utils.perception.perception_structs import RGBDImage, \ |
@@ -630,6 +630,12 @@ def step(self, action: Action) -> Observation: |
630 | 630 | else: |
631 | 631 | assert action_name == "MoveToReachObject" |
632 | 632 | obj_pose = self._last_known_object_poses[target_obj] |
| 633 | + logging.warning( |
| 634 | + f"MoveToReachObject using last known pose for " |
| 635 | + f"'{target_obj.name}': " |
| 636 | + f"({obj_pose.x:.3f}, {obj_pose.y:.3f}, " |
| 637 | + f"{obj_pose.z:.3f}). This pose may be STALE " |
| 638 | + f"if the object was not re-detected recently.") |
633 | 639 | obj_position = math_helpers.Vec3(x=obj_pose.x, |
634 | 640 | y=obj_pose.y, |
635 | 641 | z=obj_pose.z) |
@@ -734,6 +740,19 @@ def _build_realworld_observation( |
734 | 740 | if (self._detection_id_to_obj[det_id].type.name == "movable") |
735 | 741 | # or self._detection_id_to_obj[det_id].name == "clear_plastic_container") |
736 | 742 | } |
| 743 | + for obj, pose in all_objects_in_view.items(): |
| 744 | + old_pose = self._last_known_object_poses.get(obj) |
| 745 | + if old_pose is not None: |
| 746 | + dist = np.sqrt((pose.x - old_pose.x)**2 + |
| 747 | + (pose.y - old_pose.y)**2 + |
| 748 | + (pose.z - old_pose.z)**2) |
| 749 | + if dist > 0.1: |
| 750 | + logging.warning( |
| 751 | + f"Object '{obj.name}' pose changed significantly: " |
| 752 | + f"old=({old_pose.x:.3f}, {old_pose.y:.3f}, " |
| 753 | + f"{old_pose.z:.3f}) -> " |
| 754 | + f"new=({pose.x:.3f}, {pose.y:.3f}, {pose.z:.3f}) " |
| 755 | + f"(dist={dist:.3f}m)") |
737 | 756 | self._last_known_object_poses.update(all_objects_in_view) |
738 | 757 | objects_in_hand_view = set(self._detection_id_to_obj[det_id] |
739 | 758 | for det_id in hand_detections) |
@@ -1157,37 +1176,52 @@ def _actively_construct_initial_object_views( |
1157 | 1176 | self) -> Tuple[Dict[Object, math_helpers.SE3Pose], Dict[str, Any]]: |
1158 | 1177 | assert self._robot is not None |
1159 | 1178 | assert self._localizer is not None |
1160 | | - # stow_arm(self._robot) |
1161 | | - # go_home(self._robot, self._localizer) |
1162 | 1179 | self._localizer.localize() |
1163 | | - # detection_ids = self._detection_id_to_obj.keys() |
1164 | | - # import ipdb; ipdb.set_trace() |
1165 | | - # detections, artifacts = self._run_init_search_for_objects( |
1166 | | - # set(detection_ids)) |
1167 | | - # stow_arm(self._robot) |
1168 | | - # obj_to_se3_pose = { |
1169 | | - # self._detection_id_to_obj[det_id]: val |
1170 | | - # for (det_id, val) in detections.items() |
1171 | | - # } |
1172 | 1180 |
|
1173 | | - obj_to_se3_pose = get_known_movable_objects() |
1174 | | - obj_to_se3_pose.update(get_known_immovable_objects()) |
1175 | | - # Remap object types using _detection_id_to_obj so that e.g. |
1176 | | - # short_round_coffee_table gets _table_type instead of _immovable_type. |
1177 | | - det_id_to_obj = self._detection_id_to_obj |
1178 | | - name_to_remapped_obj = {o.name: o for o in det_id_to_obj.values()} |
| 1181 | + # Capture images from the current position and run detection |
| 1182 | + # without moving the robot. |
| 1183 | + rgbds = capture_images(self._robot, self._localizer) |
| 1184 | + detection_ids = set(self._detection_id_to_obj.keys()) |
| 1185 | + detections, artifacts = detect_objects( |
| 1186 | + detection_ids, rgbds, self._allowed_regions) |
| 1187 | + |
| 1188 | + if CFG.spot_render_perception_outputs: |
| 1189 | + outdir = Path(CFG.spot_perception_outdir) |
| 1190 | + time_str = time.strftime("%Y%m%d-%H%M%S") |
| 1191 | + detections_outfile = outdir / f"detections_{time_str}.png" |
| 1192 | + no_detections_outfile = outdir / f"no_detections_{time_str}.png" |
| 1193 | + visualize_all_artifacts(artifacts, detections_outfile, |
| 1194 | + no_detections_outfile) |
| 1195 | + |
1179 | 1196 | obj_to_se3_pose = { |
1180 | | - name_to_remapped_obj.get(o.name, o): pose |
1181 | | - for o, pose in obj_to_se3_pose.items() |
| 1197 | + self._detection_id_to_obj[det_id]: val |
| 1198 | + for (det_id, val) in detections.items() |
1182 | 1199 | } |
| 1200 | + |
| 1201 | + # For any movable objects not detected, fall back to known poses |
| 1202 | + # from the config map file with a warning. |
| 1203 | + known_movable = get_known_movable_objects() |
| 1204 | + det_id_to_obj = self._detection_id_to_obj |
| 1205 | + name_to_remapped_obj = {o.name: o for o in det_id_to_obj.values()} |
| 1206 | + for o, pose in known_movable.items(): |
| 1207 | + remapped = name_to_remapped_obj.get(o.name, o) |
| 1208 | + if remapped not in obj_to_se3_pose: |
| 1209 | + logging.warning( |
| 1210 | + f"Object '{o.name}' not detected by perception. " |
| 1211 | + f"Falling back to known pose from config map: " |
| 1212 | + f"({pose.x:.3f}, {pose.y:.3f}, {pose.z:.3f}). " |
| 1213 | + f"THIS POSE MAY BE INCORRECT!") |
| 1214 | + obj_to_se3_pose[remapped] = pose |
| 1215 | + |
| 1216 | + # Always use known poses for immovable objects. |
| 1217 | + known_immovable = get_known_immovable_objects() |
| 1218 | + for o, pose in known_immovable.items(): |
| 1219 | + remapped = name_to_remapped_obj.get(o.name, o) |
| 1220 | + if remapped not in obj_to_se3_pose: |
| 1221 | + obj_to_se3_pose[remapped] = pose |
| 1222 | + |
1183 | 1223 | self._last_known_object_poses.update(obj_to_se3_pose) |
1184 | | - # Move the robot into a good place to construct the initial state |
1185 | | - # by running VLM predicates. |
1186 | | - prompt = "Finished initial search for objects. Take control of the robot and move it into a good initial location for constructing the initial state of the task. Press 'Enter' when done!" |
1187 | | - _ = input(prompt) |
1188 | | - assert self._lease_client is not None |
1189 | | - self._lease_client.take() |
1190 | | - return obj_to_se3_pose, {} |
| 1224 | + return obj_to_se3_pose, artifacts |
1191 | 1225 |
|
1192 | 1226 | def _run_init_search_for_objects( |
1193 | 1227 | self, detection_ids: Set[ObjectDetectionID] |
@@ -1235,7 +1269,7 @@ def _generate_goal_description(self) -> GoalDescription: |
1235 | 1269 | ############################################################################### |
1236 | 1270 |
|
1237 | 1271 | ## Constants |
1238 | | -HANDEMPTY_GRIPPER_THRESHOLD = 2.5 # made public for use in perceiver |
| 1272 | +HANDEMPTY_GRIPPER_THRESHOLD = 4.5 # made public for use in perceiver |
1239 | 1273 | _ONTOP_Z_THRESHOLD = 0.2 |
1240 | 1274 | _INSIDE_Z_THRESHOLD = 0.3 |
1241 | 1275 | _ONTOP_SURFACE_BUFFER = 0.48 |
@@ -2791,8 +2825,12 @@ def detect_objects( |
2791 | 2825 | assert isinstance( |
2792 | 2826 | obj_id, LanguageObjectDetectionID |
2793 | 2827 | ), "Only LanguageObjectDetectionIDs are supported." |
2794 | | - object_id_to_img_detections = _query_detic_sam( |
2795 | | - object_ids, rgbd_images) # type: ignore |
| 2828 | + if CFG.spot_use_vlm_detection: |
| 2829 | + object_id_to_img_detections = _query_vlm( |
| 2830 | + object_ids, rgbd_images) # type: ignore |
| 2831 | + else: |
| 2832 | + object_id_to_img_detections = _query_detic_sam( |
| 2833 | + object_ids, rgbd_images) # type: ignore |
2796 | 2834 | # This ^ is currently a mapping of object_id -> camera_name -> |
2797 | 2835 | # SegmentedBoundingBox. |
2798 | 2836 | # We want to do our annotations by camera image, so let's turn this |
@@ -4417,9 +4455,9 @@ def _detection_id_to_obj(self) -> Dict[ObjectDetectionID, Object]: |
4417 | 4455 | if obj.name == "short_round_coffee_table": |
4418 | 4456 | table_obj = Object("short_round_coffee_table", _table_type) |
4419 | 4457 | detection_id_to_obj[stat_detection_id] = table_obj |
4420 | | - # if obj.name == "child_play_table": |
4421 | | - # table_obj = Object("child_play_table", _table_type) |
4422 | | - # detection_id_to_obj[stat_detection_id] = table_obj |
| 4458 | + elif obj.name == "childs_play_table": |
| 4459 | + table_obj = Object("childs_play_table", _table_type) |
| 4460 | + detection_id_to_obj[stat_detection_id] = table_obj |
4423 | 4461 | else: |
4424 | 4462 | detection_id_to_obj[stat_detection_id] = obj |
4425 | 4463 |
|
|
0 commit comments