Joint speed limits
Basics
Two double pendulums; the gold one has a speed limit.
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 vel_limit# change solver settings liveuv run shelf tune vel_limitSource: examples/shelf/00_basics/vel_limit/ · ported from steel-webgpu tools/scenes.py vel_limit() @ ad03e49
Presets
| Preset | Solver | Status | Checked |
|---|---|---|---|
steeldefault | steel | works | 2026-11-10, newton f6fc82a8b, NVIDIA RTX PRO 6000 Blackwell Server Edition |
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 Joint speed limits## Joint velocity limits: two double pendulums released horizontal; the gold one has |qd| <= 1.5 rad/s.## Ported from steel-webgpu's tools/scenes.py (vel_limit); the scene builds# as it does there and the shelf's preset drives the solver.## Command: python -m shelf run vel_limit############################################################################
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.3, -2.0, 1.1), 'target': (0.3, 0.0, 0.55)}
def build(self): """Joint velocity limits: two double pendulums released horizontal; the gold one has |qd| <= 1.5 rad/s.""" b = newton.ModelBuilder() b.add_ground_plane() for y, vmax, color in ((0.25, 1e6, GREY), (-0.25, 1.5, GOLD)): prev, joints = -1, [] for k in range(2): link = b.add_link(xform=tf((0.15 + 0.3 * k, y, 0.8))) b.add_shape_capsule(link, xform=tf(q=wp.quat_rpy(0.0, math.pi / 2, 0.0)), radius=0.03, half_height=0.12, cfg=cfg(density=800), color=color) parent_xform = tf((0, y, 0.8)) if prev < 0 else tf((0.15, 0, 0)) joints.append(b.add_joint_revolute(prev, link, parent_xform=parent_xform, child_xform=tf((-0.15, 0, 0)), axis=(0, 1, 0), velocity_limit=vmax)) prev = link b.add_articulation(joints) return b, {}, "Velocity limits: the grey double pendulum swings freely; the gold one is held to 1.5 rad/s per joint.", {}
def check(self): """The gold joints stay at or below their 1.5 rad/s limit.""" qd = np.abs(self.state_0.joint_qd.numpy()) assert qd[2:].max() <= 1.5 * 1.05, f"a gold joint moves at {qd[2:].max():.3f} rad/s, over its 1.5 rad/s limit"
if __name__ == "__main__": parser = Example.create_parser() viewer, args = newton.examples.init(parser) newton.examples.run(Example(viewer, args), args)example = "vel_limit"source = "steel-webgpu tools/scenes.py vel_limit() @ ad03e49"default = "steel"
[check]# Arguments `python -m shelf check` passes in test mode.args = []
[gallery]short = "Two double pendulums; the gold one has a speed limit."title = "Joint speed limits"frame = 90
[xpbd]status = "untested"
[vbd]status = "untested"
[mujoco]status = "untested"
[featherstone]status = "untested"
[semi_implicit]status = "untested"
[feather_pgs]status = "untested"
[steel]status = "works"# 6 substeps x 4 iterations, immediate response: the gold joints peak at 1.518 rad/s against their 1.5 limit (4 x 4:# 1.528, 1 x 2: 1.668) and the grey double pendulum follows a 16 x 32 run within 6 mm through its first second# (4 substeps: 10 mm, 1: 69 mm; past that the chaotic grey pendulum diverges at any step size). Its energy error# shrinks with the substep (1 substep gains 0.9 J of its 3.7 J swing in the first second, 4 gain 0.21 J, 6 gain 0.14 J).# Iterations only tighten the velocity limit; no joint has position limits, so they are off; no contacts, so the# immediate response (0.80 ms; 8 x 4 1.07 ms). The port's 4 x 12 colored: 2.00 ms.sim = { fps = 60, substeps = 6 }solver = { solve_mode = "matrix_free", iterations = 4, articulated_contact_response = "immediate", enable_joint_velocity_limits = true, enable_joint_limits = false }checked = "2026-11-10, newton f6fc82a8b, NVIDIA RTX PRO 6000 Blackwell Server Edition"
[kamino]status = "untested"
[implicit_mpm]status = "untested"
[style3d]status = "untested"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.