Here is a basic example of building a simulation using newton.
import matplotlib.pyplot as plt
import newton
import numpy as np
import warp as wp
from lwmr.utils import RECORDING_BASE_PATH, create_viewer_viser
from tqdm.auto import trange
# Tell warp to be quiet before initializing a model
wp.config.quiet = True
/Users/ajcd2020/Documents/Repositories/anthonyjclark/simer-tutorial/2026-icra/.venv/lib/python3.14/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
# Visualization timing
FRAME_STEP = 1.0 / 60.0
# Simulation timing relative to visualization
SIM_SUBSTEPS = 4
TIME_STEP = FRAME_STEP / SIM_SUBSTEPS
# Build a model
builder = newton.ModelBuilder()
body = builder.add_body()
builder.add_shape_box(body)
builder.add_ground_plane()
model = builder.finalize()
# Allocate state and create a solver
state_0 = model.state()
state_1 = model.state()
control = model.control()
contacts = model.contacts()
solver = newton.solvers.SolverMuJoCo(model)
# Step the simulation
for step in trange(1000 ):
state_0.clear_forces()
model.collide(state_0, contacts)
solver.step(state_0, state_1, control, contacts, TIME_STEP)
state_0, state_1 = state_1, state_0
0%| | 0/1000 [00:00<?, ?it/s]
0%| | 1/1000 [00:00<05:51, 2.85it/s]
6%|▌ | 62/1000 [00:00<00:05, 178.17it/s]
12%|█▎ | 125/1000 [00:00<00:02, 308.86it/s]
19%|█▉ | 188/1000 [00:00<00:02, 401.10it/s]
25%|██▌ | 251/1000 [00:00<00:01, 466.55it/s]
31%|███▏ | 313/1000 [00:00<00:01, 510.50it/s]
38%|███▊ | 376/1000 [00:00<00:01, 543.78it/s]
44%|████▍ | 438/1000 [00:01<00:00, 564.34it/s]
50%|████▉ | 499/1000 [00:01<00:00, 573.31it/s]
56%|█████▌ | 559/1000 [00:01<00:00, 579.49it/s]
62%|██████▏ | 620/1000 [00:01<00:00, 585.85it/s]
68%|██████▊ | 682/1000 [00:01<00:00, 594.42it/s]
74%|███████▍ | 744/1000 [00:01<00:00, 600.22it/s]
81%|████████ | 807/1000 [00:01<00:00, 606.67it/s]
87%|████████▋ | 870/1000 [00:01<00:00, 610.83it/s]
93%|█████████▎| 933/1000 [00:01<00:00, 613.84it/s]
100%|█████████▉| 995/1000 [00:01<00:00, 615.05it/s]
100%|██████████| 1000/1000 [00:01<00:00, 504.78it/s]
Visualization
We’ll use the built-in support for the viser visualizer in newton.
sim_time = 0.0
rec_path = str (RECORDING_BASE_PATH / "cube.viser" )
viewer = newton.viewer.ViewerViser(verbose= False , record_to_viser= rec_path)
viewer.set_model(model)
while sim_time < 4.0 :
viewer.begin_frame(sim_time)
viewer.log_state(state_0)
viewer.end_frame()
sim_time += FRAME_STEP
# NOTE : this does not work in VSCode
viewer.show_notebook()
╭────── viser (listening *:8080) ───────╮
│ ╷ │
│ HTTP │ http://localhost:8080 │
│ Websocket │ ws://localhost:8080 │
│ ╵ │
╰───────────────────────────────────────╯
Visualize a Spinning Cube
add_body() calls add_link(), add_joint_free(), and add_articulation()
builder = newton.ModelBuilder()
builder.add_ground_plane()
# Revolute body
xform = wp.transform(p= wp.vec3(0.0 , - 1.0 , 1.0 ))
body = builder.add_link()
joint = builder.add_joint_revolute(parent=- 1 , child= body, parent_xform= xform, axis= wp.vec3(0.0 , 0.0 , 1.0 ))
builder.add_articulation([joint])
builder.add_shape_box(body)
# Just a single DOF for a revolute joint
joint_index = builder.joint_q_start[joint]
joint_dim = builder.joint_dof_dim[joint_index]
assert joint_dim[0 ] == 0 and joint_dim[1 ] == 1
builder.joint_q[joint_index] = 0.5
joint_index = builder.joint_qd_start[joint]
joint_dim = builder.joint_dof_dim[joint_index]
assert joint_dim[0 ] == 0 and joint_dim[1 ] == 1
builder.joint_qd[joint_index] = 10.0
# Free body
xform = wp.transform(p= wp.vec3(0.0 , 1.0 , 1.0 ))
body = builder.add_body(xform= xform)
builder.add_shape_box(body)
joint_index = builder.joint_q_start[joint] + 1
joint_dim = builder.joint_dof_dim[joint_index]
assert joint_dim[0 ] == 3 and joint_dim[1 ] == 3
# builder.joint_q[joint_index + 2] = 0.5
joint_index = builder.joint_qd_start[joint] + 1
joint_dim = builder.joint_dof_dim[joint_index]
assert joint_dim[0 ] == 3 and joint_dim[1 ] == 3
builder.joint_qd[joint_index + 5 ] = 10.0
model = builder.finalize()
state_0 = model.state()
state_1 = model.state()
control = model.control()
contacts = model.contacts()
solver = newton.solvers.SolverMuJoCo(model)
sim_time = 0.0
viewer = create_viewer_viser("spinning_cube" , model, quiet= False , overwrite= False )
for step in trange(200 ):
for substep in range (SIM_SUBSTEPS):
state_0.clear_forces()
model.collide(state_0, contacts)
solver.step(state_0, state_1, control, contacts, TIME_STEP)
state_0, state_1 = state_1, state_0
viewer.begin_frame(sim_time)
viewer.log_state(state_0)
viewer.end_frame()
sim_time += FRAME_STEP
viewer.show_notebook()
Recording to docs/_static/spinning_cube.viser...
╭────── viser (listening *:8081) ───────╮
│ ╷ │
│ HTTP │ http://localhost:8081 │
│ Websocket │ ws://localhost:8081 │
│ ╵ │
╰───────────────────────────────────────╯
0%| | 0/200 [00:00<?, ?it/s]
0%| | 1/200 [00:00<00:23, 8.48it/s]
6%|▌ | 11/200 [00:00<00:03, 58.60it/s]
11%|█ | 22/200 [00:00<00:02, 78.04it/s]
16%|█▋ | 33/200 [00:00<00:01, 87.59it/s]
22%|██▏ | 44/200 [00:00<00:01, 92.95it/s]
28%|██▊ | 55/200 [00:00<00:01, 95.64it/s]
33%|███▎ | 66/200 [00:00<00:01, 97.78it/s]
38%|███▊ | 77/200 [00:00<00:01, 99.34it/s]
44%|████▍ | 88/200 [00:00<00:01, 100.34it/s]
50%|████▉ | 99/200 [00:01<00:01, 100.31it/s]
55%|█████▌ | 110/200 [00:01<00:00, 99.94it/s]
60%|██████ | 121/200 [00:01<00:00, 100.42it/s]
66%|██████▌ | 132/200 [00:01<00:00, 100.85it/s]
72%|███████▏ | 143/200 [00:01<00:00, 101.15it/s]
77%|███████▋ | 154/200 [00:01<00:00, 101.23it/s]
82%|████████▎ | 165/200 [00:01<00:00, 101.27it/s]
88%|████████▊ | 176/200 [00:01<00:00, 100.77it/s]
94%|█████████▎| 187/200 [00:01<00:00, 100.97it/s]
99%|█████████▉| 198/200 [00:02<00:00, 100.90it/s]
100%|██████████| 200/200 [00:02<00:00, 95.98it/s]
builder = newton.ModelBuilder()
builder.add_ground_plane()
# Revolute body
xform = wp.transform(p= wp.vec3(0.0 , - 1.0 , 1.0 ))
body = builder.add_link()
joint = builder.add_joint_revolute(parent=- 1 , child= body, parent_xform= xform, axis= wp.vec3(0.0 , 0.0 , 1.0 ))
builder.add_articulation([joint])
builder.add_shape_box(body)
# Free body
xform = wp.transform(p= wp.vec3(0.0 , 1.0 , 1.0 ))
body = builder.add_body(xform= xform, mass= 1.0 )
builder.add_shape_box(body)
model = builder.finalize()
state_0 = model.state()
state_1 = model.state()
control = model.control()
contacts = model.contacts()
solver = newton.solvers.SolverMuJoCo(model)
joint_forces = np.zeros(control.joint_f.shape, dtype= np.float32) # type: ignore
joint_index = builder.joint_qd_start[joint]
joint_forces[joint_index] = 100
joint_index = builder.joint_qd_start[joint] + 1
# joint_forces[joint_index + 0] = -10000.0
joint_forces[joint_index + 5 ] = - 5000.0
control.joint_f.assign(joint_forces) # type: ignore
sim_time = 0.0
# viewer = create_viewer("spinning_cube", model)
viewer = create_viewer_viser("spinning_cube" , model, quiet= False , overwrite= False )
for step in trange(200 ):
for substep in range (SIM_SUBSTEPS):
state_0.clear_forces()
model.collide(state_0, contacts)
solver.step(state_0, state_1, control, contacts, TIME_STEP)
state_0, state_1 = state_1, state_0
viewer.begin_frame(sim_time)
viewer.log_state(state_0)
viewer.end_frame()
sim_time += FRAME_STEP
viewer.show_notebook()
Recording to docs/_static/spinning_cube_01.viser...
╭────── viser (listening *:8083) ───────╮
│ ╷ │
│ HTTP │ http://localhost:8083 │
│ Websocket │ ws://localhost:8083 │
│ ╵ │
╰───────────────────────────────────────╯
0%| | 0/200 [00:00<?, ?it/s]
2%|▏ | 3/200 [00:00<00:06, 29.05it/s]
7%|▋ | 14/200 [00:00<00:02, 72.79it/s]
12%|█▎ | 25/200 [00:00<00:02, 85.61it/s]
18%|█▊ | 36/200 [00:00<00:01, 91.71it/s]
24%|██▎ | 47/200 [00:00<00:01, 94.90it/s]
29%|██▉ | 58/200 [00:00<00:01, 97.17it/s]
34%|███▍ | 69/200 [00:00<00:01, 99.00it/s]
40%|████ | 80/200 [00:00<00:01, 100.11it/s]
46%|████▌ | 91/200 [00:00<00:01, 100.99it/s]
51%|█████ | 102/200 [00:01<00:00, 100.60it/s]
56%|█████▋ | 113/200 [00:01<00:00, 100.43it/s]
62%|██████▏ | 124/200 [00:01<00:00, 100.91it/s]
68%|██████▊ | 135/200 [00:01<00:00, 101.38it/s]
73%|███████▎ | 146/200 [00:01<00:00, 101.66it/s]
78%|███████▊ | 157/200 [00:01<00:00, 101.88it/s]
84%|████████▍ | 168/200 [00:01<00:00, 101.87it/s]
90%|████████▉ | 179/200 [00:01<00:00, 101.33it/s]
95%|█████████▌| 190/200 [00:01<00:00, 101.70it/s]
100%|██████████| 200/200 [00:02<00:00, 97.73it/s]
builder.plot_articulation()
builder = newton.ModelBuilder()
builder.add_ground_plane()
# Revolute body
xform = wp.transform(p= wp.vec3(0.0 , - 1.0 , 1.0 ))
body = builder.add_link()
joint = builder.add_joint_revolute(
parent=- 1 ,
child= body,
parent_xform= xform,
axis= wp.vec3(0.0 , 0.0 , 1.0 ),
actuator_mode= newton.JointTargetMode.VELOCITY,
target_kd= 100 ,
)
builder.add_articulation([joint])
builder.add_shape_box(body)
model = builder.finalize()
state_0 = model.state()
state_1 = model.state()
control = model.control()
contacts = model.contacts()
solver = newton.solvers.SolverMuJoCo(model)
joint_target_vels = np.zeros(control.joint_target_vel.shape, dtype= np.float32) # type: ignore
joint_index = builder.joint_qd_start[joint]
joint_target_vels[joint_index] = 8.0
control.joint_target_vel.assign(joint_target_vels) # type: ignore
sim_time = 0.0
# viewer = create_viewer("spinning_cube", model)
viewer = create_viewer_viser("spinning_cube" , model, quiet= False , overwrite= False )
vels = []
for step in trange(400 ):
for substep in range (SIM_SUBSTEPS):
state_0.clear_forces()
model.collide(state_0, contacts)
solver.step(state_0, state_1, control, contacts, TIME_STEP)
state_0, state_1 = state_1, state_0
viewer.begin_frame(sim_time)
viewer.log_state(state_0)
viewer.end_frame()
vels.append(state_0.joint_qd.numpy().copy()) # type: ignore
sim_time += FRAME_STEP
viewer.show_notebook()
Recording to docs/_static/spinning_cube_02.viser...
╭────── viser (listening *:8084) ───────╮
│ ╷ │
│ HTTP │ http://localhost:8084 │
│ Websocket │ ws://localhost:8084 │
│ ╵ │
╰───────────────────────────────────────╯
0%| | 0/400 [00:00<?, ?it/s]
0%| | 1/400 [00:00<00:39, 9.98it/s]
4%|▍ | 15/400 [00:00<00:04, 84.82it/s]
7%|▋ | 29/400 [00:00<00:03, 108.60it/s]
11%|█ | 43/400 [00:00<00:02, 119.82it/s]
14%|█▍ | 57/400 [00:00<00:02, 125.95it/s]
18%|█▊ | 71/400 [00:00<00:02, 129.73it/s]
21%|██▏ | 85/400 [00:00<00:02, 131.87it/s]
25%|██▍ | 99/400 [00:00<00:02, 132.81it/s]
28%|██▊ | 113/400 [00:00<00:02, 133.80it/s]
32%|███▏ | 127/400 [00:01<00:02, 134.11it/s]
35%|███▌ | 141/400 [00:01<00:01, 134.68it/s]
39%|███▉ | 155/400 [00:01<00:01, 135.54it/s]
42%|████▏ | 169/400 [00:01<00:01, 135.91it/s]
46%|████▌ | 183/400 [00:01<00:01, 136.22it/s]
49%|████▉ | 197/400 [00:01<00:01, 136.56it/s]
53%|█████▎ | 211/400 [00:01<00:01, 137.08it/s]
56%|█████▋ | 225/400 [00:01<00:01, 136.84it/s]
60%|█████▉ | 239/400 [00:01<00:01, 136.97it/s]
63%|██████▎ | 253/400 [00:01<00:01, 136.27it/s]
67%|██████▋ | 267/400 [00:02<00:00, 135.90it/s]
70%|███████ | 281/400 [00:02<00:00, 135.62it/s]
74%|███████▍ | 295/400 [00:02<00:00, 136.04it/s]
77%|███████▋ | 309/400 [00:02<00:00, 136.63it/s]
81%|████████ | 323/400 [00:02<00:00, 136.80it/s]
84%|████████▍ | 337/400 [00:02<00:00, 136.95it/s]
88%|████████▊ | 351/400 [00:02<00:00, 137.20it/s]
91%|█████████▏| 365/400 [00:02<00:00, 136.73it/s]
95%|█████████▍| 379/400 [00:02<00:00, 136.95it/s]
98%|█████████▊| 393/400 [00:02<00:00, 136.47it/s]
100%|██████████| 400/400 [00:03<00:00, 132.30it/s]