Skip to content

Robot ur10

Articulations

A UR10 arm from USD under a joint-space controller.

0.00 s
The steel preset (the default), recordedon an NVIDIA RTX PRO 6000 Blackwell.

Run it

Terminal window
cd examples
# the default preset (steel), then the others
uv run shelf play robot_ur10
uv run shelf play robot_ur10 --solver mujoco
uv run shelf play robot_ur10 --solver kamino
# change solver settings live
uv run shelf tune robot_ur10

Source: examples/shelf/07_articulations/robot_ur10/ · ported from newton/examples/robot/example_robot_ur10.py @ skild-ai/newton 7565a26b1

Presets

PresetSolverStatusChecked
mujocomujocoworks2026-10-28, newton 7565a26b1, NVIDIA RTX A6000
kaminokaminoworks2026-10-28, newton 7565a26b1, NVIDIA RTX A6000

Solvers with no row are untested on this example. The full settings are inpresets.toml.

Code

examples/shelf/07_articulations/robot_ur10/example.py
# SPDX-FileCopyrightText: Copyright (c) 2025 The Newton Developers
# SPDX-License-Identifier: Apache-2.0
# Modified for Steel Shelf: preset-driven execution and shared runner integration.
###########################################################################
# Example Robot UR10
#
# Shows how to set up a simulation of a UR10 robot arm
# from a USD file using newton.ModelBuilder.add_usd() and
# applies a sinusoidal trajectory to the joint targets.
#
# Command: python -m shelf run robot_ur10 --world-count 16
# python -m shelf run robot_ur10 --solver kamino
#
###########################################################################
import numpy as np
import warp as wp
import newton
import newton.examples
import newton.utils
from newton import JointTargetMode
from newton.selection import ArticulationView
from common import presets
@wp.kernel
def update_joint_target_trajectory_kernel(
joint_target_trajectory: wp.array3d[wp.float32],
time: wp.array[wp.float32],
dt: wp.float32,
# output
joint_target: wp.array3d[wp.float32],
):
world_idx = wp.tid()
t = time[world_idx]
t = wp.mod(t + dt, float(joint_target_trajectory.shape[0] - 1))
step = int(t)
time[world_idx] = t
num_dofs = joint_target.shape[2]
for dof in range(num_dofs):
# add world_idx here to make the sequence of dofs different for each world
di = (dof + world_idx) % num_dofs
joint_target[world_idx, 0, dof] = wp.lerp(
joint_target_trajectory[step, world_idx, di],
joint_target_trajectory[step + 1, world_idx, di],
wp.frac(t),
)
class Example:
def __init__(self, viewer, args):
self.preset = presets.load(__file__)
newton.use_coord_layout_targets = True
self.fps = self.preset.fps
self.frame_dt = 1.0 / self.fps
self.sim_time = 0.0
self.sim_substeps = self.preset.substeps
self.sim_dt = self.frame_dt / self.sim_substeps
self.solver_type = self.preset.name
self.world_count = args.world_count
if self.world_count is None:
self.world_count = 4 if self.solver_type == "kamino" else 100
self.viewer = viewer
self.device = wp.get_device()
ur10 = newton.ModelBuilder()
if self.solver_type == "kamino":
newton.solvers.SolverKamino.register_custom_attributes(ur10)
else:
newton.solvers.SolverMuJoCo.register_custom_attributes(ur10)
asset_path = newton.utils.download_asset("universal_robots_ur10")
asset_file = str(asset_path / "usd" / "ur10_instanceable.usda")
height = 1.2
ur10.add_usd(
asset_file,
xform=wp.transform(wp.vec3(0.0, 0.0, height)),
collapse_fixed_joints=False,
enable_self_collisions=False,
hide_collision_shapes=True,
)
# create a pedestal
ur10.add_shape_cylinder(-1, xform=wp.transform(wp.vec3(0, 0, height / 2)), half_height=height / 2, radius=0.08)
for i in range(len(ur10.joint_target_ke)):
ur10.joint_target_ke[i] = 500
ur10.joint_target_kd[i] = 50
ur10.joint_target_mode[i] = int(JointTargetMode.POSITION)
builder = newton.ModelBuilder()
builder.replicate(ur10, self.world_count, spacing=(2, 2, 0))
# set random joint configurations
rng = np.random.default_rng(42)
joint_q = rng.uniform(-wp.pi, wp.pi, builder.joint_dof_count)
builder.joint_q = joint_q.tolist()
builder.add_ground_plane()
self.model = builder.finalize()
self.state_0 = self.model.state()
self.state_1 = self.model.state()
self.control = self.model.control()
self.contacts = None
newton.eval_fk(self.model, self.model.joint_q, self.model.joint_qd, self.state_0)
self.articulation_view = ArticulationView(
self.model, "*ur10*", exclude_joint_types=[newton.JointType.FREE, newton.JointType.DISTANCE]
)
assert self.articulation_view.count == self.world_count, (
"Number of worlds must match the number of articulations"
)
dof_count = self.articulation_view.joint_dof_count
joint_target_trajectory = np.zeros((0, self.world_count, dof_count), dtype=np.float32)
self.control_speed = 50.0
dof_lower = self.articulation_view.get_attribute("joint_limit_lower", self.model)[0, 0].numpy()
dof_upper = self.articulation_view.get_attribute("joint_limit_upper", self.model)[0, 0].numpy()
joint_q = self.articulation_view.get_attribute("joint_q", self.state_0).numpy().squeeze(axis=1)
for i in range(dof_count):
# generate sinusoidal control signal for this dof
lower = dof_lower[i]
upper = dof_upper[i]
if not np.isfinite(lower) or abs(lower) > 6.0:
# no limits; assume the joint dof is angular
lower = -wp.pi
upper = wp.pi
# first determine the phase shift such that the signal starts at the dof's initial joint_q
limit_range = upper - lower
normalized = (joint_q[:, i] - lower) / limit_range * 2.0 - 1.0
phase_shift = np.zeros(self.articulation_view.count)
mask = abs(normalized) < 1.0
phase_shift[mask] = np.arcsin(normalized[mask])
traj = np.sin(np.linspace(phase_shift, 2 * np.pi + phase_shift, int(limit_range * 50)))
traj = traj * (upper - lower) * 0.5 + 0.5 * (upper + lower)
target_trajectory = np.tile(joint_q, (len(traj), 1, 1))
target_trajectory[:, :, i] = traj
joint_target_trajectory = np.concatenate((joint_target_trajectory, target_trajectory), axis=0)
self.joint_target_trajectory = wp.array(joint_target_trajectory, dtype=wp.float32, device=self.device)
self.time_step = wp.zeros(self.world_count, dtype=wp.float32, device=self.device)
self.ctrl = self.articulation_view.get_attribute("joint_target_q", self.control)
self.solver = self.preset.make_solver(self.model)
self.viewer.set_model(self.model)
self.capture()
def capture(self):
self.graph = None
with wp.ScopedCapture() as capture:
self.simulate()
self.graph = capture.graph
def simulate(self):
for substep in range(self.sim_substeps):
self.state_0.clear_forces()
# apply forces to the model for picking, wind, etc
self.viewer.apply_forces(self.state_0)
wp.launch(
update_joint_target_trajectory_kernel,
dim=self.world_count,
inputs=[self.joint_target_trajectory, self.time_step, self.sim_dt * self.control_speed],
outputs=[self.ctrl],
device=self.device,
)
self.articulation_view.set_attribute("joint_target_q", self.control, self.ctrl)
self.solver.step(self.state_0, self.state_1, self.control, self.contacts, self.sim_dt)
# swap states
if self.sim_substeps % 2 == 1 and substep == self.sim_substeps - 1:
# an odd count under graph capture: copy the last result into state_0 instead of swapping,
# so every replay of the captured graph starts from the newest state
self.state_0.assign(self.state_1)
else:
self.state_0, self.state_1 = self.state_1, self.state_0
def step(self):
if self.graph:
wp.capture_launch(self.graph)
else:
self.simulate()
self.sim_time += self.frame_dt
def render(self):
self.viewer.begin_frame(self.sim_time)
self.viewer.log_state(self.state_0)
self.viewer.end_frame()
def test_final(self):
"""Verify the robot joint state remains finite while tracking targets."""
joint_q = self.state_0.joint_q.numpy()
if not np.isfinite(joint_q).all():
raise ValueError("UR10 joint positions contain non-finite values")
@staticmethod
def create_parser():
parser = newton.examples.create_parser()
newton.examples.add_world_count_arg(parser)
parser.set_defaults(world_count=None)
return parser
if __name__ == "__main__":
parser = Example.create_parser()
viewer, args = newton.examples.init(parser)
newton.examples.run(Example(viewer, args), args)