Skip to content

Commit ce79c8c

Browse files
committed
rename dynamics to clamping
1 parent 1f91ff7 commit ce79c8c

14 files changed

Lines changed: 85 additions & 83 deletions

File tree

README.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,17 @@ An actuator is composed from three building blocks:
1717

1818
- **Controller** — computes raw forces from state error (PD, PID, neural network).
1919
- **Delay** — optional pre-controller modifier that delays targets by N timesteps.
20-
- **Dynamics** — post-controller modifiers that shape forces (clamping,
21-
saturation, angle-dependent limits, …).
20+
- **Clamping** — post-controller force bounds (symmetric limits,
21+
velocity-dependent saturation, angle-dependent torque curves, …).
22+
Order does not matter — each clamping intersects its limits independently.
2223

2324
The `Actuator` class wires them together:
2425

2526
```
2627
Actuator
2728
├── Controller (compute raw forces)
2829
├── Delay (optional: delays targets by N timesteps)
29-
└── Dynamics[] (post-controller force modifiers, applied in order)
30+
└── Clamping[] (post-controller force bounds)
3031
├── Clamp (±max_force)
3132
├── DCMotorSaturation (velocity-dependent saturation)
3233
└── RemotizedClamp (angle-dependent lookup)
@@ -79,7 +80,7 @@ pip install "newton-actuators[torch-cu13]" --extra-index-url https://download.py
7980

8081
- **PDController**: `f = constant + act + Kp·(target_pos - q) + Kd·(target_vel - v)`
8182
- **PIDController**: `f = constant + act + Kp·e + Ki·∫e·dt + Kd·de`
82-
- **NetMLPController**: `f = network(cat(pos_error_history, vel_history)) * torque_scale`
83+
- **NetMLPController**: `f = network(cat(pos_error_history, vel_history))`
8384
- **NetLSTMController**: `f, (h', c') = network(input, (h, c))`
8485

8586
### Delay
@@ -88,25 +89,25 @@ pip install "newton-actuators[torch-cu13]" --extra-index-url https://download.py
8889
|---|---|---|
8990
| `Delay` | Delays targets by N timesteps (circular buffer) | Yes |
9091

91-
Passed to `Actuator` via the `delay=` parameter (not in the dynamics list).
92+
Passed to `Actuator` via the `delay=` parameter (not in the clamping list).
9293

93-
### Dynamics
94+
### Clamping
9495

95-
| Dynamic | Description | Stateful |
96+
| Clamping | Description | Stateful |
9697
|---|---|---|
9798
| `Clamp` | Box-clamp to ±max_force | No |
9899
| `DCMotorSaturation` | Velocity-dependent torque–speed saturation | No |
99100
| `RemotizedClamp` | Angle-dependent torque limits via lookup table | No |
100101

101102
### Actuator (Composer)
102103

103-
`Actuator(input_indices, output_indices, controller, delay=None, dynamics=[...])`
104-
composes a controller with an optional delay and zero or more dynamics.
104+
`Actuator(input_indices, output_indices, controller, delay=None, clamping=[...])`
105+
composes a controller with an optional delay and zero or more clamping objects.
105106
The `step()` method runs:
106107

107108
1. **Delay** — read delayed targets from buffer (skipped if no delay or buffer still filling)
108109
2. **Controller** — compute raw forces
109-
3. **Dynamics**modify forces (e.g. `Clamp`, `DCMotorSaturation`)
110+
3. **Clamping**bound forces (e.g. `Clamp`, `DCMotorSaturation`)
110111
4. **Scatter-add** — accumulate forces into the output array
111112
5. **State updates** — update delay buffer and controller state
112113

@@ -120,7 +121,7 @@ The `step()` method runs:
120121

121122
## Workflow
122123

123-
1. **Create an actuator** by composing a controller with dynamics
124+
1. **Create an actuator** by composing a controller with clamping
124125
2. **Check statefulness**: call `actuator.is_stateful()`
125126
3. **Initialize states**: for stateful actuators, create double-buffered states with `actuator.state()`
126127
4. **Simulation loop**: call `actuator.step()` each timestep
@@ -143,7 +144,7 @@ actuator = Actuator(
143144
kp=wp.array([100.0, 100.0, 100.0], dtype=wp.float32),
144145
kd=wp.array([10.0, 10.0, 10.0], dtype=wp.float32),
145146
),
146-
dynamics=[
147+
clamping=[
147148
Clamp(max_force=wp.array([50.0, 50.0, 50.0], dtype=wp.float32)),
148149
],
149150
)
@@ -166,7 +167,7 @@ actuator = Actuator(
166167
kd=wp.array([5.0, 5.0], dtype=wp.float32),
167168
integral_max=wp.array([10.0, 10.0], dtype=wp.float32),
168169
),
169-
dynamics=[
170+
clamping=[
170171
Clamp(max_force=wp.array([50.0, 50.0], dtype=wp.float32)),
171172
],
172173
)
@@ -182,7 +183,7 @@ for step in range(num_steps):
182183

183184
### Composing: PD + Delay + DC Motor Saturation
184185

185-
The composer pattern lets you freely combine controllers and dynamics:
186+
The composer pattern lets you freely combine controllers and clamping:
186187

187188
```python
188189
from newton_actuators import Delay, DCMotorSaturation
@@ -192,7 +193,7 @@ actuator = Actuator(
192193
output_indices=indices,
193194
controller=PDController(kp=kp, kd=kd),
194195
delay=Delay(delay=5),
195-
dynamics=[
196+
clamping=[
196197
DCMotorSaturation(
197198
saturation_effort=sat_effort,
198199
velocity_limit=vel_limit,
@@ -211,7 +212,7 @@ actuator = Actuator(
211212
input_indices=indices,
212213
output_indices=indices,
213214
controller=NetLSTMController(network=my_lstm_model),
214-
dynamics=[Clamp(max_force=max_force)],
215+
clamping=[Clamp(max_force=max_force)],
215216
)
216217

217218
state = actuator.state()

newton_actuators/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
PIDController,
1313
)
1414
from ._src.delay import Delay
15-
from ._src.dynamics import (
15+
from ._src.clamping import (
1616
Clamp,
1717
DCMotorSaturation,
18-
Dynamic,
18+
Clamping,
1919
RemotizedClamp,
2020
)
2121
from ._src.usd_parser import (
@@ -35,8 +35,8 @@
3535
"PIDController",
3636
"NetMLPController",
3737
"NetLSTMController",
38-
# Dynamics
39-
"Dynamic",
38+
# Clamping
39+
"Clamping",
4040
"Clamp",
4141
"DCMotorSaturation",
4242
"Delay",

newton_actuators/_src/actuator.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from .controllers.base import Controller
1313
from .delay import Delay
14-
from .dynamics.base import Dynamic
14+
from .clamping.base import Clamping
1515

1616

1717
# TODO: replace with a Transmission class that applies gear ratios / linkage
@@ -33,7 +33,7 @@ class ActuatorState:
3333
"""Composed state for an Actuator.
3434
3535
Holds the controller state and, if a delay is present, the delay
36-
state. Dynamics are stateless.
36+
state. Clamping objects are stateless.
3737
"""
3838

3939
controller_state: Any = None
@@ -47,15 +47,15 @@ def reset(self) -> None:
4747

4848

4949
class Actuator:
50-
"""Composed actuator: controller + optional delay + dynamics.
50+
"""Composed actuator: controller + optional delay + clamping.
5151
5252
An actuator reads from simulation state/control arrays, computes
53-
forces via a controller, applies dynamics (clamping, saturation, etc.),
53+
forces via a controller, applies clamping (force limits, saturation, etc.),
5454
and writes the result to the output array.
5555
56-
Delay is handled separately from dynamics because it is the only
56+
Delay is handled separately from clamping because it is the only
5757
pre-controller modifier (it replaces targets with delayed versions).
58-
All dynamics are post-controller (they modify forces).
58+
All clamping is post-controller (it bounds forces).
5959
6060
Usage::
6161
@@ -64,7 +64,7 @@ class Actuator:
6464
output_indices=indices,
6565
controller=PDController(kp=kp, kd=kd),
6666
delay=Delay(delay=5),
67-
dynamics=[Clamp(max_force=max_f)],
67+
clamping=[Clamp(max_force=max_f)],
6868
)
6969
7070
# Simulation loop
@@ -77,7 +77,7 @@ class Actuator:
7777
for single-output or (N, M) for multi-output actuators.
7878
controller: Controller that computes raw forces.
7979
delay: Optional Delay instance for input delay.
80-
dynamics: List of Dynamic objects (post-controller force modifiers).
80+
clamping: List of Clamping objects (post-controller force bounds).
8181
state_pos_attr: Attribute on sim_state for positions.
8282
state_vel_attr: Attribute on sim_state for velocities.
8383
control_target_pos_attr: Attribute on sim_control for target positions.
@@ -92,7 +92,7 @@ def __init__(
9292
output_indices: wp.array,
9393
controller: Controller,
9494
delay: Delay | None = None,
95-
dynamics: list[Dynamic] | None = None,
95+
clamping: list[Clamping] | None = None,
9696
state_pos_attr: str = "joint_q",
9797
state_vel_attr: str = "joint_qd",
9898
control_target_pos_attr: str = "joint_target_pos",
@@ -104,7 +104,7 @@ def __init__(
104104
self.output_indices = output_indices
105105
self.controller = controller
106106
self.delay = delay
107-
self.dynamics = dynamics or []
107+
self.clamping = clamping or []
108108
self.num_actuators = len(input_indices)
109109

110110
if len(output_indices) != self.num_actuators:
@@ -128,8 +128,8 @@ def __init__(
128128

129129
controller.set_device(device)
130130
controller.set_indices(input_indices, self._sequential_indices)
131-
for dyn in self.dynamics:
132-
dyn.set_device(device)
131+
for clamp in self.clamping:
132+
clamp.set_device(device)
133133
if self.delay is not None:
134134
self.delay.set_indices(self.num_actuators, self._sequential_indices)
135135

@@ -139,8 +139,8 @@ def SHARED_PARAMS(self) -> set[str]:
139139
params |= self.controller.SHARED_PARAMS
140140
if self.delay is not None:
141141
params |= self.delay.SHARED_PARAMS
142-
for d in self.dynamics:
143-
params |= d.SHARED_PARAMS
142+
for c in self.clamping:
143+
params |= c.SHARED_PARAMS
144144
return params
145145

146146
def is_stateful(self) -> bool:
@@ -149,7 +149,7 @@ def is_stateful(self) -> bool:
149149

150150
def is_graphable(self) -> bool:
151151
"""Return True if all components can be captured in a CUDA graph."""
152-
return self.controller.is_graphable() and all(d.is_graphable() for d in self.dynamics)
152+
return self.controller.is_graphable() and all(c.is_graphable() for c in self.clamping)
153153

154154
def has_transmission(self) -> bool:
155155
"""Return True if this actuator applies a transmission transform."""
@@ -185,7 +185,7 @@ def step(
185185
186186
1. **Delay** — read delayed targets from buffer.
187187
2. **Controller** — compute raw forces.
188-
3. **Dynamics** — modify forces and scatter-add to output.
188+
3. **Clamping** — bound forces and scatter-add to output.
189189
4. **State updates** — update delay buffer and controller state.
190190
191191
If the delay buffer is still filling, steps 2-3 are skipped
@@ -244,9 +244,9 @@ def step(
244244
dt,
245245
)
246246

247-
# --- 3. Dynamics: modify forces + write output ---
248-
for dyn in self.dynamics:
249-
dyn.modify_forces(
247+
# --- 3. Clamping: bound forces + write output ---
248+
for clamp in self.clamping:
249+
clamp.modify_forces(
250250
self._forces, positions, velocities,
251251
self.input_indices, self.num_actuators,
252252
)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# SPDX-FileCopyrightText: Copyright (c) 2025 The Newton Developers
22
# SPDX-License-Identifier: Apache-2.0
33

4-
from .base import Dynamic
4+
from .base import Clamping
55
from .clamp import Clamp
66
from .dc_motor_saturation import DCMotorSaturation
77
from .remotized_clamp import RemotizedClamp
88

99
__all__ = [
1010
"Clamp",
1111
"DCMotorSaturation",
12-
"Dynamic",
12+
"Clamping",
1313
"RemotizedClamp",
1414
]
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
import warp as wp
77

88

9-
class Dynamic:
10-
"""Base class for post-controller dynamics that modify forces.
9+
class Clamping:
10+
"""Base class for post-controller force clamping.
1111
12-
Dynamics are stacked on top of a controller to add behaviors such as
13-
clamping or velocity-dependent saturation. They modify forces in-place
12+
Clamping objects are stacked on top of a controller to bound
13+
output forces — symmetric limits, velocity-dependent saturation,
14+
angle-dependent torque curves, etc. They modify forces in-place
1415
after the controller has computed them.
1516
1617
For input delay, use the ``Delay`` class (passed separately to the
17-
Actuator, not as a Dynamic).
18+
Actuator, not as a Clamping).
1819
1920
Class Attributes:
2021
SHARED_PARAMS: Parameter names that are instance-level (shared across
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import warp as wp
88

9-
from .base import Dynamic
9+
from .base import Clamping
1010

1111

1212
@wp.kernel
@@ -19,7 +19,7 @@ def _box_clamp_kernel(
1919
forces[i] = wp.clamp(forces[i], -max_force[i], max_force[i])
2020

2121

22-
class Clamp(Dynamic):
22+
class Clamp(Clamping):
2323
"""Box-clamp dynamic.
2424
2525
Clamps controller output forces to ±max_force per actuator.

newton_actuators/_src/dynamics/dc_motor_saturation.py renamed to newton_actuators/_src/clamping/dc_motor_saturation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import warp as wp
88

9-
from .base import Dynamic
9+
from .base import Clamping
1010

1111

1212
@wp.kernel
@@ -35,7 +35,7 @@ def _dc_motor_clamp_kernel(
3535
forces[i] = wp.clamp(forces[i], min_torque, max_torque)
3636

3737

38-
class DCMotorSaturation(Dynamic):
38+
class DCMotorSaturation(Clamping):
3939
"""DC motor velocity-dependent torque saturation.
4040
4141
Clips controller output using the torque–speed characteristic:

newton_actuators/_src/dynamics/remotized_clamp.py renamed to newton_actuators/_src/clamping/remotized_clamp.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import numpy as np
77
import warp as wp
88

9-
from .base import Dynamic
9+
from .base import Clamping
1010

1111

1212
@wp.func
@@ -49,7 +49,7 @@ def _remotized_clamp_kernel(
4949
forces[i] = wp.clamp(forces[i], -limit, limit)
5050

5151

52-
class RemotizedClamp(Dynamic):
52+
class RemotizedClamp(Clamping):
5353
"""Angle-dependent torque clamping via lookup table.
5454
5555
Replaces a fixed ±max_force box clamp with angle-dependent torque

newton_actuators/_src/controllers/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class Controller:
1212
Controllers are the core computation component in an actuator. They read
1313
positions, velocities, and targets, then write raw (unclamped) forces to
1414
a scratch buffer. Clamping and other post-processing is handled by
15-
Dynamic objects composed on top.
15+
Clamping objects composed on top.
1616
1717
Subclasses must override ``compute`` and ``resolve_arguments``.
1818

newton_actuators/_src/controllers/net_lstm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class NetLSTMController(Controller):
1414
1515
Uses a pre-trained LSTM network to compute joint torques from position
1616
error and velocity. The network maintains hidden and cell state across
17-
timesteps to capture temporal dynamics.
17+
timesteps to capture temporal patterns.
1818
1919
The network must be callable as:
2020
torques, (h_new, c_new) = network(input, (h, c))

0 commit comments

Comments
 (0)