Add show_{left,right}_ui kwarg to viewer.launch(_passive).
Fixes #857 PiperOrigin-RevId: 572333909 Change-Id: I12247fe856afddf808eb8f386a594acac47c34b5
This commit is contained in:
committed by
Copybara-Service
parent
2e15574b58
commit
a1d0cbd654
+7
-4
@@ -133,6 +133,8 @@ Python bindings
|
|||||||
camera name used the default camera.
|
camera name used the default camera.
|
||||||
24. Added ``user_scn`` to the :ref:`passive viewer<PyViewerPassive>` handle, which allows users to add custom
|
24. Added ``user_scn`` to the :ref:`passive viewer<PyViewerPassive>` handle, which allows users to add custom
|
||||||
visualization geoms (`#1023 <https://github.com/google-deepmind/mujoco/issues/870>`__).
|
visualization geoms (`#1023 <https://github.com/google-deepmind/mujoco/issues/870>`__).
|
||||||
|
25. Added optional boolean keyword arguments ``show_left_ui`` and ``show_right_ui`` to the functions ``viewer.launch``
|
||||||
|
and ``viewer.launch_passive``, which allow users to launch a viewer with UI panels hidden.
|
||||||
|
|
||||||
Simulate
|
Simulate
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
@@ -141,21 +143,22 @@ Simulate
|
|||||||
:align: right
|
:align: right
|
||||||
:width: 240px
|
:width: 240px
|
||||||
|
|
||||||
25. Added **state history** mechanism to :ref:`simulate<saSimulate>` and the managed
|
26. Added **state history** mechanism to :ref:`simulate<saSimulate>` and the managed
|
||||||
:ref:`Python viewer<PyViewerManaged>`. State history can be viewed by scrubbing the History slider and (more
|
:ref:`Python viewer<PyViewerManaged>`. State history can be viewed by scrubbing the History slider and (more
|
||||||
precisely) with the left and right arrow keys. See screen capture:
|
precisely) with the left and right arrow keys. See screen capture:
|
||||||
|
|
||||||
26. The ``LOADING...`` label is now shown correctly.
|
27. The ``LOADING...`` label is now shown correctly.
|
||||||
`Contribution <https://github.com/google-deepmind/mujoco/pull/1070>`__ by
|
`Contribution <https://github.com/google-deepmind/mujoco/pull/1070>`__ by
|
||||||
`Levi Burner <https://github.com/aftersomemath>`__.
|
`Levi Burner <https://github.com/aftersomemath>`__.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
|
|
||||||
27. Fixed a bug that was causing :ref:`geom margin<body-geom-margin>` to be ignored during the construction of
|
28. Fixed a bug that was causing :ref:`geom margin<body-geom-margin>` to be ignored during the construction of
|
||||||
midphase collision trees.
|
midphase collision trees.
|
||||||
|
|
||||||
27. Fixed a bug that was generating incorrect values in ``efc_diagApprox`` for weld equality constraints.
|
29. Fixed a bug that was generating incorrect values in ``efc_diagApprox`` for weld equality constraints.
|
||||||
|
|
||||||
|
|
||||||
Version 2.3.7 (July 20, 2023)
|
Version 2.3.7 (July 20, 2023)
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|||||||
+22
-17
@@ -191,28 +191,33 @@ illustrative example that does **not** necessarily keep the physics ticking at t
|
|||||||
if time_until_next_step > 0:
|
if time_until_next_step > 0:
|
||||||
time.sleep(time_until_next_step)
|
time.sleep(time_until_next_step)
|
||||||
|
|
||||||
Optionally, ``viewer.launch_passive`` also accepts a callable as a keyword argument ``key_callback``, which gets called
|
Optionally, ``viewer.launch_passive`` accepts the following keyword arguments.
|
||||||
each time a keyboard event occurs in the viewer window. This allows user scripts to react to various key presses, e.g.,
|
|
||||||
pause or resume the run loop when the spacebar is pressed.
|
|
||||||
|
|
||||||
.. code-block:: python
|
- ``key_callback``: A callable which gets called each time a keyboard event occurs in the viewer window. This allows
|
||||||
|
user scripts to react to various key presses, e.g., pause or resume the run loop when the spacebar is pressed.
|
||||||
|
|
||||||
paused = False
|
.. code-block:: python
|
||||||
|
|
||||||
def key_callback(keycode):
|
paused = False
|
||||||
if chr(keycode) == ' ':
|
|
||||||
nonlocal paused
|
|
||||||
paused = not paused
|
|
||||||
|
|
||||||
...
|
def key_callback(keycode):
|
||||||
|
if chr(keycode) == ' ':
|
||||||
|
nonlocal paused
|
||||||
|
paused = not paused
|
||||||
|
|
||||||
with mujoco.viewer.launch_passive(m, d, key_callback=key_callback) as viewer:
|
...
|
||||||
while viewer.is_running():
|
|
||||||
...
|
with mujoco.viewer.launch_passive(m, d, key_callback=key_callback) as viewer:
|
||||||
if not paused:
|
while viewer.is_running():
|
||||||
mujoco.mj_step(m, d)
|
...
|
||||||
viewer.sync()
|
if not paused:
|
||||||
...
|
mujoco.mj_step(m, d)
|
||||||
|
viewer.sync()
|
||||||
|
...
|
||||||
|
|
||||||
|
- ``show_left_ui_panel`` and ``show_right_ui_panel``: Boolean arguments indicating whether UI panels should be visible
|
||||||
|
or hidden when the viewer is launched. Note that regardless of the values specified, the user can still toggle the
|
||||||
|
visibility of these panels after launch by pressing Tab or Shift+Tab.
|
||||||
|
|
||||||
.. _PyUsage:
|
.. _PyUsage:
|
||||||
|
|
||||||
|
|||||||
@@ -294,11 +294,17 @@ while True:
|
|||||||
break
|
break
|
||||||
|
|
||||||
# Otherwise, launch the viewer.
|
# Otherwise, launch the viewer.
|
||||||
model, data, handle_return, key_callback = task
|
model, data, handle_return, key_callback, show_left_ui, show_right_ui = task
|
||||||
ctypes.CDLL(None).mjpython_show_dock_icon()
|
ctypes.CDLL(None).mjpython_show_dock_icon()
|
||||||
mujoco.viewer._launch_internal(
|
mujoco.viewer._launch_internal(
|
||||||
model, data, run_physics_thread=False, handle_return=handle_return,
|
model,
|
||||||
key_callback=key_callback)
|
data,
|
||||||
|
run_physics_thread=False,
|
||||||
|
handle_return=handle_return,
|
||||||
|
key_callback=key_callback,
|
||||||
|
show_left_ui=show_left_ui,
|
||||||
|
show_right_ui=show_right_ui,
|
||||||
|
)
|
||||||
ctypes.CDLL(None).mjpython_hide_dock_icon()
|
ctypes.CDLL(None).mjpython_hide_dock_icon()
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@@ -314,7 +314,17 @@ PYBIND11_MODULE(_simulate, pymodule) {
|
|||||||
const auto max_length = sizeof_arr(sim.load_error);
|
const auto max_length = sizeof_arr(sim.load_error);
|
||||||
std::strncpy(sim.load_error, error.c_str(), max_length - 1);
|
std::strncpy(sim.load_error, error.c_str(), max_length - 1);
|
||||||
sim.load_error[max_length - 1] = '\0';
|
sim.load_error[max_length - 1] = '\0';
|
||||||
}));
|
}))
|
||||||
|
.def_property("ui0_enable", GetIfNotNull(&mujoco::Simulate::ui0_enable),
|
||||||
|
CallIfNotNull(+[](mujoco::Simulate& sim, int enabled) {
|
||||||
|
sim.ui0_enable = enabled;
|
||||||
|
}),
|
||||||
|
py::call_guard<py::gil_scoped_release>())
|
||||||
|
.def_property("ui1_enable", GetIfNotNull(&mujoco::Simulate::ui1_enable),
|
||||||
|
CallIfNotNull(+[](mujoco::Simulate& sim, int enabled) {
|
||||||
|
sim.ui1_enable = enabled;
|
||||||
|
}),
|
||||||
|
py::call_guard<py::gil_scoped_release>());
|
||||||
|
|
||||||
pymodule.def("set_glfw_dlhandle", [](std::uintptr_t dlhandle) {
|
pymodule.def("set_glfw_dlhandle", [](std::uintptr_t dlhandle) {
|
||||||
mujoco::Glfw(reinterpret_cast<void*>(dlhandle));
|
mujoco::Glfw(reinterpret_cast<void*>(dlhandle));
|
||||||
|
|||||||
+32
-6
@@ -319,6 +319,8 @@ def _launch_internal(
|
|||||||
loader: Optional[_InternalLoaderType] = None,
|
loader: Optional[_InternalLoaderType] = None,
|
||||||
handle_return: Optional['queue.Queue[Handle]'] = None,
|
handle_return: Optional['queue.Queue[Handle]'] = None,
|
||||||
key_callback: Optional[KeyCallbackType] = None,
|
key_callback: Optional[KeyCallbackType] = None,
|
||||||
|
show_left_ui: bool = True,
|
||||||
|
show_right_ui: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Internal API, so that the public API has more readable type annotations."""
|
"""Internal API, so that the public API has more readable type annotations."""
|
||||||
if model is None and data is not None:
|
if model is None and data is not None:
|
||||||
@@ -351,6 +353,9 @@ def _launch_internal(
|
|||||||
cam, opt, pert, user_scn, run_physics_thread, key_callback
|
cam, opt, pert, user_scn, run_physics_thread, key_callback
|
||||||
)
|
)
|
||||||
|
|
||||||
|
simulate.ui0_enable = show_left_ui
|
||||||
|
simulate.ui1_enable = show_right_ui
|
||||||
|
|
||||||
# Initialize GLFW if not using mjpython.
|
# Initialize GLFW if not using mjpython.
|
||||||
if _MJPYTHON is None:
|
if _MJPYTHON is None:
|
||||||
if not glfw.init():
|
if not glfw.init():
|
||||||
@@ -385,13 +390,23 @@ def _launch_internal(
|
|||||||
simulate.destroy()
|
simulate.destroy()
|
||||||
|
|
||||||
|
|
||||||
def launch(model: Optional[mujoco.MjModel] = None,
|
def launch(
|
||||||
data: Optional[mujoco.MjData] = None,
|
model: Optional[mujoco.MjModel] = None,
|
||||||
*,
|
data: Optional[mujoco.MjData] = None,
|
||||||
loader: Optional[LoaderType] = None) -> None:
|
*,
|
||||||
|
loader: Optional[LoaderType] = None,
|
||||||
|
show_left_ui: bool = True,
|
||||||
|
show_right_ui: bool = True,
|
||||||
|
) -> None:
|
||||||
"""Launches the Simulate GUI."""
|
"""Launches the Simulate GUI."""
|
||||||
_launch_internal(
|
_launch_internal(
|
||||||
model, data, run_physics_thread=True, loader=loader)
|
model,
|
||||||
|
data,
|
||||||
|
run_physics_thread=True,
|
||||||
|
loader=loader,
|
||||||
|
show_left_ui=show_left_ui,
|
||||||
|
show_right_ui=show_right_ui,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def launch_from_path(path: str) -> None:
|
def launch_from_path(path: str) -> None:
|
||||||
@@ -404,6 +419,8 @@ def launch_passive(
|
|||||||
data: mujoco.MjData,
|
data: mujoco.MjData,
|
||||||
*,
|
*,
|
||||||
key_callback: Optional[KeyCallbackType] = None,
|
key_callback: Optional[KeyCallbackType] = None,
|
||||||
|
show_left_ui: bool = True,
|
||||||
|
show_right_ui: bool = True,
|
||||||
) -> Handle:
|
) -> Handle:
|
||||||
"""Launches a passive Simulate GUI without blocking the running thread."""
|
"""Launches a passive Simulate GUI without blocking the running thread."""
|
||||||
if not isinstance(model, mujoco.MjModel):
|
if not isinstance(model, mujoco.MjModel):
|
||||||
@@ -425,6 +442,8 @@ def launch_passive(
|
|||||||
run_physics_thread=False,
|
run_physics_thread=False,
|
||||||
handle_return=handle_return,
|
handle_return=handle_return,
|
||||||
key_callback=key_callback,
|
key_callback=key_callback,
|
||||||
|
show_left_ui=show_left_ui,
|
||||||
|
show_right_ui=show_right_ui,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
@@ -434,7 +453,14 @@ def launch_passive(
|
|||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
'`launch_passive` requires that the Python script be run under '
|
'`launch_passive` requires that the Python script be run under '
|
||||||
'`mjpython` on macOS')
|
'`mjpython` on macOS')
|
||||||
_MJPYTHON.launch_on_ui_thread(model, data, handle_return, key_callback)
|
_MJPYTHON.launch_on_ui_thread(
|
||||||
|
model,
|
||||||
|
data,
|
||||||
|
handle_return,
|
||||||
|
key_callback,
|
||||||
|
show_left_ui,
|
||||||
|
show_right_ui,
|
||||||
|
)
|
||||||
|
|
||||||
return handle_return.get()
|
return handle_return.get()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user