Reset deformable body in replicator for data generation

Hello!
I’m currently trying to create synthetic data containing a deformable body acting as a slipsheet between different layers of cases on a pallet.
I’ve managed to get the physics working during the replicator randomization thanks to this post (https://forums.developer.nvidia.com/t/trigger-randomization/254170/8), but I’m now running into the problem that I need to reset my deformable before the next data point can be captured.
I want to randomize the position of the sheet and afterwards apply the physics again. Currently I’m only able to start the physics simulation once in the beginning and then randomize the texture and position afterwards.

So if I randomize the position of my sheet the result is sadly not usable. Ideally I want the Sheet to lay on the cases below and bend in the front without clipping into the cases.
Is there any way to reset the physics of the sheet through the replicator without instantiating a new slipsheet object and deleting the old one?

Here’s my code:

import omni
import omni.usd
import omni.kit as kit
import numpy as np
import os
import omni.replicator.core as rep
from PIL import Image
from pxr import UsdPhysics
from omni.physx.scripts import physicsUtils, deformableUtils
from omni.isaac.core.objects.ground_plane import GroundPlane

####################
# Create Functions #
####################

def create_materials():
    omni.kit.commands.execute(
        "CreateMdlMaterialPrimCommand",
        mtl_url="omniverse://localhost/NVIDIA/Materials/vMaterials_2/Paper/Cardboard_Low_Quality.mdl",
        mtl_name="Cardboard_Low_Quality",
        mtl_path="/Materials/CardboardRough"
    )

    omni.kit.commands.execute(
        "CreateMdlMaterialPrimCommand",
        mtl_url="omniverse://localhost/NVIDIA/Materials/Base/Wall_Board/MDF.mdl",
        mtl_name="MDF",
        mtl_path="/Materials/MDF"
    )

def create_cube(id, translation, scale):

    cube_prim_path = "/World/Cube_" + str(id)

    cube_object = kit.primitive.mesh.CreateMeshPrimCommand(
        prim_type="Cube",
        object_origin=(0,0,0),
        prim_path=cube_prim_path,
        u_verts_scale=1,
        v_verts_scale=1
    )
    cube_object.do()

    cube_prim =stage.GetPrimAtPath(cube_prim_path)
    cube_prim.GetAttribute('xformOp:translate').Set(translation)
    cube_prim.GetAttribute('xformOp:scale').Set(scale)
    UsdPhysics.CollisionAPI.Apply(cube_prim)

    omni.kit.commands.execute('BindMaterialCommand',
        prim_path=cube_prim_path,
        material_path="/Materials/CardboardRough",
        strength='weakerThanDescendants')

##########
# Basics #
##########

deformable = True

stage = omni.usd.get_context().get_stage()
default_prim_path = "/World"

cube_translation_list = [
    (0, 0, 0.075),
    (0, 0.205, 0.075),
    (0, -0.205, 0.075),
    (-0.255, 0, 0.075),
    (-0.255, 0.205, 0.075),
    (-0.255, -0.205, 0.075),
    (0.255, 0, 0.075),
    (0.255, 0.205, 0.075),
    (0.255, -0.205, 0.075),
#    (0.51, 0.205, 0.075),
    (-0.255, 0.205, 0.24),
    (-0.255, 0, 0.24),
]

cube_scale = (0.25, 0.2, 0.15)

create_materials()

for id, trans in enumerate(cube_translation_list):
    create_cube(id=id, translation=trans, scale=cube_scale)

GroundPlane(prim_path="/World/groundPlane", size=10, color=np.array([0.5, 0.5, 0.5]))

##############
# Deformable #
##############

cube_prim_path = "/World/Slipsheets"

cube_u_verts_scale = 30
cube_v_verts_scale = 30
cube_w_verts_scale = 2
simulation_resolution = 30

slipsheet_width = 0.95
slipsheet_depth = 0.55
slipsheet_height = 0.003
slipsheet_volume_m3 = slipsheet_width * slipsheet_depth * slipsheet_height
paper_density_kg_per_m3 = 700

weight_slipsheet = paper_density_kg_per_m3 * slipsheet_volume_m3

slipsheet_translation_1 = (0.13, 0, 0.152)
slipsheet_translation_2 = (0.13, 0, 0.35)


cube_object_1 = kit.primitive.mesh.CreateMeshPrimCommand(
    prim_type="Cube",
    object_origin=(0,0,0),
    prim_path=os.path.join(cube_prim_path,"cube_1"),
    u_verts_scale=cube_u_verts_scale,
    v_verts_scale=cube_v_verts_scale,
    w_verts_scale=cube_w_verts_scale
)
cube_object_1.do()

cube_prim_1 = stage.GetPrimAtPath(os.path.join(cube_prim_path,"cube_1"))

cube_prim_1.GetAttribute('xformOp:translate').Set(slipsheet_translation_1)
cube_prim_1.GetAttribute('xformOp:scale').Set((slipsheet_width, slipsheet_depth, 0.002))

particle_system_path = "/World/ParticleSystem"

if deformable:
    deformableUtils.add_physx_deformable_body(
            stage,
            cube_prim_1.GetPath(),
            collision_simplification=True,
            simulation_hexahedral_resolution=simulation_resolution,
            self_collision=True,
            solver_position_iteration_count=32,
        )
    
    deformable_material_path = omni.usd.get_stage_next_free_path(stage, default_prim_path + "/deformableBodyMaterial", True)
    deformableUtils.add_deformable_body_material(
        stage,
        deformable_material_path,
        youngs_modulus=1000000.0,
        poissons_ratio=0.33,
        damping_scale=0.0,
        dynamic_friction=5.0,
        elasticity_damping=0.0003
    )
    physicsUtils.add_physics_material_to_prim(stage, cube_prim_1.GetPrim(), deformable_material_path)

    cube_prim_1.GetAttribute('physxCollision:contactOffset').Set(0.001)
    cube_prim_1.GetAttribute('physxCollision:restOffset').Set(0.00099)

massApi_1 = UsdPhysics.MassAPI.Apply(cube_prim_1.GetPrim())
massApi_1.GetMassAttr().Set(weight_slipsheet)

class DummyWriter(rep.Writer):
    def __init__(self, 
                 msg,
                 output_dir,
                 rgb_save):
        self._output_dir = output_dir
        self._backend = rep.BackendDispatch({"paths": {"out_dir": output_dir}})
        self._image_output_format = "png"
        self._frame_id = 0
        self.annotators = []
        self.rgb_save = rgb_save
        self.annotators.append(rep.AnnotatorRegistry.get_annotator("rgb"))
        self.msg = msg
    def write(self, data):
        # print(self.msg)
        img = Image.fromarray(data["rgb"])
        if self.rgb_save:
            self.save_visualization(img, data)
        self._frame_id += 1
    def save_visualization(self, img, data):
        # rgb
        image_name = "rgb_{:04d}.png".format(self._frame_id)
        self._backend.write_image(image_name, img)


def move_slipsheet():
    slipsheet = rep.get.prims(path_pattern=os.path.join(cube_prim_path,"cube_1"))
    with slipsheet:
        rep.randomizer.color(colors=rep.distribution.uniform((0,0,0), (1,1,1)))
    return slipsheet.node

with rep.new_layer():
    rep.randomizer.register(move_slipsheet)

    camera = rep.create.camera(look_at=(0,0,0), position=(2,0.5,2))
    rp = rep.create.render_product(camera, (1024, 1024))

# Writer that writes every frame
writer = DummyWriter(msg="STEPPING", output_dir="./output", rgb_save=False)
writer.attach(rp)

# Writer that writes every 24 frames
writer = DummyWriter(msg="WRITING", output_dir="./output", rgb_save=True)
writer.attach(rp, trigger=rep.trigger.on_frame(max_execs=10, interval=30))

# Play timeline with replicator start
rep.orchestrator.set_capture_on_play(True)

with rep.trigger.on_frame(max_execs=10, interval=30):
    rep.randomizer.move_slipsheet()

# Run orchestrator
rep.orchestrator.run()

Any help is greatly appreciated!

Hi there,

from the provided snippet it seems the move_slipsheet function only randomizes the color of the sheet.

If however you managed to the the deformable simulation working in an expected matter, I would suggest to use a different approach for the synthetic data generation, namely using orchestrator.step()in a custom loop whenever you would like to capture the data.

This will mean you will have to disable capture on play (orchestrator.set_capture_on_play(False)) so the data in only captured when you request it during the simulation.

This approach will also allow you to take adantage of the higher level randomization functions from replicator, and will give you the customization capabilities on the simulation.

Here is a tutorial using such an approach:

Here is a snippet triggering replicator randomizers from custom events:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.