Performances of objects loaded in isaacgym don't conform to the laws of physics

hello, I want to use isaacgym to build different scenes, where multiple objects are layed randomly on the table. But when I load objects into the environment, initializing their position as random x,y above the table and incremental z, I notice lots of objects fly to the sky and begin to span out of no reason in the air. And when I don’t set their max_linear_velocity, some even shoot away like explosion when hit with other objects. It’s obviously against physics laws. what’s more, I can also see objects "drop into the table (a box) " even if I checked their collision group is set correctly. I don’t think it’s the bug of my code, but I’ll still paste here.:
import os
from isaacgym import gymapi, gymutil
import random
import math
import numpy as np
import transforms3d
import torch
import trimesh
import argparse
import tqdm
import time

np.random.seed(543)
random.seed(53)

acquire gym interface

gym = gymapi.acquire_gym()

Add custom arguments

custom_parameters = [
{“name”: “–controller”, “type”: str, “default”: “ik”,
“help”: “Controller to use for Franka. Options are {ik, osc}”},
{“name”: “–num_envs”, “type”: int, “default”: 256, “help”: “Number of environments to create”},
]
args = gymutil.parse_arguments(
description=“Franka Jacobian Inverse Kinematics (IK) + Operational Space Control (OSC) Example”,
custom_parameters=custom_parameters,
)

set torch device

device = ‘cuda:0’#args.sim_device if args.use_gpu_pipeline else ‘cpu’

configure sim

sim_params = gymapi.SimParams()

sim_params.up_axis = gymapi.UP_AXIS_Z

sim_params.gravity = gymapi.Vec3(0.0, 0.0, -9.8)

sim_params.dt = 1.0 / 60.0

# sim_params.substeps = 2

sim_params.use_gpu_pipeline = False # args.use_gpu_pipeline

sim_params.physx.solver_type = 1

sim_params.physx.num_position_iterations = 8

sim_params.physx.num_velocity_iterations = 1

sim_params.physx.rest_offset = 0.0

sim_params.physx.contact_offset = 0.001

sim_params.physx.friction_offset_threshold = 0.001

sim_params.physx.friction_correlation_distance = 0.0005

sim_params.physx.num_threads = args.num_threads

sim_params.physx.use_gpu = args.use_gpu

sim_params = gymapi.SimParams()

set common parameters

sim_params.dt = 1 / 60
sim_params.substeps = 2
sim_params.up_axis = gymapi.UP_AXIS_Z
sim_params.gravity = gymapi.Vec3(0.0, 0., -9.8)

set PhysX-specific parameters

sim_params.physx.use_gpu = True
sim_params.physx.solver_type = 1
sim_params.physx.num_position_iterations = 8
sim_params.physx.num_velocity_iterations = 0
sim_params.physx.contact_offset = 0.01
sim_params.physx.rest_offset = 0.0

sim_params.use_gpu_pipeline = False

set ground plane parameters

plane_params = gymapi.PlaneParams()
plane_params.normal = gymapi.Vec3(0, 0, 1) # z-up!
plane_params.distance = 0
plane_params.static_friction = 1
plane_params.dynamic_friction = 1
plane_params.restitution = 0

get all object codes

obj_code = os.listdir(“DexGraspNet/grasp_generation/meshdata_new”)

get all object grasp dicts

grasp_dict_dict = {}
for code in obj_code:
grasp_dict_dict[code]=np.load(f"isaacgym_simu/dataset/{code}.npy",allow_pickle=True)

options for loading 8 object assets

obj_asset_root = “isaacgym_simu/meshdata”
obj_asset_files = [f"{code}/coacd/coacd.urdf" for code in obj_code]

obj_asset_options = gymapi.AssetOptions()
obj_asset_options.override_com = True
obj_asset_options.override_inertia = True
obj_asset_options.density = 10000

obj_asset_options.vhacd_enabled = True

obj_asset_options.max_angular_velocity = 2.0

obj_asset_options.max_linear_velocity = 10
obj_asset_options.armature = 50000.
obj_asset_options.thickness = 1.0

options for loading hand asset

hand_asset_root = “isaacgym_simu/open_ai_assets”
hand_asset_file = “hand/shadow_hand.xml”

hand_asset_options = gymapi.AssetOptions()
hand_asset_options.disable_gravity = True
hand_asset_options.fix_base_link = True
hand_asset_options.collapse_fixed_joints = True

options for loading table asset

table_size = gymapi.Vec3(12,12,3)
table_asset_options = gymapi.AssetOptions()
table_asset_options.fix_base_link = True

options for loading assisting box boundary

w = table_size.x / 3.8
t = w/20
h = 3
bound_asset_options = gymapi.AssetOptions()
bound_asset_options.fix_base_link = True

select one to grasp

grasp_obj_index = random.randint(0,obj_num-1)

grasp_obj_index = 0

grasp_dict = grasp_dict_dict[scene_objs[grasp_obj_index]]

set up the env grid

total_batch = 36 # grasp_dict.shape[0]
batch_size = 36
num_per_row = 6
spacing = 8
env_lower = gymapi.Vec3(-spacing, -spacing, 0.0)
env_upper = gymapi.Vec3(spacing, spacing, 4* spacing)
safe_gap = 3
sample_num = 8

def _create_sim():
# create sim
args.compute_device_id = 0

sim = gym.create_sim(args.compute_device_id, args.graphics_device_id, args.physics_engine, sim_params)
if sim is None:
    print("*** Failed to create sim")
    quit()

gym.add_ground(sim, plane_params)

# create viewer
viewer = gym.create_viewer(sim, gymapi.CameraProperties())
if viewer is None:
    print("*** Failed to create viewer")
    quit()

# position the camera
cam_pos = gymapi.Vec3(14.0, 6.0, 4.0)
cam_target = gymapi.Vec3(0.0, 6.0, 0.0)
gym.viewer_camera_look_at(viewer, None, cam_pos, cam_target)

obj_assets_all = [gym.load_asset(sim, obj_asset_root, file, obj_asset_options) for file in obj_asset_files]
hand_asset = gym.load_asset(sim, hand_asset_root, hand_asset_file, hand_asset_options)
table_asset = gym.create_box(sim, table_size.x, table_size.y, table_size.z, table_asset_options)
bound_assets = [gym.create_box(sim, 2*w, t, h, bound_asset_options),
               gym.create_box(sim, 2*w, t, h, bound_asset_options),
               gym.create_box(sim, t, 2*w, h, bound_asset_options),
               gym.create_box(sim, t, 2*w, h, bound_asset_options),
               gym.create_box(sim, 2*w, 2*w, t, bound_asset_options)]

return sim,viewer,obj_assets_all,hand_asset,table_asset,bound_assets

view in batches

offset = 0
for batch in [0]:#range(total_batch//batch_size):
offset_ = min(offset + batch_size, total_batch)
print(f"batch {batch+1} : adding {offset_-offset} envs to sim")

# cache useful handles
envs = []
obj_idxs = []
hand_idxs = []
hand_handles = []
bound_handles = []

sim,viewer,obj_assets_all,hand_asset,table_asset,bound_assets=_create_sim()

# add a batch of envs
for index in range(offset, offset_):

    # randomly sample 8 objects for scene building and one object for grasping
    scene_objs_idx = random.sample(range(len(obj_code)),k=sample_num)
    scene_objs_code = [obj_code[idx]for idx in scene_objs_idx]
    grasp_obj_idx = random.choice(scene_objs_idx)
    grasp_obj_code = obj_code[grasp_obj_idx]
    grasp_dict = grasp_dict_dict[grasp_obj_code]

    obj_assets = [obj_assets_all[idx]for idx in scene_objs_idx]
    
    # create env
    env = gym.create_env(sim, env_lower, env_upper, num_per_row)
    envs.append(env)

    # add table
    table_pose = gymapi.Transform()
    table_pose.p = gymapi.Vec3(0.0, 0.0, 0.5 * table_size.z)
    table_handle = gym.create_actor(env, table_asset, table_pose, "table", index, 0)

    # set table restitution
    shape_props = gym.get_actor_rigid_shape_properties(env, table_handle)
    shape_props[0].restitution = 0
    gym.set_actor_rigid_shape_properties(env, table_handle, shape_props)

    # # add bound
    # box_pose = gymapi.Transform()
    # box_pose.p = gymapi.Vec3(0.0, w+t/2, h/2)
    # bound_handles.append(gym.create_actor(env, bound_assets[0], box_pose, "bound_1", index, 0))
    # box_pose.p = gymapi.Vec3(0.0, -w-t/2, h/2)
    # bound_handles.append(gym.create_actor(env, bound_assets[1], box_pose, "bound_2", index, 0))
    # box_pose.p = gymapi.Vec3(w+t/2, 0.0, h/2)
    # bound_handles.append(gym.create_actor(env, bound_assets[2], box_pose, "bound_3", index, 0))
    # box_pose.p = gymapi.Vec3(-w-t/2, 0.0, h/2)
    # bound_handles.append(gym.create_actor(env, bound_assets[3], box_pose, "bound_4", index, 0))
    # box_pose.p = gymapi.Vec3(0.0, 0.0, h+t/2)
    # bound_handles.append(gym.create_actor(env, bound_assets[4], box_pose, "bound_5", index, 0))

    # add actor(all objects)
    obj_handles = []
    pose = gymapi.Transform()
    for idx in range(sample_num):
        pose.p = gymapi.Vec3(random.uniform(-w/2,w/2), random.uniform(-w/2,w/2), table_size.z+(2+idx)*safe_gap)
        pose.r = gymapi.Quat.from_axis_angle(gymapi.Vec3(0, 0, 1), np.random.uniform(-math.pi, math.pi))
        obj_handle = gym.create_actor(env, obj_assets[idx], pose, f"env_{index}_obj_{idx}_{scene_objs_code[idx][9:12]}", index, 0)
        color = gymapi.Vec3(np.random.uniform(0, 1), np.random.uniform(0, 1), np.random.uniform(0, 1))
        gym.set_rigid_body_color(env, obj_handle, 0, gymapi.MESH_VISUAL_AND_COLLISION, color)            

        obj_shape_props = gym.get_actor_rigid_shape_properties(
            env, obj_handle)

        for i in range(len(obj_shape_props)):
            obj_shape_props[i].friction = 3.
        gym.set_actor_rigid_shape_properties(env, obj_handle,
                                             obj_shape_props)

        # set coefficience of restitution
        shape_props = gym.get_actor_rigid_shape_properties(env, obj_handle)
        for sp_prop in shape_props:
            sp_prop.restitution = 0
        gym.set_actor_rigid_shape_properties(env, obj_handle, shape_props)

        # set mass
        rb_props = gym.get_actor_rigid_body_properties(env, obj_handle)
        for rb_prop in rb_props:
            rb_prop.mass = 0.1
        gym.set_actor_rigid_body_properties(env, obj_handle, rb_props)
        
        # get global index of object in rigid body state tensor
        obj_idx = gym.get_actor_rigid_body_index(env, obj_handle, 0, gymapi.DOMAIN_SIM)
        obj_idxs.append(obj_idx)
        obj_handles.append(obj_handle)

    # add hand TODO set hand DOF value
    hand_pose = gymapi.Transform()
    hand_pose.p = gymapi.Vec3(0,0,4)
    hand_handle = gym.create_actor(env, hand_asset, hand_pose, "shand", index, -1)
    hand_handles.append(hand_handle)

# simulate a batch of envs
thred = 0.1
start_time = time.time()
while not gym.query_viewer_has_closed(viewer):
    # step the physics
    gym.simulate(sim)
    gym.fetch_results(sim, True)

    # refresh tensors
    gym.refresh_rigid_body_state_tensor(sim)
    # obj_pos = rb

    # update the viewer
    gym.step_graphics(sim)
    gym.draw_viewer(viewer, sim, True)
    # Wait for dt to elapse in real time.
    # This synchronizes the physics simulation with the rendering rate.
    gym.sync_frame_time(sim)

    body_states = gym.get_sim_rigid_body_states(sim, gymapi.STATE_ALL)
    vels = [list(state[1][0]) for state in body_states]
    vels_sum = sum([1 if sum(lst)<thred else 0 for lst in vels])
    
    if time.time()-start_time > 5:
        if vels_sum == body_states.shape[0]:
            print(">>>> all static")
            time.sleep(100)
            break

# body_states = gym.get_sim_rigid_body_states(sim, gymapi.STATE_ALL)
# data_dict = {}
# data_dict['scene_objects']={}
# for code in scene_objs_code:
#     data_dict['scene_objects'][code] = 


gym.destroy_viewer(viewer)
gym.destroy_sim(sim)

offset = offset_

print("Done")

sorry I used the wrong format. When you see titled big words, they are just “#” as explanation in python
and here’s the photo