[Question] Spawn different asset in different environment
How can I spawn different assets (for example, objects with different shapes) in different environment using the current version of Orbit?
Hi,
This is not readily supported. However, it should not be that difficult to make it work.
Currently, all spawners are decorated with clone decorator. This handles cloning a single object into multiple environments. If you do not want to do this, then you can simply remove the decorator and make a custom function that handles spawning over multiple environments.
An example of the pseudo-code:
from omni.isaac.orbit.sim.spawners.from_files import _spawn_from_usd_file
def spawn_from_multiple_usd(
prim_path: str,
my_asset_list: list[from_files_cfg.UsdFileCfg],
translation: tuple[float, float, float] | None = None,
orientation: tuple[float, float, float, float] | None = None,
) -> Usd.Prim:
# resolve: {SPAWN_NS}/AssetName
# note: this assumes that the spawn namespace already exists in the stage
root_path, asset_path = prim_path.rsplit("/", 1)
# check if input is a regex expression
# note: a valid prim path can only contain alphanumeric characters, underscores, and forward slashes
is_regex_expression = re.match(r"^[a-zA-Z0-9/_]+$", root_path) is None
# resolve matching prims for source prim path expression
if is_regex_expression and root_path != "":
source_prim_paths = find_matching_prim_paths(root_path)
# if no matching prims are found, raise an error
if len(source_prim_paths) == 0:
raise RuntimeError(
f"Unable to find source prim path: '{root_path}'. Please create the prim before spawning."
)
else:
source_prim_paths = [root_path]
# resolve prim paths for spawning
prim_paths = [f"{source_prim_path}/{asset_path}" for source_prim_path in source_prim_paths]
# spawn asset from the given usd file
for prim_path in prim_paths:
# sample the asset config to load
cfg = random.choice(my_asset_list)
# load the asset
prim = _spawn_from_usd_file(prim_path, cfg.usd_path, cfg, translation, orientation)
return prim
Hi guys,
This is still in the works, but we made a minimal example of doing this operation nicely and efficiently. I wanted to share this progress here since it may be blocking some of you.
The attached script has two functions, spawn_multi_object_randomly and spawn_multi_object_randomly_sdf. The former is akin to the pseudo-code I posted above (based on USD APIs), while the latter uses Sdf APIs. With USD APIs, we saw that it takes 45 seconds to create 2048 objects. However, with Sdf APIs, it takes 2.15 seconds for the same number of objects.
The script demonstrates the following:
- Spawn different objects in different environments
- Randomize the material color of the object in each environment
This is what the output looks like:
You can place the script from this zip file inside the directory source/standalone/demos/multi_object.py and execute it as:
./orbit.sh -p source/standalone/demos/multi_object.py --num_envs 2048
You can do all kind of variations of this spawning based on the code here. Hope this helps getting started with it!
EDIT (14.05.2024): Please make sure to set the flag replicate_physics as False in the interactive scene.
Mass properties randomization
Hi, first of all thanks for the code above, I am relying on this piece of code heavily at the moment.
I wanted to try out randomization of mass distribution through setting center of mass. My code runs in the with Sdf.ChangeBlock(): section of the script above.
def set_random_mass(env_spec, prim_path, box_dimensions, mass_range=(2, 25), sigma_percent=2):
"""
Sets the mass values as well as the center of mass.
"""
length_dir = random.gauss(0., box_dimensions[0] * sigma_percent)
width_dir = random.gauss(0., box_dimensions[1] * sigma_percent)
center_of_mass = env_spec.GetAttributeAtPath(prim_path + ".physics:centerOfMass")
if center_of_mass is None:
center_of_mass = Sdf.AttributeSpec(env_spec, "physics:centerOfMass", Sdf.ValueTypeNames.Double3)
center_of_mass.default = Gf.Vec3d(length_dir, width_dir, 0.)
mass = env_spec.GetAttributeAtPath(prim_path + ".physics:mass")
if mass is None:
mass = Sdf.AttributeSpec(env_spec, "physics:mass", Sdf.ValueTypeNames.Double)
mass.default = random.uniform(*mass_range)
However it does not work. If I run the script without Fabric, I see the values set correctly in the GUI and even the mass debug view. If I then edit any of the values a little bit through GUI, everything starts working. I feel like I must be missing some physics update step after setting the values. Does anyone know what to do here?
@melecmat Do you call the above method at the spawn time (i.e. before sim.reset() gets called)?
Hi, I am trying the randomization of the center of mass of an articulation through sdf API. However, I am struggling in finding a way to access the mass property of the robot base.
Do you have any suggestions or examples to help me understand how to implement it?
Thanks a lot!
@Mayankm96
Hi, I am using the above code to spawn different USD files in different environments for legged robots. I am facing an issue wherein if my USD files have different structure: for example different dof robots, or even just different number of Xforms; the articulation is not initialized properly. I noticed that the InteractiveScene keeps just one object of the articulation class type.
Is there some way to work with the current code to spawn different USD files with different articulations in the environments? Any help or suggestion on this would be really helpful, thanks.
Hi, I am trying to get position and orientation of these different objects. Can I obtain these object poses like "pos = self.object.data.root_pos_w" ?
Thank you very much
Collision Not working as expected
Solved by setting "replicate_physics" to False in interactive scene cfg
Thank you for the great utility. Unfortunately, collision doesn't seem working properly with some objects floating or penetrating each others. The colliders looks fine. So I wonder where the problem originates?
for reproducing the error: multi_object.zip