Issue with omni.isaac.core.World class : Unable to add physics callback

Hello.
I’m trying to monitor the kinetic energy (or velocity) of a set of rigid bodies on a stage. For that , i’m planning to use the omni.isaac.core.World class since it provides a way to add a callback to handle time events and/or physics events (see here.
But no matter how i try to add a callback function to the object, it does not seem to work.
Steps to reproduce :

  1. Load a world of your choice (wooden_world for me)
  2. Execute this script in your script editor :

import omni.usd
import carb
import omni.isaac.core
import os
stage = omni.usd.get_context().get_stage()
def ticker(n : float) : #Some dummy function here
print("Ticked once with argument : ",n)
carb.log_warn(“Ticked once with argument : {}”.format(n))
return
world = omni.isaac.core.World(set_defaults=True)
world.add_physics_callback(“TickerFunction”,ticker)

Result (for me at least)
[Error] [omni.kit.app.plugin] [py stderr]: AttributeError: ‘World’ object has no attribute ‘_physics_context’

I figured out that the PhysicsContext object that was suppose to be a private attribute of the SimulationContext class that the World class inherited from. So i tried to create my own physics scene. And the result was this after trying to add the callback once again :
Exception: Failed to create simulation view backend

After a peek in the omni.isaac.core physics_context , into the init function of the PhysicsContext class
i see this :# TODO: add backend for physics (I guess this explains that)

So does anyone have a fix , or workaround for this?
Keep in mind that my goal here is to be able to make step by step simulation with python in order to compute some things between two simulation steps.
Thank you.

Hi @a.adjanohoun. I’ve moved this over to the Isaac Sim forum for you.

1 Like

Hi @a.adjanohoun - Someone from our team will review and provide answer to you.

1 Like

Hi @a.adjanohoun - Apologies for the delay in response. Please let us know if you are still having any issues or questions after using the latest Isaac Sim release.

This code works in the Script Editor, tested on Isaac Sim 4.5.0:

from omni.isaac.core import SimulationContext

simulation_context = SimulationContext(physics_prim_path="/World/PhysicsScene")
simulation_context.initialize_physics()

simulation_context.remove_physics_callback("your_function_here")
simulation_context.add_physics_callback("controller_loop_routine", your_alive_instance.your_function_here)`

You must define the PhysicsScene before registering an add_physics_callback. In:

SimulationContext(physics_prim_path="/World/PhysicsScene")`

The PhysicsScene prim must already exist in the USD stage. If you want to create a new PhysicsScene at runtime, omit the physics_prim_path argument.

Important: Ensure physics_prim_path=“/World/PhysicsScene” is valid. If invalid, PhysicsScene will be set to None without warnings!

your_alive_instance is an instance of a class containing the function your_function_here. This instance is critical to prevent the function from being garbage-collected. The callback function must be defined with a mandatory argument, likely the delta_time (dt), as follows:

def your_function_here(self, dt):
    # Your function logic here
    return

To better understand the initialization sequence of world components in the Script Editor approach, review the source code at:

[path_prefix_here]\isaacsim\exts\omni.isaac.core\omni\isaac\core\simulation_context\simulation_context.py

Specifically, examine the _initialize_stage_async method:

async def _initialize_stage_async(
    self,
    physics_dt: Optional[float] = None,
    rendering_dt: Optional[float] = None,
    stage_units_in_meters: Optional[float] = None,
    physics_prim_path: str = "/physicsScene",
    sim_params: dict = None,
    set_defaults: bool = True,
    device: Optional[str] = None,
) -> Usd.Stage:
    if get_current_stage() is None:
        await create_new_stage_async()
    set_stage_up_axis("z")
    if stage_units_in_meters is not None:
        set_stage_units(stage_units_in_meters=stage_units_in_meters)
    await omni.kit.app.get_app().next_update_async()
    self._physics_context = PhysicsContext(
        physics_dt=physics_dt, prim_path=physics_prim_path, sim_params=sim_params, set_defaults=set_defaults
    )
    if device is not None:
        SimulationManager.set_physics_sim_device(device)
    self.set_simulation_dt(physics_dt=physics_dt, rendering_dt=rendering_dt)
    return self.stage

I hope this helps! Feel free to ask more questions.
Regards!