Pinch grip
Basic contacts
Fingertips pinch a bar off-centre; the gold pair holds it level.
steel preset (the default), recordedon an NVIDIA RTX PRO 6000 Blackwell.Run it
cd examples# the default preset (steel), then the othersuv run shelf play torsion# change solver settings liveuv run shelf tune torsionSource: examples/shelf/01_basic_contacts/torsion/ · ported from steel-webgpu tools/scenes.py torsion() @ ad03e49
Presets
| Preset | Solver | Status | Checked |
|---|---|---|---|
steeldefault | steel | works | 2026-11-10, newton f6fc82a8b, NVIDIA RTX PRO 6000 Blackwell Server Edition |
xpbd | xpbd | unsupported | the fingertips use Steel's steel:min_torsional_patch_radius shape attribute |
vbd | vbd | unsupported | the fingertips use Steel's steel:min_torsional_patch_radius shape attribute |
mujoco | mujoco | unsupported | the fingertips use Steel's steel:min_torsional_patch_radius shape attribute |
featherstone | featherstone | unsupported | the fingertips use Steel's steel:min_torsional_patch_radius shape attribute |
semi_implicit | semi_implicit | unsupported | the fingertips use Steel's steel:min_torsional_patch_radius shape attribute |
feather_pgs | feather_pgs | unsupported | the fingertips use Steel's steel:min_torsional_patch_radius shape attribute |
kamino | kamino | unsupported | the fingertips use Steel's steel:min_torsional_patch_radius shape attribute |
implicit_mpm | implicit_mpm | unsupported | the fingertips use Steel's steel:min_torsional_patch_radius shape attribute |
style3d | style3d | unsupported | the fingertips use Steel's steel:min_torsional_patch_radius shape attribute |
Solvers with no row are untested on this example. The full settings are inpresets.toml.
Code
# SPDX-FileCopyrightText: Copyright (c) 2026 Skild AI and the Steel contributors# SPDX-License-Identifier: Apache-2.0# Direct source: steel-webgpu; see presets.toml and THIRD_PARTY.md.# Modified for Steel Shelf: preset-driven execution and shared runner integration.
############################################################################ Example Pinch grip## Contact torsion: sphere-tipped grippers pinch a bar 8 cm from its center; only the gold pair has a torsion radius.## Ported from steel-webgpu's tools/scenes.py (torsion); the scene builds# as it does there and the shelf's preset drives the solver.## Command: python -m shelf run torsion############################################################################
import math
import numpy as npimport warp as wp
import newtonimport newton.examplesfrom common.steel_scenes import BLUE, GOLD, GREY, RED, TEAL, SceneExample, cfg, tf
class Example(SceneExample): file = __file__ camera = {'eye': (0.5, -1.0, 0.7), 'target': (0.05, 0.0, 0.45)}
def build(self): """Contact torsion: sphere-tipped grippers pinch a bar 8 cm from its center; only the gold pair has a torsion radius.""" b = newton.ModelBuilder() newton.solvers.SolverSteel.register_custom_attributes(b) b.add_ground_plane() for y, radius, color in ((0.25, 0.0, GREY), (-0.25, 0.01, GOLD)): tip_cfg = cfg(mu=0.8, density=2000) custom = {"steel:min_torsional_patch_radius": radius} if radius > 0 else None base = b.add_link(xform=tf((0.0, y, 0.5))) b.add_shape_box(base, xform=tf((0.0, 0.0, 0.08)), hx=0.02, hy=0.06, hz=0.01, cfg=cfg(density=500), color=GREY) joints = [b.add_joint_fixed(-1, base, parent_xform=tf((0.0, y, 0.5)))] for side in (1.0, -1.0): finger = b.add_link(xform=tf((0.0, y + side * 0.022, 0.5))) b.add_shape_box(finger, xform=tf((0.0, side * 0.01, 0.04)), hx=0.008, hy=0.004, hz=0.04, cfg=cfg(density=500), color=color) b.add_shape_sphere(finger, radius=0.012, cfg=tip_cfg, color=color, custom_attributes=custom) joints.append(b.add_joint_prismatic(base, finger, parent_xform=tf((0.0, side * 0.022, 0.0)), axis=(0, side, 0), target_pos=-0.004, target_ke=3000.0, target_kd=50.0, effort_limit=30.0, limit_lower=-0.02, limit_upper=0.03)) b.add_articulation(joints) bar = b.add_body(xform=tf((0.08, y, 0.5))) b.add_shape_box(bar, hx=0.12, hy=0.01, hz=0.025, cfg=cfg(mu=0.8, density=500), color=[BLUE, TEAL][y < 0]) return b, {}, "Contact torsion: sphere fingertips pinch a bar off its center; the gold tips (min_torsional_patch_radius 1 cm) hold it level, the grey ones let it swing."
def _tilt(self): """Each bar's long axis against the horizontal [deg], grey then gold.""" q = self.state_0.body_q.numpy()[[3, 7], 3:] x, y, z, w = q.T return np.degrees(np.arcsin(np.clip(2 * (x * z - w * y), -1.0, 1.0)))
def test_post_step(self): t = self._tilt() self._grey_min = min(getattr(self, "_grey_min", 0.0), t[0]) self._gold_max = max(getattr(self, "_gold_max", 0.0), abs(t[1]))
def check(self): """The gold tips (torsion radius) hold their bar level; the grey ones let theirs swing down.""" assert self._gold_max < 5.0, f"the gold bar tilted {self._gold_max:.1f} deg" assert self._grey_min < -45.0, f"the grey bar only swung to {self._grey_min:.1f} deg"
if __name__ == "__main__": parser = Example.create_parser() viewer, args = newton.examples.init(parser) newton.examples.run(Example(viewer, args), args)example = "torsion"source = "steel-webgpu tools/scenes.py torsion() @ ad03e49"default = "steel"
[check]# Arguments `python -m shelf check` passes in test mode: 300 frames, 5 s, the grey bar's first swings; the example's check() asserts the outcome.args = ["--num-frames", "300"]
[gallery]short = "Fingertips pinch a bar off-centre; the gold pair holds it level."title = "Pinch grip"
[xpbd]status = "unsupported"reason = "the fingertips use Steel's steel:min_torsional_patch_radius shape attribute"
[vbd]status = "unsupported"reason = "the fingertips use Steel's steel:min_torsional_patch_radius shape attribute"
[mujoco]status = "unsupported"reason = "the fingertips use Steel's steel:min_torsional_patch_radius shape attribute"
[featherstone]status = "unsupported"reason = "the fingertips use Steel's steel:min_torsional_patch_radius shape attribute"
[semi_implicit]status = "unsupported"reason = "the fingertips use Steel's steel:min_torsional_patch_radius shape attribute"
[feather_pgs]status = "unsupported"reason = "the fingertips use Steel's steel:min_torsional_patch_radius shape attribute"
[steel]status = "works"# articulation_constraint_max 64: without the gap gate below, the fingers' contact, friction and torsion rows need# 42 dense rows; at the default 32 Steel dropped 11 every step and the gold bar swung down like the grey one. With# the 5 mm gate the gold bar also holds level at 16 and 32 rows (newton f6fc82a8b); 64 stays as headroom.# 4 substeps x 8 iterations: the gold bar stays level, the grey one swings and loses energy as at 16 x 50# (its centre returns to 78, 76, 74 mm above the bottom in the first seconds; 16 x 50: 78, 77, 76). 2 substeps# damp the swing (74, 69, 65) and 1 x 8 or 2 x 4 let the gold bar droop 75 to 80 deg; the squeeze sinks the# tips 0.3 mm into the bars (4 x 12: 0.07, 2 x 8: 1.6, 16 x 50: 0).# contact_gap_gate 0.005: only touching contacts get rows, which cuts the torsion grouping cost (4 x 12: 6.2 -> 3.8# ms). Joint limits off (3.8 -> 3.2 ms): the finger drives (target 4 mm into the bar) never reach the limits.# contact_torsion_device: the colored response carries the fingertips' torsion rows only on the device path.sim = { fps = 60, substeps = 4 }solver = { solve_mode = "matrix_free", iterations = 8, articulated_contact_response = "propagation_colored", contact_torsion_device = true, articulation_constraint_max = 64, contact_gap_gate = 0.005 }checked = "2026-11-10, newton f6fc82a8b, NVIDIA RTX PRO 6000 Blackwell Server Edition"
[kamino]status = "unsupported"reason = "the fingertips use Steel's steel:min_torsional_patch_radius shape attribute"
[implicit_mpm]status = "unsupported"reason = "the fingertips use Steel's steel:min_torsional_patch_radius shape attribute"
[style3d]status = "unsupported"reason = "the fingertips use Steel's steel:min_torsional_patch_radius shape attribute"Steel docs and tutorials are licensed under Apache-2.0. Third-party notices. "Skild", "Skild AI" and the Skild logo are trademarks of Skild AI and are not licensed under Apache-2.0.