Skip to content

BrainCo

BrainCo is a rigid articulated model of the BrainCo Revo 2 robotic hand using the official MuJoCo XML and STL assets.

Setup

BrainCo downloads automatically on first use. To prefetch and save the path:

# Download the BrainCo MuJoCo XML and STL assets.
body-models download brainco

When passed manually, model_path should contain left.xml, right.xml, and meshes/{left,right}/*.STL.

Usage

from body_models.brainco.numpy import BrainCoHand

# Load the right hand with scalar hinge coordinates for the active joints.
hand = BrainCoHand(side="right", rotation_type="hinge")

Notes

The model exposes the six active Revo 2 joints for each hand: thumb metacarpal, thumb proximal, and the proximal joints for index, middle, ring, and pinky. Passive distal joints are included in the skeleton and meshes.

API

body_models.robots.brainco.numpy.BrainCoHand

BrainCoHand(model_path=None, *, side='right', rotation_type='rotmat')

Bases: BodyModel

BrainCo Revo 2 as rigid STL links attached to its MuJoCo hand skeleton.

Initialize the BrainCoHand model.

PARAMETER DESCRIPTION
model_path

Path to model assets, or the default assets when omitted.

TYPE: Path | str | None DEFAULT: None

side

Hand side to load.

TYPE: Side DEFAULT: 'right'

rotation_type

Rotation representation expected by pose inputs.

TYPE: RotationType DEFAULT: 'rotmat'

METHOD DESCRIPTION
forward_skeleton

Compute posed joint transforms.

forward_vertices

Compute posed mesh vertices.

joint_index

Resolve a standard joint to this model's native joint index.

get_tpose

Get parameters for the SMPL-style T-pose.

get_apose

Get parameters for the MHR-style A-pose.

prepare_skinning

Pack prepared model state into renderer-ready skinning inputs.

Source code in src/body_models/robots/brainco/numpy.py
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def __init__(
    self,
    model_path: Path | str | None = None,
    *,
    side: Side = "right",
    rotation_type: core.RotationType = "rotmat",
) -> None:
    """Initialize the BrainCoHand model.

    Args:
        model_path: Path to model assets, or the default assets when omitted.
        side: Hand side to load.
        rotation_type: Rotation representation expected by pose inputs.
    """
    if rotation_type not in core.VALID_ROTATION_TYPES:
        raise ValueError(f"Invalid rotation_type: {rotation_type}")
    self.rotation_type = rotation_type
    self.num_rot_dims = 2 if rotation_type in ("matrix", "rotmat") else 1
    self.weights = load_model_data(model_path, side=side)

forward_skeleton

forward_skeleton(
    hand_pose,
    global_translation=None,
    *,
    global_rotation=None,
    joint_indices=None,
)

Compute posed joint transforms.

PARAMETER DESCRIPTION
hand_pose

Local hand joint rotations.

TYPE: Float[ndarray, 'B Q N'] | Float[ndarray, 'B Q 3 3']

global_translation

Global model translation.

TYPE: Float[ndarray, 'B 3'] | None DEFAULT: None

global_rotation

Global model rotation.

TYPE: Float[ndarray, 'B N'] | Float[ndarray, 'B 3 3'] | None DEFAULT: None

joint_indices

Optional subset of joints to return.

TYPE: list[int] | None DEFAULT: None

RETURNS DESCRIPTION
Float[ndarray, 'B J 4 4']

Joint transforms in the model hierarchy.

Source code in src/body_models/robots/brainco/numpy.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
def forward_skeleton(
    self,
    hand_pose: Float[np.ndarray, "B Q N"] | Float[np.ndarray, "B Q 3 3"],
    global_translation: Float[np.ndarray, "B 3"] | None = None,
    *,
    global_rotation: Float[np.ndarray, "B N"] | Float[np.ndarray, "B 3 3"] | None = None,
    joint_indices: list[int] | None = None,
) -> Float[np.ndarray, "B J 4 4"]:
    """Compute posed joint transforms.

    Args:
        hand_pose: Local hand joint rotations.
        global_translation: Global model translation.
        global_rotation: Global model rotation.
        joint_indices: Optional subset of joints to return.

    Returns:
        Joint transforms in the model hierarchy.
    """
    return backend.forward_skeleton(
        self.weights,
        hand_pose,
        global_translation,
        global_rotation=global_rotation,
        joint_indices=joint_indices,
        rotation_type=self.rotation_type,
    )

forward_vertices

forward_vertices(
    hand_pose,
    global_translation=None,
    *,
    global_rotation=None,
    vertex_indices=None,
)

Compute posed mesh vertices.

PARAMETER DESCRIPTION
hand_pose

Local hand joint rotations.

TYPE: Float[ndarray, 'B Q N'] | Float[ndarray, 'B Q 3 3']

global_translation

Global model translation.

TYPE: Float[ndarray, 'B 3'] | None DEFAULT: None

global_rotation

Global model rotation.

TYPE: Float[ndarray, 'B N'] | Float[ndarray, 'B 3 3'] | None DEFAULT: None

vertex_indices

Optional subset of vertices to return.

TYPE: list[int] | None DEFAULT: None

RETURNS DESCRIPTION
Float[ndarray, 'B V 3']

Posed vertex positions.

Source code in src/body_models/robots/brainco/numpy.py
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
def forward_vertices(
    self,
    hand_pose: Float[np.ndarray, "B Q N"] | Float[np.ndarray, "B Q 3 3"],
    global_translation: Float[np.ndarray, "B 3"] | None = None,
    *,
    global_rotation: Float[np.ndarray, "B N"] | Float[np.ndarray, "B 3 3"] | None = None,
    vertex_indices: list[int] | None = None,
) -> Float[np.ndarray, "B V 3"]:
    """Compute posed mesh vertices.

    Args:
        hand_pose: Local hand joint rotations.
        global_translation: Global model translation.
        global_rotation: Global model rotation.
        vertex_indices: Optional subset of vertices to return.

    Returns:
        Posed vertex positions.
    """
    return backend.forward_vertices(
        self.weights,
        hand_pose,
        global_translation,
        global_rotation=global_rotation,
        vertex_indices=vertex_indices,
        rotation_type=self.rotation_type,
    )

joint_index

joint_index(joint)

Resolve a standard joint to this model's native joint index.

Source code in src/body_models/base.py
77
78
79
80
81
82
83
84
85
def joint_index(self, joint: Joint) -> int:
    """Resolve a standard joint to this model's native joint index."""
    if not isinstance(joint, Joint):
        raise TypeError("joint_index() expects a body_models.Joint; use joint_names.index(...) for native names.")
    try:
        native_name = self.common_joints[joint]
    except KeyError as exc:
        raise KeyError(f"{self.__class__.__name__} has no standard joint {joint.value!r}") from exc
    return self.joint_names.index(native_name)

get_tpose

get_tpose(batch_dims=(), **kwargs)

Get parameters for the SMPL-style T-pose.

Source code in src/body_models/base.py
134
135
136
137
138
139
140
def get_tpose(
    self,
    batch_dims: tuple[int, ...] = (),
    **kwargs: Any,
) -> dict[str, Any]:
    """Get parameters for the SMPL-style T-pose."""
    raise NotImplementedError("Canonical body poses are not defined for this model.")

get_apose

get_apose(batch_dims=(), **kwargs)

Get parameters for the MHR-style A-pose.

Source code in src/body_models/base.py
142
143
144
145
146
147
148
def get_apose(
    self,
    batch_dims: tuple[int, ...] = (),
    **kwargs: Any,
) -> dict[str, Any]:
    """Get parameters for the MHR-style A-pose."""
    raise NotImplementedError("Canonical body poses are not defined for this model.")

prepare_skinning

prepare_skinning(*, identity, pose)

Pack prepared model state into renderer-ready skinning inputs.

Source code in src/body_models/base.py
161
162
163
164
165
166
167
168
169
170
171
172
173
174
def prepare_skinning(self, *, identity: Mapping[str, Any], pose: Mapping[str, Any]) -> SkinningPayload:
    """Pack prepared model state into renderer-ready skinning inputs."""
    if self.is_rigid_body:
        raise NotImplementedError(f"{self.__class__.__name__} is rigid and does not support skinning.")

    skinning: SkinningPayload = {
        "rest_vertices": identity["rest_vertices"],
        "skinning_transforms": pose["skinning_transforms"],
        "skin_weights": self.skin_weights,
        "faces": self.faces,
    }
    if "pose_offsets" in pose:
        skinning["pose_offsets"] = pose["pose_offsets"]
    return skinning