Failed to get pose changes of deformable object

Isaac Sim Version

4.2.0
4.1.0
4.0.0
2023.1.1
2023.1.0-hotfix.1
Other (please specify):

Operating System

Ubuntu 22.04
Ubuntu 20.04
Windows 11
Windows 10
Other (please specify):

GPU Information

  • Model: NVIDIA GeForce RTX 3090 Ti
  • Driver Version: 535.183.01

Topic Description

Detailed Description

I created a deformable object on the ground and grasped it using a Franka robot.
I want to get the pose changes of this deformed body but it always outputs the default pose.

Steps to Reproduce

def load_deformable(world: World):
    current_stage = omni.usd.get_context().get_stage()
    
    for i in range(num_envs):
        deformable_prim_path = f"/World/env_{i}/deformable"
        deformable_name = f"tissue_{i}"
        current_stage.DefinePrim(deformable_prim_path).GetReferences().AddReference(box_usd)
        cube_mesh = UsdGeom.Mesh.Define(current_stage, deformable_prim_path)
            
        cube_mesh.AddTranslateOp().Set(Gf.Vec3f(i+0.3893, 0.005, 0.005))
        cube_mesh.AddScaleOp().Set(Gf.Vec3f(0.1, 0.2, 0.015))
        cube_mesh.CreateDisplayColorAttr().Set([Gf.Vec3f(1, 1, 0)])

        # Add PhysX deformable body
        deformableUtils.add_physx_deformable_body(
            current_stage,
            # cube_mesh.GetPath(),
            deformable_prim_path,
            collision_simplification=True,
            simulation_hexahedral_resolution=30, 
            solver_position_iteration_count=20, 
            self_collision=True,
        )
        
        # Create a physics material
        deformable_material_path = omni.usd.get_stage_next_free_path(current_stage, "/DeformableBodyMaterial", True)
        deformableUtils.add_deformable_body_material(
            current_stage,
            deformable_material_path,
            youngs_modulus=1000.0,
            poissons_ratio=0.3,
            damping_scale=0.0,
            elasticity_damping=0.0001,
            dynamic_friction=0.5,
            density=100,
        )

        # Assign the material to the mesh
        physicsUtils.add_physics_material_to_prim(current_stage, cube_mesh.GetPrim(), deformable_material_path)
        physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(cube_mesh.GetPrim())
        physxCollisionAPI.GetContactOffsetAttr().Set(0.02)
        physxCollisionAPI.CreateRestOffsetAttr().Set(0.001)
    
    deformables = XFormPrimView(
        prim_paths_expr="/World/env_*/deformable",
        name="deformables_view",
    )
    world.scene.add(deformables)
    return deformables

Additional Information

What I’ve Tried

def get_current_poses(deformables):    
    current_positions, current_orientations = deformables.get_world_poses()  
    return current_positions, current_orientations

world = World(backend=backend, device=device)
if device == "cuda":
    world.get_physics_context().enable_gpu_dynamics(True)
world.scene.add_default_ground_plane()

The output is always the same no matter how the object is deformed by robot: (tensor([[0.3893, 0.0050, 0.0050]], device='cuda:0'), tensor([[1., 0., 0., 0.]], device='cuda:0')).

Additional Context

I followed FrankaDeformableDemo.py to create the deformable object in the standard Isaac sim environment.
My guess is I didn’t use exactly the same physX environment as the demo script provided.
What should I add/change to make things work?

What did you mean when you said, “I didn’t use exactly the same PhysX environment as the demo script provided”? Could you please share the complete Python code?

So here is what the FrankaDeformableDemo.py did, I believe it’s all on PhysX.

import carb
import math
import numpy as np
import omni
from pxr import Gf, Sdf, UsdGeom, UsdShade, PhysxSchema, UsdPhysics
import omni.physxdemos as demo
from omni.physx.scripts import deformableUtils, utils, physicsUtils

from omni.physxdemos.utils import franka_helpers
from omni.physxdemos.utils import numpy_utils


class FrankaDeformableDemo(demo.AsyncDemoBase):
    title = "Franka Deformable"
    category = demo.Categories.COMPLEX_SHOWCASES
    short_description = "Demo showing Franka robot arms interacting with deformable cubes"
    description = "The Franka robot arms use Jacobian-based inverse kinematics to lift and drop the red cube in a bowl of deformable cubes."

    kit_settings = {
        "persistent/app/viewport/displayOptions": demo.get_viewport_minimal_display_options_int(),
    }

    params = {"Num_Frankas": demo.IntParam(4, 1, 20, 1), "Num_Greens": demo.IntParam(9, 0, 9, 1)}

    demo_camera = Sdf.Path("/World/Camera")

    def __init__(self):
        super().__init__(enable_tensor_api=True, enable_fabric=False)
        self._reset_hydra_instancing_on_shutdown = False

        # when looping, box will be dropped after lifting and picking action will repeat
        self.loop = True

        self.asset_paths = {
            "franka": demo.get_demo_asset_path("FrankaDeformable/SubUSDs/Franka/franka_alt_fingers.usd"),
            "table": demo.get_demo_asset_path("FrankaDeformable/SubUSDs/Table_Rounded/Table_Rounded.usd"),
            "stool": demo.get_demo_asset_path("FrankaDeformable/SubUSDs/Franka_Stool/Franka_Stool.usd"),
            "cube": demo.get_demo_asset_path("FrankaDeformable/SubUSDs/box_high.usd"),
            "bowl": demo.get_demo_asset_path("FrankaDeformable/SubUSDs/bowl_plate.usd"),
            "cube_materials": demo.get_demo_asset_path("FrankaDeformable/SubUSDs/deformable_cubes_materials.usd"),
        }
        self.demo_base_usd_url = demo.get_demo_asset_path("FrankaDeformable/StagingDeformable.usd")

    def on_startup(self):
        sceneGraphInstancingEnabled = carb.settings.get_settings().get("/persistent/omnihydra/useSceneGraphInstancing")
        if not sceneGraphInstancingEnabled:
            carb.settings.get_settings().set("/persistent/omnihydra/useSceneGraphInstancing", True)
            self._reset_hydra_instancing_on_shutdown = True

    def create_jello_cube(self, stage, path, name, position, size, mesh_path, phys_material_path, grfx_material):
        cube_path = path.AppendChild(name)
        stage.DefinePrim(cube_path).GetReferences().AddReference(mesh_path)
        skinMesh = UsdGeom.Mesh.Define(stage, cube_path)
        skinMesh.AddTranslateOp().Set(position)
        skinMesh.AddOrientOp().Set(Gf.Quatf(1.0))
        skinMesh.AddScaleOp().Set(Gf.Vec3f(size, size, size))
        deformableUtils.add_physx_deformable_body(
            stage,
            cube_path,
            simulation_hexahedral_resolution=3,
            collision_simplification=True,
            self_collision=False,
            solver_position_iteration_count=self.pos_iterations,
        )
        physicsUtils.add_physics_material_to_prim(stage, skinMesh.GetPrim(), phys_material_path)
        physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(skinMesh.GetPrim())
        physxCollisionAPI.GetContactOffsetAttr().Set(0.02)
        physxCollisionAPI.CreateRestOffsetAttr().Set(0.001)
        omni.kit.commands.execute(
            "BindMaterialCommand", prim_path=cube_path, material_path=grfx_material, strength=None
        )

    def create(self, stage, Num_Frankas, Num_Greens):
        self.defaultPrimPath = stage.GetDefaultPrim().GetPath()
        self.stage = stage
        self.num_envs = Num_Frankas
        self.num_greens = Num_Greens

        # Physics scene
        scene = UsdPhysics.Scene.Define(stage, self.defaultPrimPath.AppendChild("physicsScene"))
        scene.CreateGravityDirectionAttr().Set(Gf.Vec3f(0.0, 0.0, -1.0))
        scene.CreateGravityMagnitudeAttr().Set(9.807)
        utils.set_physics_scene_asyncsimrender(scene.GetPrim())
        physxSceneAPI = PhysxSchema.PhysxSceneAPI.Apply(scene.GetPrim())
        physxSceneAPI.CreateFrictionOffsetThresholdAttr().Set(0.001)
        physxSceneAPI.CreateFrictionCorrelationDistanceAttr().Set(0.0005)
        physxSceneAPI.CreateGpuTotalAggregatePairsCapacityAttr().Set(10 * 1024)
        physxSceneAPI.CreateGpuFoundLostPairsCapacityAttr().Set(10 * 1024)
        physxSceneAPI.CreateGpuCollisionStackSizeAttr().Set(64 * 1024 * 1024)
        physxSceneAPI.CreateGpuFoundLostAggregatePairsCapacityAttr().Set(10 * 1024)
        # clamp iterations:
        self.pos_iterations = 20
        self.vel_iterations = 1
        physxSceneAPI.GetMaxPositionIterationCountAttr().Set(self.pos_iterations)
        UsdGeom.SetStageUpAxis(stage, UsdGeom.Tokens.z)
        UsdGeom.SetStageMetersPerUnit(stage, 1.0)

        # setup ground collision plane:
        utils.addPlaneCollider(stage, "/World/physicsGroundPlaneCollider", "Z")

        # deformable material path
        deformable_material_path = omni.usd.get_stage_next_free_path(stage, "/DeformableBodyMaterial", True)
        deformableUtils.add_deformable_body_material(
            stage,
            deformable_material_path,
            youngs_modulus=10000000.0,
            poissons_ratio=0.499,
            damping_scale=0.0,
            elasticity_damping=0.0001,
            dynamic_friction=1.0,
            density=300,
        )
        deformable_material2_path = omni.usd.get_stage_next_free_path(stage, "/DeformableBodyMaterial2", True)
        deformableUtils.add_deformable_body_material(
            stage,
            deformable_material2_path,
            youngs_modulus=4000000.0,
            poissons_ratio=0.499,
            damping_scale=0.0,
            elasticity_damping=0.005,
            dynamic_friction=0.05,
            density=100,
        )

        # Franka finger friction
        mat_prim = UsdShade.Material.Define(stage, "/World/FrankaFingerPhysicsMaterial")
        finger_material = UsdPhysics.MaterialAPI.Apply(mat_prim.GetPrim())
        finger_material.CreateStaticFrictionAttr().Set(1.0)
        finger_material.CreateDynamicFrictionAttr().Set(1.0)

        # position parameters
        table_scale = 0.8
        table_height = 0.762 * table_scale
        table_position = Gf.Vec3f(0.5, 0.0, 0.0)
        env_spacing = 2
        num_envs_per_side = max(1, round(math.sqrt(self.num_envs)))
        row_half_length = (num_envs_per_side - 1) * env_spacing * 0.5

        # create deformable cube parameters
        self.box_size = 0.05
        box_loc = Gf.Vec3f(table_position) + Gf.Vec3f(0.0, 0.0, table_height + self.box_size * 3.5)

        # Position Camera Based on Scene Size
        cam = UsdGeom.Camera.Define(stage, self.demo_camera)
        cam_height = 1.1
        location = Gf.Vec3f(row_half_length + 6.5, row_half_length + 4.0, cam_height)
        target = Gf.Vec3f(0.0, 0.0, cam_height - 0.4)
        delta = target - location
        rotZ = math.degrees(math.atan2(-delta[0], delta[1]))
        rotX = math.degrees(math.atan2(delta[2], math.sqrt(delta[0] ** 2.0 + delta[1] ** 2.0)))
        rotZQ = Gf.Quatf(Gf.Rotation(Gf.Vec3d([0, 0, 1]), rotZ).GetQuat())
        rotXQ = Gf.Quatf(Gf.Rotation(Gf.Vec3d([1, 0, 0]), rotX + 90).GetQuat())
        physicsUtils.setup_transform_as_scale_orient_translate(cam)
        physicsUtils.set_or_add_translate_op(cam, translate=location)
        physicsUtils.set_or_add_orient_op(cam, orient=rotZQ * rotXQ)
        cam.CreateClippingRangeAttr(Gf.Vec2f(0.01, 100))

        # get materials for deformable cubes
        looks_path = self.defaultPrimPath.AppendChild("Looks")
        stage.DefinePrim(looks_path).GetReferences().AddReference(self.asset_paths["cube_materials"], "/Looks")

        green_glass_path = looks_path.AppendChild("GreenGlass")
        red_glass_path = looks_path.AppendChild("RedGlass")

        # drive and default dof pos:
        self.default_dof_pos, drive_params = self.get_franka_parameters()

        # create grid of frankas and tables:
        envsScopePath = self.defaultPrimPath.AppendPath("envs")
        UsdGeom.Scope.Define(stage, envsScopePath)
        for i in range(self.num_envs):
            # create env:
            col_number = i % num_envs_per_side
            row_number = i // num_envs_per_side
            x_pos = -row_half_length + col_number * env_spacing
            y_pos = -row_half_length + row_number * env_spacing
            env_xform = UsdGeom.Xform.Define(stage, envsScopePath.AppendChild(f"env_{i}"))
            env_xform.AddTranslateOp().Set(Gf.Vec3f(x_pos, y_pos, 0.0))

            # add franka and its stool
            franka_stool_position = Gf.Vec3f(-0.027, 0.0, -0.001)
            stool_path = env_xform.GetPath().AppendChild("franka_stool")
            stage.DefinePrim(stool_path).GetReferences().AddReference(self.asset_paths["stool"])
            stool_xform = UsdGeom.Xform.Get(stage, stool_path)
            utils.setStaticCollider(stool_xform.GetPrim(), approximationShape="boundingCube")
            assert stool_xform
            physicsUtils.set_or_add_translate_op(stool_xform, translate=franka_stool_position)
            franka_path = env_xform.GetPath().AppendChild("franka")
            assert stage.DefinePrim(franka_path).GetReferences().AddReference(self.asset_paths["franka"], "/panda")
            franka_xform = UsdGeom.Xform.Get(stage, franka_path)
            assert franka_xform
            physicsUtils.set_or_add_translate_op(franka_xform, translate=Gf.Vec3f(0.0, 0.0, table_height - 0.4))
            physicsUtils.set_or_add_scale_op(franka_xform, scale=Gf.Vec3f(0.01))
            # setup drives:
            franka_helpers.configure_franka_drives(stage, franka_path, self.default_dof_pos, drive_params)
            # setup iterations:
            physxArticulationAPI = PhysxSchema.PhysxArticulationAPI.Apply(franka_xform.GetPrim())
            physxArticulationAPI.GetSolverPositionIterationCountAttr().Set(self.pos_iterations)
            physxArticulationAPI.GetSolverVelocityIterationCountAttr().Set(self.vel_iterations)
            # setup fingers
            prim = stage.GetPrimAtPath(str(env_xform.GetPath()) + "/franka/panda_leftfinger/geometry")
            bindingAPI = UsdShade.MaterialBindingAPI.Apply(prim)
            bindingAPI.Bind(mat_prim, UsdShade.Tokens.weakerThanDescendants, "physics")
            prim = stage.GetPrimAtPath(str(env_xform.GetPath()) + "/franka/panda_rightfinger/geometry")
            bindingAPI = UsdShade.MaterialBindingAPI.Apply(prim)
            bindingAPI.Bind(mat_prim, UsdShade.Tokens.weakerThanDescendants, "physics")
            # set max joint velocity
            joint = PhysxSchema.PhysxJointAPI.Get(
                stage, str(env_xform.GetPath()) + "/franka/panda_hand/panda_finger_joint1"
            )
            joint.GetMaxJointVelocityAttr().Set(1)
            joint = PhysxSchema.PhysxJointAPI.Get(
                stage, str(env_xform.GetPath()) + "/franka/panda_hand/panda_finger_joint2"
            )
            joint.GetMaxJointVelocityAttr().Set(1)

            # add table:
            table_path = env_xform.GetPath().AppendPath("table")
            assert stage.DefinePrim(table_path).GetReferences().AddReference(self.asset_paths["table"])
            xform = UsdGeom.Xform.Get(stage, table_path)
            utils.setStaticCollider(xform.GetPrim(), approximationShape="boundingCube")
            physicsUtils.set_or_add_translate_op(xform, translate=table_position)
            physicsUtils.set_or_add_scale_op(xform, scale=Gf.Vec3f(table_scale))

            # add bowl:
            bowl_path = env_xform.GetPath().AppendPath("bowl")
            assert (
                stage.DefinePrim(bowl_path).GetReferences().AddReference(self.asset_paths["bowl"], "/World/bowl_plate")
            )
            xform = UsdGeom.Xform.Get(stage, bowl_path)
            xform.AddTranslateOp().Set(table_position + Gf.Vec3f(0.0, 0.0, table_height))
            rigidbody_api = PhysxSchema.PhysxRigidBodyAPI.Apply(
                stage.GetPrimAtPath(bowl_path.AppendChild("bowl_plate"))
            )
            rigidbody_api.CreateSolverPositionIterationCountAttr(self.pos_iterations)
            rigidbody_api.CreateSolverVelocityIterationCountAttr(self.vel_iterations)

            # create soft cube
            self.create_jello_cube(
                stage,
                env_xform.GetPath(),
                "box",
                box_loc,
                self.box_size,
                self.asset_paths["cube"],
                deformable_material_path,
                red_glass_path,
            )

            # create extras
            extras_path = env_xform.GetPath().AppendChild("extras")
            ex_spacing = 1.5
            for z in range(3):
                for y in range(3):
                    for x in range(3):
                        if x == 1 & y == 1 & z == 1:
                            continue
                        j = x + y * 3 + z * 3 * 3
                        if j > 13:
                            j -= 1
                        if j >= self.num_greens:
                            break
                        self.create_jello_cube(
                            stage,
                            extras_path,
                            f"extra_{j}",
                            box_loc
                            + Gf.Vec3f((x - 1) * ex_spacing, (y - 1) * ex_spacing, (z - 1) * ex_spacing)
                            * self.box_size,
                            self.box_size,
                            self.asset_paths["cube"],
                            deformable_material2_path,
                            green_glass_path,
                        )
        omni.usd.get_context().get_selection().set_selected_prim_paths([], False)

    def on_tensor_start(self, tensorApi):
        sim = tensorApi.create_simulation_view("numpy")
        sim.set_subspace_roots("/World/envs/*")
        # franka view
        self.frankas = sim.create_articulation_view("/World/envs/*/franka")
        self.franka_indices = np.arange(self.frankas.count, dtype=np.int32)

        # set default dof pos:
        init_dof_pos = np.stack(self.num_envs * [np.array(self.default_dof_pos, dtype=np.float32)])
        self.frankas.set_dof_positions(init_dof_pos, self.franka_indices)

        # end effector view
        self.hands = sim.create_rigid_body_view("/World/envs/*/franka/panda_hand")

        # get initial hand transforms
        init_hand_transforms = self.hands.get_transforms().copy()
        self.init_pos = init_hand_transforms[:, :3]
        self.init_rot = init_hand_transforms[:, 3:]

        # self.boxes = sim.create_rigid_body_view("/World/envs/*/box")
        self.boxes = sim.create_soft_body_view("/World/envs/*/box")

        # box corner coords, used to determine grasping angle
        box_half_size = 0.5 * self.box_size
        corner_coord = np.array([box_half_size, box_half_size, box_half_size])
        self.corners = np.stack(self.num_envs * [corner_coord])

        # get initial box transforms
        self.init_box_transforms = self.boxes.get_transforms().copy()

        # downward direction
        self.down_dir = np.array([0, 0, -1]).reshape(3, 1)

        # hand orientation for grasping
        self.down_q = np.stack(self.num_envs * [np.array([1.0, 0.0, 0.0, 0.0])])

        # prevent garbage collector from deleting the sim 
        self.sim = sim

    def on_shutdown(self):
        self.frankas = None
        self.hands = None
        self.boxes = None
        self.sim = None

        # disable hydra instancing if they had to be enabled
        if self._reset_hydra_instancing_on_shutdown:
            carb.settings.get_settings().set("/persistent/omnihydra/useSceneGraphInstancing", False)
        super().on_shutdown()

    def on_physics_step(self, dt):
        # get box transforms
        box_transforms = self.boxes.get_transforms()
        box_pos = box_transforms[:, :3]

        # get end effector transforms
        hand_transforms = self.hands.get_transforms()
        hand_pos = hand_transforms[:, :3]
        hand_rot = hand_transforms[:, 3:]

        # get franka DOF states
        dof_pos = self.frankas.get_dof_positions()

        # get franka jacobians
        jacobians = self.frankas.get_jacobians()

        # direction from end effector to box
        to_box = box_pos - hand_pos
        box_dist = np.linalg.norm(to_box, axis=1)
        box_dir = to_box / box_dist[:, None]
        box_dot = (box_dir @ self.down_dir).flatten()

        # how far the hand should be from box for grasping
        grasp_offset = 0.10

        # determine if we're holding the box (grippers are closed and box is near)
        gripper_sep = dof_pos[:, 7] + dof_pos[:, 8]
        gripped = (gripper_sep < self.box_size) & (box_dist < grasp_offset * 2.0)

        # determine if the box is unreachable (too far from initial box position)
        from_start = box_pos - self.init_box_transforms[:, :3]
        start_dist = np.linalg.norm(from_start, axis=1)
        unreachable = start_dist > 0.5

        # if hand is above box, descend to grasp offset; otherwise, seek a position above the box
        above_box = (box_dot >= 0.9) & (box_dist < grasp_offset * 3)
        grasp_pos = box_pos.copy()
        grasp_pos[:, 2] = np.where(above_box, box_pos[:, 2] + grasp_offset, box_pos[:, 2] + grasp_offset * 2.5)

        # if box is gripped, return to initial pose; otherwise get into grasping pose
        goal_pos = np.where(gripped[:, None], self.init_pos, grasp_pos)
        goal_rot = self.down_q

        # compute position and orientation error
        pos_err = goal_pos - hand_pos
        max_err = 0.05  # clamp max position error
        pos_err_mag = (
            np.linalg.norm(pos_err, axis=1)[:, None] + 0.0001
        )  # VR: add a tiny number to prevent division-by-zero warning
        pos_err = np.where(pos_err_mag > max_err, pos_err * max_err / pos_err_mag, pos_err)  # !!!
        orn_err = orientation_error(goal_rot, hand_rot)
        dpose = np.concatenate([pos_err, orn_err], -1)[:, None].transpose(0, 2, 1)

        # jacobian entries corresponding to franka hand
        franka_hand_index = 8  # !!!
        j_eef = jacobians[:, franka_hand_index - 1, :]

        # solve damped least squares
        j_eef_T = np.transpose(j_eef, (0, 2, 1))
        d = 0.05  # damping term
        lmbda = np.eye(6) * (d**2)
        u = (j_eef_T @ np.linalg.inv(j_eef @ j_eef_T + lmbda) @ dpose).reshape(self.num_envs, 9)

        # update position targets
        pos_targets = dof_pos + u  # * 0.3

        # close the grippers when we're near the box; if looping, open them when we return to starting position
        if self.loop:
            close_gripper = np.where(gripped, (box_dist < grasp_offset * 1.5), (box_dist < grasp_offset * 1.1))
        else:
            close_gripper = box_dist < grasp_offset

        grip0 = 0.015
        grip1 = 0.05

        grip_acts = np.where(
            close_gripper[:, None],
            [[grip0, grip0]] * self.num_envs,
            [[grip1, grip1]] * self.num_envs,
        )
        # pos_targets[:, 7:9] = pos_targets[:, 7:9] * 0.3 + grip_acts * 0.7
        pos_targets[:, 7:9] = grip_acts

        # reset the hand if the cube's unreachable
        pos_targets = np.where(unreachable[:, None], self.default_dof_pos, pos_targets)

        # apply position targets
        self.frankas.set_dof_position_targets(pos_targets, self.franka_indices)

Here is how I did

import argparse
from isaacsim import SimulationApp

# create argparser
parser = argparse.ArgumentParser(description="dVRK in an empty environment")
parser.add_argument("--num_envs", type=int, default=1, help="Number of environments to spawn.")
parser.add_argument("--headless", action="store_true", dest="headless")
parser.add_argument("--gpu", action="store_true", dest="gpu")

args = parser.parse_args()
headless = args.headless
gpu = args.gpu
num_envs = args.num_envs

if gpu:
    device = "cuda"
    backend = "torch"
else:
    device = "cpu"
    backend = "numpy"

# Initialize SimulationApp
simulation_app = SimulationApp({"headless": headless})

import omni
import torch
from omni.isaac.core.utils import stage
from omni.isaac.core.world import World
import omni.isaac.core.utils.prims as prims_utils
from omni.isaac.core.utils.semantics import add_update_semantics
from omni.physx.scripts import deformableUtils, physicsUtils, deformableMeshUtils, utils
from pxr import UsdGeom, UsdShade, Gf, PhysxSchema, UsdPhysics, Sdf, PhysicsSchemaTools
from omni.isaac.core.prims import XFormPrim, RigidPrim, RigidPrimView, XFormPrimView


def load_franka(world: World):
    for i in range(num_envs):
        robot_prim_path = f"/World/env_{i}/robot"
        robot_name = f"franka_{i}"
        
        position = np.array([i, 0.0, 0.0])
        if device == "cuda":
            position = torch.tensor(position, dtype=torch.float32).to(device)
            
        franka = Franka(
            prim_path=robot_prim_path,
            name=robot_name,
            position=position,
        )
    
    robots = ArticulationView(
        prim_paths_expr="/World/env_*/robot",
        name="franka_view",
    )
    world.scene.add(robots)
    return robots


def load_deformable(world: World):
    current_stage = omni.usd.get_context().get_stage()
    
    for i in range(num_envs):
        
        deformable_prim_path = f"/World/env_{i}/deformable"
        deformable_name = f"tissue_{i}"
        current_stage.DefinePrim(deformable_prim_path).GetReferences().AddReference(box_usd)
        cube_mesh = UsdGeom.Mesh.Define(current_stage, deformable_prim_path)
            
        cube_mesh.AddTranslateOp().Set(Gf.Vec3f(i+0.3893, 0.005, 0.005))
        cube_mesh.AddScaleOp().Set(Gf.Vec3f(0.1, 0.2, 0.015))
        cube_mesh.CreateDisplayColorAttr().Set([Gf.Vec3f(1, 1, 0)])

        # Add PhysX deformable body
        deformableUtils.add_physx_deformable_body(
            current_stage,
            # cube_mesh.GetPath(),
            deformable_prim_path,
            collision_simplification=True,
            simulation_hexahedral_resolution=30,  # The parameter controlling the resolution of the soft body simulation mesh
            solver_position_iteration_count=20,   # Number of the solver's positional iteration counts
            self_collision=True,
        )
        
        # Create a physics material
        deformable_material_path = omni.usd.get_stage_next_free_path(current_stage, "/DeformableBodyMaterial", True)
        deformableUtils.add_deformable_body_material(
            current_stage,
            deformable_material_path,
            youngs_modulus=1000.0,
            poissons_ratio=0.3,
            damping_scale=0.0,
            elasticity_damping=0.0001,
            dynamic_friction=0.5,
            density=100,
        )

        # Assign the material to the mesh
        physicsUtils.add_physics_material_to_prim(current_stage, cube_mesh.GetPrim(), deformable_material_path)
        physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(cube_mesh.GetPrim())
        physxCollisionAPI.GetContactOffsetAttr().Set(0.02)
        physxCollisionAPI.CreateRestOffsetAttr().Set(0.001)
        add_update_semantics(prims_utils.get_prim_at_path(deformable_prim_path), deformable_name)
    
    deformables = XFormPrimView(
        prim_paths_expr="/World/env_*/deformable",
        name="deformables_view",
    )
    world.scene.add(deformables)
    return deformables


def run_simulator(world: World, deformables):
    while simulation_app.is_running():      
        positions, orientations = deformables.get_world_poses()
        print(positions, orientations) 


def main():       
    # Create the World
    world = World(backend=backend, device=device)
    if device == "cuda":
        world.get_physics_context().enable_gpu_dynamics(True)
    world.scene.add_default_ground_plane()
    
    robots = load_franka(world)
    deformables = load_deformable(world)

    # initialize physics
    world.initialize_physics()
    
    # Reset the world and start simulation
    world.reset()
    print("[INFO]: Setup complete...")
    
    # Run the simulation
    run_simulator(world, deformables)

    # Close the simulation app
    simulation_app.close()


if __name__ == "__main__":
    main()

So no matter how I changed the deformable object in the simulator (move it using cursor or grasp it using robot), the output of its pose won’t change.