Applying a force to the centre of mass of a satellite composed of multiple rigid bodies

Dear all,

I am working on a project about developing a small satellite with multiple robotic arms attached.
I would like to apply force to the center of the mass of the satellite, however we don’t know how to get the center of the mass of the entire satellite with multiple rigid bodies. We have been trying to apply a force on the articulation of the root body. But since the mass is not distributed evenly and the center of mass is not situated in the center of the root body, we cannot have the proper results.

Is there a way to get the position of the center of mass of the whole satellite, then apply a force on the entire object?
Also, is it possible to get the position of the center of mass of each rigid body/robotic arm attached to the satellite, and apply force on them individually?

Thank you in advance for your help

You could use directly omni physx features to implement something like this though not out of the box.

  1. Its possible to apply force to the rigid body/arm COM, you can PhysxSchema.PhysxForceAPI, check the Force demo for usage. (Window->Simulation->Demos). The force API if applied to a body will apply the force to the COM, while you change the applied force attribute
  2. Its possible to retrieve the mass information for individual bodies see this code snippet:
            selection = usd.get_context().get_selection()
            paths = list(selection.get_selected_prim_paths())
            def rigid_info_received(rigid_info : PhysxPropertyQueryRigidBodyResponse):
                print("Printing out rigid body information for prims:")
                if rigid_info.result == PhysxPropertyQueryResult.VALID:
                    print("Prim: " + str(prim.GetPrimPath()) + "\nRigid Body Info:" + 
                            "\n\tmass:" + str(rigid_info.mass) +
                            "\n\tinertia:" + str(rigid_info.inertia) +
                            "\n\tcenter of mass:" + str(rigid_info.center_of_mass) +
                            "\n\tprincipal axes:" + str(rigid_info.principal_axes))
                    print(f"Error while waiting for query to finish code={rigid_info.result}")
            def collider_info_received(collider_info : PhysxPropertyQueryColliderResponse):
                print("Printing out rigid body information for prims:")
                if collider_info.result == PhysxPropertyQueryResult.VALID:
                    print("Prim: " + str(prim.GetPrimPath()) + "\nCollider Info:" + 
                            "\n\tAABB Min:" + str(collider_info.aabb_local_min) +
                            "\n\tAABB Max:" + str(collider_info.aabb_local_max) +
                            "\n\tVolume:"   + str(collider_info.volume)
                    print(f"Error while waiting for query to finish code={collider_info.result}")
            stage_id = UsdUtils.StageCache.Get().Insert(usd.get_context().get_stage()).ToLongInt()
            for p in paths:
                selected_prim = usd.get_context().get_stage().GetPrimAtPath(p)
                for prim in Usd.PrimRange(selected_prim):
                    if prim.HasAPI(UsdPhysics.RigidBodyAPI):
                        body_path = PhysicsSchemaTools.sdfPathToInt(prim.GetPrimPath())
                        get_physx_property_query_interface().query_prim(stage_id = stage_id, 
                                                                        prim_id = body_path, 
                                                                        rigid_body_fn = rigid_info_received, 
                                                                        collider_fn = collider_info_received, 
                                                                        timeout_ms = 2000) # Timeout after 2 sec

Once you have the mass information for the individual masses you would have to use some mass computer to get the sum, (For example I added recently the computer into pxr UsdPhysics: USD/massProperties.h at release · PixarAnimationStudios/USD · GitHub)

Once you have the COM for the whole thing, you can add the ForceAPI to the root link with relative transformation matching the COM or you can use get_physx_interface().apply_force_at_pos(“/xform”, force, position)

So the information should be available, just not directly out of the box, but it should be possible to do what you need.


1 Like

Hi Ales,

Thank you very much for your reply.
I will try what you said in the message.

Have a nice day
Best regards,