> This page is for version Release 3.0 (default).
> For other versions, use one of these documentation indexes:
> - Release 3.0 (default): https://docs.nvidia.com/isaaclab/3.0/llms.txt
> - Release 2.3: https://docs.nvidia.com/isaaclab/2.3/llms.txt
> - Release 2.2: https://docs.nvidia.com/isaaclab/2.2/llms.txt
> - Release 2.1: https://docs.nvidia.com/isaaclab/2.1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/isaaclab/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/isaaclab/_mcp/server.

# Joint Wrench Sensor

A `~sensors.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 `sensors.JointWrenchSensor.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 `sensors.JointWrenchSensorCfg.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 `sensors.JointWrenchSensor.body_names` or
`~sensors.JointWrenchSensor.find_bodies` instead of assuming that different backends expose
the same number or order of entries:

```python
joint_wrench = JointWrenchSensorCfg(prim_path="{ENV_REGEX_NS}/Robot")
```

Manager-based environments can select a body subset through
`~isaaclab.managers.SceneEntityCfg` and use
`~isaaclab.envs.mdp.body_incoming_wrench` as an observation term:

```python
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.

```python
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.