【Maniskill】Articulation说明
Articulation
关键属性
-
links(List[Link]):
封装的连杆对象列表;每个Link再封装对应的刚体、网格等信息。
对于 GPU 模式,属性如link.pose、link.linear_velocity等通常为形状(N, ...)的张量。 -
links_map(Dict[str, Link]):
名称到Link的映射,可用links_map["gripper"]这种方式快速索引。 -
root(Link):
根连杆(基座)的Link对象。 -
joints(List[ArticulationJoint]),joints_map(Dict[str, ArticulationJoint]):
封装的关节对象及其名称映射。 -
active_joints,active_joints_map:
仅包含活动自由度(可驱动的关节)的列表及名称映射。 -
name(str):
当前 articulation 的名字。 -
merged(bool):
是否为合并 articulation:- 若为
True,很多与“单一物理对象结构”紧密相关的属性(如links、joints、接触力等)将不再有直接物理语义,仅保留 DOF 级别的统一访问。 - 合并 articulation 主要用于批量管理不同 DOF/结构的对象,如统一
qpos/qvel张量形状。
- 若为
-
max_dof(int, 只读):
所有内部PhysxArticulation中 DOF 的最大值,用于对qpos、qvel、qf等进行零填充,使其形状统一为(N, max_dof)。 -
dof(torch.Tensor):
每个内部 articulation 的 DOF 数,形状(N,),在 GPU 模式下保持在device上。 -
pose/root_pose(Pose/sapien.Pose):
根连杆的姿态(位置 + 四元数);pose是root_pose的别名。 -
qpos,qvel,qacc,qf(torch.Tensor):- 形状:
(N, max_dof),其中N为并行 articulation 数。 - 在 GPU 模式下,直接映射到底层
px.cuda_articulation_*的统一视图张量; - 在 CPU 模式下,对第一个物理 articulation 读写(并在第 0 维扩展一维批次)。
- 形状:
-
drive_targets,drive_velocities(torch.Tensor):- 当前活动关节的驱动位置/速度目标,形状为
(N, M),M为活动 DOF 数。 - GPU 模式直接从
px.cuda_articulation_target_qpos/qvel中以 meshgrid 索引方式切片。
- 当前活动关节的驱动位置/速度目标,形状为
常用方法(高层接口)
下面列出在上层任务/控制代码中最常使用的一些方法。除非特别指出,张量形状中的:
-
(N) 表示并行环境数(或批量 articulation 数);
-
(M) 表示活动关节数;
-
max_dof为Articulation.max_dof。 -
get_state()→torch.Tensor
打包并返回整条 articulation 的状态:
[
[\text{root_pos}(3), \text{root_quat}(4), \text{root_lin_vel}(3), \text{root_ang_vel}(3), qpos(\text{max_dof}), qvel(\text{max_dof})]
]
输出形状为(N, 13 + 2 * max_dof)。 -
set_state(state, env_idx=None)
与get_state()对偶,从打包状态张量中恢复 articulation 的根姿态、线速度、角速度以及qpos、qvel。state(Array): 形状(N, 13 + 2 * max_dof)或单样本;env_idx(torch.Tensor, 可选): 在 GPU 模式下,只对部分环境应用状态重置,内部会暂时修改scene._reset_mask做安全防护。
-
get_first_collision_mesh(to_world_frame=True)→trimesh.Trimesh | None
返回第一个管理对象的整体碰撞网格(合并各 link 的碰撞几何),可选是否转到世界坐标系。可能返回None。 -
get_collision_meshes(to_world_frame=True, first_only=False)→List[trimesh.Trimesh] | trimesh.Trimesh
返回所有管理对象的碰撞网格列表,或在first_only=True时仅返回第一个对象的网格。 -
get_first_visual_mesh(to_world_frame=True),
get_visual_meshes(to_world_frame=True, first_only=False)
与碰撞网格接口类似,但使用渲染形状(visual meshes)。 -
get_net_contact_impulses(link_names)→torch.Tensor
批量获取若干 link 的净接触冲量,形状为(N, len(link_names), 3)。- GPU 模式下通过缓存的
PhysxGpuContactBodyImpulseQuery高效查询; - CPU 模式下遍历场景接触并按 link 名义聚合。
- GPU 模式下通过缓存的
-
get_net_contact_forces(link_names)→torch.Tensor
将get_net_contact_impulses的输出除以scene.timestep,得到接触力((N, len(link_names), 3))。 -
get_joint_target_indices(joint_indices)
为一组活动关节(或关节索引)返回在 GPU 目标张量 (cuda_articulation_target_qpos/qvel) 中的 meshgrid 索引(gx, gy),并进行缓存,用于后续高效写入。 -
set_joint_drive_targets(targets, joints=None, joint_indices=None)
设置活动关节的驱动位置目标:- GPU 模式下仅支持
joint_indices,targets形状通常为(N, K);内部通过 meshgrid 索引写入目标张量; - CPU 模式下需要显式传入
joints列表,逐个调用joint.set_drive_target。
- GPU 模式下仅支持
-
set_joint_drive_velocity_targets(targets, joints=None, joint_indices=None)
与上类似,但写入速度目标。 -
**
get_links()/get_joints()/get_active_joints()/get_name()/get_pose()…
这些方法大多是更清晰的别名或轻量封装,行为与对应属性一致,便于与原生 SAPIEN / PhysX API 对齐。
形状与后端约定
-
在 GPU 模式(
scene.gpu_sim_enabled == True)下:qpos/qvel/qacc/qf等属性直接映射为底层px.cuda_articulation_*张量的切片视图;- 读写操作将直接修改 PhysX GPU 侧的统一缓冲区;
- 某些函数(如
compute_passive_force、create_pinocchio_model)目前不支持,会抛出NotImplementedError。
-
在 CPU 模式下:
qpos等通过self._objs[0](第一个PhysxArticulation)的值构造torch.Tensor,并在第 0 维增加批维度;- 写操作会在必要时将张量转回 NumPy,并写回到 PhysX 对象。
使用示例
from mani_skill.envs.scene import ManiSkillScene
from mani_skill.utils.structs import Articulation
# 假设已经创建好 scene,并在其中构建了若干 physx_articulations
physx_articulations = [...] # List[physx.PhysxArticulation]
scene_idxs = torch.arange(len(physx_articulations), device="cuda")
articulation = Articulation.create_from_physx_articulations(
physx_articulations=physx_articulations,
scene=scene,
scene_idxs=scene_idxs,
)
# 读取/设置关节状态
qpos = articulation.get_qpos() # (N, max_dof)
qvel = articulation.get_qvel()
target_qpos = qpos + 0.1
articulation.set_qpos(target_qpos)
# 批量设置活动关节驱动目标(GPU 模式下,使用 joint_indices)
active_indices = torch.arange(articulation.active_joints.__len__(), device="cuda")
targets = torch.zeros_like(articulation.drive_targets)
articulation.set_joint_drive_targets(targets, joint_indices=active_indices)
# 导出第一个机器人的碰撞网格
mesh = articulation.get_first_collision_mesh(to_world_frame=True)
更多推荐



所有评论(0)