Trigger Randomization

Hello all!

I am still busy with generating synthetic data (lidar sensor) and now I am facing some issues.

  • My plan is to trigger the randomization using a custom event. I just saw that there is the opportunity to register triggers using the replicator api:
omni.replicator.core.trigger.register(fn, override=True)

Is it possible to do so? Are there any examples of the registration of trigger events?

  • The next point is to trigger all writers using a custom event node. Is it possible to call a simple function that is acting as a trigger for them? However, I would use the _attach_trigger function for the writers to connect both of them

My overall plan for the data generation is the following:

triggerRandomization()         # trigger randomization
world.step()                   # do physics simulation
triggerWriters()               #  trigger the writers to retrieve the latest data

Are there any suggestions from you? I did not find any documentation to go ahead with this.
Does my plan make sense?

Best regard,
Christof

Just for my understanding:

What is the order of execution in action graph? Is it that the randomization is first executed and when it is finished that the sensor measurement is scheduled?

Hi @christof.schuetzenhoefer! You’re correct, randomization is executed, then measurement (ie. annotation) is scheduled, but may not be complete by the time the scene is modified for the next frame. Custom triggers for randomization is possible but not yet easily done. Triggers for writers is a feature we’re actively developing and which is not currently possible. Could you give more details on your use case? We may be able to provide you with a workaround until these features are available, and I’d love to incorporate your feedback into the development and ensure we’re offering the best experience.

Thanks for the response @jlafleche !

Workflow should look like this (preferable that the functions blocks the execution until the desired processing is done):

triggerRandomization()         # trigger randomization
world.step()                   # do physics simulation
triggerWriters()               # trigger the writers to retrieve the latest data

For my use case, I want to use the replicator for the randomization of a scene. When this is done, then the measurement of the sensors can be initiated (or a way that I can get the correct results for the finished scene). Finally, the writer can be directly triggered from a function (or after one correct measurement?).

In my opinion, it should be guaranteed that the measurement is captured when the randomization is done (this is essentially for synthetic data). Or another idea is to get the first measurement of the randomized scene after the randomization step (additionally the writers are also triggered).

I hope it is clear for my use case and I am looking forward to figuring out a workaround until this becomes a feature!
: -)

Best Regards,
Christof

Hi @christof.schuetzenhoefer ! If I understood your need correctly, you effectively want to be able to run the simulation for X frames before capturing. We are working on a better solution for this scenario, but for now, please try the following workaround, and do let us know if you have any questions!

import omni.replicator.core as rep
import omni.timeline

class DummyWriter(rep.Writer):
    def __init__(self):
        self.annotators = ["rgb"]
    def write(self, data):
        print("WRITING")

sphere = rep.create.sphere()
with sphere:
    rep.physics.rigid_body()
    
rp = rep.create.render_product("/OmniverseKit_Persp", (1024, 1024))
writer = DummyWriter()
writer.attach(rp)


async def main():
    # Play timeline
    omni.timeline.get_timeline_interface().play()

    # Render some frames (not captured)
    for _ in range(24):
        await omni.kit.app.get_app().next_update_async()
    
    # Now render+write one frame
    await rep.orchestrator.step_async()
    
    # Override timeline control setting - only need to do this after the first step
    omni.timeline.get_timeline_interface().set_auto_update(True)
    print("STEPPED")
    
    # The step call will pause simulation, so call play again to render more frames
    omni.timeline.get_timeline_interface().play()
    for _ in range(24):
        await omni.kit.app.get_app().next_update_async()
    
    # Now render+write one frame again
    await rep.orchestrator.step_async()
    print("STEPPED")

import asyncio; asyncio.ensure_future(main())

You should see in the console:

WRITING
STEPPED
WRITING
STEPPED

Thank you for the workaround!

I have a question:

  • If I want to use some randomization, how can I ensure that the randomization is finished before capturing images/pointclouds?

Otherwise this workaround looks very good to me! :-)

Hi @christof.schuetzenhoefer,

Apologies for the delay. If you’re referring to per-frame randomizations, then they will always be performed before writing. (ie. step_async() will trigger randomizations, then schedule the frame for capture)

Hello,
To update on this topic, we can now share a solution to this type of workflow available in the latest release of Omniverse Isaac Sim. Writers can now be hooked up to Replicator triggers, including the new Event and Conditional triggers. Here I take the previous demonstration snippet shared above and write it with the new functionality:

import omni.replicator.core as rep

class DummyWriter(rep.Writer):
    def __init__(self, msg):
        self.annotators = ["rgb"]
        self.msg = msg
    def write(self, data):
        print(self.msg)

sphere = rep.create.sphere()
with sphere:
    rep.physics.rigid_body()
    
rp = rep.create.render_product("/OmniverseKit_Persp", (1024, 1024))

# Writer that writes every frame
writer = DummyWriter(msg="STEPPING")
writer.attach(rp)

# Writer that writes every 24 frames
writer = DummyWriter(msg="WRITING")
writer.attach(rp, trigger=rep.trigger.on_frame(interval=24))

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

# Run orchestrator
rep.orchestrator.run()