Skip to content

Commit

Permalink
Add auto render and change MultiverseFunction to MultiverseCallback
Browse files Browse the repository at this point in the history
  • Loading branch information
HoangGiang93 committed Feb 13, 2025
1 parent 84c8f70 commit 261c4aa
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 251 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
MultiverseSimulatorState,
MultiverseSimulatorConstraints,
MultiverseSimulatorStopReason,
MultiverseFunctionResult,
MultiverseFunction
MultiverseCallbackResult,
MultiverseCallback
)

from .multiverse_simulator_compiler import (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ def logging_interval(self) -> float:


@dataclass
class MultiverseFunctionResult:
class MultiverseCallbackResult:
"""Multiverse Function Result Enum"""

class OutType(str, Enum):
Expand All @@ -326,29 +326,34 @@ class ResultType(Enum):
info: str = None
"""Information about the result"""
result: Any = None
"""Result of the function"""
"""Result of the callback"""

def __call__(self):
self.result = self.result()
return self


class MultiverseFunction:
"""Base class for Multiverse Function"""
class MultiverseCallback:
"""Base class for Multiverse Callback"""

def __init__(self, callback: Callable):
"""
Initialize the function with the callback
:param callback: Callable, callback function, must return MultiverseFunctionResult
:param callback: Callable, callback function, must return MultiverseCallbackResult
"""
self._call = callback
self.__name__ = callback.__name__

def __call__(self, *args, **kwargs):
def __call__(self, *args, render: bool=True, **kwargs):
result = self._call(*args, **kwargs)
if not isinstance(result, MultiverseFunctionResult):
raise TypeError("Callback function must return MultiverseFunctionResult")
if not isinstance(result, MultiverseCallbackResult):
raise TypeError("Callback function must return MultiverseCallbackResult")
simulator = args[0]
if not isinstance(simulator, MultiverseSimulator):
raise TypeError("First argument must be of type MultiverseSimulator")
if render:
simulator.renderer.sync()
return result


Expand All @@ -367,10 +372,10 @@ class MultiverseSimulator:
logger: logging.Logger = logging.getLogger(__name__)
"""Logger for the simulator"""

class_level_callbacks: List[MultiverseFunction] = []
class_level_callbacks: List[MultiverseCallback] = []
"""Class level callback functions"""

instance_level_callbacks: List[MultiverseFunction] = None
instance_level_callbacks: List[MultiverseCallback] = None
"""Instance level callback functions"""

def __init__(self,
Expand All @@ -379,7 +384,7 @@ def __init__(self,
headless: bool = False,
real_time_factor: float = 1.0,
step_size: float = 1E-3,
callbacks: List[MultiverseFunction] = None,
callbacks: List[MultiverseCallback] = None,
**kwargs):
"""
Initialize the simulator with the viewer and the following keyword arguments:
Expand All @@ -389,7 +394,7 @@ def __init__(self,
:param headless: bool, True to run the simulator in headless mode
:param real_time_factor: float, real time factor
:param step_size: float, step size
:param callbacks: List[MultiverseFunction], list of callback functions
:param callbacks: List[MultiverseCallback], list of callback functions
"""
self._headless = headless
self._real_time_factor = real_time_factor
Expand Down Expand Up @@ -674,23 +679,23 @@ def renderer(self) -> MultiverseRenderer:
return self._renderer

@classmethod
def add_callback(cls, callback: Callable | MultiverseFunction, callbacks: List[MultiverseFunction]):
if not isinstance(callback, MultiverseFunction):
def add_callback(cls, callback: Callable | MultiverseCallback, callbacks: List[MultiverseCallback]):
if not isinstance(callback, MultiverseCallback):
if isinstance(callback, Callable):
callback = MultiverseFunction(callback=callback)
callback = MultiverseCallback(callback=callback)
else:
raise TypeError(f"Function {callback} must be an instance of MultiverseFunction or Callable, "
raise TypeError(f"Function {callback} must be an instance of MultiverseCallback or Callable, "
f"got {type(callback)}")
if callback.__name__ in [callback.__name__ for callback in callbacks]:
raise AttributeError(f"Function {callback.__name__} is already defined")
callbacks.append(callback)
cls.log_info(f"Function {callback.__name__} is registered")

def add_instance_callback(self, callback: Callable | MultiverseFunction):
def add_instance_callback(self, callback: Callable | MultiverseCallback):
self.add_callback(callback, self.instance_level_callbacks)

@classmethod
def add_class_callback(cls, callback: Callable | MultiverseFunction):
def add_class_callback(cls, callback: Callable | MultiverseCallback):
cls.add_callback(callback, cls.class_level_callbacks)

@classmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from isaac_sim_connector import MultiverseIsaacSimConnector
from multiverse_simulator import MultiverseSimulatorConstraints, MultiverseSimulatorState, MultiverseViewer, \
MultiverseFunctionResult
MultiverseCallbackResult
from test_multiverse_simulator import MultiverseSimulatorTestCase

resources_path = os.path.join(os.path.dirname(__file__), "..", "resources")
Expand All @@ -28,63 +28,63 @@ def test_functions(self):
for step in range(10000):
if step < 1000:
result = simulator.get_all_body_names()
self.assertIsInstance(result, MultiverseFunctionResult)
self.assertEqual(result.type, MultiverseFunctionResult.ResultType.SUCCESS_WITHOUT_EXECUTION)
self.assertIsInstance(result, MultiverseCallbackResult)
self.assertEqual(result.type, MultiverseCallbackResult.ResultType.SUCCESS_WITHOUT_EXECUTION)
self.assertEqual(result.result, ['world', 'link0', 'link1', 'link2', 'link3', 'link4',
'link5', 'link6', 'link7', 'hand', 'left_finger',
'right_finger', 'box', 'mocap_target'])

result = simulator.get_all_joint_names()
self.assertIsInstance(result, MultiverseFunctionResult)
self.assertEqual(result.type, MultiverseFunctionResult.ResultType.SUCCESS_WITHOUT_EXECUTION)
self.assertIsInstance(result, MultiverseCallbackResult)
self.assertEqual(result.type, MultiverseCallbackResult.ResultType.SUCCESS_WITHOUT_EXECUTION)
self.assertEqual(result.result, ['joint1', 'joint2', 'joint3', 'joint4', 'joint5',
'joint6', 'joint7', 'finger_joint1', 'finger_joint2', ''])

if step == 1000 or step == 3000:
result = simulator.attach(body_1_name="abc")
self.assertEqual(MultiverseFunctionResult.ResultType.FAILURE_BEFORE_EXECUTION_ON_MODEL, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.FAILURE_BEFORE_EXECUTION_ON_MODEL, result.type)
self.assertEqual("Body 1 abc not found", result.info)

result = simulator.attach(body_1_name="world")
self.assertEqual(MultiverseFunctionResult.ResultType.FAILURE_BEFORE_EXECUTION_ON_MODEL, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.FAILURE_BEFORE_EXECUTION_ON_MODEL, result.type)
self.assertEqual("Body 1 and body 2 are the same", result.info)

result = simulator.attach(body_1_name="box")
self.assertEqual(MultiverseFunctionResult.ResultType.SUCCESS_WITHOUT_EXECUTION, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.SUCCESS_WITHOUT_EXECUTION, result.type)
self.assertEqual("Body 1 box is already attached to body 2 world", result.info)

result = simulator.attach(body_1_name="box", body_2_name="hand")
self.assertEqual(MultiverseFunctionResult.ResultType.SUCCESS_AFTER_EXECUTION_ON_MODEL, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.SUCCESS_AFTER_EXECUTION_ON_MODEL, result.type)
self.assertIn("Attached body 1 box to body 2 hand", result.info)

result = simulator.attach(body_1_name="box", body_2_name="hand")
self.assertEqual(MultiverseFunctionResult.ResultType.SUCCESS_WITHOUT_EXECUTION, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.SUCCESS_WITHOUT_EXECUTION, result.type)
self.assertEqual("Body 1 box is already attached to body 2 hand", result.info)

if step == 2000 or step == 4000:
result = simulator.detach(body_name="abc")
self.assertEqual(MultiverseFunctionResult.ResultType.FAILURE_BEFORE_EXECUTION_ON_MODEL, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.FAILURE_BEFORE_EXECUTION_ON_MODEL, result.type)
self.assertEqual("Body abc not found", result.info)

result = simulator.detach(body_name="world")
self.assertEqual(MultiverseFunctionResult.ResultType.SUCCESS_WITHOUT_EXECUTION, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.SUCCESS_WITHOUT_EXECUTION, result.type)
self.assertEqual("Body world is already detached", result.info)

result = simulator.detach(body_name="box")
self.assertEqual(MultiverseFunctionResult.ResultType.SUCCESS_AFTER_EXECUTION_ON_MODEL, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.SUCCESS_AFTER_EXECUTION_ON_MODEL, result.type)
self.assertEqual("Detached body box from body hand", result.info)

result = simulator.detach(body_name="box")
self.assertEqual(MultiverseFunctionResult.ResultType.SUCCESS_WITHOUT_EXECUTION, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.SUCCESS_WITHOUT_EXECUTION, result.type)
self.assertEqual("Body box is already detached", result.info)

if step == 8000:
result = simulator.get_contact_bodies(body_name="abc")
self.assertEqual(MultiverseFunctionResult.ResultType.FAILURE_WITHOUT_EXECUTION, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.FAILURE_WITHOUT_EXECUTION, result.type)
self.assertEqual("Body abc not found", result.info)

result = simulator.get_contact_bodies(body_name="hand")
self.assertEqual(MultiverseFunctionResult.ResultType.SUCCESS_WITHOUT_EXECUTION, result.type)
self.assertEqual(MultiverseCallbackResult.ResultType.SUCCESS_WITHOUT_EXECUTION, result.type)
self.assertIsInstance(result.result, set)

simulator.step()
Expand Down
Loading

0 comments on commit 261c4aa

Please sign in to comment.