Isaac Sim Version
4.2.0
Operating System
Ubuntu 22.04
GPU Information
- Model: 4x Nvidia RTX A4000
- Driver Version: 550.90.07
Topic Description
Detailed Description
Hello! I am attempting to figure out the best way to apply forces to rigid body objects in Isaac Sim via a cpp extension.
What I have tried
I have attempted to use two different libraries.
Note: this code is condensed and generalized for this forum post. Attempt 1, with usdrt’s physxForceAPI does not work. It compiles and runs fine without crashing, however, the rigid body does not move. Attempt 2 using the dynamic control library works! However, I also notice that this library is deprecated ( Omniverse Isaac Sim Glossary — Omniverse IsaacSim), so I am hesitant to continue developing with it. Is method 1 using usdrt physxForceAPI the best route to go? If so, are there any examples on how to use it? Is there anything obvious as to why my attempts to use physxForceAPI don’t work? Also, why is dynamic control being deprecated in the first place?
Attempt 1:
PXR_NS::UsdStageRefPtr activeStage = allStages[0];
PXR_NS::UsdStageCache stageCache = PXR_NS::UsdUtilsStageCache::Get();
long int stageId = stageCache.GetId(activeStage).ToLongInt();
usdrt::UsdStageRefPtr usdrtStage = usdrt::UsdStage::Attach(omni::fabric::UsdStageId(stageId));
const usdrt::SdfPath kRigidBodyPath(“/World/RigidBodyBox”);
usdrt::UsdPrim myPrim = usdrtStage->GetPrimAtPath(kRigidBodyPath);
std::shared_ptr<usdrt::PhysxSchemaPhysxForceAPI> forceAPI = std::make_shared<usdrt::PhysxSchemaPhysxForceAPI>
(usdrt::PhysxSchemaPhysxForceAPI::Apply(myPrim));
forceAPI->CreateForceEnabledAttr().Set(true);
forceAPI->GetForceEnabledAttr().Set(true);
forceAPI->CreateModeAttr().Set(usdrt::PhysxSchemaTokens->force);
forceAPI->GetModeAttr().Set(usdrt::PhysxSchemaTokens->force);
GfVec3f force(10000, 100000, 100000000);
forceAPI.GetForceAttr().Set(force);
Attempt 2:
// Get the Dynamic Control interface
omni::isaac::dynamic_control::DynamicControl* dc = carb::getFramework()->acquireInterface<omni::isaac::dynamic_control::DynamicControl>();
std::shared_ptr<omni::isaac::dynamic_control::DcHandle> body
= std::make_shared<omni::isaac::dynamic_control::DcHandle>(dc->getRigidBody(“/World/RigidBodyBox”));
carb::Float3 force = {0.0f, 2000.0f, 0.0f};
carb::Float3 position= {0.0f, 0.0f, 0.0f};
dc->applyBodyForce(*body, force, position, true);
Thanks,
Alex
1 Like
I have tried a similar approach with the Dynamic Control library but was disappointed to hear that it has been deprecated. Is there another library that has a similar interface ?
Hi,
The Attempt 1 would have worked if you would apply the API through USD API not USDRT API, structural changes have to be done through USD API. Then you can use USDRT API to do runtime changes to attributes.
So instead of using USDRT use USD API, then in your runtime loop you can change the force attribute through USDRT, but the schema API has to be applied through USD.
Regards,
Ales
Hey! Thanks for the response @AlesBorovicka. How would you go about that? As far as I can tell, the only physxForceAPI.h header resides in usdrt/scenegraph/usd/physxSchema, and its “Apply” function expects a usdrt::UsdPrim as an input (as opposed to a PXR_NS::UsdPrim).
Or is there some other way to go about this that I am missing?
Ah yes, the headers are problematic to obtain, I need to fix this.
Anyway you dont need the headers, you can do something like this:
UsdPrim prim = stage->GetPrimAtPath(SdfPath("/World/box"));
if (prim)
{
prim.ApplyAPI(TfToken("PhysxForceAPI"));
UsdAttribute attr = prim.GetAttribute(TfToken("physxForce:force"));
if (attr)
{
attr.Set(GfVec3f(500.0f, .0f, .0f));
}
}
To see what all attribute tokens look like you can check this schema documentation:
https://docs.omniverse.nvidia.com/kit/docs/omni_usd_schema_physics/106.1/class_physx_schema_physx_force_a_p_i.html
Sorry about that,
regards,
Ales
Thanks again for the quick response @AlesBorovicka . However, I am still running into issues here. It appears this ApplyAPI function you provide is a templated function that requires a SchemaType and requires the SchemaType to be of kind MultipleApplyAPI.
template <typename SchemaType>
bool ApplyAPI(const TfToken &instanceName) const {
static_assert(std::is_base_of<UsdAPISchemaBase, SchemaType>::value,
“Provided type must derive UsdAPISchemaBase.”);
static_assert(!std::is_same<UsdAPISchemaBase, SchemaType>::value,
“Provided type must not be UsdAPISchemaBase.”);
static_assert(SchemaType::schemaKind == UsdSchemaKind::MultipleApplyAPI,
“Provided schema type must be a multiple apply API schema.”);
static const TfType schemaType = TfType::Find();
return _ApplyAPI(schemaType, instanceName);
}
The other two options are:
template
bool ApplyAPI() const {
static_assert(std::is_base_of<UsdAPISchemaBase, SchemaType>::value,
“Provided type must derive UsdAPISchemaBase.”);
static_assert(!std::is_same<UsdAPISchemaBase, SchemaType>::value,
“Provided type must not be UsdAPISchemaBase.”);
static_assert(SchemaType::schemaKind == UsdSchemaKind::SingleApplyAPI,
“Provided schema type must be a single apply API schema.”);
static const TfType schemaType = TfType::Find();
return _ApplyAPI(schemaType);
}
/// Non-templated overload of the templated ApplyAPI above.
///
/// This function behaves exactly like the templated ApplyAPI
/// except for the runtime schemaType validation which happens at compile
/// time in the templated version. This method is provided for python
/// clients. Use of the templated ApplyAPI is preferred.
USD_API
bool ApplyAPI(const TfType& schemaType) const;
Overall, it appears to me that all of these functions, in one way or another require me to have access to PXR_NS::PhysxSchemaPhysxForceAPI.
Alex
I believe I have solved the issue. First, I attempted to use a similar approach to what @AlesBorovicka mentioned regarding the TfToken/GetAttribute solution, but with usdrt by doing the following:
usdrt::TfToken schemaIdentifier(“PhysxForceAPI”);
bool success = prim.ApplyAPI(schemaIdentifier, usdrt::TfToken());
usdrt::UsdAttribute attr = prim.GetAttribute(usdrt::TfToken(“physxForce:force”));
if (attr)
{
attr.Set(GfVec3f(-500.0f, -500.0f, -500.0f));
}
However, it still was not working. But then I realized that I could add a Force component to my rigid body prim via the Isaac Sim gui. Once I did that, not only did the code above work, but also Attempt 1 was working from my initial prompt.
Overall, thanks @AlesBorovicka for the quick feedback and insight.
Ah I see, I am already using newer USD version, where this function exists. Sorry…
Ok but this should work then still:
TfType forceAPIType = UsdSchemaRegistry::GetTypeFromSchemaTypeName(TfToken("PhysxForceAPI"));
prim.ApplyAPI(forceAPIType);
Regards,
Ales
I can confirm that this works as well! As a side note, @AlesBorovicka, are these methods of applying forces additive to existing forces (like gravity) being applied? Or is this overwriting all other forces?
Great, glad to hear that. Its adding the force, not overwritting.
1 Like