Isaac Sim Version
4.5.0
4.2.0
4.1.0
4.0.0
4.5.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: 3080 GTX
- Driver Version:
Topic Description
Detailed Description
I want to have characters animated via standalone python scripts so I can use them in a larger simulation. For now, being able to only use GoTo command is enough.
In Isaac 4.2, there are a few applications that can use Omni People using a similar logic. For example:
- GitHub - cadop/siborg-simulate-walk: An Omniverse extension to quickly add target goal positions for virtual agents · GitHub
- API Reference — Pegasus Simulator documentation
In short, they use the commands
import omni.anim.graph.core as ag
omni.kit.commands.execute(
"RemoveAnimationGraphAPICommand",
paths=[Sdf.Path(self.skel_root_prim.GetPrimPath())]
)
omni.kit.commands.execute(
"ApplyAnimationGraphAPICommand",
paths=[Sdf.Path(self.skel_root_prim.GetPrimPath())],
animation_graph_path=Sdf.Path(animation_graph.GetPrimPath())
)
character_graph = ag.get_character(skel_root_path)
character_graph.set_variable("Walk", 1.0)
in a world with a person and a Navmesh, to apply a desired pose to a sim person, and it works fine in 4.2.
Those applications are now broken with 4.5.
Steps to Reproduce
To help the discussion, I have created a minimal working example, which works on 4.2 but not on 4.5 (launch with Isaac’s <python.sh>):
from isaacsim import SimulationApp
# Launch Isaac Sim
simulation_app = SimulationApp({"headless": False})
import omni
import carb
import random
import numpy as np
from dataclasses import dataclass
try:
# Isaac Sim 4.2
from omni.isaac.core.utils.extensions import enable_extension
except ModuleNotFoundError:
# Isaac Sim 4.5
from isaacsim.core.utils.extensions import enable_extension
# Enable the extensions required for animated characters
enable_extension("omni.kit.scripting")
enable_extension("omni.anim.graph.core")
enable_extension("omni.anim.graph.schema")
enable_extension("omni.anim.graph.ui")
enable_extension("omni.anim.people")
from pxr import Gf, Sdf
import omni.client
import omni.anim.graph.core as ag
from omni.anim.people import PeopleSettings
try:
from omni.isaac.core import World
from omni.isaac.core.utils import prims
from omni.isaac.nucleus import get_assets_root_path
except ModuleNotFoundError:
from isaacsim.core.api.world import World
from isaacsim.core.utils import prims
from isaacsim.nucleus import get_assets_root_path
from omni.usd import get_stage_next_free_path
# Make sure extensions are fully loaded
simulation_app.update()
# These lines are needed to restart the USD stage and make sure that the people extension is loaded
import omni.usd
omni.usd.get_context().new_stage()
@dataclass
class PersonState:
"""Pose container for the simulated character."""
position: np.ndarray = np.array([0.0, 0.0, 0.0])
orientation: np.ndarray = np.array([0.0, 0.0, 0.0, 1.0])
def _quat_from_yaw(yaw: float) -> np.ndarray:
"""Return [x, y, z, w] quaternion from a yaw angle."""
half = yaw * 0.5
return np.array([0.0, 0.0, np.sin(half), np.cos(half)])
class Person:
"""Helper that spawns and animates a character."""
setting_dict = carb.settings.get_settings()
people_asset_folder = setting_dict.get(PeopleSettings.CHARACTER_ASSETS_PATH)
character_root_prim_path = setting_dict.get(PeopleSettings.CHARACTER_PRIM_PATH)
assets_root_path = None
if not character_root_prim_path:
character_root_prim_path = "/World/Characters"
if people_asset_folder:
assets_root_path = people_asset_folder
else:
root_path = get_assets_root_path()
if root_path is not None:
assets_root_path = f"{root_path}/Isaac/People/Characters"
@staticmethod
def _find_skel_root(stage, path):
"""Locate the SkelRoot prim below ``path``."""
prim = stage.GetPrimAtPath(path)
if prim.GetTypeName() == "SkelRoot":
return prim, path
for child in prim.GetAllChildren():
child_prim, child_path = Person._find_skel_root(stage, f"{path}/{child.GetName()}")
if child_prim:
return child_prim, child_path
return None, None
def __init__(self, world: World, name: str, character: str, init_pos=None, init_yaw: float = 0.0) -> None:
init_pos = init_pos or [0.0, 0.0, 0.0]
self._world = world
self._stage = world.stage
self._state = PersonState(np.array(init_pos), _quat_from_yaw(init_yaw))
self._target_position = np.array(init_pos)
self._target_speed = 0.0
self._target_yaw = float(init_yaw)
self._stage_prefix = get_stage_next_free_path(self._stage, f"{Person.character_root_prim_path}/{name}", False)
self.character_usd_path = self.get_character_usd_path(character)
self.spawn_character(self.character_usd_path, self._stage_prefix, init_pos, init_yaw)
self.character_graph = None
self.add_animation_graph()
self._world.add_physics_callback(self._stage_prefix + "/state", self.update_state)
self._world.add_physics_callback(self._stage_prefix + "/update", self.update)
# ------------------------------------------------------------------
def update(self, dt: float) -> None:
if not self.character_graph and self.skel_root_prim:
self.character_graph = ag.get_character(self.skel_root_path)
dist = np.linalg.norm(self._target_position - self._state.position)
if dist > 0.1 and self.character_graph:
self.character_graph.set_variable("Action", "Walk")
self.character_graph.set_variable("PathPoints", [carb.Float3(self._state.position), carb.Float3(self._target_position)])
self.character_graph.set_variable("Walk", self._target_speed)
else:
if self.character_graph:
self.character_graph.set_variable("Walk", 0.0)
self.character_graph.set_variable("Action", "Idle")
if dist <= 0.1:
attr = self.character_prim.GetAttribute("xformOp:orient")
quat = Gf.Quatf(Gf.Rotation(Gf.Vec3d(0, 0, 1), self._target_yaw).GetQuat()) if isinstance(attr.Get(), Gf.Quatf) else Gf.Rotation(Gf.Vec3d(0, 0, 1), self._target_yaw).GetQuat()
attr.Set(quat)
def update_target_pose(self, position, yaw, walk_speed=1.0) -> None:
self._target_position = np.array(position)
self._target_yaw = float(yaw)
self._target_speed = walk_speed
attr = self.character_prim.GetAttribute("xformOp:orient")
quat = Gf.Quatf(Gf.Rotation(Gf.Vec3d(0, 0, 1), self._target_yaw).GetQuat()) if isinstance(attr.Get(), Gf.Quatf) else Gf.Rotation(Gf.Vec3d(0, 0, 1), self._target_yaw).GetQuat()
attr.Set(quat)
def update_state(self, dt: float) -> None:
if not self.character_graph and self.skel_root_prim:
self.character_graph = ag.get_character(self.skel_root_path)
if self.character_graph:
pos = carb.Float3(0, 0, 0)
rot = carb.Float4(0, 0, 0, 0)
self.character_graph.get_world_transform(pos, rot)
self._state.position = np.array([pos[0], pos[1], pos[2]])
self._state.orientation = np.array([rot.x, rot.y, rot.z, rot.w])
# ------------------------------------------------------------------
def spawn_character(self, usd_file: str, stage_name: str, init_pos, init_yaw) -> None:
if not self._stage.GetPrimAtPath(Person.character_root_prim_path):
prims.create_prim(Person.character_root_prim_path, "Xform")
if not self._stage.GetPrimAtPath(Person.character_root_prim_path + "/Biped_Setup"):
setup_prim = prims.create_prim(
Person.character_root_prim_path + "/Biped_Setup",
"Xform",
usd_path=Person.assets_root_path + "/Biped_Setup.usd",
)
setup_prim.GetAttribute("visibility").Set("invisible")
self.character_prim = prims.create_prim(stage_name, "Xform", usd_path=usd_file)
self.character_prim.GetAttribute("xformOp:translate").Set(Gf.Vec3d(float(init_pos[0]), float(init_pos[1]), float(init_pos[2])))
orient_attr = self.character_prim.GetAttribute("xformOp:orient")
quat = Gf.Quatf(Gf.Rotation(Gf.Vec3d(0, 0, 1), float(init_yaw)).GetQuat()) if isinstance(orient_attr.Get(), Gf.Quatf) else Gf.Rotation(Gf.Vec3d(0, 0, 1), float(init_yaw)).GetQuat()
orient_attr.Set(quat)
prim, path = Person._find_skel_root(self._stage, stage_name)
self.skel_root_path = path
self.skel_root_prim = prim
def add_animation_graph(self) -> None:
if not self.skel_root_prim:
return
animation_graph = self._stage.GetPrimAtPath(Person.character_root_prim_path + "/Biped_Setup/CharacterAnimation/AnimationGraph")
omni.kit.commands.execute("RemoveAnimationGraphAPICommand", paths=[Sdf.Path(self.skel_root_prim.GetPrimPath())])
omni.kit.commands.execute("ApplyAnimationGraphAPICommand", paths=[Sdf.Path(self.skel_root_prim.GetPrimPath())], animation_graph_path=Sdf.Path(animation_graph.GetPrimPath()))
self.character_graph = ag.get_character(self.skel_root_path)
# ------------------------------------------------------------------
@staticmethod
def get_character_usd_path(agent_name: str) -> str | None:
agent_folder = f"{Person.assets_root_path}/{agent_name}"
result, _ = omni.client.stat(agent_folder)
if result != omni.client.Result.OK:
carb.log_error("Character folder does not exist.")
return None
character_usd = Person.find_usd_file(agent_folder)
return f"{agent_folder}/{character_usd}" if character_usd else None
@staticmethod
def find_usd_file(folder: str) -> str | None:
result, items = omni.client.list(folder)
if result != omni.client.Result.OK:
carb.log_error(f"Unable to read character folder path at {folder}")
return None
for item in items:
if item.relative_path.endswith(".usd"):
return item.relative_path
carb.log_error(f"Unable to find a .usd file in {folder} character folder")
return None
class SimpleApp:
"""Application that drives a single person."""
def __init__(self) -> None:
self.timeline = omni.timeline.get_timeline_interface()
self.world = World(stage_units_in_meters=1.0)
self.world.scene.add_default_ground_plane()
self.person = Person(
self.world,
"person",
"original_male_adult_construction_02",
init_pos=[0.0, 0.0, 0.0],
init_yaw=0.0,
)
self.world.reset()
def run(self) -> None:
self.timeline.play()
AREA = 5.0
while simulation_app.is_running():
if random.random() < 0.01:
pos = [random.uniform(-AREA, AREA), random.uniform(-AREA, AREA), 0.0]
speed = random.uniform(0.5, 2.0)
self.person.update_target_pose(pos, 0.0, speed)
self.world.step(render=True)
self.timeline.stop()
simulation_app.close()
def main() -> None:
app = SimpleApp()
app.run()
if __name__ == "__main__":
main()
Screenshots or Videos
On Isaac Sim 4.2:
Error Messages
On Isaac Sim 4.5:
2025-06-10 13:45:10 [33,731ms] [Warning] [omni.usd] Coding Error: in HasAPI at line 164 of /builds/omniverse/usd-ci/USD/pxr/usd/usd/prim.cpp -- HasAPI: Invalid unknown schema type (TfType::_Unknown)
2025-06-10 13:45:10 [33,871ms] [Error] [asyncio] Task exception was never retrieved
future: <Task finished name='Task-133' coro=<VariablesService._pending_dirty_handler() done, defined at /home/edson/.local/share/ov/pkg/isaac-sim-4.5.0/extscache/omni.anim.graph.core-106.5.1+106.5.0.lx64.r.cp310/omni/anim/graph/core/scripts/variables_service.py:115> exception=ErrorException(Error in 'pxrInternal_v0_22__pxrReserved__::UsdPrim::HasAPI' at line 170 in file /builds/omniverse/usd-ci/USD/pxr/usd/usd/prim.cpp : 'HasAPI: provided schema type ( AnimGraphSchemaAnimationGraphAPI ) is not an applied API schema type.')>
Traceback (most recent call last):
File "/home/edson/.local/share/ov/pkg/isaac-sim-4.5.0/extscache/omni.anim.graph.core-106.5.1+106.5.0.lx64.r.cp310/omni/anim/graph/core/scripts/variables_service.py", line 130, in _pending_dirty_handler
if prim.HasAPI(AnimGraphSchema.AnimationGraphAPI):
pxr.Tf.ErrorException:
Error in 'pxrInternal_v0_22__pxrReserved__::UsdPrim::HasAPI' at line 170 in file /builds/omniverse/usd-ci/USD/pxr/usd/usd/prim.cpp : 'HasAPI: provided schema type ( AnimGraphSchemaAnimationGraphAPI ) is not an applied API schema type.'
Additional Information
What I’ve Tried
I have followed the migration guides and none of the related extensions are listed as renamed or deprecated:
enable_extension("omni.anim.graph.core")
enable_extension("omni.anim.graph.schema")
enable_extension("omni.anim.graph.ui")
enable_extension("omni.anim.people")
Additional Context
I understand there is a new way of using Omni People with Isaacsim.Replicator.Agent, but there aren’t any instructions on how to achieve this in a more flexible way through python scripts. I would like help on that.
Ideally, I would like the attached standalone script to be modified in a way that works in Isaac Sim 4.5 (and future releases) or any guidance on how to do so.
Isaacsim.Replicator.Agent:
https://docs.isaacsim.omniverse.nvidia.com/latest/replicator_tutorials/ext_replicator-agent/agent_control.html#add-a-custom-command
Thanks!
Any help/guidance appreciated! Thanks!