This project is in active beta development. This means the API is unstable, features may be added or removed, and breaking changes are likely to occur frequently and without notice as the design is refined.
GPU-accelerated actuator library for physics simulations.
This library provides a collection of actuator implementations that integrate with physics simulation pipelines. Actuators read from simulation state arrays and write computed forces/torques back to control arrays.
pip install newton-actuatorsOr install from source:
cd newton-actuators
pip install -e .| Actuator | Description | Stateful | Transmission |
|---|---|---|---|
ActuatorPD |
Stateless PD controller | No | No |
ActuatorPID |
PID controller with integral term | Yes | No |
ActuatorDelayedPD |
PD controller with input delay | Yes | No |
- ActuatorPD:
τ = clamp(constant + act + Kp*e_pos + Kd*e_vel, ±max_force) - ActuatorPID:
τ = clamp(constant + act + Kp*e + Ki*∫e·dt + Kd*ė, ±max_force) - ActuatorDelayedPD: Same as PD but with delayed targets (circular buffer)
All actuators inherit from Actuator and provide these methods:
resolve_arguments(args) -> dict: (classmethod) Resolve user-provided arguments with defaultsis_stateful() -> bool: Returns True if the actuator maintains internal statehas_transmission() -> bool: Returns True if the actuator has a transmission phasestate() -> State | None: Returns a new state instance (None for stateless actuators)step(sim_state, sim_control, current_state, next_state, dt): Execute one control step
Stateful actuators use nested State classes:
ActuatorPID.State- Contains the integral term for PID controlActuatorDelayedPD.State- Contains circular buffers for delayed targets
- Create actuators with appropriate parameters
- Check statefulness: Call
actuator.is_stateful()to determine if state management is needed - Initialize states: For stateful actuators, create double-buffered states with
actuator.state() - Simulation loop: Call
actuator.step()to compute forces - Swap buffers: For stateful actuators, swap state buffers after each step
import warp as wp
from newton_actuators import ActuatorPD
# Create a PD actuator for 3 DOFs
indices = wp.array([0, 1, 2], dtype=wp.uint32)
pd_actuator = ActuatorPD(
input_indices=indices,
output_indices=indices,
kp=wp.array([100.0, 100.0, 100.0], dtype=wp.float32),
kd=wp.array([10.0, 10.0, 10.0], dtype=wp.float32),
max_force=wp.array([50.0, 50.0, 50.0], dtype=wp.float32),
constant_force=wp.array([0.0, 0.0, 0.0], dtype=wp.float32),
)
# In simulation loop - stateless actuators don't need state management
pd_actuator.step(sim_state, sim_control, None, None, dt=0.01)import warp as wp
from newton_actuators import ActuatorPID
indices = wp.array([0, 1], dtype=wp.uint32)
pid_actuator = ActuatorPID(
input_indices=indices,
output_indices=indices,
kp=wp.array([100.0, 100.0], dtype=wp.float32),
ki=wp.array([10.0, 10.0], dtype=wp.float32),
kd=wp.array([5.0, 5.0], dtype=wp.float32),
max_force=wp.array([50.0, 50.0], dtype=wp.float32),
integral_max=wp.array([10.0, 10.0], dtype=wp.float32),
constant_force=wp.array([0.0, 0.0], dtype=wp.float32),
)
# Check if actuator needs state management
if pid_actuator.is_stateful():
# Create double-buffered states
state_a = pid_actuator.state()
state_b = pid_actuator.state()
# Simulation loop with state swapping
current_state, next_state = state_a, state_b
for step in range(num_steps):
pid_actuator.step(sim_state, sim_control, current_state, next_state, dt=0.01)
current_state, next_state = next_state, current_state # Swap buffersThe library includes utilities for parsing actuator definitions from USD files:
from newton_actuators import parse_actuator_prim
# Parse a USD prim with actuator attributes
result = parse_actuator_prim(prim)
if result is not None:
actuator_class = result.actuator_class # e.g., ActuatorPD
target_paths = result.target_paths # e.g., ["/World/Robot/Joint1"]
kwargs = result.kwargs # e.g., {"kp": 100.0, "kd": 10.0}Apache-2.0