Skip to content
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

Allow run/pause toggling from passive UI and handle, closes #2481 #2493

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jjyyxx
Copy link
Contributor

@jjyyxx jjyyxx commented Mar 11, 2025

Closes #2481.

The actual behavior of paused simulation in passive viewers is up to the user. To work as intended, the user should check handle.run to choose between mj_step and mj_forward:

import time
import mujoco, mujoco.viewer
model = mujoco.MjModel.from_xml_string("""
<mujoco>
    <worldbody>
        <body name="box" pos="0 0 0">
            <joint type="slide" axis="1 0 0"/>
            <geom type="box" size="1 1 1" rgba="1 0 0 1"/>
        </body>
        <body name="sphere" pos="3 0 0">
            <joint type="free"/>
            <geom type="sphere" size="1" rgba="0 1 0 1"/>
        </body>
    </worldbody>
</mujoco>
""")
data = mujoco.MjData(model)
handle = mujoco.viewer.launch_passive(model, data)
while handle.is_running():
    if handle.run:
        mujoco.mj_step(model, data)
    else:
        # Forward to reflect direct position perturb
        mujoco.mj_forward(model, data)
    handle.sync()
    time.sleep(0.001)

When the simulation is paused, the user can apply direct qpos manipulation and pose perturbation in the simulator.

Several concerns:

  1. The Handle class already has a method is_running to check if the simulation window is running or exited, while the simulator uses run=1/0 to indicate run/pause. The naming would potentially cause confusion.

  2. (Off-topic) The following line does not quite make sense to me (and opposite to several other cases above and below). Should !sim->is_passive_ be sim->is_passive_?

    if ((sim->m_ || !sim->is_passive_) && sim->ncam_) {

@yuvaltassa
Copy link
Collaborator

Thanks for this! We will check it soon.

@josechenf
Copy link

josechenf commented Mar 11, 2025

Hello!

I use the passive viewer from time to time, and I'm wondering if you can achieve the same with something like this (untested pseudo-code):

_IS_RUNNING = True
def _key_callback(key: int) -> None:
  global _IS_RUNNING
  if key == 32:  # Space bar
    _IS_RUNNING = not _IS_RUNNING
 
handle = mujoco.viewer.launch_passive(
      model,
      data,
      key_callback=_key_callback,
  )
while handle.is_running():
   with handle.lock()
      if _IS_RUNNING:
        mujoco.mj_step(model, data)
      else:
        # Forward to reflect direct position perturb
        mujoco.mj_forward(model, data)
      handle.sync()
   time.sleep(0.001)

The advantage of this is that you can also create much more complex behavior.

@jjyyxx
Copy link
Contributor Author

jjyyxx commented Mar 12, 2025

Sure, I also used to toggle run/pause like this. But this PR comes with further benefits:

  1. UI shows "PAUSE" banner properly
  2. Interactive manipulation of qpos and free pose

This feature does not contradict with "more complex behavior", since the run flag can be toggled from both UI side and program side. It just exposes a mechanism to pause in a more "standard" way than a _IS_RUNNING flag.

There are several other simulator features disabled in passive mode, like step forward/backward, and reload. These features suit well with the key_callback mechanism if needed.

@josechenf
Copy link

josechenf commented Mar 19, 2025

I am curious about what a user should do to visualize a trajectory of saved states without running mj_step. Is the user expected to set handle.run = False, and not press spacebar? EDIT: Sorry to be completely honest the viewer code still confuses me sometimes.

RE(2), this is currently possible by calling mjv_applyPerturbForce and mjv_applyPerturbPose.

@michael-lutz
Copy link

Seems like a pretty useful feature - been looking to pause and modify joint qpos.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enable pausing in passive viewer
4 participants