Skip to content

Commit

Permalink
[python/viewer] Fix some edge-cases with panda3d backend.
Browse files Browse the repository at this point in the history
  • Loading branch information
duburcqa committed Dec 10, 2023
1 parent 56c8896 commit fdb1fd9
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
WIDGET_MARGIN_REL = 0.02

PANDA3D_FRAMERATE_MAX = 40
PANDA3D_REQUEST_TIMEOUT = 30.0


Tuple3FType = Union[Tuple[float, float, float], np.ndarray]
Expand Down Expand Up @@ -1530,6 +1531,7 @@ def set_material(self,
if texture_path:
texture = self.loader.load_texture(texture_path)
node.set_texture(texture)
node.set_transparency(TransparencyAttrib.M_alpha)

def set_scale(self,
root_path: str,
Expand Down Expand Up @@ -1856,7 +1858,7 @@ def __getattr__(self, name: str) -> Callable[..., Any]:
@wraps(getattr(Panda3dApp, name))
def _send(*args: Any, **kwargs: Any) -> Any:
if self._host_conn.closed:
raise ViewerError("Viewer not available anymore.")
raise ViewerClosedError("Viewer not available anymore.")
while self._host_conn.poll():
try:
reply = self._host_conn.recv()
Expand All @@ -1872,12 +1874,14 @@ def _send(*args: Any, **kwargs: Any) -> Any:
self._host_conn.send((name, args, kwargs, self._is_async))
if self._is_async:
return None
if self._host_conn.poll(10.0):
if self._host_conn.poll(PANDA3D_REQUEST_TIMEOUT):
reply = self._host_conn.recv()
else:
# Something is wrong... aborting to prevent potential deadlock
self._host_conn.send(("stop", (), (), True))
self._host_conn.close()
raise ViewerError("Viewer not available anymore.")
raise ViewerClosedError(
"Viewer has been because it did not respond.")
if isinstance(reply, Exception):
if isinstance(reply, ViewerClosedError):
# Close pipe to make sure it is not used in future
Expand Down
39 changes: 26 additions & 13 deletions python/jiminy_py/src/jiminy_py/viewer/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

import numpy as np

from panda3d_viewer.viewer_errors import ViewerClosedError
from panda3d_viewer.viewer_errors import ViewerError, ViewerClosedError
try:
from psutil import Process
except ImportError:
Expand Down Expand Up @@ -553,6 +553,7 @@ def __init__(self, # pylint: disable=unused-argument
"Robot name already exists but must be unique. Please choose "
"a different one, or close the associated viewer.")
Viewer._backend_robot_names.add(robot_name)
Viewer._backend_robot_colors[robot_name] = None

# Enforce some arguments based on available features
if not backend.startswith('panda3d'):
Expand Down Expand Up @@ -598,6 +599,7 @@ def __init__(self, # pylint: disable=unused-argument
prefix="_".join((Viewer.window_name, scene_name, robot_name, "")))

# Access the current backend or create one if none is available
self._client = None
self.__is_open = False
self.is_backend_parent = not Viewer.is_alive()
try:
Expand Down Expand Up @@ -688,15 +690,16 @@ def _setup(self,
assert Viewer.backend is not None

# Delete existing robot, if any
assert self.robot_name in Viewer._backend_robot_names
robot_node_path = '/'.join((self.scene_name, self.robot_name))
Viewer._delete_nodes_viewer([
'/'.join((robot_node_path, "visuals")),
'/'.join((robot_node_path, "collisions"))])

# Backup desired color
assert self.robot_name in Viewer._backend_robot_colors.keys()
self.robot_color = get_color_code(robot_color)
Viewer._backend_robot_colors.update({
self.robot_name: self.robot_color})
Viewer._backend_robot_colors[self.robot_name] = self.robot_color

# Create backend wrapper to get (almost) backend-independent API.
backend_type = get_backend_type(Viewer.backend)
Expand Down Expand Up @@ -1111,6 +1114,10 @@ def close(self: Optional[Union["Viewer", Type["Viewer"]]] = None) -> None:
Viewer._backend_proc = None
Viewer._has_gui = False
else:
# Consider that the robot is not available anymore, no matter what
Viewer._backend_robot_names.discard(self.robot_name)
Viewer._backend_robot_colors.pop(self.robot_name, None)

# Disable travelling if associated with this viewer instance
if (Viewer._camera_travelling is not None and
Viewer._camera_travelling['viewer'] is self):
Expand All @@ -1130,15 +1137,16 @@ def close(self: Optional[Union["Viewer", Type["Viewer"]]] = None) -> None:
if Viewer.backend == 'meshcat' and Viewer.is_alive():
Viewer._backend_obj.gui.window.zmq_socket.RCVTIMEO = 200

# Consider that the robot is not available anymore, no matter what
Viewer._backend_robot_names.discard(self.robot_name)
Viewer._backend_robot_colors.pop(self.robot_name, None)
# Delete robot from scene if requested
if (self.delete_robot_on_close and self._client is not None and
self.is_open()): # type: ignore[misc]
Viewer._delete_nodes_viewer([
self._client.visual_group,
self._client.collision_group,
self._markers_group])
self.is_open()): # type: ignore[unreachable]
try: # type: ignore[unreachable]
Viewer._delete_nodes_viewer([
self._client.visual_group,
self._client.collision_group,
self._markers_group])
except ViewerError:
pass

# Restore zmq socket timeout, which is disable by default
if Viewer.backend == 'meshcat':
Expand Down Expand Up @@ -1386,8 +1394,8 @@ def set_legend(labels: Optional[Sequence[str]] = None) -> None:
if labels is not None and (
len(labels) != len(Viewer._backend_robot_colors)):
raise RuntimeError(
f"Inconsistency between robots {Viewer._backend_robot_names}' "
f"and labels {labels}")
f"Inconsistency between robots {Viewer._backend_robot_names} "
f"({Viewer._backend_robot_colors}) and labels {labels}")

# Make sure all robots have a specific color
if any(color is None for color in Viewer._backend_robot_colors):
Expand Down Expand Up @@ -1762,6 +1770,7 @@ def set_color(self,
# Sanitize user-specified color code
color_ = get_color_code(color)

# Update the color of all the geometries of the robot
for model, geom_type in zip(
(self._client.visual_model, self._client.collision_model),
pin.GeometryType.names.values()):
Expand All @@ -1772,8 +1781,12 @@ def set_color(self,
color = geom.meshColor
self._gui.set_material(*node_name, color)

# Backup the new color
assert self.robot_name in Viewer._backend_robot_colors.keys()
self.robot_color = color_
Viewer._backend_robot_colors[self.robot_name] = color_

# Refresh the legend accordingly
Viewer._backend_obj.gui.set_legend()

@staticmethod
Expand Down

0 comments on commit fdb1fd9

Please sign in to comment.