Joint Wrench Sensor#
A JointWrenchSensor reports the incoming reaction wrench at each selected
articulation body’s parent joint. It exposes force [N] and torque [N·m] separately, with entries
ordered by body_names.
Wrench convention#
The incoming_joint_frame convention expresses the wrench in the child-side joint frame at the
child-side joint anchor. This matches the placement of a six-axis force/torque sensor mounted at the
joint. Backend implementations convert their native solver output to this common convention.
PhysX’s get_link_incoming_joint_force() already returns the wrench in the child-side joint frame,
referenced at its anchor, so the PhysX sensor exposes those components directly. Applying the USD
localPos1 and localRot1 again would shift and rotate the wrench twice.
Configure the sensor#
Set prim_path to the articulation root. Reported body coverage
depends on the physics backend:
PhysX and OVPhysX report every articulation link, including the root link.
Newton reports the child link of each non-free joint in the articulation tree, including fixed connections between bodies such as a welded wrist sensor or tool flange. Free joints, fixed joints to the world, and loop-closing constraints are excluded. The reported wrench at a weld includes the loads transmitted by its child subtree, even though the joint has no degrees of freedom.
Use body_names or
find_bodies() instead of assuming that different backends expose
the same number or order of entries:
joint_wrench = JointWrenchSensorCfg(prim_path="{ENV_REGEX_NS}/Robot")
Manager-based environments can select a body subset through
SceneEntityCfg and use
body_incoming_wrench() as an observation term:
feet_body_forces = ObsTerm(
func=mdp.body_incoming_wrench,
scale=0.1,
params={"sensor_cfg": SceneEntityCfg("joint_wrench", body_names=FEET_BODY_NAMES)},
)
actions = ObsTerm(func=mdp.last_action)
Read the data#
For E environments and B reported bodies, force.torch and torque.torch each have
shape (E, B, 3). Both buffers are None before simulation initialization.
joint_wrench = scene["joint_wrench"]
foot_ids, _ = joint_wrench.find_bodies([".*foot"])
force = joint_wrench.data.force.torch[:, foot_ids]
torque = joint_wrench.data.torque.torch[:, foot_ids]
wrench = torch.cat((force, torque), dim=-1)
The composed wrench has shape (E, num_selected_bodies, 6) with force components followed by
torque components. B and the entry ordering can differ between backends.