Skip to content

Commit 3f436b3

Browse files
committed
added thesis tasks
1 parent 8d674b5 commit 3f436b3

8 files changed

Lines changed: 936 additions & 47 deletions

File tree

predicators/envs/spot_env.py

Lines changed: 375 additions & 8 deletions
Large diffs are not rendered by default.

predicators/ground_truth_models/spot_env/nsrts.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ def _move_to_hand_view_object_sampler(state: State, goal: Set[GroundAtom],
8484
robot_obj = objs[0]
8585
obj_to_nav_to = objs[1]
8686

87+
if obj_to_nav_to.name == "blue_toy_chair":
88+
min_dist = 1.8
89+
max_dist = 1.9
90+
8791
min_angle, max_angle = _get_approach_angle_bounds(obj_to_nav_to, state)
8892

8993
return _move_offset_sampler(state, robot_obj, obj_to_nav_to, rng, min_dist,
@@ -103,6 +107,12 @@ def _move_to_reach_object_sampler(state: State, goal: Set[GroundAtom],
103107
robot_obj = objs[0]
104108
obj_to_nav_to = objs[1]
105109

110+
if obj_to_nav_to.name == "wooden_table":
111+
# For the table, we want to be a bit farther so we can reach over it.
112+
# import ipdb; ipdb.set_trace()
113+
min_dist = 0.8
114+
max_dist = 0.9
115+
106116
min_angle, max_angle = _get_approach_angle_bounds(obj_to_nav_to, state)
107117
ret_val = _move_offset_sampler(state, robot_obj, obj_to_nav_to, rng,
108118
min_dist, max_dist, min_angle, max_angle)
@@ -114,6 +124,13 @@ def _get_approach_angle_bounds(obj: Object,
114124
"""Helper for move samplers."""
115125
angle_bounds = load_spot_metadata().get("approach_angle_bounds", {})
116126
if obj.name in angle_bounds:
127+
if obj.name == "blue_toy_chair":
128+
# if location of chair is far from the table
129+
# we cant approach it from the side
130+
# 1.45993 0.6244 -0.0938282
131+
# 0.082429 0.991738 -0.178306
132+
if state.get(obj, "x") > 1.0:
133+
return [-1.6, -1.53]
117134
return angle_bounds[obj.name]
118135
# Mega-hack for when the container is next to something with angle bounds,
119136
# i.e., it is ready to sweep.
@@ -230,7 +247,7 @@ def _drag_to_unblock_object_sampler(state: State, goal: Set[GroundAtom],
230247
objs: Sequence[Object]) -> Array:
231248
# Parameters are relative dx, dy, dyaw to move while holding.
232249
del state, goal, objs, rng # randomization coming soon
233-
return np.array([0.0, 0.0, np.pi / 1.5])
250+
return np.array([0.0, 0.0, -np.pi / 2])
234251

235252
def _drag_to_open_object_sampler(state: State, goal: Set[GroundAtom],
236253
rng: np.random.Generator,
@@ -252,14 +269,15 @@ def _drag_to_block_object_sampler(state: State, goal: Set[GroundAtom],
252269
objs: Sequence[Object]) -> Array:
253270
# Parameters are relative dx, dy, dyaw to move while holding.
254271
del state, goal, objs, rng # randomization coming soon
255-
return np.array([0.0, 0.0, -np.pi / 1.5])
272+
return np.array([0.0, 0.0, np.pi / 2])
256273

257274

258275
def _sweep_into_container_sampler(state: State, goal: Set[GroundAtom],
259276
rng: np.random.Generator,
260277
objs: Sequence[Object]) -> Array:
261278
# Parameters are just one number, a velocity.
262279
del goal
280+
# TODO # return np.array([2.0])
263281
if CFG.spot_use_perfect_samplers:
264282
if CFG.spot_run_dry:
265283
if len(objs) == 6: # SweepTwoObjectsIntoContainer
@@ -295,6 +313,25 @@ def _prepare_sweeping_sampler(state: State, goal: Set[GroundAtom],
295313
return np.array([param_dict["dx"], param_dict["dy"], param_dict["angle"]])
296314

297315

316+
def _wipe_table_sampler(state: State, goal: Set[GroundAtom],
317+
rng: np.random.Generator,
318+
objs: Sequence[Object]) -> Array:
319+
# Parameters are stroke_dx, stroke_dy, num_strokes, duration.
320+
del state, goal, objs # not used for now
321+
if CFG.spot_use_perfect_samplers:
322+
# Default values for wiping
323+
stroke_dx = 0.0
324+
stroke_dy = 0.4
325+
num_strokes = 5
326+
duration = 1.0
327+
else:
328+
stroke_dx = rng.uniform(-0.1, 0.1)
329+
stroke_dy = rng.uniform(0.3, 0.5)
330+
num_strokes = rng.integers(3, 8)
331+
duration = rng.uniform(0.8, 1.5)
332+
return np.array([stroke_dx, stroke_dy, num_strokes, duration])
333+
334+
298335
class SpotEnvsGroundTruthNSRTFactory(GroundTruthNSRTFactory):
299336
"""Ground-truth NSRTs for the Spot Env."""
300337

@@ -305,7 +342,8 @@ def get_env_names(cls) -> Set[str]:
305342
"spot_soda_bucket_env", "spot_soda_chair_env",
306343
"spot_main_sweep_env", "spot_ball_and_cup_sticky_table_env",
307344
"spot_brush_shelf_env", "lis_spot_block_floor_env", "lis_spot_block_drawer_env",
308-
"lis_spot_collect_misplaced_items_env"
345+
"lis_spot_collect_misplaced_items_env", "lis_spot_balls_yellow_table_env",
346+
"lis_spot_bear_panda_bucket_sweep_env", "lis_spot_wipe_table_env"
309347
}
310348

311349
@staticmethod
@@ -339,6 +377,7 @@ def get_nsrts(env_name: str, types: Dict[str, Type],
339377
"PrepareContainerForSweeping": _prepare_sweeping_sampler,
340378
"DropNotPlaceableObject": utils.null_sampler,
341379
"MoveToReadySweep": utils.null_sampler,
380+
"WipeTable": _wipe_table_sampler,
342381
}
343382

344383
# If we're doing proper bilevel planning with a simulator, then

predicators/ground_truth_models/spot_env/options.py

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from predicators.spot_utils.skills.spot_place import place_at_relative_position
3535
from predicators.spot_utils.skills.spot_stow_arm import stow_arm
3636
from predicators.spot_utils.skills.spot_sweep import sweep
37+
from predicators.spot_utils.skills.spot_wipe_table import wipe_multiple_strokes
3738
from predicators.spot_utils.spot_localization import SpotLocalizer
3839
from predicators.spot_utils.utils import DEFAULT_HAND_DROP_OBJECT_POSE, \
3940
DEFAULT_HAND_LOOK_STRAIGHT_DOWN_POSE, DEFAULT_HAND_POST_DUMP_POSE, \
@@ -440,22 +441,22 @@ def _sweep_objects_into_container_policy(name: str, robot_obj_idx: int,
440441
) * middle_bottom_surface_pose
441442
# Now, compute the actual pose the hand should start sweeping from by
442443
# clamping it between the surface poses.
443-
start_x = np.clip(middle_bottom_surface_rel_pose.x, mean_x + 0.175,
444+
start_x = np.clip(middle_bottom_surface_rel_pose.x, mean_x + 0.275,
444445
upper_left_surface_rel_pose.x)
445446
start_y = np.clip(middle_bottom_surface_rel_pose.y, mean_y + 0.41,
446447
upper_left_surface_rel_pose.y)
447448
# use absolute value so that we don't get messed up by noise in the
448449
# perception height estimate.
449-
start_z = 0.14
450+
start_z = 0.17
450451
pitch = math_helpers.Quat.from_pitch(np.pi / 2)
451452
yaw = math_helpers.Quat.from_yaw(np.pi / 4)
452453
rot = pitch * yaw
453-
sweep_start_pose = math_helpers.SE3Pose(x=start_x,
454-
y=start_y,
454+
sweep_start_pose = math_helpers.SE3Pose(x=start_x + 1.0,
455+
y=start_y + 0.4,
455456
z=start_z,
456457
rot=rot)
457458
sweep_move_dx = 0.0
458-
sweep_move_dy = -0.8
459+
sweep_move_dy = -1.0
459460
sweep_move_dz = 0.0
460461

461462
# Execute the sweep. Note simulation fn and args not implemented yet.
@@ -496,13 +497,19 @@ def _pick_and_dump_policy(name: str, robot_obj_idx: int, target_obj_idx: int,
496497

497498
def _fn() -> None:
498499
for action in actions:
499-
assert isinstance(action.extra_info, (list, tuple))
500-
_, _, action_fn, action_fn_args, _, _ = action.extra_info
501-
action_fn(*action_fn_args)
500+
if isinstance(action.extra_info, (list, tuple)):
501+
_, _, action_fn, action_fn_args, _, _ = action.extra_info
502+
action_fn(*action_fn_args)
503+
continue
504+
else:
505+
action_fn = action.extra_info.real_world_fn
506+
action_fn_args = action.extra_info.real_world_fn_args
507+
action_fn(*action_fn_args)
508+
continue
502509

503510
# Note simulation fn and args not implemented yet.
504-
action_extra_info = SpotActionExtraInfo(name, objects, _fn, tuple(), None,
505-
tuple())
511+
action_extra_info = SpotActionExtraInfo(name, objects, _fn, tuple(), None, tuple())
512+
506513
return utils.create_spot_env_action(action_extra_info)
507514

508515

@@ -595,7 +602,7 @@ def _pick_object_to_drag_policy(state: State, memory: Dict,
595602
params: Array) -> Action:
596603
name = "PickObjectToDrag"
597604
target_obj_idx = 1
598-
if objects[target_obj_idx ].name == 'green_handle':
605+
if objects[target_obj_idx ].name == 'green_handle' or 'chair' in objects[target_obj_idx].name:
599606
return _grasp_policy(name, target_obj_idx, state, memory, objects, params, do_not_stow=True)
600607
return _grasp_policy(name, target_obj_idx, state, memory, objects, params)
601608

@@ -892,7 +899,7 @@ def _prepare_container_for_sweeping_policy(state: State, memory: Dict,
892899
rot = math_helpers.Quat.from_pitch(np.pi / 2)
893900
place_rel_pose = math_helpers.SE3Pose(x=0.6,
894901
y=0.0,
895-
z=container_z - 0.15,
902+
z=container_z, # TODO - 0.15,
896903
rot=rot)
897904

898905
# Push towards the target a little bit after placing.
@@ -917,7 +924,7 @@ def _move_to_ready_sweep_policy(state: State, memory: Dict,
917924
name = "MoveToReadySweep"
918925

919926
# Always approach from the same angle.
920-
yaw = np.pi / 2.0
927+
yaw = 0.0 #np.pi / 2.0
921928
# Make up new params.
922929
distance = 0.8
923930
params = np.array([distance, yaw])
@@ -931,6 +938,55 @@ def _move_to_ready_sweep_policy(state: State, memory: Dict,
931938
state, memory, objects, params)
932939

933940

941+
def _wipe_table_policy(state: State, memory: Dict,
942+
objects: Sequence[Object],
943+
params: Array) -> Action:
944+
del memory # not used
945+
946+
robot, _, _ = get_robot()
947+
name = "WipeTable"
948+
949+
robot_obj = objects[0]
950+
surface_obj = objects[2]
951+
952+
robot_pose = utils.get_se3_pose_from_state(state, robot_obj)
953+
surface_pose = utils.get_se3_pose_from_state(state, surface_obj)
954+
surface_height = state.get(surface_obj, "height")
955+
if surface_obj.name == "wooden_table":
956+
surface_height -= 1.0
957+
958+
# Compute relative pose for wiping start position
959+
surface_rel_pose = robot_pose.inverse() * surface_pose
960+
961+
# Extract parameters
962+
stroke_dx, stroke_dy, num_strokes_float, duration = params
963+
num_strokes = max(1, int(num_strokes_float))
964+
965+
# Define wipe start pose relative to robot
966+
pitch = math_helpers.Quat.from_pitch(np.pi / 2)
967+
wipe_start_pose = math_helpers.SE3Pose(
968+
x=surface_rel_pose.x,
969+
y=surface_rel_pose.y - 0.2,
970+
z=surface_height + 0.05,
971+
rot=pitch)
972+
973+
# End look pose after wiping
974+
end_look_pose = math_helpers.SE3Pose(
975+
x=surface_rel_pose.x - 0.1,
976+
y=surface_rel_pose.y,
977+
z=surface_height + 0.3,
978+
rot=math_helpers.Quat.from_pitch(np.pi / 2.5))
979+
980+
# Delta between strokes
981+
delta_between_strokes = (0.05, 0.0)
982+
983+
action_extra_info = SpotActionExtraInfo(
984+
name, objects, wipe_multiple_strokes,
985+
(robot, wipe_start_pose, end_look_pose, stroke_dx, stroke_dy,
986+
delta_between_strokes, num_strokes, duration), None, ())
987+
return utils.create_spot_env_action(action_extra_info)
988+
989+
934990
###############################################################################
935991
# Parameterized option factory #
936992
###############################################################################
@@ -963,6 +1019,7 @@ def _move_to_ready_sweep_policy(state: State, memory: Dict,
9631019
"PrepareContainerForSweeping": Box(-np.inf, np.inf, (3, )), # dx, dy, dyaw
9641020
"DropNotPlaceableObject": Box(0, 1, (0, )), # empty
9651021
"MoveToReadySweep": Box(0, 1, (0, )), # empty
1022+
"WipeTable": Box(-np.inf, np.inf, (4, )), # stroke_dx, stroke_dy, num_strokes, duration
9661023
}
9671024

9681025
# NOTE: the policies MUST be unique because they output actions with extra info
@@ -988,6 +1045,7 @@ def _move_to_ready_sweep_policy(state: State, memory: Dict,
9881045
"PrepareContainerForSweeping": _prepare_container_for_sweeping_policy,
9891046
"DropNotPlaceableObject": _drop_not_placeable_object_policy,
9901047
"MoveToReadySweep": _move_to_ready_sweep_policy,
1048+
"WipeTable": _wipe_table_policy,
9911049
}
9921050

9931051

@@ -1034,7 +1092,10 @@ def get_env_names(cls) -> Set[str]:
10341092
"spot_brush_shelf_env",
10351093
"lis_spot_block_floor_env",
10361094
"lis_spot_block_drawer_env",
1037-
"lis_spot_collect_misplaced_items_env"
1095+
"lis_spot_collect_misplaced_items_env",
1096+
"lis_spot_balls_yellow_table_env",
1097+
"lis_spot_bear_panda_bucket_sweep_env",
1098+
"lis_spot_wipe_table_env"
10381099
}
10391100

10401101
@classmethod

predicators/perception/spot_perceiver.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""A perceiver specific to spot envs."""
22

3+
from datetime import datetime
34
import logging
45
import time
56
from pathlib import Path
@@ -284,6 +285,11 @@ def _create_state(self) -> State:
284285
# Now finish the state.
285286
state = _PartialPerceptionState(percept_state.data,
286287
simulator_state=simulator_state)
288+
289+
# Save state for debugging
290+
now = datetime.now()
291+
with open(CFG.spot_perception_outdir + f"/0_{now.strftime('%Y%m%d_%H%M%S')}_latest_perceived_state.txt", "w") as f:
292+
f.write(state.pretty_str())
287293

288294
return state
289295

@@ -452,6 +458,28 @@ def _create_goal(self, state: State,
452458
return {
453459
GroundAtom(On, [bucket, shelf]),
454460
}
461+
if goal_description == "sweep the brown bear toy and panda toy into the bucket":
462+
brown_bear = Object("brown_bear_toy", _movable_object_type)
463+
panda = Object("panda_toy", _movable_object_type)
464+
chick_toy = Object("chick_toy", _movable_object_type)
465+
bucket = Object("bucket", _container_type)
466+
Inside = pred_name_to_pred["Inside"]
467+
# table = Object("wooden_table", _immovable_object_type)
468+
# On = pred_name_to_pred["On"]
469+
wooden_table = Object("wooden_table", _immovable_object_type)
470+
NotBlocked = pred_name_to_pred["NotBlocked"]
471+
blue_toy_chair = Object("blue_toy_chair", _movable_object_type)
472+
Blocking = pred_name_to_pred["Blocking"]
473+
NotInsideAnyContainer = pred_name_to_pred["NotInsideAnyContainer"]
474+
return {
475+
GroundAtom(Inside, [brown_bear, bucket]),
476+
GroundAtom(Inside, [panda, bucket]),
477+
# GroundAtom(Inside, [chick_toy, bucket]),
478+
# GroundAtom(NotBlocked, [wooden_table]),
479+
# GroundAtom(Blocking, [blue_toy_chair, wooden_table]),
480+
#GroundAtom(NotInsideAnyContainer, [brown_bear]),
481+
#GroundAtom(NotInsideAnyContainer, [panda])
482+
}
455483
if goal_description == "pick up the brush":
456484
robot = Object("robot", _robot_type)
457485
brush = Object("brush", _movable_object_type)
@@ -492,6 +520,26 @@ def _create_goal(self, state: State,
492520
GroundAtom(Inside, [yellow_cup, cardboard_box]),
493521
GroundAtom(Inside, [toy_plane, cardboard_box]),
494522
}
523+
if goal_description == "put the tennis ball and red ball on the yellow table":
524+
tennis_ball = Object("tennis_ball", _movable_object_type)
525+
red_ball = Object("red_ball", _movable_object_type)
526+
yellow_table = Object("yellow_table", _immovable_object_type)
527+
On = pred_name_to_pred["On"]
528+
Inside = pred_name_to_pred["Inside"]
529+
return {
530+
GroundAtom(On, [tennis_ball, yellow_table]),
531+
GroundAtom(On, [red_ball, yellow_table]),
532+
}
533+
if goal_description == "wipe the wooden table with the sponge":
534+
wooden_table = Object("wooden_table", _immovable_object_type)
535+
sponge = Object("sponge", _movable_object_type)
536+
orange_bucket = Object("orange_bucket", _container_type)
537+
SurfaceWiped = pred_name_to_pred["SurfaceWiped"]
538+
Inside = pred_name_to_pred["Inside"]
539+
return {
540+
GroundAtom(SurfaceWiped, [wooden_table]),
541+
GroundAtom(Inside, [sponge, orange_bucket]),
542+
}
495543
if goal_description == "setup sweeping":
496544
robot = Object("robot", _robot_type)
497545
brush = Object("brush", _movable_object_type)

predicators/planning.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,11 +322,11 @@ def task_plan(
322322
in tests/test_planning for usage examples.
323323
"""
324324
if not goal.issubset(reachable_atoms):
325-
logging.info(f"Detected goal unreachable. Goal: {goal}")
326-
logging.info(f"Initial atoms: {init_atoms}")
325+
logging.info(f"Detected goal unreachable. Goal: {sorted(list(goal))}\n")
326+
logging.info(f"Initial atoms: {sorted(list(init_atoms))}\n")
327327
logging.info(
328-
f"Reachable atoms not in init: {reachable_atoms - init_atoms}")
329-
raise PlanningFailure(f"Goal {goal} not dr-reachable")
328+
f"Reachable atoms not in init: {sorted(list(reachable_atoms - init_atoms))}\n")
329+
raise PlanningFailure(f"Goal {sorted(list(goal))} not dr-reachable\n")
330330
dummy_task = Task(DefaultState, goal)
331331
metrics: Metrics = defaultdict(float)
332332
generator = _skeleton_generator(

0 commit comments

Comments
 (0)