Moving ground with collision - Isaaclab

Isaac Sim Version

[ X ] 4.2.0
4.1.0
4.0.0
2023.1.1
2023.1.0-hotfix.1
Other (please specify):

Isaac Lab Version (if applicable)

1.3
1.1
1.0
Other (please specify):

Operating System

Ubuntu 22.04
Ubuntu 20.04
Windows 11
Windows 10
Other (please specify):

GPU Information

  • Model: A2000
  • Driver Version:

Topic Description

Detailed Description

Hi guys,
I’m new to modeling and simulating with Isaaclab.
In my project, I need to create a ground with an object above it. The ground must move up and down, while the object must follow the movement. Just as a simple platform. Currently, the ground is moving but there is no collision. If I change the physics on simulation to enable rigid body, the prims will overlap and not follow the ground movement.

I’m stuck right now and it is kinda hard to find material online about isaaclab, so I came here asking for help…

Steps to Reproduce

  1. Create a python file with this content:

import argparse
import math
from omni.isaac.lab.app import AppLauncher

parser = argparse.ArgumentParser(description=“Tutorial on spawning prims into the scene.”)
AppLauncher.add_app_launcher_args(parser)
args_cli = parser.parse_args()
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app

“”“Rest everything follows.”“”

import omni.isaac.core.utils.prims as prim_utils

import omni.isaac.lab.sim as sim_utils
from omni.isaac.lab.utils.assets import ISAAC_NUCLEUS_DIR

def design_scene():
“”“Designs the scene by spawning ground plane, light, objects and meshes from usd files.”“”
# Ground-plane
# cfg_ground = sim_utils.GroundPlaneCfg()
# cfg_ground.func(“/World/defaultGroundPlane”, cfg_ground)

ground = prim_utils.create_prim('/World/defaultGroundPlane', usd_path='http://omniverse-content-production.s3-us-west-2.amazonaws.com/Assets/Isaac/4.2/Isaac/Environments/Grid/default_environment.usd', translation=None, orientation=None)

# spawn distant light
cfg_light_distant = sim_utils.DistantLightCfg(
    intensity=3000.0,
    color=(0.75, 0.75, 0.75),
)
cfg_light_distant.func("/World/lightDistant", cfg_light_distant, translation=(1, 0, 10))
return ground

def main():
“”“Main function.”“”

# Initialize the simulation context
sim_cfg = sim_utils.SimulationCfg(dt=0.01, device=args_cli.device)
sim = sim_utils.SimulationContext(sim_cfg)
# Set main camera
sim.set_camera_view([2.0, 0.0, 2.5], [-0.5, 0.0, 0.5])

# Design scene by adding assets to it
ground = design_scene()

# Play the simulator
sim.reset()
# Now we are ready!
print("[INFO]: Setup complete...")

# Simulate physics
count = 0
amplitude = 0.1
oscillation_speed = 0.05
while simulation_app.is_running():
    oscillation_angle = amplitude * math.sin(oscillation_speed * count)
    current_position = ground.GetAttribute("xformOp:translate").Get()
    new_position = (current_position[0], current_position[1], current_position[2] +oscillation_angle)
    ground.GetAttribute("xformOp:translate").Set(new_position)
    count += 1
    sim.step()

if name == “main”:
# run the main function
main()
# close sim app
simulation_app.close()

  1. Run it
  2. Edit >> Add Shape (as a cuboid). You can also try to add new physics property, but I’ve done it without success
    (Add more steps as needed)

Additional Information

What I’ve Tried

Create the prim in the code,
Use a slim cuboid as ground, instead of the GroundPlane,
Use a MeshCuboid with deformable properties

Did you have a look at source/standalone/tutorials/01_assets/run_rigid_object.py ?

Why did you choose to create an object using UI when you are using a RL framework?

If you just want to simulate robots when read Isaac Sim tutorial.

Thank you for your interest in Isaac Lab. To ensure efficient support and collaboration, please submit your topic to its GitHub repo following the instructions provided on Isaac Lab’s Contributing Guidelines regarding discussions, submitting issues, feature requests, and contributing to the project.

We appreciate your understanding and look forward to assisting you.

Yep! I’ve checked it. I’ll try to make my code based on it.
I’ve added the object using UI just to test if the collision would happen, but ideally, it will be created in my code. In the example provived, the cuboid is tunneling, going through the ground.

The problem right now is that, using the run_rigid_object, the collision with the ground does not happen. My rigid object is going through it. Do you have any idea?

Copyright (c) 2022-2024, The Isaac Lab Project Developers.

All rights reserved.

SPDX-License-Identifier: BSD-3-Clause

“”"
This script demonstrates different legged robots.

… code-block:: bash

# Usage
./isaaclab.sh -p source/standalone/demos/quadrupeds.py

“”"

“”“Launch Isaac Sim Simulator first.”“”

import argparse
import math

from omni.isaac.lab.app import AppLauncher

add argparse arguments

parser = argparse.ArgumentParser(description=“This script demonstrates different legged robots.”)

append AppLauncher cli args

AppLauncher.add_app_launcher_args(parser)

parse the arguments

args_cli = parser.parse_args()

launch omniverse app

app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app

“”“Rest everything follows.”“”

import numpy as np
import torch

import omni.isaac.core.utils.prims as prim_utils

import omni.isaac.lab.sim as sim_utils
from omni.isaac.lab.assets import Articulation, RigidObject, RigidObjectCfg

Pre-defined configs

from omni.isaac.lab_assets.anymal import ANYMAL_B_CFG, ANYMAL_C_CFG, ANYMAL_D_CFG # isort:skip
from omni.isaac.lab_assets.spot import SPOT_CFG # isort:skip
from omni.isaac.lab_assets.unitree import UNITREE_A1_CFG, UNITREE_GO1_CFG, UNITREE_GO2_CFG # isort:skip

def define_origins(num_origins: int, spacing: float) → list[list[float]]:
“”“Defines the origins of the scene.”“”
env_origins = torch.zeros(num_origins, 3)
num_cols = np.floor(np.sqrt(num_origins))
num_rows = np.ceil(num_origins / num_cols)
xx, yy = torch.meshgrid(torch.arange(num_rows), torch.arange(num_cols), indexing=“xy”)
env_origins[:, 0] = spacing * xx.flatten()[:num_origins] - spacing * (num_rows - 1) / 2
env_origins[:, 1] = spacing * yy.flatten()[:num_origins] - spacing * (num_cols - 1) / 2
env_origins[:, 2] = 0.0
return env_origins.tolist()

def design_scene() → tuple[dict, list[list[float]]]:
“”“Designs the scene.”“”
# Ground-plane como RigidObject móvel
ground_cfg = RigidObjectCfg(
prim_path=“/World/MovingGround”,
spawn=sim_utils.CuboidCfg(
size=(10.0, 10.0, 0.1),
rigid_props=sim_utils.RigidBodyPropertiesCfg(),
mass_props=sim_utils.MassPropertiesCfg(mass=0.0), # Massa zero para objeto cinemático
collision_props=sim_utils.CollisionPropertiesCfg(collision_enabled=True, contact_offset=0.15, rest_offset=0.15),
visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.5, 0.5, 0.5)),
),
init_state=RigidObjectCfg.InitialStateCfg(pos=(0.0, 0.0, 0.0)),
)
ground = RigidObject(cfg=ground_cfg)

# Lights
cfg = sim_utils.DomeLightCfg(intensity=2000.0, color=(0.75, 0.75, 0.75))
cfg.func("/World/Light", cfg)

# Create separate groups called "Origin1", "Origin2", etc.
origins = define_origins(num_origins=7, spacing=1.25)

# Origin 1 with Anymal B
prim_utils.create_prim("/World/Origin1", "Xform", translation=origins[0])
anymal_b = Articulation(ANYMAL_B_CFG.replace(prim_path="/World/Origin1/Robot"))

# Origin 2 with Anymal C
prim_utils.create_prim("/World/Origin2", "Xform", translation=origins[1])
anymal_c = Articulation(ANYMAL_C_CFG.replace(prim_path="/World/Origin2/Robot"))

# Origin 3 with Anymal D
prim_utils.create_prim("/World/Origin3", "Xform", translation=origins[2])
anymal_d = Articulation(ANYMAL_D_CFG.replace(prim_path="/World/Origin3/Robot"))

# Origin 4 with Unitree A1
prim_utils.create_prim("/World/Origin4", "Xform", translation=origins[3])
unitree_a1 = Articulation(UNITREE_A1_CFG.replace(prim_path="/World/Origin4/Robot"))

# Origin 5 with Unitree Go1
prim_utils.create_prim("/World/Origin5", "Xform", translation=origins[4])
unitree_go1 = Articulation(UNITREE_GO1_CFG.replace(prim_path="/World/Origin5/Robot"))

# Origin 6 with Unitree Go2
prim_utils.create_prim("/World/Origin6", "Xform", translation=origins[5])
unitree_go2 = Articulation(UNITREE_GO2_CFG.replace(prim_path="/World/Origin6/Robot"))

# Origin 7 with Boston Dynamics Spot
prim_utils.create_prim("/World/Origin7", "Xform", translation=origins[6])
spot = Articulation(SPOT_CFG.replace(prim_path="/World/Origin7/Robot"))

scene_entities = {
    "ground": ground,
    "anymal_b": anymal_b,
    "anymal_c": anymal_c,
    "anymal_d": anymal_d,
    "unitree_a1": unitree_a1,
    "unitree_go1": unitree_go1,
    "unitree_go2": unitree_go2,
    "spot": spot,
}
return scene_entities, origins

def run_simulator(sim: sim_utils.SimulationContext, entities: dict[str, Articulation], origins: torch.Tensor):
“”“Runs the simulation loop.”“”
sim_dt = sim.get_physics_dt()
sim_time = 0.0
count = 0
ground = entities[“ground”]

# Parâmetros do movimento do chão
amplitude = 1  # Amplitude do movimento em metros
frequency = 1  # Frequência em Hz

while simulation_app.is_running():
    # Reset periódico
    if count % 200 == 0:
        sim_time = 0.0
        count = 0
        # Separar robôs das outras entidades
        robots = [e for e in entities.values() if isinstance(e, Articulation)]
        for index, robot in enumerate(robots):
            root_state = robot.data.default_root_state.clone()
            root_state[:, :3] += origins[index]
            robot.write_root_state_to_sim(root_state)
            joint_pos, joint_vel = robot.data.default_joint_pos.clone(), robot.data.default_joint_vel.clone()
            robot.write_joint_state_to_sim(joint_pos, joint_vel)
            robot.reset()
        print("[INFO]: Resetting robots state...")

    ground_z = amplitude * math.sin(2 * math.pi * frequency * sim_time)
    ground_state = ground.data.default_root_state.clone()
    ground_state[:, 2] = ground_z
    ground.write_root_state_to_sim(ground_state)

    # Aplicar ações aos robôs
    for name, robot in entities.items():
        if isinstance(robot, Articulation):  # Apenas para os robôs
            joint_pos_target = robot.data.default_joint_pos + torch.randn_like(robot.data.joint_pos) * 0.1
            robot.set_joint_position_target(joint_pos_target)
            robot.write_data_to_sim()

    # Step de simulação
    sim.step()
    sim_time += sim_dt
    count += 1

    # Atualizar estados dos robôs
    for name, robot in entities.items():
        if isinstance(robot, Articulation):
            robot.update(sim_dt)

def main():
“”“Main function.”“”
sim = sim_utils.SimulationContext(sim_utils.SimulationCfg(dt=0.01, physx=sim_utils.PhysxCfg(enable_ccd=True)))
sim.set_camera_view(eye=[2.5, 2.5, 2.5], target=[0.0, 0.0, 0.0])
scene_entities, scene_origins = design_scene()
scene_origins = torch.tensor(scene_origins, device=sim.device)
sim.reset()
print(“[INFO]: Setup complete…”)
run_simulator(sim, scene_entities, scene_origins)

if name == “main”:
main()
simulation_app.close()