mani-skill-nightly 2025.5.3.1545__py3-none-any.whl → 2025.5.3.1548__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mani_skill/agents/robots/xarm6/xarm6_robotiq.py +12 -0
- mani_skill/envs/tasks/tabletop/plug_charger.py +22 -21
- mani_skill/examples/motionplanning/xarm6/__init__.py +0 -0
- mani_skill/examples/motionplanning/xarm6/motionplanner.py +111 -0
- mani_skill/examples/motionplanning/xarm6/run.py +148 -0
- mani_skill/examples/motionplanning/xarm6/solutions/__init__.py +4 -0
- mani_skill/examples/motionplanning/xarm6/solutions/pick_cube.py +66 -0
- mani_skill/examples/motionplanning/xarm6/solutions/plug_charger.py +111 -0
- mani_skill/examples/motionplanning/xarm6/solutions/push_cube.py +38 -0
- mani_skill/examples/motionplanning/xarm6/solutions/stack_cube.py +92 -0
- mani_skill/utils/assets/data.py +1 -0
- {mani_skill_nightly-2025.5.3.1545.dist-info → mani_skill_nightly-2025.5.3.1548.dist-info}/METADATA +1 -1
- {mani_skill_nightly-2025.5.3.1545.dist-info → mani_skill_nightly-2025.5.3.1548.dist-info}/RECORD +16 -8
- {mani_skill_nightly-2025.5.3.1545.dist-info → mani_skill_nightly-2025.5.3.1548.dist-info}/LICENSE +0 -0
- {mani_skill_nightly-2025.5.3.1545.dist-info → mani_skill_nightly-2025.5.3.1548.dist-info}/WHEEL +0 -0
- {mani_skill_nightly-2025.5.3.1545.dist-info → mani_skill_nightly-2025.5.3.1548.dist-info}/top_level.txt +0 -0
@@ -403,6 +403,18 @@ class XArm6Robotiq(BaseAgent):
|
|
403
403
|
)
|
404
404
|
return torch.logical_and(lflag, rflag)
|
405
405
|
|
406
|
+
@staticmethod
|
407
|
+
def build_grasp_pose(approaching, closing, center):
|
408
|
+
"""Build a grasp pose ()."""
|
409
|
+
assert np.abs(1 - np.linalg.norm(approaching)) < 1e-3
|
410
|
+
assert np.abs(1 - np.linalg.norm(closing)) < 1e-3
|
411
|
+
assert np.abs(approaching @ closing) <= 1e-3
|
412
|
+
ortho = np.cross(closing, approaching)
|
413
|
+
T = np.eye(4)
|
414
|
+
T[:3, :3] = np.stack([ortho, closing, approaching], axis=1)
|
415
|
+
T[:3, 3] = center
|
416
|
+
return sapien.Pose(T)
|
417
|
+
|
406
418
|
def is_static(self, threshold: float = 0.2):
|
407
419
|
qvel = self.robot.get_qvel()[..., :-6]
|
408
420
|
return torch.max(torch.abs(qvel), 1)[0] <= threshold
|
@@ -183,28 +183,29 @@ class PlugChargerEnv(BaseEnv):
|
|
183
183
|
self.scene_builder.initialize(env_idx)
|
184
184
|
|
185
185
|
# Initialize agent
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
qpos = (
|
200
|
-
torch.normal(
|
201
|
-
0, self.robot_init_qpos_noise, (b, len(qpos)), device=self.device
|
186
|
+
if self.agent.uid == "panda_wristcam":
|
187
|
+
qpos = torch.tensor(
|
188
|
+
[
|
189
|
+
0.0,
|
190
|
+
np.pi / 8,
|
191
|
+
0,
|
192
|
+
-np.pi * 5 / 8,
|
193
|
+
0,
|
194
|
+
np.pi * 3 / 4,
|
195
|
+
np.pi / 4,
|
196
|
+
0.04,
|
197
|
+
0.04,
|
198
|
+
]
|
202
199
|
)
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
200
|
+
qpos = (
|
201
|
+
torch.normal(
|
202
|
+
0, self.robot_init_qpos_noise, (b, len(qpos)), device=self.device
|
203
|
+
)
|
204
|
+
+ qpos
|
205
|
+
)
|
206
|
+
qpos[:, -2:] = 0.04
|
207
|
+
self.agent.robot.set_qpos(qpos)
|
208
|
+
self.agent.robot.set_pose(sapien.Pose([-0.615, 0, 0]))
|
208
209
|
|
209
210
|
# Initialize charger
|
210
211
|
xy = randomization.uniform(
|
File without changes
|
@@ -0,0 +1,111 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import mplib
|
3
|
+
from mani_skill.examples.motionplanning.panda.motionplanner import PandaArmMotionPlanningSolver
|
4
|
+
from mani_skill.envs.sapien_env import BaseEnv
|
5
|
+
import sapien.core as sapien
|
6
|
+
|
7
|
+
from mani_skill.utils.structs.pose import to_sapien_pose
|
8
|
+
|
9
|
+
|
10
|
+
class XArm6RobotiqMotionPlanningSolver(PandaArmMotionPlanningSolver):
|
11
|
+
CLOSED = 0.81
|
12
|
+
OPEN = 0
|
13
|
+
|
14
|
+
def __init__(self, env: BaseEnv, debug: bool = False, vis: bool = True, base_pose: sapien.Pose = None, visualize_target_grasp_pose: bool = True, print_env_info: bool = True, joint_vel_limits=0.9, joint_acc_limits=0.9):
|
15
|
+
super().__init__(env, debug, vis, base_pose, visualize_target_grasp_pose, print_env_info, joint_vel_limits, joint_acc_limits)
|
16
|
+
self.gripper_state = self.OPEN
|
17
|
+
|
18
|
+
def setup_planner(self):
|
19
|
+
link_names = [link.get_name() for link in self.robot.get_links()]
|
20
|
+
joint_names = [joint.get_name() for joint in self.robot.get_active_joints()]
|
21
|
+
planner = mplib.Planner(
|
22
|
+
urdf=self.env_agent.urdf_path,
|
23
|
+
srdf=self.env_agent.urdf_path.replace(".urdf", ".srdf"),
|
24
|
+
user_link_names=link_names,
|
25
|
+
user_joint_names=joint_names,
|
26
|
+
move_group="eef",
|
27
|
+
joint_vel_limits=np.ones(6) * self.joint_vel_limits,
|
28
|
+
joint_acc_limits=np.ones(6) * self.joint_acc_limits,
|
29
|
+
)
|
30
|
+
planner.set_base_pose(np.hstack([self.base_pose.p, self.base_pose.q]))
|
31
|
+
return planner
|
32
|
+
|
33
|
+
def open_gripper(self):
|
34
|
+
self.gripper_state = self.OPEN
|
35
|
+
qpos = self.robot.get_qpos()[0, :6].cpu().numpy()
|
36
|
+
for i in range(6):
|
37
|
+
if self.control_mode == "pd_joint_pos":
|
38
|
+
action = np.hstack([qpos, self.gripper_state])
|
39
|
+
else:
|
40
|
+
action = np.hstack([qpos, qpos * 0, self.gripper_state])
|
41
|
+
obs, reward, terminated, truncated, info = self.env.step(action)
|
42
|
+
self.elapsed_steps += 1
|
43
|
+
if self.print_env_info:
|
44
|
+
print(
|
45
|
+
f"[{self.elapsed_steps:3}] Env Output: reward={reward} info={info}"
|
46
|
+
)
|
47
|
+
if self.vis:
|
48
|
+
self.base_env.render_human()
|
49
|
+
return obs, reward, terminated, truncated, info
|
50
|
+
|
51
|
+
def close_gripper(self, t=6, gripper_state = CLOSED):
|
52
|
+
self.gripper_state = gripper_state
|
53
|
+
qpos = self.robot.get_qpos()[0, :6].cpu().numpy()
|
54
|
+
for i in range(t):
|
55
|
+
if self.control_mode == "pd_joint_pos":
|
56
|
+
action = np.hstack([qpos, self.gripper_state])
|
57
|
+
else:
|
58
|
+
action = np.hstack([qpos, qpos * 0, self.gripper_state])
|
59
|
+
obs, reward, terminated, truncated, info = self.env.step(action)
|
60
|
+
self.elapsed_steps += 1
|
61
|
+
if self.print_env_info:
|
62
|
+
print(
|
63
|
+
f"[{self.elapsed_steps:3}] Env Output: reward={reward} info={info}"
|
64
|
+
)
|
65
|
+
if self.vis:
|
66
|
+
self.base_env.render_human()
|
67
|
+
return obs, reward, terminated, truncated, info
|
68
|
+
|
69
|
+
def move_to_pose_with_RRTStar(
|
70
|
+
self, pose: sapien.Pose, dry_run: bool = False, refine_steps: int = 0
|
71
|
+
):
|
72
|
+
pose = to_sapien_pose(pose)
|
73
|
+
if self.grasp_pose_visual is not None:
|
74
|
+
self.grasp_pose_visual.set_pose(pose)
|
75
|
+
pose = sapien.Pose(p=pose.p, q=pose.q)
|
76
|
+
result = self.planner.plan_qpos_to_pose(
|
77
|
+
np.concatenate([pose.p, pose.q]),
|
78
|
+
self.robot.get_qpos().cpu().numpy()[0],
|
79
|
+
time_step=self.base_env.control_timestep,
|
80
|
+
use_point_cloud=self.use_point_cloud,
|
81
|
+
rrt_range=0.0,
|
82
|
+
planning_time=1,
|
83
|
+
planner_name="RRTstar",
|
84
|
+
wrt_world=True,
|
85
|
+
)
|
86
|
+
if result["status"] != "Success":
|
87
|
+
print(result["status"])
|
88
|
+
self.render_wait()
|
89
|
+
return -1
|
90
|
+
self.render_wait()
|
91
|
+
if dry_run:
|
92
|
+
return result
|
93
|
+
return self.follow_path(result, refine_steps=refine_steps)
|
94
|
+
|
95
|
+
|
96
|
+
class XArm6PandaGripperMotionPlanningSolver(PandaArmMotionPlanningSolver):
|
97
|
+
def setup_planner(self):
|
98
|
+
link_names = [link.get_name() for link in self.robot.get_links()]
|
99
|
+
joint_names = [joint.get_name() for joint in self.robot.get_active_joints()]
|
100
|
+
planner = mplib.Planner(
|
101
|
+
urdf=self.env_agent.urdf_path,
|
102
|
+
srdf=self.env_agent.urdf_path.replace(".urdf", ".srdf"),
|
103
|
+
user_link_names=link_names,
|
104
|
+
user_joint_names=joint_names,
|
105
|
+
move_group="panda_hand_tcp",
|
106
|
+
joint_vel_limits=np.ones(6) * self.joint_vel_limits,
|
107
|
+
joint_acc_limits=np.ones(6) * self.joint_acc_limits,
|
108
|
+
)
|
109
|
+
planner.set_base_pose(np.hstack([self.base_pose.p, self.base_pose.q]))
|
110
|
+
return planner
|
111
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
import multiprocessing as mp
|
2
|
+
import os
|
3
|
+
from copy import deepcopy
|
4
|
+
import time
|
5
|
+
import argparse
|
6
|
+
import gymnasium as gym
|
7
|
+
import numpy as np
|
8
|
+
from tqdm import tqdm
|
9
|
+
import os.path as osp
|
10
|
+
from mani_skill.utils.wrappers.record import RecordEpisode
|
11
|
+
from mani_skill.trajectory.merge_trajectory import merge_trajectories
|
12
|
+
from mani_skill.examples.motionplanning.xarm6.solutions import solvePickCube, solvePushCube, solveStackCube, solvePlugCharger
|
13
|
+
|
14
|
+
MP_SOLUTIONS = {
|
15
|
+
"PickCube-v1": solvePickCube,
|
16
|
+
"PushCube-v1": solvePushCube,
|
17
|
+
"StackCube-v1": solveStackCube,
|
18
|
+
"PlugCharger-v1": solvePlugCharger,
|
19
|
+
}
|
20
|
+
|
21
|
+
def parse_args(args=None):
|
22
|
+
parser = argparse.ArgumentParser()
|
23
|
+
parser.add_argument("-e", "--env-id", type=str, default="PickCube-v1", help=f"Environment to run motion planning solver on. Available options are {list(MP_SOLUTIONS.keys())}")
|
24
|
+
parser.add_argument("-o", "--obs-mode", type=str, default="none", help="Observation mode to use. Usually this is kept as 'none' as observations are not necesary to be stored, they can be replayed later via the mani_skill.trajectory.replay_trajectory script.")
|
25
|
+
parser.add_argument("-n", "--num-traj", type=int, default=10, help="Number of trajectories to generate.")
|
26
|
+
parser.add_argument("--only-count-success", action="store_true", help="If true, generates trajectories until num_traj of them are successful and only saves the successful trajectories/videos")
|
27
|
+
parser.add_argument("--reward-mode", type=str)
|
28
|
+
parser.add_argument("-b", "--sim-backend", type=str, default="auto", help="Which simulation backend to use. Can be 'auto', 'cpu', 'gpu'")
|
29
|
+
parser.add_argument("--render-mode", type=str, default="rgb_array", help="can be 'sensors' or 'rgb_array' which only affect what is saved to videos")
|
30
|
+
parser.add_argument("--vis", action="store_true", help="whether or not to open a GUI to visualize the solution live")
|
31
|
+
parser.add_argument("--save-video", action="store_true", help="whether or not to save videos locally")
|
32
|
+
parser.add_argument("--traj-name", type=str, help="The name of the trajectory .h5 file that will be created.")
|
33
|
+
parser.add_argument("--shader", default="default", type=str, help="Change shader used for rendering. Default is 'default' which is very fast. Can also be 'rt' for ray tracing and generating photo-realistic renders. Can also be 'rt-fast' for a faster but lower quality ray-traced renderer")
|
34
|
+
parser.add_argument("--record-dir", type=str, default="demos", help="where to save the recorded trajectories")
|
35
|
+
parser.add_argument("--num-procs", type=int, default=1, help="Number of processes to use to help parallelize the trajectory replay process. This uses CPU multiprocessing and only works with the CPU simulation backend at the moment.")
|
36
|
+
return parser.parse_args()
|
37
|
+
|
38
|
+
def _main(args, proc_id: int = 0, start_seed: int = 0) -> str:
|
39
|
+
env_id = args.env_id
|
40
|
+
env = gym.make(
|
41
|
+
env_id,
|
42
|
+
obs_mode=args.obs_mode,
|
43
|
+
control_mode="pd_joint_pos",
|
44
|
+
render_mode=args.render_mode,
|
45
|
+
robot_uids="xarm6_robotiq",
|
46
|
+
reward_mode="dense" if args.reward_mode is None else args.reward_mode,
|
47
|
+
sensor_configs=dict(shader_pack=args.shader),
|
48
|
+
human_render_camera_configs=dict(shader_pack=args.shader),
|
49
|
+
viewer_camera_configs=dict(shader_pack=args.shader),
|
50
|
+
sim_backend=args.sim_backend
|
51
|
+
)
|
52
|
+
if env_id not in MP_SOLUTIONS:
|
53
|
+
raise RuntimeError(f"No already written motion planning solutions for {env_id}. Available options are {list(MP_SOLUTIONS.keys())}")
|
54
|
+
|
55
|
+
if not args.traj_name:
|
56
|
+
new_traj_name = time.strftime("%Y%m%d_%H%M%S")
|
57
|
+
else:
|
58
|
+
new_traj_name = args.traj_name
|
59
|
+
|
60
|
+
if args.num_procs > 1:
|
61
|
+
new_traj_name = new_traj_name + "." + str(proc_id)
|
62
|
+
env = RecordEpisode(
|
63
|
+
env,
|
64
|
+
output_dir=osp.join(args.record_dir, env_id, "motionplanning"),
|
65
|
+
trajectory_name=new_traj_name, save_video=args.save_video,
|
66
|
+
source_type="motionplanning",
|
67
|
+
source_desc="official motion planning solution from ManiSkill contributors",
|
68
|
+
video_fps=30,
|
69
|
+
save_on_reset=False
|
70
|
+
)
|
71
|
+
output_h5_path = env._h5_file.filename
|
72
|
+
solve = MP_SOLUTIONS[env_id]
|
73
|
+
print(f"Motion Planning Running on {env_id}")
|
74
|
+
pbar = tqdm(range(args.num_traj), desc=f"proc_id: {proc_id}")
|
75
|
+
seed = start_seed
|
76
|
+
successes = []
|
77
|
+
solution_episode_lengths = []
|
78
|
+
failed_motion_plans = 0
|
79
|
+
passed = 0
|
80
|
+
while True:
|
81
|
+
try:
|
82
|
+
res = solve(env, seed=seed, debug=False, vis=True if args.vis else False)
|
83
|
+
except Exception as e:
|
84
|
+
print(f"Cannot find valid solution because of an error in motion planning solution: {e}")
|
85
|
+
res = -1
|
86
|
+
|
87
|
+
if res == -1:
|
88
|
+
success = False
|
89
|
+
failed_motion_plans += 1
|
90
|
+
else:
|
91
|
+
success = res[-1]["success"].item()
|
92
|
+
elapsed_steps = res[-1]["elapsed_steps"].item()
|
93
|
+
solution_episode_lengths.append(elapsed_steps)
|
94
|
+
successes.append(success)
|
95
|
+
if args.only_count_success and not success:
|
96
|
+
seed += 1
|
97
|
+
env.flush_trajectory(save=False)
|
98
|
+
if args.save_video:
|
99
|
+
env.flush_video(save=False)
|
100
|
+
continue
|
101
|
+
else:
|
102
|
+
env.flush_trajectory()
|
103
|
+
if args.save_video:
|
104
|
+
env.flush_video()
|
105
|
+
pbar.update(1)
|
106
|
+
pbar.set_postfix(
|
107
|
+
dict(
|
108
|
+
success_rate=np.mean(successes),
|
109
|
+
failed_motion_plan_rate=failed_motion_plans / (seed + 1),
|
110
|
+
avg_episode_length=np.mean(solution_episode_lengths),
|
111
|
+
max_episode_length=np.max(solution_episode_lengths),
|
112
|
+
# min_episode_length=np.min(solution_episode_lengths)
|
113
|
+
)
|
114
|
+
)
|
115
|
+
seed += 1
|
116
|
+
passed += 1
|
117
|
+
if passed == args.num_traj:
|
118
|
+
break
|
119
|
+
env.close()
|
120
|
+
return output_h5_path
|
121
|
+
|
122
|
+
def main(args):
|
123
|
+
if args.num_procs > 1 and args.num_procs < args.num_traj:
|
124
|
+
if args.num_traj < args.num_procs:
|
125
|
+
raise ValueError("Number of trajectories should be greater than or equal to number of processes")
|
126
|
+
args.num_traj = args.num_traj // args.num_procs
|
127
|
+
seeds = [*range(0, args.num_procs * args.num_traj, args.num_traj)]
|
128
|
+
pool = mp.Pool(args.num_procs)
|
129
|
+
proc_args = [(deepcopy(args), i, seeds[i]) for i in range(args.num_procs)]
|
130
|
+
res = pool.starmap(_main, proc_args)
|
131
|
+
pool.close()
|
132
|
+
# Merge trajectory files
|
133
|
+
output_path = res[0][: -len("0.h5")] + "h5"
|
134
|
+
merge_trajectories(output_path, res)
|
135
|
+
for h5_path in res:
|
136
|
+
tqdm.write(f"Remove {h5_path}")
|
137
|
+
os.remove(h5_path)
|
138
|
+
json_path = h5_path.replace(".h5", ".json")
|
139
|
+
tqdm.write(f"Remove {json_path}")
|
140
|
+
os.remove(json_path)
|
141
|
+
else:
|
142
|
+
_main(args)
|
143
|
+
|
144
|
+
if __name__ == "__main__":
|
145
|
+
# start = time.time()
|
146
|
+
mp.set_start_method("spawn")
|
147
|
+
main(parse_args())
|
148
|
+
# print(f"Total time taken: {time.time() - start}")
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import sapien
|
3
|
+
|
4
|
+
from mani_skill.envs.tasks import PickCubeEnv
|
5
|
+
from mani_skill.examples.motionplanning.xarm6.motionplanner import \
|
6
|
+
XArm6RobotiqMotionPlanningSolver, XArm6PandaGripperMotionPlanningSolver
|
7
|
+
from mani_skill.examples.motionplanning.panda.utils import (
|
8
|
+
compute_grasp_info_by_obb, get_actor_obb)
|
9
|
+
|
10
|
+
def solve(env: PickCubeEnv, seed=None, debug=False, vis=False):
|
11
|
+
env.reset(seed=seed)
|
12
|
+
|
13
|
+
if env.unwrapped.robot_uids == "xarm6_robotiq":
|
14
|
+
planner_cls = XArm6RobotiqMotionPlanningSolver
|
15
|
+
elif env.unwrapped.robot_uids == "xarm6_pandagripper":
|
16
|
+
planner_cls = XArm6PandaGripperMotionPlanningSolver
|
17
|
+
else:
|
18
|
+
raise ValueError(f"Unsupported robot uid: {env.robot_uid}")
|
19
|
+
planner = planner_cls(
|
20
|
+
env,
|
21
|
+
debug=debug,
|
22
|
+
vis=vis,
|
23
|
+
base_pose=env.unwrapped.agent.robot.pose,
|
24
|
+
visualize_target_grasp_pose=vis,
|
25
|
+
print_env_info=False,
|
26
|
+
)
|
27
|
+
|
28
|
+
FINGER_LENGTH = 0.025
|
29
|
+
env = env.unwrapped
|
30
|
+
|
31
|
+
# retrieves the object oriented bounding box (trimesh box object)
|
32
|
+
obb = get_actor_obb(env.cube)
|
33
|
+
|
34
|
+
approaching = np.array([0, 0, -1])
|
35
|
+
# get transformation matrix of the tcp pose, is default batched and on torch
|
36
|
+
target_closing = env.agent.tcp.pose.to_transformation_matrix()[0, :3, 1].cpu().numpy()
|
37
|
+
# we can build a simple grasp pose using this information
|
38
|
+
grasp_info = compute_grasp_info_by_obb(
|
39
|
+
obb,
|
40
|
+
approaching=approaching,
|
41
|
+
target_closing=target_closing,
|
42
|
+
depth=FINGER_LENGTH,
|
43
|
+
)
|
44
|
+
closing, center = grasp_info["closing"], grasp_info["center"]
|
45
|
+
grasp_pose = env.agent.build_grasp_pose(approaching, closing, env.cube.pose.sp.p)
|
46
|
+
|
47
|
+
# -------------------------------------------------------------------------- #
|
48
|
+
# Reach
|
49
|
+
# -------------------------------------------------------------------------- #
|
50
|
+
reach_pose = grasp_pose * sapien.Pose([0, 0, -0.05])
|
51
|
+
planner.move_to_pose_with_RRTStar(reach_pose)
|
52
|
+
|
53
|
+
# -------------------------------------------------------------------------- #
|
54
|
+
# Grasp
|
55
|
+
# -------------------------------------------------------------------------- #
|
56
|
+
planner.move_to_pose_with_screw(grasp_pose)
|
57
|
+
planner.close_gripper()
|
58
|
+
|
59
|
+
# -------------------------------------------------------------------------- #
|
60
|
+
# Move to goal pose
|
61
|
+
# -------------------------------------------------------------------------- #
|
62
|
+
goal_pose = sapien.Pose(env.goal_site.pose.sp.p, grasp_pose.q)
|
63
|
+
res = planner.move_to_pose_with_screw(goal_pose)
|
64
|
+
|
65
|
+
planner.close()
|
66
|
+
return res
|
@@ -0,0 +1,111 @@
|
|
1
|
+
import gymnasium as gym
|
2
|
+
import numpy as np
|
3
|
+
import sapien.core as sapien
|
4
|
+
import trimesh
|
5
|
+
from tqdm import tqdm
|
6
|
+
from transforms3d.euler import euler2quat
|
7
|
+
|
8
|
+
from mani_skill.envs.tasks import PlugChargerEnv
|
9
|
+
from mani_skill.examples.motionplanning.xarm6.motionplanner import \
|
10
|
+
XArm6RobotiqMotionPlanningSolver, XArm6PandaGripperMotionPlanningSolver
|
11
|
+
from mani_skill.examples.motionplanning.panda.utils import (
|
12
|
+
compute_grasp_info_by_obb, get_actor_obb)
|
13
|
+
|
14
|
+
|
15
|
+
def main():
|
16
|
+
env: PlugChargerEnv = gym.make(
|
17
|
+
"PlugCharger-v1",
|
18
|
+
obs_mode="none",
|
19
|
+
control_mode="pd_joint_pos",
|
20
|
+
render_mode="rgb_array",
|
21
|
+
reward_mode="sparse",
|
22
|
+
)
|
23
|
+
for seed in tqdm(range(100)):
|
24
|
+
res = solve(env, seed=seed, debug=False, vis=True)
|
25
|
+
print(res[-1])
|
26
|
+
env.close()
|
27
|
+
|
28
|
+
|
29
|
+
def solve(env: PlugChargerEnv, seed=None, debug=False, vis=False):
|
30
|
+
env.reset(seed=seed)
|
31
|
+
assert env.unwrapped.control_mode in [
|
32
|
+
"pd_joint_pos",
|
33
|
+
"pd_joint_pos_vel",
|
34
|
+
], env.unwrapped.control_mode
|
35
|
+
if env.unwrapped.robot_uids == "xarm6_robotiq":
|
36
|
+
planner_cls = XArm6RobotiqMotionPlanningSolver
|
37
|
+
elif env.unwrapped.robot_uids == "xarm6_pandagripper":
|
38
|
+
planner_cls = XArm6PandaGripperMotionPlanningSolver
|
39
|
+
else:
|
40
|
+
raise ValueError(f"Unsupported robot uid: {env.robot_uid}")
|
41
|
+
planner = planner_cls(
|
42
|
+
env,
|
43
|
+
debug=debug,
|
44
|
+
vis=vis,
|
45
|
+
base_pose=env.unwrapped.agent.robot.pose,
|
46
|
+
visualize_target_grasp_pose=False,
|
47
|
+
print_env_info=False,
|
48
|
+
joint_vel_limits=0.5,
|
49
|
+
joint_acc_limits=0.5,
|
50
|
+
)
|
51
|
+
|
52
|
+
FINGER_LENGTH = 0.025
|
53
|
+
env = env.unwrapped
|
54
|
+
charger_base_pose = env.charger_base_pose
|
55
|
+
charger_base_size = np.array(env.unwrapped._base_size) * 2
|
56
|
+
|
57
|
+
obb = trimesh.primitives.Box(
|
58
|
+
extents=charger_base_size,
|
59
|
+
transform=charger_base_pose.sp.to_transformation_matrix(),
|
60
|
+
)
|
61
|
+
|
62
|
+
approaching = np.array([0, 0, -1])
|
63
|
+
target_closing = env.agent.tcp.pose.sp.to_transformation_matrix()[:3, 1]
|
64
|
+
grasp_info = compute_grasp_info_by_obb(
|
65
|
+
obb,
|
66
|
+
approaching=approaching,
|
67
|
+
target_closing=target_closing,
|
68
|
+
depth=FINGER_LENGTH,
|
69
|
+
)
|
70
|
+
closing, center = grasp_info["closing"], grasp_info["center"]
|
71
|
+
grasp_pose = env.agent.build_grasp_pose(approaching, closing, center)
|
72
|
+
|
73
|
+
# add a angle to grasp
|
74
|
+
grasp_angle = np.deg2rad(15)
|
75
|
+
grasp_pose = grasp_pose * sapien.Pose(q=euler2quat(0, grasp_angle, 0))
|
76
|
+
|
77
|
+
# -------------------------------------------------------------------------- #
|
78
|
+
# Reach
|
79
|
+
# -------------------------------------------------------------------------- #
|
80
|
+
reach_pose = grasp_pose * sapien.Pose([0, 0, -0.05])
|
81
|
+
planner.move_to_pose_with_RRTStar(reach_pose)
|
82
|
+
|
83
|
+
# -------------------------------------------------------------------------- #
|
84
|
+
# Grasp
|
85
|
+
# -------------------------------------------------------------------------- #
|
86
|
+
planner.move_to_pose_with_screw(grasp_pose)
|
87
|
+
planner.close_gripper()
|
88
|
+
|
89
|
+
# -------------------------------------------------------------------------- #
|
90
|
+
# Align
|
91
|
+
# -------------------------------------------------------------------------- #
|
92
|
+
pre_insert_pose = (
|
93
|
+
env.goal_pose.sp
|
94
|
+
* sapien.Pose([-0.05, 0.0, 0.0])
|
95
|
+
* env.charger.pose.sp.inv()
|
96
|
+
* env.agent.tcp.pose.sp
|
97
|
+
)
|
98
|
+
insert_pose = env.goal_pose.sp * env.charger.pose.sp.inv() * env.agent.tcp.pose.sp * sapien.Pose([0, 0, -0.005])
|
99
|
+
planner.move_to_pose_with_screw(pre_insert_pose, refine_steps=0)
|
100
|
+
planner.move_to_pose_with_screw(pre_insert_pose, refine_steps=5)
|
101
|
+
# -------------------------------------------------------------------------- #
|
102
|
+
# Insert
|
103
|
+
# -------------------------------------------------------------------------- #
|
104
|
+
res = planner.move_to_pose_with_screw(insert_pose)
|
105
|
+
|
106
|
+
planner.close()
|
107
|
+
return res
|
108
|
+
|
109
|
+
|
110
|
+
if __name__ == "__main__":
|
111
|
+
main()
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import sapien
|
3
|
+
|
4
|
+
from mani_skill.envs.tasks import PushCubeEnv
|
5
|
+
from mani_skill.examples.motionplanning.xarm6.motionplanner import \
|
6
|
+
XArm6RobotiqMotionPlanningSolver, XArm6PandaGripperMotionPlanningSolver
|
7
|
+
|
8
|
+
def solve(env: PushCubeEnv, seed=None, debug=False, vis=False):
|
9
|
+
env.reset(seed=seed)
|
10
|
+
if env.unwrapped.robot_uids == "xarm6_robotiq":
|
11
|
+
planner_cls = XArm6RobotiqMotionPlanningSolver
|
12
|
+
elif env.unwrapped.robot_uids == "xarm6_pandagripper":
|
13
|
+
planner_cls = XArm6PandaGripperMotionPlanningSolver
|
14
|
+
else:
|
15
|
+
raise ValueError(f"Unsupported robot uid: {env.robot_uid}")
|
16
|
+
planner = planner_cls(
|
17
|
+
env,
|
18
|
+
debug=debug,
|
19
|
+
vis=vis,
|
20
|
+
base_pose=env.unwrapped.agent.robot.pose,
|
21
|
+
visualize_target_grasp_pose=vis,
|
22
|
+
print_env_info=False,
|
23
|
+
)
|
24
|
+
|
25
|
+
FINGER_LENGTH = 0.025
|
26
|
+
env = env.unwrapped
|
27
|
+
planner.close_gripper()
|
28
|
+
reach_pose = sapien.Pose(p=env.obj.pose.sp.p + np.array([-0.05, 0, 0]), q=env.agent.tcp.pose.sp.q)
|
29
|
+
planner.move_to_pose_with_RRTStar(reach_pose)
|
30
|
+
|
31
|
+
# -------------------------------------------------------------------------- #
|
32
|
+
# Move to goal pose
|
33
|
+
# -------------------------------------------------------------------------- #
|
34
|
+
goal_pose = sapien.Pose(p=env.goal_region.pose.sp.p,q=env.agent.tcp.pose.sp.q)
|
35
|
+
res = planner.move_to_pose_with_screw(goal_pose)
|
36
|
+
|
37
|
+
planner.close()
|
38
|
+
return res
|
@@ -0,0 +1,92 @@
|
|
1
|
+
import argparse
|
2
|
+
import gymnasium as gym
|
3
|
+
import numpy as np
|
4
|
+
import sapien
|
5
|
+
from transforms3d.euler import euler2quat
|
6
|
+
|
7
|
+
from mani_skill.envs.tasks import StackCubeEnv
|
8
|
+
from mani_skill.examples.motionplanning.xarm6.motionplanner import \
|
9
|
+
XArm6RobotiqMotionPlanningSolver, XArm6PandaGripperMotionPlanningSolver
|
10
|
+
from mani_skill.examples.motionplanning.panda.utils import (
|
11
|
+
compute_grasp_info_by_obb, get_actor_obb)
|
12
|
+
from mani_skill.utils.wrappers.record import RecordEpisode
|
13
|
+
|
14
|
+
def solve(env: StackCubeEnv, seed=None, debug=False, vis=False):
|
15
|
+
env.reset(seed=seed)
|
16
|
+
assert env.unwrapped.control_mode in [
|
17
|
+
"pd_joint_pos",
|
18
|
+
"pd_joint_pos_vel",
|
19
|
+
], env.unwrapped.control_mode
|
20
|
+
if env.unwrapped.robot_uids == "xarm6_robotiq":
|
21
|
+
planner_cls = XArm6RobotiqMotionPlanningSolver
|
22
|
+
elif env.unwrapped.robot_uids == "xarm6_pandagripper":
|
23
|
+
planner_cls = XArm6PandaGripperMotionPlanningSolver
|
24
|
+
else:
|
25
|
+
raise ValueError(f"Unsupported robot uid: {env.robot_uid}")
|
26
|
+
planner = planner_cls(
|
27
|
+
env,
|
28
|
+
debug=debug,
|
29
|
+
vis=vis,
|
30
|
+
base_pose=env.unwrapped.agent.robot.pose,
|
31
|
+
visualize_target_grasp_pose=vis,
|
32
|
+
print_env_info=False,
|
33
|
+
)
|
34
|
+
FINGER_LENGTH = 0.025
|
35
|
+
env = env.unwrapped
|
36
|
+
obb = get_actor_obb(env.cubeA)
|
37
|
+
|
38
|
+
approaching = np.array([0, 0, -1])
|
39
|
+
target_closing = env.agent.tcp.pose.to_transformation_matrix()[0, :3, 1].numpy()
|
40
|
+
grasp_info = compute_grasp_info_by_obb(
|
41
|
+
obb,
|
42
|
+
approaching=approaching,
|
43
|
+
target_closing=target_closing,
|
44
|
+
depth=FINGER_LENGTH,
|
45
|
+
)
|
46
|
+
closing, center = grasp_info["closing"], grasp_info["center"]
|
47
|
+
grasp_pose = env.agent.build_grasp_pose(approaching, closing, center)
|
48
|
+
|
49
|
+
# Search a valid pose
|
50
|
+
angles = np.arange(0, np.pi * 2 / 3, np.pi / 2)
|
51
|
+
angles = np.repeat(angles, 2)
|
52
|
+
angles[1::2] *= -1
|
53
|
+
for angle in angles:
|
54
|
+
delta_pose = sapien.Pose(q=euler2quat(0, 0, angle))
|
55
|
+
grasp_pose2 = grasp_pose * delta_pose
|
56
|
+
res = planner.move_to_pose_with_RRTStar(grasp_pose2, dry_run=True)
|
57
|
+
if res == -1:
|
58
|
+
continue
|
59
|
+
grasp_pose = grasp_pose2
|
60
|
+
break
|
61
|
+
else:
|
62
|
+
print("Fail to find a valid grasp pose")
|
63
|
+
|
64
|
+
# -------------------------------------------------------------------------- #
|
65
|
+
# Reach
|
66
|
+
# -------------------------------------------------------------------------- #
|
67
|
+
reach_pose = grasp_pose * sapien.Pose([0, 0, -0.05])
|
68
|
+
planner.move_to_pose_with_RRTStar(reach_pose)
|
69
|
+
|
70
|
+
# -------------------------------------------------------------------------- #
|
71
|
+
# Grasp
|
72
|
+
# -------------------------------------------------------------------------- #
|
73
|
+
planner.move_to_pose_with_screw(grasp_pose)
|
74
|
+
planner.close_gripper()
|
75
|
+
|
76
|
+
# -------------------------------------------------------------------------- #
|
77
|
+
# Lift
|
78
|
+
# -------------------------------------------------------------------------- #
|
79
|
+
lift_pose = sapien.Pose([0, 0, 0.1]) * grasp_pose
|
80
|
+
planner.move_to_pose_with_screw(lift_pose)
|
81
|
+
|
82
|
+
# -------------------------------------------------------------------------- #
|
83
|
+
# Stack
|
84
|
+
# -------------------------------------------------------------------------- #
|
85
|
+
goal_pose = env.cubeB.pose * sapien.Pose([0, 0, env.cube_half_size[2] * 2])
|
86
|
+
offset = (goal_pose.p - env.cubeA.pose.p).numpy()[0] # remember that all data in ManiSkill is batched and a torch tensor
|
87
|
+
align_pose = sapien.Pose(lift_pose.p + offset, lift_pose.q)
|
88
|
+
planner.move_to_pose_with_RRTStar(align_pose)
|
89
|
+
|
90
|
+
res = planner.open_gripper()
|
91
|
+
planner.close()
|
92
|
+
return res
|
mani_skill/utils/assets/data.py
CHANGED
@@ -185,6 +185,7 @@ def initialize_data_sources():
|
|
185
185
|
)
|
186
186
|
DATA_SOURCES["xarm6"] = DataSource(
|
187
187
|
source_type="robot",
|
188
|
+
# TODO: update to new url with .convex.stl assets for xarm6 to support motion planning
|
188
189
|
url="https://github.com/haosulab/ManiSkill-XArm6/archive/refs/tags/v0.1.0.zip",
|
189
190
|
target_path="robots/xarm6",
|
190
191
|
)
|
{mani_skill_nightly-2025.5.3.1545.dist-info → mani_skill_nightly-2025.5.3.1548.dist-info}/RECORD
RENAMED
@@ -65,7 +65,7 @@ mani_skill/agents/robots/xarm/__init__.py,sha256=6Mhn4vV4f9XxcK493U5W9VE6yGGgydP
|
|
65
65
|
mani_skill/agents/robots/xarm/xarm7_ability.py,sha256=yj7CUBQpbGVUiT22qweJKTniJE0DxdEyyKj329vr0HY,6106
|
66
66
|
mani_skill/agents/robots/xarm6/__init__.py,sha256=0r19OsKmm1ssKB5Rrie8syWQvpXNooVOv6m-iygrdM0,109
|
67
67
|
mani_skill/agents/robots/xarm6/xarm6_nogripper.py,sha256=FPhOpWQw5RPsSHLhZ9JWjYeh25GboO4I5_Hn05Ub84Q,7379
|
68
|
-
mani_skill/agents/robots/xarm6/xarm6_robotiq.py,sha256=
|
68
|
+
mani_skill/agents/robots/xarm6/xarm6_robotiq.py,sha256=80DsYdfcPbqL-o1VjZ_KkTWweEH1a9NS9y4lFHCtMSk,16129
|
69
69
|
mani_skill/assets/maniskill2-scene-2.glb,sha256=C5om9o9r6B-fWoauzNfUm2WV5sh8Nf7AvZRlYo1-IXQ,4737204
|
70
70
|
mani_skill/assets/deformable_manipulation/beaker.glb,sha256=MMaoH6OruVSzO8CKuK2AMyaxA5kjsbbDQXyTVycWsPI,18104
|
71
71
|
mani_skill/assets/deformable_manipulation/bottle.glb,sha256=AHWoATBEBeesfbiYNfSB0O0PWhsH0oa2wUBv79w9AVA,36476
|
@@ -602,7 +602,7 @@ mani_skill/envs/tasks/tabletop/pick_cube.py,sha256=dQC3smYUttMLJHXAFMO31vFZKzQ4N
|
|
602
602
|
mani_skill/envs/tasks/tabletop/pick_cube_cfgs.py,sha256=Zz_F3QI_sSqKNDsngp1mzPgkiyewVu47N2iHz522uOg,2166
|
603
603
|
mani_skill/envs/tasks/tabletop/pick_single_ycb.py,sha256=mrqEoOa9UVF34Z5fpsvjcr683diUffsKEjJ9Zh0qfFU,10409
|
604
604
|
mani_skill/envs/tasks/tabletop/place_sphere.py,sha256=J3ReBFK7TyZQlleIFspz7Pl1wqAzaYoveGZfNNL5DVM,10101
|
605
|
-
mani_skill/envs/tasks/tabletop/plug_charger.py,sha256=
|
605
|
+
mani_skill/envs/tasks/tabletop/plug_charger.py,sha256=jgLD2o0eRj-raAEh3ma8OLZ09es6wg8wX1ckWBdr53o,10710
|
606
606
|
mani_skill/envs/tasks/tabletop/poke_cube.py,sha256=KV6mp-Xgm9h4GYUcAUop2AZ4IECTdQKEMRRd9NThyBo,9343
|
607
607
|
mani_skill/envs/tasks/tabletop/pull_cube.py,sha256=txtWuIRFzTKxJtWbrygxVEgOPDvm73WlERXldjlUB-I,5546
|
608
608
|
mani_skill/envs/tasks/tabletop/pull_cube_tool.py,sha256=NaZpdbYYL4zC41GVY__eq4uRIQpVXthzAqe5oSq8YWU,9951
|
@@ -669,6 +669,14 @@ mani_skill/examples/motionplanning/panda/solutions/pull_cube.py,sha256=rQkvCRYjV
|
|
669
669
|
mani_skill/examples/motionplanning/panda/solutions/pull_cube_tool.py,sha256=g6adx921V2SOVYYFlh_gLwV5I0tnz70qCLm81oA6YhA,3609
|
670
670
|
mani_skill/examples/motionplanning/panda/solutions/push_cube.py,sha256=EynyseBJ_njMP74o9gVxqWOOqoC5j1rBc4XQzFug9EQ,1113
|
671
671
|
mani_skill/examples/motionplanning/panda/solutions/stack_cube.py,sha256=QIa280jNOJfJqqgbb5WWEBxErFPE7Mv4-_ZL9TCsRos,3280
|
672
|
+
mani_skill/examples/motionplanning/xarm6/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
673
|
+
mani_skill/examples/motionplanning/xarm6/motionplanner.py,sha256=OcJ2OgY09j3kKl7tFa8GcuGGknF999I_bWZGHZF8lps,4751
|
674
|
+
mani_skill/examples/motionplanning/xarm6/run.py,sha256=yejnUUasyllXZYWpWD9ksvdjgM8o9TwGVfY24kXQxSI,7053
|
675
|
+
mani_skill/examples/motionplanning/xarm6/solutions/__init__.py,sha256=csJg82Tjow5MsYEQEY86ETdPoR59s55KwSg4xaEVyy0,191
|
676
|
+
mani_skill/examples/motionplanning/xarm6/solutions/pick_cube.py,sha256=7gKuTgGrQOuSQr32nZDg07IRk2Dp9jIRCl3TZ1xlPsc,2566
|
677
|
+
mani_skill/examples/motionplanning/xarm6/solutions/plug_charger.py,sha256=myvHjl9Gc2RM2UYb12cOi56C3QbEbeNmvUBLMiHcHp0,3895
|
678
|
+
mani_skill/examples/motionplanning/xarm6/solutions/push_cube.py,sha256=iiZHwvOGGAaxPkzE_sAN6WdTYfcxEMVx0Da3e2rzL48,1419
|
679
|
+
mani_skill/examples/motionplanning/xarm6/solutions/stack_cube.py,sha256=zarkqZ2MSfBu-Uv7DNNiRmqyv_JLPiIWcpONGyfbf0Y,3595
|
672
680
|
mani_skill/examples/teleoperation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
673
681
|
mani_skill/examples/teleoperation/interactive_panda.py,sha256=NsGy_ghtXl3HPbwLjKINkizOXqX_rMr30lUfscmhyQ4,10423
|
674
682
|
mani_skill/render/__init__.py,sha256=Uy6h1bzammUO8QVPVCDcuCuhnuN3e5votaho45drAGw,118
|
@@ -698,7 +706,7 @@ mani_skill/utils/registration.py,sha256=u8ftfGvQP4qzlKNqLQjGi3cRF_-h6Rz-28xbLkW_
|
|
698
706
|
mani_skill/utils/sapien_utils.py,sha256=QMV0jRZO51KzIMB5CVW_Ne-4fPw0-mqM4a3yhNZaMYo,16430
|
699
707
|
mani_skill/utils/assets/README.md,sha256=5kkmsIiV64ySEGO34HaAlpjXTyrGs1KTV5WnofK46G0,70
|
700
708
|
mani_skill/utils/assets/__init__.py,sha256=gQVKwAczcImTXArSltBWKlSUUuguO12sZYO3Jh5KLso,159
|
701
|
-
mani_skill/utils/assets/data.py,sha256=
|
709
|
+
mani_skill/utils/assets/data.py,sha256=7TsxGBVL05Cg6TLjzx9Nv93uzLby1TaatHs-m15oHew,8686
|
702
710
|
mani_skill/utils/building/__init__.py,sha256=quCI5WYGhzGLMVg_NDyYv2G_MxRTBL8R6XD4a6iY8qc,218
|
703
711
|
mani_skill/utils/building/_mjcf_loader.py,sha256=SqzSoRootFvItHrzwrDuSHScePxbaPqWb7262M7HzIU,37011
|
704
712
|
mani_skill/utils/building/actor_builder.py,sha256=sTnpoThOqWegD-87Q7GyaVvB40fiWUwPOQpYkth-sis,14956
|
@@ -802,8 +810,8 @@ mani_skill/vector/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
802
810
|
mani_skill/vector/wrappers/gymnasium.py,sha256=v1MDPIrVACBKCulrpdXBK2jDZQI7LKYFZgGgaCC5avY,7408
|
803
811
|
mani_skill/vector/wrappers/sb3.py,sha256=SlXdiEPqcNHYMhJCzA29kBU6zK7DKTe1nc0L6Z3QQtY,4722
|
804
812
|
mani_skill/viewer/__init__.py,sha256=srvDBsk4LQU75K2VIttrhiQ68p_ro7PSDqQRls2PY5c,1722
|
805
|
-
mani_skill_nightly-2025.5.3.
|
806
|
-
mani_skill_nightly-2025.5.3.
|
807
|
-
mani_skill_nightly-2025.5.3.
|
808
|
-
mani_skill_nightly-2025.5.3.
|
809
|
-
mani_skill_nightly-2025.5.3.
|
813
|
+
mani_skill_nightly-2025.5.3.1548.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
814
|
+
mani_skill_nightly-2025.5.3.1548.dist-info/METADATA,sha256=MFsr_RXRUCYN__3kPl9e6aAwQ8wkLN_Cwe4dC4thaB4,9291
|
815
|
+
mani_skill_nightly-2025.5.3.1548.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
816
|
+
mani_skill_nightly-2025.5.3.1548.dist-info/top_level.txt,sha256=bkBgOVl_MZMoQx2aRFsSFEYlZLxjWlip5vtJ39FB3jA,11
|
817
|
+
mani_skill_nightly-2025.5.3.1548.dist-info/RECORD,,
|
{mani_skill_nightly-2025.5.3.1545.dist-info → mani_skill_nightly-2025.5.3.1548.dist-info}/LICENSE
RENAMED
File without changes
|
{mani_skill_nightly-2025.5.3.1545.dist-info → mani_skill_nightly-2025.5.3.1548.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|