mani-skill-nightly 2025.5.3.1548__py3-none-any.whl → 2025.5.3.1619__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.
@@ -131,7 +131,7 @@ class OpenCabinetDrawerEnv(BaseEnv):
131
131
  model_ids = self._batched_episode_rng.choice(self.all_model_ids)
132
132
  link_ids = self._batched_episode_rng.randint(0, 2**31)
133
133
 
134
- self._cabinets = []
134
+ self._cabinets: List[Articulation] = []
135
135
  handle_links: List[List[Link]] = []
136
136
  handle_links_meshes: List[List[trimesh.Trimesh]] = []
137
137
  for i, model_id in enumerate(model_ids):
@@ -163,7 +163,7 @@ class OpenCabinetDrawerEnv(BaseEnv):
163
163
  handle_links[-1].append(link)
164
164
  # save the first mesh in the link object that correspond with a handle
165
165
  handle_links_meshes[-1].append(
166
- link.generate_visual_mesh(
166
+ link.generate_mesh(
167
167
  filter=lambda _, render_shape: "handle"
168
168
  in render_shape.name,
169
169
  mesh_name="handle",
@@ -242,27 +242,33 @@ class Actor(PhysxRigidDynamicComponentStruct[sapien.Entity]):
242
242
  cg[group] = value
243
243
  cs.set_collision_groups(cg)
244
244
 
245
- def get_first_collision_mesh(self, to_world_frame: bool = True) -> trimesh.Trimesh:
245
+ def get_first_collision_mesh(
246
+ self, to_world_frame: bool = True
247
+ ) -> Union[trimesh.Trimesh, None]:
246
248
  """
247
249
  Returns the collision mesh of the first managed actor object. Note results of this are not cached or optimized at the moment
248
- so this function can be slow if called too often
250
+ so this function can be slow if called too often. Some actors have no collision meshes, in which case this function returns None
249
251
 
250
252
  Args:
251
253
  to_world_frame (bool): Whether to transform the collision mesh pose to the world frame
252
254
  """
253
- return self.get_collision_meshes(to_world_frame=to_world_frame, first_only=True)
255
+ mesh = self.get_collision_meshes(to_world_frame=to_world_frame, first_only=True)
256
+ if isinstance(mesh, trimesh.Trimesh):
257
+ return mesh
258
+ return None
254
259
 
255
260
  def get_collision_meshes(
256
261
  self, to_world_frame: bool = True, first_only: bool = False
257
- ) -> List[trimesh.Trimesh]:
262
+ ) -> Union[List[trimesh.Trimesh], trimesh.Trimesh]:
258
263
  """
259
264
  Returns the collision mesh of each managed actor object. Note results of this are not cached or optimized at the moment
260
- so this function can be slow if called too often
265
+ so this function can be slow if called too often. Some actors have no collision meshes, in which case this function returns an empty list.
261
266
 
262
267
  Args:
263
268
  to_world_frame (bool): Whether to transform the collision mesh pose to the world frame
264
269
  first_only (bool): Whether to return the collision mesh of just the first actor managed by this object. If True,
265
- this also returns a single Trimesh.Mesh object instead of a list
270
+ this also returns a single Trimesh.Mesh object instead of a list. This can be useful for efficiency reasons if you know
271
+ ahead of time all of the managed actors have the same collision mesh
266
272
  """
267
273
  assert (
268
274
  not self.merged
@@ -274,9 +280,12 @@ class Actor(PhysxRigidDynamicComponentStruct[sapien.Entity]):
274
280
  actor_meshes = []
275
281
  for comp in actor.components:
276
282
  if isinstance(comp, physx.PhysxRigidBaseComponent):
277
- actor_meshes.append(merge_meshes(get_component_meshes(comp)))
283
+ merged = merge_meshes(get_component_meshes(comp))
284
+ if merged is not None:
285
+ actor_meshes.append(merged)
278
286
  mesh = merge_meshes(actor_meshes)
279
- meshes.append(mesh)
287
+ if mesh is not None:
288
+ meshes.append(mesh)
280
289
  if first_only:
281
290
  break
282
291
  if to_world_frame:
@@ -287,6 +296,8 @@ class Actor(PhysxRigidDynamicComponentStruct[sapien.Entity]):
287
296
  mesh.apply_transform(mat[i].sp.to_transformation_matrix())
288
297
  else:
289
298
  mesh.apply_transform(mat.sp.to_transformation_matrix())
299
+ if len(meshes) == 0:
300
+ return []
290
301
  if first_only:
291
302
  return meshes[0]
292
303
  return meshes
@@ -320,19 +320,24 @@ class Articulation(BaseStruct[physx.PhysxArticulation]):
320
320
  # g0, g1, g2, g3 = s.get_collision_groups()
321
321
  # s.set_collision_groups([g0, g1, g2 | (1 << 29), g3])
322
322
 
323
- def get_first_collision_mesh(self, to_world_frame: bool = True) -> trimesh.Trimesh:
323
+ def get_first_collision_mesh(
324
+ self, to_world_frame: bool = True
325
+ ) -> Union[trimesh.Trimesh, None]:
324
326
  """
325
327
  Returns the collision mesh of the first managed articulation object. Note results of this are not cached or optimized at the moment
326
- so this function can be slow if called too often
328
+ so this function can be slow if called too often. Some articulations have no collision meshes, in which case this function returns None
327
329
 
328
330
  Args:
329
331
  to_world_frame (bool): Whether to transform the collision mesh pose to the world frame
330
332
  """
331
- return self.get_collision_meshes(to_world_frame=to_world_frame, first_only=True)
333
+ mesh = self.get_collision_meshes(to_world_frame=to_world_frame, first_only=True)
334
+ if isinstance(mesh, trimesh.Trimesh):
335
+ return mesh
336
+ return None
332
337
 
333
338
  def get_collision_meshes(
334
339
  self, to_world_frame: bool = True, first_only: bool = False
335
- ) -> List[trimesh.Trimesh]:
340
+ ) -> Union[List[trimesh.Trimesh], trimesh.Trimesh]:
336
341
  """
337
342
  Returns the collision mesh of each managed articulation object. Note results of this are not cached or optimized at the moment
338
343
  so this function can be slow if called too often
@@ -340,7 +345,8 @@ class Articulation(BaseStruct[physx.PhysxArticulation]):
340
345
  Args:
341
346
  to_world_frame (bool): Whether to transform the collision mesh pose to the world frame
342
347
  first_only (bool): Whether to return the collision mesh of just the first articulation managed by this object. If True,
343
- this also returns a single Trimesh.Mesh object instead of a list
348
+ this also returns a single Trimesh.Mesh object instead of a list. This can be useful for efficiency reasons if you know
349
+ ahead of time all of the managed actors have the same collision mesh
344
350
  """
345
351
  assert (
346
352
  not self.merged
@@ -365,9 +371,12 @@ class Articulation(BaseStruct[physx.PhysxArticulation]):
365
371
  link_mesh.apply_transform(pose.sp.to_transformation_matrix())
366
372
  art_meshes.append(link_mesh)
367
373
  mesh = merge_meshes(art_meshes)
368
- meshes.append(mesh)
374
+ if mesh is not None:
375
+ meshes.append(mesh)
369
376
  if first_only:
370
377
  break
378
+ if len(meshes) == 0:
379
+ return []
371
380
  if first_only:
372
381
  return meshes[0]
373
382
  return meshes
@@ -0,0 +1,85 @@
1
+ import torch
2
+ import gymnasium as gym
3
+ from mani_skill.envs.sapien_env import BaseEnv
4
+ from mani_skill.utils.structs.types import Array
5
+
6
+
7
+ class ActionRepeatWrapper(gym.Wrapper):
8
+ def __init__(self, env: BaseEnv, repeat: int):
9
+ """
10
+ Environment wrapper that repeats the action for a number of steps.
11
+ This wrapper will perform the same action at most repeat times, if the environment is done before repeating the action repeat times, then we only return valid data (up to the done=True).
12
+
13
+ Args:
14
+ env (BaseEnv): The base environment to wrap.
15
+ repeat (int): The number of times to repeat the action, repeat=1 means no action repeat (we use perform 1 action per step), repeat=2 means the action is repeated twice, so the environment will step twice with the same action.
16
+ """
17
+ super().__init__(env)
18
+ self.repeat = repeat
19
+
20
+ @property
21
+ def num_envs(self):
22
+ return self.base_env.num_envs
23
+
24
+ @property
25
+ def base_env(self) -> BaseEnv:
26
+ return self.env.unwrapped
27
+
28
+ def step(self, action):
29
+ final_obs, final_rew, final_terminations, final_truncations, infos = (
30
+ super().step(action)
31
+ )
32
+
33
+ is_obs_dict = isinstance(final_obs, dict)
34
+
35
+ dones = torch.logical_or(final_terminations, final_truncations)
36
+ not_dones = ~dones
37
+
38
+ if not_dones.any():
39
+ for _ in range(self.repeat - 1):
40
+ new_obs, new_rew, new_terminations, new_truncations, new_infos = (
41
+ super().step(action)
42
+ )
43
+
44
+ if is_obs_dict:
45
+ self._update_dict_values(
46
+ from_dict=new_obs, to_dict=final_obs, not_dones=not_dones
47
+ )
48
+ else:
49
+ final_obs[not_dones] = new_obs[not_dones]
50
+
51
+ final_rew[not_dones] += new_rew[not_dones]
52
+ final_terminations[not_dones] = torch.logical_or(
53
+ final_terminations, new_terminations
54
+ )[not_dones]
55
+ final_truncations[not_dones] = torch.logical_or(
56
+ final_truncations, new_truncations
57
+ )[not_dones]
58
+ self._update_dict_values(
59
+ from_dict=new_infos, to_dict=infos, not_dones=not_dones
60
+ )
61
+
62
+ dones = torch.logical_or(final_terminations, final_truncations)
63
+ not_dones = ~dones
64
+
65
+ if dones.all():
66
+ break
67
+
68
+ return final_obs, final_rew, final_terminations, final_truncations, infos
69
+
70
+ def _update_dict_values(self, from_dict: dict, to_dict: dict, not_dones: Array):
71
+ """
72
+ Recursively updates the values of a dictionary with the values from another dictionary but only for the envs that are not done.
73
+ This allows us to update the observation and info dictionaries with new values only for the environments that are not done.
74
+ If a sub-env becomes done, its future step data will be discarded since not_dones will be false for this sub-environment.
75
+ Therefore the final observation/info will come from the true last step of the sub-env.
76
+ """
77
+ for k, v in from_dict.items():
78
+ if isinstance(v, dict):
79
+ self._update_dict_values(
80
+ from_dict=v, to_dict=to_dict[k], not_dones=not_dones
81
+ )
82
+ elif isinstance(v, Array):
83
+ to_dict[k][not_dones] = v[not_dones]
84
+ else:
85
+ to_dict[k] = v
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mani-skill-nightly
3
- Version: 2025.5.3.1548
3
+ Version: 2025.5.3.1619
4
4
  Summary: ManiSkill3: A Unified Benchmark for Generalizable Manipulation Skills
5
5
  Home-page: https://github.com/haosulab/ManiSkill
6
6
  Author: ManiSkill contributors
@@ -587,7 +587,7 @@ mani_skill/envs/tasks/humanoid/assets/cardboard_box/01.png,sha256=UAzLp_o885YkTu
587
587
  mani_skill/envs/tasks/humanoid/assets/cardboard_box/box.mtl,sha256=E7F4ELdSP2Yd62T_rF_-gN1xa6N6Eo3AqAb17R5TSa8,219
588
588
  mani_skill/envs/tasks/humanoid/assets/cardboard_box/textured.obj,sha256=XQEt4EeMiW4kx4GhNOYk8TPi7lSuS6XTEBQjWSsxKJ0,12723
589
589
  mani_skill/envs/tasks/mobile_manipulation/__init__.py,sha256=GQajIA-t_p_9Hrhkj5-MEEmbGfaIkCYgaDepVUdhJ2Q,98
590
- mani_skill/envs/tasks/mobile_manipulation/open_cabinet_drawer.py,sha256=RBSjXseWSulU76gMIkDdAAhghZ2Wp38qF3hxb21UI8I,15925
590
+ mani_skill/envs/tasks/mobile_manipulation/open_cabinet_drawer.py,sha256=xokzhopVVnNJJjm0kyw7OlvrdADmIz7rkxyXG6XPj9E,15938
591
591
  mani_skill/envs/tasks/mobile_manipulation/robocasa/__init__.py,sha256=mjpK3FNM5GnR4CaWfD1i2gVk5tU4N6tTkDm2pCqsfoo,40
592
592
  mani_skill/envs/tasks/mobile_manipulation/robocasa/kitchen.py,sha256=fXLoTIDgk-0eEaH7TrCODYWfVOVkGP6cRzinyfKEkWc,25625
593
593
  mani_skill/envs/tasks/quadruped/__init__.py,sha256=_AHS3H9Cj2XT7--5jwW1NMmVWbZxRpdGDNXudT6OrZM,92
@@ -784,8 +784,8 @@ mani_skill/utils/scene_builder/table/assets/Dining_Table_204_1.glb,sha256=IleHi3
784
784
  mani_skill/utils/scene_builder/table/assets/table.glb,sha256=yw69itZDjBFg8JXZAr9VQV-dZD-MaZChhqBSJR_nlRo,3891588
785
785
  mani_skill/utils/structs/README.md,sha256=qnYKimp_ZkgNcduURrYQxVTimNmq_usDMKoQ8VtMdCs,286
786
786
  mani_skill/utils/structs/__init__.py,sha256=BItR3Xe0z6xCrMHAEaH0AAAVyeonsQ3q-DJUyRUibAA,524
787
- mani_skill/utils/structs/actor.py,sha256=ImzUZULVnsaBksk5Zu2FD-GgYpfg1u4XZcH1jCtd-vQ,16772
788
- mani_skill/utils/structs/articulation.py,sha256=6olG0RxQ84J8p7479Mn3bdy6tsMKLpWKMu3NRbbgzfo,34235
787
+ mani_skill/utils/structs/actor.py,sha256=L0p6vkr8rGtJmF22xAq8Q7nhXKnDD5dahzODSAko0bg,17394
788
+ mani_skill/utils/structs/articulation.py,sha256=c7e_Rfkhskg_Rqz1bkesqHCTzNubObLGZQS0BkkFZF0,34691
789
789
  mani_skill/utils/structs/articulation_joint.py,sha256=TY6joQ0RpnVlHbQHdtx_QQYqTWgFHLiZ642SSWZUuTw,11736
790
790
  mani_skill/utils/structs/base.py,sha256=meGQK5Y4KtHKLnp9VeOZS2gtwg9tE55whuEeqOguBaI,19465
791
791
  mani_skill/utils/structs/decorators.py,sha256=Lv6wQ989dOnreo2tB-qopDnkeBp_jsn1pmfUR-OY8VQ,535
@@ -800,6 +800,7 @@ mani_skill/utils/visualization/jupyter_utils.py,sha256=dXXUQz-rFTOV_Xq5yA6YE6cXg
800
800
  mani_skill/utils/visualization/misc.py,sha256=KrDCef7F5GmGOdiBQ4qFUnmUTe-7-nNBz2DVBGFD8YU,5041
801
801
  mani_skill/utils/visualization/renderer.py,sha256=-Z18-fXe5NLBYBYXFB9m2EDKdhOkAdDVWSs9vjxGCSQ,1245
802
802
  mani_skill/utils/wrappers/__init__.py,sha256=f6HDHHoM8gyNgX5RwTr2u3oGlAeHqawRvVNQiWXEJfI,229
803
+ mani_skill/utils/wrappers/action_repeat.py,sha256=RhCtzt3fYCtD-CClIOhAzdycGwVTXP_FG61yEf-QLqY,3542
803
804
  mani_skill/utils/wrappers/flatten.py,sha256=GuHJ3fCOdj9G_jm--XgG8k0p2G1eJx4LY1tesQQjnkg,4913
804
805
  mani_skill/utils/wrappers/frame_stack.py,sha256=pCp83HqXnFxbsKRYgwXreNBHnhD-yF0R2_7jdtGOTWQ,4213
805
806
  mani_skill/utils/wrappers/gymnasium.py,sha256=p0kl29kkedD2arIvGskClKhYDBAH97mZO4rTepz62jQ,4174
@@ -810,8 +811,8 @@ mani_skill/vector/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
810
811
  mani_skill/vector/wrappers/gymnasium.py,sha256=v1MDPIrVACBKCulrpdXBK2jDZQI7LKYFZgGgaCC5avY,7408
811
812
  mani_skill/vector/wrappers/sb3.py,sha256=SlXdiEPqcNHYMhJCzA29kBU6zK7DKTe1nc0L6Z3QQtY,4722
812
813
  mani_skill/viewer/__init__.py,sha256=srvDBsk4LQU75K2VIttrhiQ68p_ro7PSDqQRls2PY5c,1722
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,,
814
+ mani_skill_nightly-2025.5.3.1619.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
815
+ mani_skill_nightly-2025.5.3.1619.dist-info/METADATA,sha256=_GtuLPVaaiZsUUCPLl9Twf3rCk5MAQnQkGuxVJ5hjsY,9291
816
+ mani_skill_nightly-2025.5.3.1619.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
817
+ mani_skill_nightly-2025.5.3.1619.dist-info/top_level.txt,sha256=bkBgOVl_MZMoQx2aRFsSFEYlZLxjWlip5vtJ39FB3jA,11
818
+ mani_skill_nightly-2025.5.3.1619.dist-info/RECORD,,