diff --git a/docs/tutorials/physics/mocap_control.md b/docs/tutorials/physics/mocap_control.md
index 2b64469..d65b5a0 100644
--- a/docs/tutorials/physics/mocap_control.md
+++ b/docs/tutorials/physics/mocap_control.md
@@ -10,7 +10,7 @@ from textwrap import dedent
from killport import kill_ports
from vuer import Vuer, VuerSession
from vuer.events import ClientEvent
-from vuer.schemas import MuJoCo, Scene, Fog, Sphere, Hands, HandActuator
+from vuer.schemas import MuJoCo, Scene, Fog, Sphere, Hands, HandActuator, MotionControllers, MotionControllerActuator
```
@@ -90,7 +90,8 @@ async def main(sess: VuerSession):
# grid=False,
bgChildren=[
Fog(color=0x2C3F57, near=10, far=20),
- Hands(),
+ # Hands(),
+ MotionControllers(),
Sphere(
args=[50, 10, 10],
materialType="basic",
@@ -101,8 +102,8 @@ async def main(sess: VuerSession):
await sleep(0.0005)
sess.upsert @ MuJoCo(
- HandActuator(key="pinch-on-squeeze"),
-
+ # HandActuator(key="pinch-on-squeeze"),
+ MotionControllerActuator(high=0.15, low=0.01, ctrlId=-1),
key="franka-gripper",
src=asset_pref + "scene.xml",
assets=[asset_pref + fn for fn in ASSETS_LIST],
@@ -113,40 +114,3 @@ async def main(sess: VuerSession):
await sleep(100.0)
```
-
-
-```{admonition} Note
-:class: tip
-
-Note the `HandActuator` that is used to add control to the
-gripper fingers. This is currently hand-specific.
-
- class HandActuator(SceneElement):
- tag = "HandActuator"
-
- ctrlId = -1
- offset = 0.01
- low = 0.01
- high = 1.0
- cond = 'right-squeeze'
- value = "right:thumb-tip,right:index-finger-tip"
- scale = 1.0
-```
-
-This correspond to the following actuator definition
-in the MJCF file:
-
-```xml
-...
-
-
-
-
-
-...
-
-
-
-
-```
diff --git a/docs/tutorials/physics/mocap_control.py b/docs/tutorials/physics/mocap_control.py
index 08315f9..e2c3e6f 100644
--- a/docs/tutorials/physics/mocap_control.py
+++ b/docs/tutorials/physics/mocap_control.py
@@ -3,7 +3,7 @@
from cmx import doc
-MAKE_DOCS = os.getenv("MAKE_DOCS", True)
+MAKE_DOCS = os.getenv("MAKE_DOCS", False)
doc @ """
# MuJoCo VR Mocap Example
@@ -17,7 +17,7 @@
from killport import kill_ports
from vuer import Vuer, VuerSession
from vuer.events import ClientEvent
- from vuer.schemas import MuJoCo, Scene, Fog, Sphere, Hands, HandActuator
+ from vuer.schemas import MuJoCo, Scene, Fog, Sphere, Hands, HandActuator, MotionControllers, MotionControllerActuator
doc @ """
@@ -97,7 +97,8 @@ async def main(sess: VuerSession):
# grid=False,
bgChildren=[
Fog(color=0x2C3F57, near=10, far=20),
- Hands(),
+ # Hands(),
+ MotionControllers(),
Sphere(
args=[50, 10, 10],
materialType="basic",
@@ -108,8 +109,8 @@ async def main(sess: VuerSession):
await sleep(0.0005)
sess.upsert @ MuJoCo(
- HandActuator(key="pinch-on-squeeze"),
-
+ # HandActuator(key="pinch-on-squeeze"),
+ MotionControllerActuator(high=0.15, low=0.01, ctrlId=-1),
key="franka-gripper",
src=asset_pref + "scene.xml",
assets=[asset_pref + fn for fn in ASSETS_LIST],
diff --git a/vuer/schemas/physics_components.py b/vuer/schemas/physics_components.py
index b5f2bda..00a17a8 100644
--- a/vuer/schemas/physics_components.py
+++ b/vuer/schemas/physics_components.py
@@ -49,3 +49,34 @@ class HandActuator(SceneElement):
cond = 'right-squeeze'
value = "right:thumb-tip,right:index-finger-tip"
scale = 1.0
+
+class MotionControllerActuator(SceneElement):
+ """
+ MotionControllerActuator component for actuating the MuJoCo simulation based on motion controller inputs.
+
+ :param ctrlId: The control ID in the MuJoCo simulation to actuate.
+ :type ctrlId: int
+ :param low: The minimum value for actuation.
+ :type low: float
+ :param high: The maximum value for actuation.
+ :type high: float
+ :param cond: The condition for actuation, e.g., 'right-trigger'.
+ :type cond: str
+ :param scale: The scaling factor applied to the input value for actuation.
+ :type scale: float
+ """
+ tag = "MotionControllerActuator"
+
+ ctrlId: int = -1
+ low: float = 0.0
+ high: float = 1.0
+ cond: str = 'right-trigger'
+ scale: float = 1.0
+
+ def __init__(self, ctrlId=-1, low=0.0, high=1.0, cond='right-trigger', scale=1.0, **kwargs):
+ super().__init__(**kwargs)
+ self.ctrlId = ctrlId
+ self.low = low
+ self.high = high
+ self.cond = cond
+ self.scale = scale
\ No newline at end of file
diff --git a/vuer/schemas/scene_components.py b/vuer/schemas/scene_components.py
index 8c5e688..f83fa15 100644
--- a/vuer/schemas/scene_components.py
+++ b/vuer/schemas/scene_components.py
@@ -628,6 +628,49 @@ def __init__(
**kwargs,
)
+class MotionControllers(SceneElement):
+ """
+ MotionController for tracking XR controller poses and button states.
+
+ :param key: Unique identifier for the controller.
+ :type key: str, optional
+ :param eventTypes: A tuple or list of events to track (e.g., "trigger", "squeeze").
+ :type eventTypes: tuple or list, optional
+ :param stream: Whether to enable streaming of controller data.
+ :type stream: bool, optional
+ :param left: Boolean indicating if the left controller should be tracked.
+ :type left: bool, optional
+ :param right: Boolean indicating if the right controller should be tracked.
+ :type right: bool, optional
+ :param showLeft: Boolean indicating if the left controller visualization should be shown.
+ :type showLeft: bool, optional
+ :param showRight: Boolean indicating if the right controller visualization should be shown.
+ :type showRight: bool, optional
+ """
+
+ tag = "MotionControllers"
+
+ def __init__(
+ self,
+ key="motionControllers",
+ eventTypes=("trigger", "squeeze"),
+ stream=True,
+ left=None,
+ right=None,
+ showLeft=True,
+ showRight=True,
+ **kwargs,
+ ):
+ super().__init__(
+ key=key,
+ eventTypes=eventTypes,
+ stream=stream,
+ left=left,
+ right=right,
+ showLeft=showLeft,
+ showRight=showRight,
+ **kwargs,
+ )
class Obj(SceneElement):
tag = "Obj"
@@ -771,6 +814,7 @@ def __init__(
AmbientLight(key="ambient", intensity=0.25),
PointLight(key="spot", intensity=1, position=[0, 1, 1]),
Hands(fps=30, eventType=["squeeze"], stream=True),
+ MotionControllers(fps=30, eventType=["trigger", "squeeze"], stream=True),
]
self.up = up