-
Notifications
You must be signed in to change notification settings - Fork 455
Add built-in simulation reset: Model.reset_state() + viewer R key #2468
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b4a0509
d7480db
14f3b01
d6c54f0
50afe72
896d803
7e9ec0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,6 +69,7 @@ newton | |
| eval_ik | ||
| eval_jacobian | ||
| eval_mass_matrix | ||
| reset_state | ||
|
|
||
| .. rubric:: Constants | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -849,6 +849,48 @@ def state(self, requires_grad: bool | None = None) -> State: | |
|
|
||
| return s | ||
|
|
||
| def reset_state(self, state: State, eval_fk: bool = True) -> None: | ||
| """ | ||
| Reset a :class:`State` to this model's initial configuration in-place. | ||
|
|
||
| Copies the model's initial position and velocity arrays into ``state`` | ||
| and zeroes all force arrays. Unlike :meth:`state`, this reuses the | ||
| existing GPU allocations -- no new arrays are created. | ||
|
|
||
| Args: | ||
| state: The state object to reset (must have been created by this model). | ||
| eval_fk: If True and the model has joints, re-evaluate forward | ||
| kinematics so that :attr:`State.body_q` and :attr:`State.body_qd` | ||
| are consistent with the restored joint coordinates. | ||
| """ | ||
| if self.particle_count: | ||
| wp.copy(state.particle_q, self.particle_q) | ||
| wp.copy(state.particle_qd, self.particle_qd) | ||
| state.particle_f.zero_() | ||
|
|
||
| if self.body_count: | ||
| wp.copy(state.body_q, self.body_q) | ||
| wp.copy(state.body_qd, self.body_qd) | ||
| state.body_f.zero_() | ||
| if getattr(state, "body_q_prev", None) is not None: | ||
| wp.copy(state.body_q_prev, self.body_q) | ||
| if getattr(state, "body_qdd", None) is not None: | ||
| state.body_qdd.zero_() | ||
| if getattr(state, "body_parent_f", None) is not None: | ||
| state.body_parent_f.zero_() | ||
|
|
||
| if self.joint_count: | ||
| wp.copy(state.joint_q, self.joint_q) | ||
| wp.copy(state.joint_qd, self.joint_qd) | ||
| mujoco_ns = getattr(state, "mujoco", None) | ||
| if mujoco_ns is not None and getattr(mujoco_ns, "qfrc_actuator", None) is not None: | ||
| mujoco_ns.qfrc_actuator.zero_() | ||
|
|
||
| if eval_fk and self.joint_count: | ||
| from .articulation import eval_fk as _eval_fk # noqa: PLC0415 | ||
|
|
||
| _eval_fk(self, self.joint_q, self.joint_qd, state) | ||
|
|
||
|
Comment on lines
+852
to
+893
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reset registered custom
🤖 Prompt for AI Agents |
||
| def control(self, requires_grad: bool | None = None, clone_variables: bool = True) -> Control: | ||
| """ | ||
| Create and return a new :class:`Control` object for this model. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -187,7 +187,6 @@ class _ExampleBrowser: | |
| def __init__(self, viewer): | ||
| self.viewer = viewer | ||
| self.switch_target: str | None = None | ||
| self._reset_requested = False | ||
| self.callback = None | ||
| self._tree: dict[str, list[tuple[str, str]]] = {} | ||
|
|
||
|
|
@@ -214,7 +213,7 @@ def _browser_ui(imgui): | |
| imgui.tree_pop() | ||
| imgui.separator() | ||
| if imgui.button("Reset"): | ||
| self._reset_requested = True | ||
| self.viewer.request_reset() | ||
|
|
||
| self.callback = _browser_ui | ||
| viewer.register_ui_callback(_browser_ui, position="panel") | ||
|
|
@@ -240,7 +239,6 @@ def switch(self, example_class): | |
|
|
||
| def reset(self, example_class): | ||
| """Reset the current example by re-creating it. Returns the new example or None.""" | ||
| self._reset_requested = False | ||
| self.viewer.clear_model() | ||
| try: | ||
| parser = getattr(example_class, "create_parser", create_parser)() | ||
|
|
@@ -279,8 +277,17 @@ def run(example, args): | |
| example, example_class = browser.switch(example_class) | ||
| continue | ||
|
|
||
| if browser is not None and browser._reset_requested: | ||
| example = browser.reset(example_class) | ||
| if viewer.is_reset_requested(): | ||
| viewer.clear_reset_request() | ||
| if hasattr(example, "reset"): | ||
| example.reset() | ||
| elif hasattr(example, "model"): | ||
| for attr in ("state_0", "state_1"): | ||
| s = getattr(example, attr, None) | ||
| if s is not None: | ||
| example.model.reset_state(s) | ||
| if hasattr(example, "sim_time"): | ||
| example.sim_time = 0.0 | ||
|
Comment on lines
+282
to
+290
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reset The generic reset only rewinds 💡 Minimal fix elif hasattr(example, "model"):
for attr in ("state_0", "state_1"):
s = getattr(example, attr, None)
if s is not None:
example.model.reset_state(s)
+ if getattr(example, "control", None) is not None:
+ example.control = example.model.control()
if hasattr(example, "sim_time"):
example.sim_time = 0.0🤖 Prompt for AI Agents |
||
| continue | ||
|
|
||
| if example is None: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: newton-physics/newton
Length of output: 504
🏁 Script executed:
Repository: newton-physics/newton
Length of output: 2281
🏁 Script executed:
Repository: newton-physics/newton
Length of output: 1430
Run
docs/generate_api.pyto include the newreset_stateexport in the API documentation.The symbol was added to the public API in
newton/__init__.pybut is missing from the generated API reference file (docs/api/newton.rst). Running the script will ensure the documentation stays in sync with the code.🤖 Prompt for AI Agents