Skip to content

Newton Simulator

Fast, differentiable physics simulator with a new physics engine optimized for robot learning.

Overview

Newton features a new, purpose-built physics engine designed for machine learning with:

  • Blazing fast GPU-accelerated physics
  • Differentiable simulation
  • Simple API - minimal boilerplate
  • Massive parallelization (100,000+ envs)
  • PyTorch integration

Installation

pip install newton-sim

Quick Start

import newton
import torch

# Create environment
env = newton.make("FrankaReach-v0", num_envs=4096, device="cuda")

# Reset
obs = env.reset()

# Run
for _ in range(1000):
    actions = torch.randn(4096, env.action_dim, device="cuda")
    obs, rewards, dones, info = env.step(actions)

print(f"Steps per second: {env.fps}")

Built-in Environments

# Available environments
envs = newton.list_envs()

# Manipulation
env = newton.make("FrankaReach-v0")
env = newton.make("FrankaPickAndPlace-v0")

# Locomotion
env = newton.make("AntWalk-v0")
env = newton.make("HumanoidWalk-v0")

# Classic control
env = newton.make("Cartpole-v0")
env = newton.make("Pendulum-v0")

Custom Environments

import newton
from newton.envs import BaseEnv

class MyRobotEnv(BaseEnv):
    def __init__(self, num_envs=1024, device="cuda"):
        super().__init__(num_envs, device)

        # Define observation and action spaces
        self.obs_dim = 10
        self.action_dim = 4

        # Load robot
        self.robot = newton.load_urdf("robot.urdf", num_instances=num_envs)

    def reset(self):
        # Reset robot state
        self.robot.set_joint_positions(torch.zeros(self.num_envs, 7))
        return self.get_observations()

    def step(self, actions):
        # Apply actions
        self.robot.set_joint_torques(actions)

        # Step physics
        newton.step()

        # Compute rewards and observations
        obs = self.get_observations()
        rewards = self.compute_rewards()
        dones = self.check_termination()

        return obs, rewards, dones, {}

    def get_observations(self):
        return torch.cat([
            self.robot.get_joint_positions(),
            self.robot.get_joint_velocities()
        ], dim=-1)

    def compute_rewards(self):
        # Implement reward logic
        pass

Differentiable Simulation

import torch

# Create environment
env = newton.make("FrankaReach-v0", num_envs=1, device="cuda")

# Get initial state
state = env.reset()

# Optimize actions via gradient descent
actions = torch.randn(100, env.action_dim, device="cuda", requires_grad=True)
optimizer = torch.optim.Adam([actions], lr=0.01)

for iteration in range(100):
    state = env.reset()
    total_reward = 0

    for t in range(100):
        state, reward, done, info = env.step(actions[t])
        total_reward += reward

    # Backprop through entire trajectory
    loss = -total_reward
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    print(f"Iteration {iteration}: Reward = {total_reward.item()}")

Physics Configuration

env = newton.make(
    "FrankaReach-v0",
    num_envs=4096,
    physics_dt=1/120,        # Physics timestep
    control_dt=1/30,         # Control frequency
    gravity=[0, 0, -9.81],
    solver_iterations=4,     # Solver accuracy
    enable_ccd=True          # Continuous collision detection
)

Domain Randomization

class RandomizedEnv(newton.BaseEnv):
    def reset(self):
        # Randomize physics parameters
        self.robot.set_mass(
            torch.rand(self.num_envs, 1) * 2.0 + 1.0  # 1-3 kg
        )

        self.robot.set_friction(
            torch.rand(self.num_envs, 1) * 0.5 + 0.5  # 0.5-1.0
        )

        # Randomize initial state
        init_q = torch.randn(self.num_envs, 7) * 0.1
        self.robot.set_joint_positions(init_q)

        return self.get_observations()

Sensors

# Add camera
camera = newton.Camera(
    resolution=(640, 480),
    fov=60,
    position=[2, 0, 1],
    target=[0, 0, 0]
)

# Get RGB image
rgb = camera.get_image()  # (num_envs, 3, 480, 640)

# Get depth
depth = camera.get_depth()  # (num_envs, 1, 480, 640)

Performance Benchmarks

Environment Envs GPU Steps/sec
FrankaReach 4096 RTX 3090 50,000
FrankaReach 4096 A100 100,000
AntWalk 16384 A100 200,000

Integration with RL Libraries

Stable-Baselines3

import newton
from stable_baselines3 import PPO
from stable_baselines3.common.vec_env import DummyVecEnv

# Wrap Newton env for SB3
class NewtonEnvWrapper:
    def __init__(self, env_name, num_envs):
        self.env = newton.make(env_name, num_envs=num_envs)

    def reset(self):
        return self.env.reset().cpu().numpy()

    def step(self, actions):
        actions_tensor = torch.tensor(actions).to(self.env.device)
        obs, rewards, dones, info = self.env.step(actions_tensor)
        return obs.cpu().numpy(), rewards.cpu().numpy(), dones.cpu().numpy(), info

# Train
env = NewtonEnvWrapper("FrankaReach-v0", num_envs=4096)
model = PPO("MlpPolicy", env, verbose=1)
model.learn(total_timesteps=10_000_000)

Custom Training Loop

import torch

env = newton.make("FrankaReach-v0", num_envs=4096)
policy = PolicyNetwork()
optimizer = torch.optim.Adam(policy.parameters())

obs = env.reset()

for step in range(1_000_000):
    # Get actions
    actions = policy(obs)

    # Step environment
    next_obs, rewards, dones, info = env.step(actions)

    # Compute loss and update
    loss = compute_ppo_loss(obs, actions, rewards, next_obs, dones)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    # Reset done environments
    if dones.any():
        next_obs[dones] = env.reset_indexed(dones.nonzero())

    obs = next_obs

Advantages

Feature Newton IsaacLab IsaacSim
Setup Time 5 min 30 min 2 hours
Learning Curve Easy Medium Hard
Max Parallel Envs 100,000+ 10,000+ 1,000
Differentiable Yes No No
Graphics Basic Good Photorealistic

Use Cases

Best for:

  • Fast RL prototyping
  • Trajectory optimization
  • Model-based RL
  • Large-scale parallel training
  • Gradient-based planning

Not ideal for:

  • Photorealistic rendering
  • Complex sensor simulation
  • Digital twins
  • Visual perception research

Next Steps