Computation of the forces between rigid and soft bodies with joint data

Hello everyone,

I’m using Isaac Sim 4.2 to simulate and measure forces through deformable bodies (that I simulate with CUDA since with CPU is not possible). Specifically, I have a cylinder with deformable body properties that is attached to a rigid body using a fixed joint. Initially, I tried creating a fixed joint between the deformable cylinder and the rigid body. To test this setup, I dropped a cube with a certain mass onto the structure and used the [get_measured_joint_forces] function to retrieve the 6D forces.

However, I encountered several issues:

  • The joint function doesn’t seem to work as expected. Although the function executes, the force values are incorrect since the mass of the cube isn’t detected.
  • Additionally, the sensor behaves abnormally, flying into space and failing to stay grounded even with gravity enabled.

After researching how to attach deformable bodies to rigid ones, I realized I should use an “attachment.” This resolved the gravity issues. Now, I have attached two rigid bodies using a joint to read force data via the function, and I attached the second rigid body to the deformable body. However, the data I receive is still inaccurate, as it doesn’t detect the impact when the cube collides with the setup (see picture).

Interestingly, when I replace the deformable cylinder with a rigid body, the force values are accurate and behave as expected.

Does anyone know how I could resolve this issue? Has anyone faced similar challenges or have suggestions for fixing this behavior?

Hey @milan.francois.t.amighi! Could you please try Isaac Sim 4.5 and see if this issue persists?

Hello @zhengwang, just try it and it doesn’t work even with version 4.5 of Isaac Sim.

Hey @milan.francois.t.amighi. Could you please explain what you are trying to achieve? Why do you have two rigid bodies attached to one deformable body?

Did you add articulation to the joint?

Hey @milan.francois.t.amighi ! I talked to our internal team and they confirmed that this is a known issue. The fix should come out in Isaac Sim 5.0.0. Please stay tuned!

Hey @milan.francois.t.amighi! Could you please share a minimal setup of your scene?

Hello @zhengwang,

Thank you for your response and assistance.

To provide more context, I am trying to simulate a compliant force sensor capable of measuring both normal and shear forces. The sensor we aim to replicate consists of a support, a ship, and a deformable elastomer (the cylinder) embedded with a magnet. Based on the elastomer’s deformation, we obtain a force measurement in 3D (see picture shared before).

In the simulation, the support and ship can be rigid (although, in reality, the ship is not strictly necessary—it’s mainly included to replicate our lab setup). The deformable body is attached using a attachement rather than a joint, as a direct joint attachment isn’t feasible with deformable body. The goal is to use this setup to retrieve forces via:

sensor_joint_forces = robots.get_measured_joint_forces()

For that, I wanted first to compute the force of the joint between the elastomer and the ship (but cannot since would be an attachement) or between the ship and the support. Like said before, if we put a cube on the top, we received good force data in case we consider the elastomer as a rigid body, no a deformable one.

This approach would essentially create a digital twin of our lab sensor. While treating the elastomer as a rigid body works in the simulation, it does not behave as expected when modeled as a deformable body, as it should in reality.

I have two additional questions:

  1. Do you know when Isaac Sim 5.0 will be released?
  2. Is the function get_measured_joint_forces() available in Isaac Lab? I am aware of the contact force option, but it operates on a different principle.

Thanks again for your help!

Thanks @milan.francois.t.amighi. If I understand correctly, you don’t actually need to attach two rigid bodies to the deformable cylinder. One rigid body can be used to mimic the support and the ship. Is that correct?

Let me reach out to our internal team about the release date of Isaac Sim 5.0.

As for Isaac Lab questions, please use isaac-sim/IsaacLab · Discussions · GitHub for better support. Thanks!

Hi @milan.francois.t.amighi! Could you please provide a minimal setup of your system?
Our engineering team wants to try to reproduce your issue and confirm if their fix actually solves it. Thanks!

Hello @zhengwang,

Here is the minimal setup of my system:

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: RTX4090
  • Driver Version: 535.183.01

CUDA version: 12.2

And yes, one rigid body can be used to mimic the support and the ship.

Do you need any more information?

Hi @milan.francois.t.amighi Sorry my question wasn’t clear.
I meant the USD file and the script you wrote for getting the force. Thanks!

Hello @zhengwang,

This is the code

from omni.isaac.core.articulations import Articulation
from omni.isaac.core.prims import RigidPrimView
import asyncio
from omni.isaac.core import World
from omni.isaac.core.utils.stage import (
    add_reference_to_stage,
    create_new_stage_async,
    get_current_stage,
)
from omni.isaac.core.utils.nucleus import get_assets_root_path
from pxr import UsdPhysics, PhysxSchema
import torch
import numpy as np

async def joint_force():
    World.clear_instance()

    # Initialize the world with GPU dynamic simulation (XPBD solver for deformables)
    my_world = World(stage_units_in_meters=1.0, backend="torch", device="cuda")
    await my_world.initialize_simulation_context_async()
    await omni.kit.app.get_app().next_update_async()

    # Set XPBD solver for deformable simulation
    stage = get_current_stage()
    scene_prim = UsdPhysics.Scene.Define(stage, "/physicsScene")
    physx_scene_api = PhysxSchema.PhysxSceneAPI.Apply(scene_prim.GetPrim())
    physx_scene_api.CreateSolverTypeAttr().Set("XPBD")

    # Load the asset and ground plane
    assets_root_path = get_assets_root_path()
    asset_path = "/Desktop/Example.usd"
    add_reference_to_stage(usd_path=asset_path, prim_path="/World/Sensor")
    await omni.kit.app.get_app().next_update_async()
    my_world.scene.add_default_ground_plane()

    # Add the articulation and initialize
    arti_view = Articulation("/World/Sensor/Base/Base")
    my_world.scene.add(arti_view)

    # Initialize RigidPrimView for contact force measurement
    box_view = RigidPrimView(
        prim_paths_expr="/World/Sensor/Base/Base",
        contact_filter_prim_paths_expr=["/World/defaultGroundPlane/GroundPlane/CollisionPlane"],
        max_contact_count=10
    )
    my_world.scene.add(box_view)

    # Use double precision if necessary
    torch.set_default_dtype(torch.float64)

    await my_world.reset_async(soft=False)

    # Main simulation loop with stop condition
    while my_world.is_playing():
        my_world.step_async()
        torch.cuda.synchronize()  # Synchronize GPU for accurate force retrieval

        # Get joint forces
        sensor_joint_forces = arti_view.get_measured_joint_forces().clone().detach().cpu()
        
        print(f"Jointforces: {sensor_joint_forces}")

        # Capture friction and contact forces
        friction_forces, friction_points, _, _ = box_view.get_friction_data(dt=1/60)
        forces, points, normals, distances, pair_contacts_count, pair_start_indices = box_view.get_contact_force_data(dt=1/60)

        # Ensure non-empty data
        if forces.numel() > 0 and normals.numel() > 0:
            contact_force_vectors = forces * normals  # Compute 3D contact force vectors
            contact_force_vectors = contact_force_vectors.clone().detach().cpu()

            # Print friction and contact forces
            #print(f"Friction Forces: {friction_forces.clone().detach().cpu()}")
            #print(f"3D Contact Forces: {contact_force_vectors}")

        # Wait for the next simulation update
        await asyncio.sleep(0.1)

    print("Simulation has stopped.")
    await my_world.stop_async()

# Run the corrected simulation loop
asyncio.ensure_future(joint_force())

I tried to send the USD file but it doesn’t let me so here is a picture of the structure:

Hi @milan.francois.t.amighi Thanks for your script!
For the USD file, you can try to zip it and attach it in the forum. Or you can upload it to github/gitlab/google drive and share with me.