isaac-sim / IsaacLab

Unified framework for robot learning built on NVIDIA Isaac Sim
https://isaac-sim.github.io/IsaacLab
Other
2.15k stars 880 forks source link

[Question] Resetting a Cloth object (or any custom object outside of SceneCfg) #250

Closed haastregt closed 1 month ago

haastregt commented 8 months ago

I am using cloth with particle physics for a simulation that I have. Since the cloth physics are not yet available in Orbit, I have been using the Isaac Sim API directly. I added the cloth in a post_init step like so:

@configclass
class ClothEnvCfg(BaseEnvCfg):
    scene: ClothRemovalSceneCfg = ClothRemovalSceneCfg(num_envs=1, env_spacing=2.0)
    actions: ActionsCfg = ActionsCfg()
    observations: ObservationsCfg = ObservationsCfg()
    randomization: RandomizationCfg = RandomizationCfg()

    def __post_init__(self):
        self.decimation = 5
        self.sim.dt = 0.005

        stage = omni.usd.get_context().get_stage()
        default_prim: Usd.Prim = UsdGeom.Xform.Define(stage, Sdf.Path("/World")).GetPrim()
        stage.SetDefaultPrim(default_prim)

        default_prim_path = stage.GetDefaultPrim().GetPath()
        scene = UsdPhysics.Scene.Define(stage, default_prim_path.AppendPath("physicsScene"))
        create_cloth(stage, default_prim_path, scene)

# Create Cloth from Isaac Sim ParticleClothDemo
def create_cloth(stage, default_prim_path, scene):
    plane_resolution = 100
    plane_width = 20.0

    success, tmp_path = omni.kit.commands.execute(
        "CreateMeshPrimWithDefaultXform",
        prim_type="Plane",
        u_patches=plane_resolution,
        v_patches=plane_resolution,
        u_verts_scale=1,
        v_verts_scale=1,
        half_scale=0.5 * plane_width,
    )
    if not success:
        print(f"Failed to create plane")

    cloth_mesh_path = Sdf.Path(omni.usd.get_stage_next_free_path(stage, "/Cloth", True))
    omni.kit.commands.execute("MovePrim", path_from=tmp_path, path_to=cloth_mesh_path)

    cloth_mesh = UsdGeom.Mesh.Define(stage, cloth_mesh_path)
    physicsUtils.setup_transform_as_scale_orient_translate(cloth_mesh)
    physicsUtils.set_or_add_translate_op(cloth_mesh, Gf.Vec3f(0.5, 0.0, 0.3))
    physicsUtils.set_or_add_orient_op(cloth_mesh, Gf.Quatf(1.0, Gf.Vec3f(0.0, 0.0, 0.0)))
    physicsUtils.set_or_add_scale_op(cloth_mesh, Gf.Vec3f(1.0))

    particle_system_path = default_prim_path.AppendChild("particleSystem")

    # size rest offset according to plane resolution and width so that particles are just touching at rest
    radius = 0.5 * (plane_width / plane_resolution)/20
    restOffset = radius
    contactOffset = restOffset * 1.5

    particleUtils.add_physx_particle_system(
        stage=stage,
        particle_system_path=particle_system_path,
        contact_offset=contactOffset,
        rest_offset=restOffset,
        particle_contact_offset=contactOffset,
        solid_rest_offset=restOffset,
        fluid_rest_offset=0.0,
        solver_position_iterations=16,
        simulation_owner=scene.GetPath(),
    )

    # create material and assign it to the system:
    particle_material_path = default_prim_path.AppendChild("particleMaterial")
    particleUtils.add_pbd_particle_material(stage, particle_material_path)
    # add some drag and lift to get aerodynamic effects
    particleUtils.add_pbd_particle_material(stage, particle_material_path, drag=0.02, lift=0.02, friction=1.0)
    physicsUtils.add_physics_material_to_prim(
        stage, stage.GetPrimAtPath(particle_system_path), particle_material_path
    )

    # configure as cloth
    stretchStiffness = 10000.0
    bendStiffness = 200.0
    shearStiffness = 100.0
    damping = 0.2
    particleUtils.add_physx_particle_cloth(
        stage=stage,
        path=cloth_mesh_path,
        dynamic_mesh_path=None,
        particle_system_path=particle_system_path,
        spring_stretch_stiffness=stretchStiffness,
        spring_bend_stiffness=bendStiffness,
        spring_shear_stiffness=shearStiffness,
        spring_damping=damping,
        self_collision=True,
        self_collision_filter=True,
    )

    # configure mass:
    particle_mass = 0.002
    num_verts = len(cloth_mesh.GetPointsAttr().Get())
    mass = particle_mass * num_verts
    massApi = UsdPhysics.MassAPI.Apply(cloth_mesh.GetPrim())
    massApi.GetMassAttr().Set(mass)

    # add render material:
    def create_pbd_material(mat_name: str, color_rgb: Gf.Vec3f = Gf.Vec3f(0.2, 0.2, 0.8)) -> Sdf.Path:
        # create material for extras
        create_list = []
        omni.kit.commands.execute(
            "CreateAndBindMdlMaterialFromLibrary",
            mdl_name="OmniPBR.mdl",
            mtl_name="OmniPBR",
            mtl_created_list=create_list,
            bind_selected_prims=False,
        )
        target_path = "/World/Looks/" + mat_name
        if create_list[0] != target_path:
            omni.kit.commands.execute("MovePrims", paths_to_move={create_list[0]: target_path})
        shader = UsdShade.Shader.Get(stage, target_path + "/Shader")
        shader.CreateInput("diffuse_color_constant", Sdf.ValueTypeNames.Color3f).Set(color_rgb)

    material_path = create_pbd_material("OmniPBR")
    omni.kit.commands.execute(
        "BindMaterialCommand", prim_path=cloth_mesh_path, material_path=material_path, strength=None
    )

My RandomizationCfg looks as follows:

@configclass
class RandomizationCfg:
    reset_scene = RandomizationTermCfg(
        func=mdp.reset_scene_to_default,
        mode="reset",
    )

Unfortunately, mdp.reset_scene_to_default() does not reset the cloth object (it does reset other objects such as cubes, robot). I guess that this is because it is not in the ClothRemovalSceneCfg with the other Assets.

Would there be a way to write a custom reset function for this? Or could I somehow create the cloth in the ClothRemovalSceneCfg anyways (I could call the create_cloth function in there maybe, but then what kind of return value should I use? How could I wrap it in an AssetCfg? Or suggestions that involve making changes to Orbit are also fine, I'd gladly contribute)

Alternatively, in Isaac Sim resetting particle systems seems to be done by stopping and restarting the simulation, however I can't find this functionality in the Orbit environments (BaseEnv class). The GUI does not have a stop button anymore either. I did not manage to find any API calls to reset particle physics to their initial state.

I understand that you are still hard at work on making deformable and particle physics work streamlined within Orbit. However since some examples of cloth physics have been shown in the paper and the website, I assume that some method must exist even if it is cumbersome.

Any help or insight is greatly appreciated!

Dhoeller19 commented 1 month ago

Hi @haastregt, This feature will come as soon as we officially support it in Isaac Lab. A workaround for now is to create a direct workflow environment.