Trouble with apply_rigid_body_force_tensor for magnet simulation

Hi all,

I am currently trying to simulate magnets in Isaac gym. I created and tested the magnet computation code using Isaac gym Spheres, which works fine. You can see what I mean through this YouTube video link: Isaac gym magnet calculation success using spheres - YouTube.

However, the end goal is to add this “magnetic” feature to the tip of a rigid body that I upload to Isaac gym using a URDF file. Unfortunately, when applying the same magnetic computation code to an external URDF file, magnet computation “explodes”… I am not sure why this happens. For reference, this is what happens: Isaac gym servo links magnet force "explosion" - YouTube

My system configurations:

  • OS: Ubuntu 18.04.6 LTS
  • CUDA: v11.7
  • Python: 3.7
  • Environment: conda rlgpu

I am currently running the simulation on the GPU with the following parameters:

  • sim_params.up_axis = gymapi.UP_AXIS_Z
  • sim_params.dt = 1.0 / 60.0
  • sim_params.gravity = gymapi.Vec3(0.0, 0.0, -9.81)
  • sim_params.substeps = 4
  • sim_params.physx.solver_type = 1
  • sim_params.physx.num_position_iterations = 4
  • sim_params.physx.num_velocity_iterations = 1
  • sim_params.physx.contact_offset = 0.02
  • sim_params.physx.rest_offset = 0.001
  • sim_params.physx.friction_correlation_distance = 0.0005
  • sim_params.physx.friction_offset_threshold = 0.04
  • sim_params.physx.max_depenetration_velocity = 0.1

To explain a little more regarding the URDF file:

  • 9 rigid bodies (body, Shaft0, Cone0, Tip0, Magnet0, Shaft1, Cone1, Tip1, Magnet1)
  • 2 prismatic joints.
  • 6 fixed joints

The two ball-looking things at the object’s tip (Magent0 and Magent1) are what I want to behave as a magnet. It is connected to the rigid body named Tip0 and Tip1, respectively through a fixed joint. For every frame, I calculate the magnetic force based on the location of Magent0 and Magent1 and apply a force tensor using apply_rigid_body_force_tensor()

Here is my code for clarity:

# simulation runner
def run_crawl_magnets(Sim, Env, Asset, vectorize):

    if Asset.dof_count > 0:
        tensor = torch.tensor([0.0, 0.0], dtype=torch.float32, device=Sim.args.sim_device)
        base_state = torch.flatten(tensor.repeat(Asset.n, 2)).view(-1, 2)
        was_successful = Sim.gym.set_dof_state_tensor(Sim.sim, gymtorch.unwrap_tensor(base_state))
        print(was_successful)

    frame_count = 0
    while not Sim.gym.query_viewer_has_closed(Env.viewer):

        Sim.gym.simulate(Sim.sim)
        Sim.gym.fetch_results(Sim.sim, True)

        if frame_count > 100:
            mag_status = apply_servo_magnet_force(Sim, Asset, frame_count, vectorize = vectorize)

        crawl_status = apply_crawl(Sim, Asset)

        # refresh the state tensors (from tensor api)
        Sim.gym.refresh_actor_root_state_tensor(Sim.sim)

        # update the viewer
        Sim.gym.step_graphics(Sim.sim)
        Sim.gym.draw_viewer(Env.viewer, Sim.sim, True)

        Sim.gym.sync_frame_time(Sim.sim)
        frame_count += 1

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


# applying magnetic force on Magnet0 and Magent1
def apply_servo_magnet_force(Sim, Asset, frame, vectorize = False):
    force_mat = torch.zeros((Asset.n*Asset.num_bodies, 3), device=Sim.device, dtype=torch.float)
    torques = torch.zeros((Asset.n*Asset.num_bodies, 3), device=Sim.device, dtype=torch.float)
    mag_mat =  get_servo_magnet_mat(Sim, Asset)

    tmp = 0
    for n in range(Asset.n):
        force_mat[n*Asset.num_bodies+4,:] = mag_mat[tmp,:] 
        force_mat[n*Asset.num_bodies+8,:] = mag_mat[tmp+1,:] 
        tmp += 2

    status = Sim.gym.apply_rigid_body_force_tensors(Sim.sim, gymtorch.unwrap_tensor(force_mat.type(torch.float32)), gymtorch.unwrap_tensor(torques), gymapi.ENV_SPACE)

    return status

# magnet calculation code
def calculate_mag_force(Sim, v1, v2):
    dir_vector = v1 - v2
    magnitude = torch.tensor([torch.linalg.norm(dir_vector)], device=Sim.device, dtype=torch.float)
    direction = dir_vector/magnitude
    tmp = torch.tensor([1e-12], device=Sim.device, dtype=torch.float)
    if torch.isnan(magnitude):
        print("ERROR: magnets ARE NAN")
    elif magnitude**2 < 1e-9:
        print("ERROR: magnets are too close")
    force = (MAX_MAGNETIC_FORCE/torch.maximum(magnitude**2, tmp))*direction
    return force

def get_servo_magnet_mat(Sim, Asset):
    mag_mat = torch.zeros((Asset.n*2, 3), device=Sim.device, dtype=torch.float)
    tensor = Sim.gym.acquire_rigid_body_state_tensor(Sim.sim)
    states = gymtorch.wrap_tensor(tensor).type(torch.float64)
    positions = states[:, 0:3]
    mask = Asset.magnet_mask*Asset.n
    positions = positions[mask]

    # calculate magnet force
    for i in range(positions.shape[0]):
        total_force = torch.zeros((1, 3), device=Sim.device, dtype=torch.float)
        for j in range(positions.shape[0]):
            if i == j:
                continue
            else:
                v1 = positions[i, :]; v2 = positions[j, :]
                total_force -= calculate_mag_force(Sim, v1, v2)
        mag_mat[i] = total_force

    return mag_mat

I have tried changing AssetOptions, RigidShapeProperties, and SImulation parameters, and nothing is working…
Please let me know if there is anything I need to do differently. Thank you!

Hi @donghankim,

At first glance, this doesn’t look like the common explosion that can happen in physics when you have object interpenetration causing very strong depenetration forces to be applied. To me this looks like the forces you are applying might be getting too strong - the behaviour early at 0:19 appears to show the green magnet under acceleration as it shoots away, rather than getting a one-time force boost.

I’d suggest that you first very carefully debug the forces you’re applying to the objects. Printing things out is usually good practice and can help you see whether you’re starting to apply forces that are too strong.

It’s certainly not impossible that we have some bugs or issues somewhere that is causing this. We haven’t done that much work with continuously applied forces like you’re doing here. Aside from the QuadCopter and Ingenuity examples, we’ve mostly used applied forces to help with domain randomization work.

You can also try to record a PhysX Visual Debugger export of what’s going on using the GYM_PVD_FILE environment variable. You’ll need to be running with CPU simulation rather than GPU simulation, and run something like export GYM_PVD_FILE=myoutput.pvd before running your code. This should output a pvd file that can be viewed in the PhysX Visual Debugger. Unfortunately the older only runs on Windows.

You might also want to try doing your magnetic simulation using Isaac Sim instead of standalone Isaac Gym. There we have the Omniverse PhysX Debugger that can help out.

Good Luck!
-Gav

Hi Gav,

You mentioned that there were two continued force application examples “QuadCopter” and “Ingenuity.” Do you know where I can access them, as I can’t find them in the examples folder.

All the best,
RM

For Isaac Sim / Omniverse, these are in:
OmniIsaacGymEnvs/omniisaacgymenvs/tasks at main · NVIDIA-Omniverse/OmniIsaacGymEnvs · GitHub

For standalone Isaac Gym, they’re here:
IsaacGymEnvs/isaacgymenvs/tasks at main · NVIDIA-Omniverse/IsaacGymEnvs · GitHub

Take care,
-Gav