diff --git a/docs/source/device/soma.rst b/docs/source/device/soma.rst index ae7299cfef..30fd524333 100644 --- a/docs/source/device/soma.rst +++ b/docs/source/device/soma.rst @@ -30,8 +30,9 @@ select their body and hand sources independently. The body schema contains SOMA's complete body control set, including its hand controls. The standalone hand schemas provide independent left and right hand -streams. Isaac Teleop does not automatically fuse standalone hands with the -hand controls in a body payload. +streams, identified by ``hand_side`` (``SomaHandSide.LEFT`` or +``SomaHandSide.RIGHT``). Isaac Teleop does not automatically fuse standalone +hands with the hand controls in a body payload. Choose a representation ----------------------- diff --git a/docs/source/device/trackers.rst b/docs/source/device/trackers.rst index faec8789c3..0cbc4dfc47 100644 --- a/docs/source/device/trackers.rst +++ b/docs/source/device/trackers.rst @@ -348,7 +348,7 @@ reference-frame convention as ``SomaBodyJointRotations``. When a producer has already evaluated forward kinematics, it can instead publish ``SomaHandJointPoses``. That profile carries a global position, orientation, and validity for each of the same 25 joints and requires no downstream FK. Create one tracker per hand collection; each -payload identifies its side through ``handedness``. As with the body contract, a vendor adapter +payload identifies its side through ``hand_side``. As with the body contract, a vendor adapter converts its device-native hand data before calling ``SchemaPusher``. For a retargeting graph, ``SomaHandSource`` selects the rotation tracker by default and emits an diff --git a/examples/deviceio_live_view/python/isaaccapture_examples/deviceio_live_view/soma_hand.py b/examples/deviceio_live_view/python/isaaccapture_examples/deviceio_live_view/soma_hand.py index e9ff49c901..54fbef9a85 100644 --- a/examples/deviceio_live_view/python/isaaccapture_examples/deviceio_live_view/soma_hand.py +++ b/examples/deviceio_live_view/python/isaaccapture_examples/deviceio_live_view/soma_hand.py @@ -10,7 +10,7 @@ SomaHandSource, ) from isaaccapture.retargeting_engine.tensor_types import SomaHandInputIndex -from isaaccapture.schema import SomaHandedness, SomaHandJoint +from isaaccapture.schema import SomaHandSide, SomaHandJoint from .hand_pipeline import HandViewLayout, HandViewPipeline @@ -98,14 +98,14 @@ def create_soma_hand_pipeline( left = SomaHandSource( "hand_left", left_collection_id, - SomaHandedness.LEFT, + SomaHandSide.LEFT, layers[0], representation=representation, ) right = SomaHandSource( "hand_right", right_collection_id, - SomaHandedness.RIGHT, + SomaHandSide.RIGHT, layers[1], representation=representation, ) diff --git a/examples/soma_hand_publisher/python/isaaccapture_examples/soma_hand_publisher/publisher.py b/examples/soma_hand_publisher/python/isaaccapture_examples/soma_hand_publisher/publisher.py index a7e8e329bf..ce0277fb08 100644 --- a/examples/soma_hand_publisher/python/isaaccapture_examples/soma_hand_publisher/publisher.py +++ b/examples/soma_hand_publisher/python/isaaccapture_examples/soma_hand_publisher/publisher.py @@ -20,7 +20,7 @@ Point, Pose, Quaternion, - SomaHandedness, + SomaHandSide, SomaHandJoint, SomaHandJointPose, SomaHandJointPoses, @@ -150,31 +150,31 @@ def demo_hand_frames(path: Path, body, hands): return frames -def soma_joint_rotations(rotations, translation, handedness): +def soma_joint_rotations(rotations, translation, hand_side): joints = [ SomaHandJointRotation(joint, Quaternion(*rotation)) for joint, rotation in zip(HAND_JOINTS, rotations, strict=True) ] - return SomaHandJointRotations(joints, Point(*translation), True, handedness) + return SomaHandJointRotations(joints, Point(*translation), True, hand_side) -def soma_joint_poses(positions, orientations, handedness): +def soma_joint_poses(positions, orientations, hand_side): joints = [ SomaHandJointPose(joint, Pose(Point(*position), Quaternion(*orientation))) for joint, position, orientation in zip( HAND_JOINTS, positions, orientations, strict=True ) ] - return SomaHandJointPoses(joints, handedness) + return SomaHandJointPoses(joints, hand_side) -def _payload(frame, index: int, representation: str, handedness): +def _payload(frame, index: int, representation: str, hand_side): if representation == "joint-poses": return soma_joint_poses( - frame["positions"][index], frame["orientations"][index], handedness + frame["positions"][index], frame["orientations"][index], hand_side ).to_bytes() return soma_joint_rotations( - frame["rotations"][index], frame["translation"][index], handedness + frame["rotations"][index], frame["translation"][index], hand_side ).to_bytes() @@ -237,13 +237,13 @@ def main(argv: list[str]) -> int: frames["left"], index, args.hand_representation, - SomaHandedness.LEFT, + SomaHandSide.LEFT, ) right = _payload( frames["right"], index, args.hand_representation, - SomaHandedness.RIGHT, + SomaHandSide.RIGHT, ) if len(left) > max_payload_size or len(right) > max_payload_size: raise ValueError("SOMA hand payload exceeds transport capacity") diff --git a/src/core/schema/fbs/soma_common.fbs b/src/core/schema/fbs/soma_common.fbs index fea03b88be..d3b2971ea1 100644 --- a/src/core/schema/fbs/soma_common.fbs +++ b/src/core/schema/fbs/soma_common.fbs @@ -3,8 +3,8 @@ namespace core; -// Hand side shared by the SOMA pose transport schemas. -enum SomaHandedness : uint8 { +// Anatomical hand side, independent of the right-handed reference frame. +enum SomaHandSide : uint8 { UNSPECIFIED = 0, LEFT = 1, RIGHT = 2, diff --git a/src/core/schema/fbs/soma_hand_joint_poses.fbs b/src/core/schema/fbs/soma_hand_joint_poses.fbs index 1df71e7678..074626b90d 100644 --- a/src/core/schema/fbs/soma_hand_joint_poses.fbs +++ b/src/core/schema/fbs/soma_hand_joint_poses.fbs @@ -24,7 +24,7 @@ table SomaHandJointPoses { // Use CreateVectorOfSortedStructs when building the vector directly. // A joint absent from this vector is not provided by the producer. joint_poses: [SomaHandJointPose] (id: 0); - handedness: SomaHandedness = UNSPECIFIED (id: 1); + hand_side: SomaHandSide = UNSPECIFIED (id: 1); } table SomaHandJointPosesRecord { diff --git a/src/core/schema/fbs/soma_hand_joint_rotations.fbs b/src/core/schema/fbs/soma_hand_joint_rotations.fbs index 65741c98ba..56c5fb336b 100644 --- a/src/core/schema/fbs/soma_hand_joint_rotations.fbs +++ b/src/core/schema/fbs/soma_hand_joint_rotations.fbs @@ -65,7 +65,7 @@ table SomaHandJointRotations { // when global_translation_is_valid is false. global_translation: Point (id: 1); global_translation_is_valid: bool (id: 2); - handedness: SomaHandedness = UNSPECIFIED (id: 3); + hand_side: SomaHandSide = UNSPECIFIED (id: 3); } table SomaHandJointRotationsRecord { diff --git a/src/core/schema/golden/soma_common.bfbs b/src/core/schema/golden/soma_common.bfbs index 7a9eb4d4de..2556609b36 100644 Binary files a/src/core/schema/golden/soma_common.bfbs and b/src/core/schema/golden/soma_common.bfbs differ diff --git a/src/core/schema/golden/soma_hand_joint_poses.bfbs b/src/core/schema/golden/soma_hand_joint_poses.bfbs index 25119933db..cbc71c0a1c 100644 Binary files a/src/core/schema/golden/soma_hand_joint_poses.bfbs and b/src/core/schema/golden/soma_hand_joint_poses.bfbs differ diff --git a/src/core/schema/golden/soma_hand_joint_rotations.bfbs b/src/core/schema/golden/soma_hand_joint_rotations.bfbs index f14fa7eea3..62767a6dc1 100644 Binary files a/src/core/schema/golden/soma_hand_joint_rotations.bfbs and b/src/core/schema/golden/soma_hand_joint_rotations.bfbs differ diff --git a/src/core/schema/python/soma_common_bindings.h b/src/core/schema/python/soma_common_bindings.h index 175dc8d6c8..32d2ba2c13 100644 --- a/src/core/schema/python/soma_common_bindings.h +++ b/src/core/schema/python/soma_common_bindings.h @@ -13,10 +13,10 @@ namespace core inline void bind_soma_common(py::module& m) { - py::enum_(m, "SomaHandedness") - .value("UNSPECIFIED", SomaHandedness_UNSPECIFIED) - .value("LEFT", SomaHandedness_LEFT) - .value("RIGHT", SomaHandedness_RIGHT); + py::enum_(m, "SomaHandSide") + .value("UNSPECIFIED", SomaHandSide_UNSPECIFIED) + .value("LEFT", SomaHandSide_LEFT) + .value("RIGHT", SomaHandSide_RIGHT); } } // namespace core diff --git a/src/core/schema/python/soma_hand_joint_poses_bindings.h b/src/core/schema/python/soma_hand_joint_poses_bindings.h index 2a5ea85954..74390275ad 100644 --- a/src/core/schema/python/soma_hand_joint_poses_bindings.h +++ b/src/core/schema/python/soma_hand_joint_poses_bindings.h @@ -29,7 +29,7 @@ inline void bind_soma_hand_joint_poses(py::module& m) serialized_class(m, "SomaHandJointPoses", "Encoded evaluated SOMA hand poses.") .def(py::init( - [](std::vector joint_poses, SomaHandedness handedness) + [](std::vector joint_poses, SomaHandSide hand_side) { std::sort(joint_poses.begin(), joint_poses.end(), [](const auto& a, const auto& b) { return a.joint() < b.joint(); }); @@ -50,11 +50,10 @@ inline void bind_soma_hand_joint_poses(py::module& m) } SomaHandJointPosesT native; native.joint_poses = std::move(joint_poses); - native.handedness = handedness; + native.hand_side = hand_side; return pack(native); }), - py::arg("joint_poses") = std::vector{}, - py::arg("handedness") = SomaHandedness_UNSPECIFIED) + py::arg("joint_poses") = std::vector{}, py::arg("hand_side") = SomaHandSide_UNSPECIFIED) .def_property_readonly("joint_poses", [](const Serialized& self) { @@ -79,7 +78,7 @@ inline void bind_soma_hand_joint_poses(py::module& m) return found != nullptr ? py::cast(*found) : py::none(); }, py::arg("joint"), "Return one provided joint pose, or None when absent.") - .def_property_readonly("handedness", field(&SomaHandJointPoses::handedness)); + .def_property_readonly("hand_side", field(&SomaHandJointPoses::hand_side)); bind_record(m, "SomaHandJointPosesRecord", "SomaHandJointPoses"); } diff --git a/src/core/schema/python/soma_hand_joint_rotations_bindings.h b/src/core/schema/python/soma_hand_joint_rotations_bindings.h index ceeda65be2..7d3c1b8ab5 100644 --- a/src/core/schema/python/soma_hand_joint_rotations_bindings.h +++ b/src/core/schema/python/soma_hand_joint_rotations_bindings.h @@ -58,7 +58,7 @@ inline void bind_soma_hand_joint_rotations(py::module& m) serialized_class(m, "SomaHandJointRotations", "Encoded SOMA hand joint rotations.") .def(py::init( [](std::vector joint_rotations, const Point& global_translation, - bool global_translation_is_valid, SomaHandedness handedness) + bool global_translation_is_valid, SomaHandSide hand_side) { std::sort(joint_rotations.begin(), joint_rotations.end(), [](const auto& a, const auto& b) { return a.joint() < b.joint(); }); @@ -81,11 +81,11 @@ inline void bind_soma_hand_joint_rotations(py::module& m) native.joint_rotations = std::move(joint_rotations); native.global_translation = std::make_shared(global_translation); native.global_translation_is_valid = global_translation_is_valid; - native.handedness = handedness; + native.hand_side = hand_side; return pack(native); }), py::arg("joint_rotations") = std::vector{}, py::arg("global_translation") = Point(), - py::arg("global_translation_is_valid") = false, py::arg("handedness") = SomaHandedness_UNSPECIFIED) + py::arg("global_translation_is_valid") = false, py::arg("hand_side") = SomaHandSide_UNSPECIFIED) .def_property_readonly("joint_rotations", [](const Serialized& self) { @@ -113,7 +113,7 @@ inline void bind_soma_hand_joint_rotations(py::module& m) .def_property_readonly("global_translation", field(&SomaHandJointRotations::global_translation), py::return_value_policy::reference_internal) .def_property_readonly("global_translation_is_valid", field(&SomaHandJointRotations::global_translation_is_valid)) - .def_property_readonly("handedness", field(&SomaHandJointRotations::handedness)); + .def_property_readonly("hand_side", field(&SomaHandJointRotations::hand_side)); bind_record( m, "SomaHandJointRotationsRecord", "SomaHandJointRotations"); diff --git a/src/python/isaaccapture/retargeting_engine/deviceio_source_nodes/soma_hand_source.py b/src/python/isaaccapture/retargeting_engine/deviceio_source_nodes/soma_hand_source.py index e4dbb83b10..7b39f5f916 100644 --- a/src/python/isaaccapture/retargeting_engine/deviceio_source_nodes/soma_hand_source.py +++ b/src/python/isaaccapture/retargeting_engine/deviceio_source_nodes/soma_hand_source.py @@ -11,7 +11,7 @@ SomaHandJointPosesTracker, SomaHandJointRotationsTracker, ) -from isaaccapture.schema import SomaHandedness +from isaaccapture.schema import SomaHandSide from .deviceio_tensor_types import ( DeviceIOSomaHandJointPosesTracked, @@ -43,7 +43,7 @@ def __init__( self, name: str, collection_id: str, - handedness: SomaHandedness, + hand_side: SomaHandSide, layer: Any | None = None, *, representation: SomaHandRepresentation @@ -51,9 +51,9 @@ def __init__( ) -> None: if not collection_id: raise ValueError("SOMA hand collection_id must not be empty") - if handedness not in (SomaHandedness.LEFT, SomaHandedness.RIGHT): - raise ValueError("SOMA hand source requires LEFT or RIGHT handedness") - self.handedness = handedness + if hand_side not in (SomaHandSide.LEFT, SomaHandSide.RIGHT): + raise ValueError("SOMA hand source requires LEFT or RIGHT hand side") + self.hand_side = hand_side self.representation = SomaHandRepresentation(representation) self._tracker: SomaHandJointRotationsTracker | SomaHandJointPosesTracker if self.representation is SomaHandRepresentation.JOINT_ROTATIONS: @@ -65,7 +65,7 @@ def __init__( self._tracker = SomaHandJointPosesTracker(collection_id) self._input_type = DeviceIOSomaHandJointPosesTracked() # Pybind enum values read from buffers are not singleton objects. - expected_hand_type = "left" if handedness == SomaHandedness.LEFT else "right" + expected_hand_type = "left" if hand_side == SomaHandSide.LEFT else "right" self._evaluator = ( _SomaHandEvaluator(layer, expected_hand_type) if layer is not None else None ) @@ -91,10 +91,10 @@ def _compute_fn(self, inputs: RetargeterIO, outputs: RetargeterIO, context) -> N if data is None: group.set_none() return - if data.handedness != self.handedness: + if data.hand_side != self.hand_side: raise ValueError( - f"SOMA hand payload handedness {data.handedness} does not match " - f"source handedness {self.handedness}" + f"SOMA hand payload hand side {data.hand_side} does not match " + f"source hand side {self.hand_side}" ) if self.representation is SomaHandRepresentation.JOINT_ROTATIONS: diff --git a/src/python/isaaccapture/schema/__init__.py b/src/python/isaaccapture/schema/__init__.py index 768ba08704..06e6235d7f 100644 --- a/src/python/isaaccapture/schema/__init__.py +++ b/src/python/isaaccapture/schema/__init__.py @@ -85,7 +85,7 @@ FullBodyPose, FullBodyPoseRecord, # Shared SOMA types. - SomaHandedness, + SomaHandSide, # SOMA body joint-rotation types. SomaBodyJoint, SomaBodyJointRotation, @@ -210,7 +210,7 @@ def __getattr__(name: str): "FullBodyPose", "FullBodyPoseRecord", # Shared SOMA types. - "SomaHandedness", + "SomaHandSide", # SOMA body joint-rotation types. "SomaBodyJoint", "SomaBodyJointRotation", diff --git a/tests/cpp/core/schema/test_soma_hand_joint_poses.cpp b/tests/cpp/core/schema/test_soma_hand_joint_poses.cpp index deb1bbecfe..3120239fe6 100644 --- a/tests/cpp/core/schema/test_soma_hand_joint_poses.cpp +++ b/tests/cpp/core/schema/test_soma_hand_joint_poses.cpp @@ -19,7 +19,7 @@ constexpr auto vt(uint16_t field_id) } // namespace static_assert(core::SomaHandJointPoses::VT_JOINT_POSES == vt(0)); -static_assert(core::SomaHandJointPoses::VT_HANDEDNESS == vt(1)); +static_assert(core::SomaHandJointPoses::VT_HAND_SIDE == vt(1)); static_assert(core::SomaHandJointPosesRecord::VT_DATA == vt(0)); static_assert(core::SomaHandJointPosesRecord::VT_TIMESTAMP == vt(1)); static_assert(std::is_trivially_copyable_v); @@ -30,7 +30,7 @@ TEST_CASE("SOMA hand joint poses round trip as a sparse keyed vector", "[soma_ha core::SomaHandJointPosesT pose; pose.joint_poses.emplace_back(core::SomaHandJoint_INDEX_END, core::Pose(core::Point(1.0f, 2.0f, 3.0f), core::Quaternion(0.0f, 0.0f, 0.6f, 0.8f))); - pose.handedness = core::SomaHandedness_LEFT; + pose.hand_side = core::SomaHandSide_LEFT; flatbuffers::FlatBufferBuilder builder; builder.Finish(core::SomaHandJointPoses::Pack(builder, &pose)); @@ -46,5 +46,5 @@ TEST_CASE("SOMA hand joint poses round trip as a sparse keyed vector", "[soma_ha CHECK(index_end->pose().position().x() == Catch::Approx(1.0f)); CHECK(index_end->pose().orientation().w() == Catch::Approx(0.8f)); CHECK(decoded->joint_poses()->LookupByKey(core::SomaHandJoint_WRIST) == nullptr); - CHECK(decoded->handedness() == core::SomaHandedness_LEFT); + CHECK(decoded->hand_side() == core::SomaHandSide_LEFT); } diff --git a/tests/cpp/core/schema/test_soma_hand_joint_rotations.cpp b/tests/cpp/core/schema/test_soma_hand_joint_rotations.cpp index 98dc24d110..4dcd7d4068 100644 --- a/tests/cpp/core/schema/test_soma_hand_joint_rotations.cpp +++ b/tests/cpp/core/schema/test_soma_hand_joint_rotations.cpp @@ -15,7 +15,7 @@ static_assert(core::SomaHandJointRotations::VT_JOINT_ROTATIONS == VT(0)); static_assert(core::SomaHandJointRotations::VT_GLOBAL_TRANSLATION == VT(1)); static_assert(core::SomaHandJointRotations::VT_GLOBAL_TRANSLATION_IS_VALID == VT(2)); -static_assert(core::SomaHandJointRotations::VT_HANDEDNESS == VT(3)); +static_assert(core::SomaHandJointRotations::VT_HAND_SIDE == VT(3)); static_assert(core::SomaHandJointRotationsRecord::VT_DATA == VT(0)); static_assert(core::SomaHandJointRotationsRecord::VT_TIMESTAMP == VT(1)); @@ -23,7 +23,7 @@ static_assert(core::SomaHandJointRotationsRecord::VT_TIMESTAMP == VT(1)); static_assert(std::is_same_v*>); static_assert(std::is_same_v); static_assert(std::is_same_v); -static_assert(std::is_same_v); +static_assert(std::is_same_v); static_assert(std::is_trivially_copyable_v); static_assert(sizeof(core::SomaHandJointRotation) == 20); @@ -49,7 +49,7 @@ TEST_CASE("SOMA hand joint rotations round trip as a sparse keyed vector", "[som pose.joint_rotations.emplace_back(core::SomaHandJoint_INDEX_END, core::Quaternion(0.0f, 0.0f, 0.6f, 0.8f)); pose.global_translation = std::make_shared(1.0f, 2.0f, 3.0f); pose.global_translation_is_valid = true; - pose.handedness = core::SomaHandedness_RIGHT; + pose.hand_side = core::SomaHandSide_RIGHT; flatbuffers::FlatBufferBuilder builder; builder.Finish(core::SomaHandJointRotations::Pack(builder, &pose)); @@ -66,7 +66,7 @@ TEST_CASE("SOMA hand joint rotations round trip as a sparse keyed vector", "[som CHECK(decoded->joint_rotations()->LookupByKey(core::SomaHandJoint_WRIST) == nullptr); CHECK(decoded->global_translation()->x() == Catch::Approx(1.0f)); CHECK(decoded->global_translation_is_valid()); - CHECK(decoded->handedness() == core::SomaHandedness_RIGHT); + CHECK(decoded->hand_side() == core::SomaHandSide_RIGHT); } TEST_CASE("SOMA hand record preserves keyed quaternion components", "[soma_hand_joint_rotations][flatbuffers]") @@ -80,7 +80,7 @@ TEST_CASE("SOMA hand record preserves keyed quaternion components", "[soma_hand_ core::SomaHandJoint_PINKY_END, core::Quaternion(-scale, 2.0f * scale, -3.0f * scale, 4.0f * scale)); record.data->global_translation = std::make_shared(1.0f, -2.0f, 3.0f); record.data->global_translation_is_valid = false; - record.data->handedness = core::SomaHandedness_LEFT; + record.data->hand_side = core::SomaHandSide_LEFT; record.timestamp = std::make_shared(100, 200, 300); flatbuffers::FlatBufferBuilder builder; @@ -106,7 +106,7 @@ TEST_CASE("SOMA hand record preserves keyed quaternion components", "[soma_hand_ CHECK(pinky->rotation().z() == Catch::Approx(-3.0f * scale)); CHECK(pinky->rotation().w() == Catch::Approx(4.0f * scale)); CHECK(values->LookupByKey(core::SomaHandJoint_INDEX1) == nullptr); - CHECK(decoded->data()->handedness() == core::SomaHandedness_LEFT); + CHECK(decoded->data()->hand_side() == core::SomaHandSide_LEFT); CHECK(decoded->timestamp()->available_time_local_common_clock() == 100); CHECK(decoded->timestamp()->sample_time_local_common_clock() == 200); CHECK(decoded->timestamp()->sample_time_raw_device_clock() == 300); diff --git a/tests/python/core/retargeting_engine/test_soma_hand_source.py b/tests/python/core/retargeting_engine/test_soma_hand_source.py index 591368398f..f48a8f050f 100644 --- a/tests/python/core/retargeting_engine/test_soma_hand_source.py +++ b/tests/python/core/retargeting_engine/test_soma_hand_source.py @@ -25,7 +25,7 @@ Point, Pose, Quaternion, - SomaHandedness, + SomaHandSide, SomaHandJoint, SomaHandJointPose, SomaHandJointPoses, @@ -88,15 +88,15 @@ def fake_layer(hand_type="left"): return layer -def rotations(handedness=SomaHandedness.LEFT): +def rotations(hand_side=SomaHandSide.LEFT): joints = [ SomaHandJointRotation(SomaHandJoint(index), Quaternion(0, 0, 0, 1)) for index in range(25) ] - return SomaHandJointRotations(joints, Point(1, 2, 3), True, handedness) + return SomaHandJointRotations(joints, Point(1, 2, 3), True, hand_side) -def poses(handedness=SomaHandedness.LEFT): +def poses(hand_side=SomaHandSide.LEFT): positions = np.arange(75, dtype=np.float32).reshape(25, 3) joints = [ SomaHandJointPose( @@ -105,7 +105,7 @@ def poses(handedness=SomaHandedness.LEFT): ) for index, position in enumerate(positions) ] - return SomaHandJointPoses(joints, handedness) + return SomaHandJointPoses(joints, hand_side) def payload_group(group_type, data): @@ -116,7 +116,7 @@ def payload_group(group_type, data): def test_rotation_source_evaluates_received_payload(): layer = fake_layer() - source = SomaHandSource("left", "vendor.left", SomaHandedness.LEFT, layer) + source = SomaHandSource("left", "vendor.left", SomaHandSide.LEFT, layer) assert isinstance(source.get_tracker(), SomaHandJointRotationsTracker) layer.get_reference_pose.assert_called_once_with(version="v0.3.1") raw = rotations() @@ -143,16 +143,16 @@ def test_rotation_source_evaluates_received_payload(): @pytest.mark.parametrize( - "handedness,hand_type", - [(SomaHandedness.LEFT, "left"), (SomaHandedness.RIGHT, "right")], + "hand_side,hand_type", + [(SomaHandSide.LEFT, "left"), (SomaHandSide.RIGHT, "right")], ) -def test_rotation_source_accepts_payload_handedness(handedness, hand_type): - payload = rotations(handedness) +def test_rotation_source_accepts_payload_hand_side(hand_side, hand_type): + payload = rotations(hand_side) layer = fake_layer(hand_type) - source = SomaHandSource("hand", "vendor.hand", payload.handedness, layer) + source = SomaHandSource("hand", "vendor.hand", payload.hand_side, layer) - assert source.handedness == handedness + assert source.hand_side == hand_side assert source._evaluator.layer is layer @@ -160,7 +160,7 @@ def test_joint_pose_source_maps_without_fk(): source = SomaHandSource( "left", "vendor.left", - SomaHandedness.LEFT, + SomaHandSide.LEFT, representation=SomaHandRepresentation.JOINT_POSES, ) assert isinstance(source.get_tracker(), SomaHandJointPosesTracker) @@ -187,7 +187,7 @@ def test_joint_pose_source_invalidates_bad_numeric_entries(): source = SomaHandSource( "left", "vendor.left", - SomaHandedness.LEFT, + SomaHandSide.LEFT, representation=SomaHandRepresentation.JOINT_POSES, ) raw = SomaHandJointPoses( @@ -205,7 +205,7 @@ def test_joint_pose_source_invalidates_bad_numeric_entries(): Pose(Point(0, 0, 0), Quaternion()), ), ], - SomaHandedness.LEFT, + SomaHandSide.LEFT, ) inputs = payload_group(source.input_spec()["deviceio_soma_hand"], raw) @@ -219,17 +219,17 @@ def test_joint_pose_source_invalidates_bad_numeric_entries(): ) -def test_payload_handedness_must_match_collection(): +def test_payload_hand_side_must_match_collection(): source = SomaHandSource( "left", "vendor.left", - SomaHandedness.LEFT, + SomaHandSide.LEFT, representation=SomaHandRepresentation.JOINT_POSES, ) inputs = payload_group( - source.input_spec()["deviceio_soma_hand"], poses(SomaHandedness.RIGHT) + source.input_spec()["deviceio_soma_hand"], poses(SomaHandSide.RIGHT) ) - with pytest.raises(ValueError, match="handedness"): + with pytest.raises(ValueError, match="hand side"): source({"deviceio_soma_hand": inputs}) @@ -244,12 +244,12 @@ def test_hand_transport_profiles_are_distinct(): def test_rotation_source_requires_layer_and_valid_side(): with pytest.raises(ValueError, match="prepared SOMA hand layer"): - SomaHandSource("left", "vendor.left", SomaHandedness.LEFT) + SomaHandSource("left", "vendor.left", SomaHandSide.LEFT) with pytest.raises(ValueError, match="LEFT or RIGHT"): SomaHandSource( "left", "vendor.left", - SomaHandedness.UNSPECIFIED, + SomaHandSide.UNSPECIFIED, fake_layer(), ) @@ -259,7 +259,7 @@ def test_rotation_source_rejects_layer_for_other_hand(): SomaHandSource( "left", "vendor.left", - SomaHandedness.LEFT, + SomaHandSide.LEFT, fake_layer("right"), ) @@ -272,7 +272,7 @@ def test_rotation_source_rejects_wrong_hand_hierarchy(): SomaHandSource( "left", "vendor.left", - SomaHandedness.LEFT, + SomaHandSide.LEFT, layer, ) @@ -304,7 +304,7 @@ def test_rotation_source_rejects_incompatible_hand_contract(change, error): SomaHandSource( "left", "vendor.left", - SomaHandedness.LEFT, + SomaHandSide.LEFT, layer, ) @@ -318,7 +318,7 @@ def test_hand_rotation_inputs_normalize_and_invalidate_numeric_values(): ], Point(np.inf, 0, 0), True, - SomaHandedness.LEFT, + SomaHandSide.LEFT, ) rotations, valid, translation, translation_valid = _SomaHandEvaluator._pose_inputs( diff --git a/tests/python/core/schema/test_soma_hand_joint_poses.py b/tests/python/core/schema/test_soma_hand_joint_poses.py index f4ab28a30b..060220e1ad 100644 --- a/tests/python/core/schema/test_soma_hand_joint_poses.py +++ b/tests/python/core/schema/test_soma_hand_joint_poses.py @@ -8,7 +8,7 @@ Point, Pose, Quaternion, - SomaHandedness, + SomaHandSide, SomaHandJoint, SomaHandJointPose, SomaHandJointPoses, @@ -24,13 +24,13 @@ def test_soma_hand_joint_poses_are_keyed_and_sparse(): Pose(Point(1.0, 2.0, 3.0), Quaternion(0.0, 0.0, 0.0, 1.0)), ) ], - SomaHandedness.LEFT, + SomaHandSide.LEFT, ) assert len(payload.joint_poses) == 1 assert payload.lookup(SomaHandJoint.INDEX_END).pose.position.y == pytest.approx(2.0) assert payload.lookup(SomaHandJoint.WRIST) is None - assert payload.handedness == SomaHandedness.LEFT + assert payload.hand_side == SomaHandSide.LEFT def test_soma_hand_joint_poses_sort_and_reject_duplicates(): @@ -54,12 +54,12 @@ def test_soma_hand_joint_poses_record_round_trip(): Pose(Point(72.0, 73.0, 74.0), Quaternion(0.0, 0.0, 0.0, 1.0)), ) ], - SomaHandedness.RIGHT, + SomaHandSide.RIGHT, ) record = SomaHandJointPosesRecord(payload, DeviceDataTimestamp(10, 20, 30)) assert record.data.lookup(SomaHandJoint.PINKY_END).pose.position.z == pytest.approx( 74.0 ) - assert record.data.handedness == SomaHandedness.RIGHT + assert record.data.hand_side == SomaHandSide.RIGHT assert record.timestamp.available_time_local_common_clock == 10 diff --git a/tests/python/core/schema/test_soma_hand_joint_rotations.py b/tests/python/core/schema/test_soma_hand_joint_rotations.py index e253028a9f..144a9f64bf 100644 --- a/tests/python/core/schema/test_soma_hand_joint_rotations.py +++ b/tests/python/core/schema/test_soma_hand_joint_rotations.py @@ -8,7 +8,7 @@ DeviceDataTimestamp, Point, Quaternion, - SomaHandedness, + SomaHandSide, SomaHandJoint, SomaHandJointRotation, SomaHandJointRotations, @@ -35,7 +35,7 @@ def test_soma_hand_rotations_sort_lookup_and_omit_unavailable_joints(): ], Point(1.0, 2.0, 3.0), True, - SomaHandedness.LEFT, + SomaHandSide.LEFT, ) assert [entry.joint for entry in payload.joint_rotations] == [ @@ -44,7 +44,7 @@ def test_soma_hand_rotations_sort_lookup_and_omit_unavailable_joints(): ] assert payload.lookup(SomaHandJoint.PINKY_END).rotation.w == pytest.approx(0.8) assert payload.lookup(SomaHandJoint.INDEX1) is None - assert payload.handedness == SomaHandedness.LEFT + assert payload.hand_side == SomaHandSide.LEFT def test_soma_hand_rotations_reject_duplicate_joint_identifiers(): @@ -58,7 +58,7 @@ def test_soma_hand_rotation_record_preserves_quaternion_layout(): quaternion /= np.linalg.norm(quaternion) payload = SomaHandJointRotations( [SomaHandJointRotation(SomaHandJoint.WRIST, Quaternion(*quaternion))], - handedness=SomaHandedness.RIGHT, + hand_side=SomaHandSide.RIGHT, ) record = SomaHandJointRotationsRecord(payload, DeviceDataTimestamp(100, 200, 300)) @@ -67,5 +67,5 @@ def test_soma_hand_rotation_record_preserves_quaternion_layout(): [wrist.rotation.x, wrist.rotation.y, wrist.rotation.z, wrist.rotation.w], quaternion, ) - assert record.data.handedness == SomaHandedness.RIGHT + assert record.data.hand_side == SomaHandSide.RIGHT assert record.timestamp.sample_time_local_common_clock == 200 diff --git a/tests/python/examples/deviceio_live_view/test_soma_viewer.py b/tests/python/examples/deviceio_live_view/test_soma_viewer.py index c1b0a71b38..12706c790e 100644 --- a/tests/python/examples/deviceio_live_view/test_soma_viewer.py +++ b/tests/python/examples/deviceio_live_view/test_soma_viewer.py @@ -36,7 +36,7 @@ SomaBodyJointPoses, SomaBodyJointRotation, SomaBodyJointRotations, - SomaHandedness, + SomaHandSide, SomaHandJoint, SomaHandJointPose, SomaHandJointPoses, @@ -110,7 +110,7 @@ def soma_joint_poses(positions, orientations): return SomaBodyJointPoses(joints) -def soma_hand_joint_poses(positions, orientations, handedness): +def soma_hand_joint_poses(positions, orientations, hand_side): joints = [ SomaHandJointPose( SomaHandJoint(index), @@ -120,15 +120,15 @@ def soma_hand_joint_poses(positions, orientations, handedness): zip(positions, orientations, strict=True) ) ] - return SomaHandJointPoses(joints, handedness) + return SomaHandJointPoses(joints, hand_side) -def soma_hand_joint_rotations(rotations, translation, handedness): +def soma_hand_joint_rotations(rotations, translation, hand_side): joints = [ SomaHandJointRotation(SomaHandJoint(index), Quaternion(*rotation)) for index, rotation in enumerate(rotations) ] - return SomaHandJointRotations(joints, Point(*translation), True, handedness) + return SomaHandJointRotations(joints, Point(*translation), True, hand_side) def fake_viz( @@ -228,7 +228,7 @@ def test_soma_hand_pose_reaches_native_25_joint_renderer(): positions = np.arange(75, dtype=np.float32).reshape(25, 3) / 100 orientations = np.tile([0, 0, 0, 1], (25, 1)).astype(np.float32) sources["hand_left"]._tracker.get_data.return_value = soma_hand_joint_poses( - positions, orientations, SomaHandedness.LEFT + positions, orientations, SomaHandSide.LEFT ) sources["hand_right"]._tracker.get_data.return_value = None @@ -477,15 +477,15 @@ def test_native_soma_hand_rotations_reach_renderer(monkeypatch, soma_assets): inputs[node.name][key] = group identity = np.tile([0, 0, 0, 1], (25, 1)).astype(np.float32) - for name, handedness in ( - ("hand_left", SomaHandedness.LEFT), - ("hand_right", SomaHandedness.RIGHT), + for name, hand_side in ( + ("hand_left", SomaHandSide.LEFT), + ("hand_right", SomaHandSide.RIGHT), ): source = sources[name] assert isinstance(source.get_tracker(), SomaHandJointRotationsTracker) source._tracker = MagicMock() source._tracker.get_data.return_value = soma_hand_joint_rotations( - identity, [0, 0, 0], handedness + identity, [0, 0, 0], hand_side ) inputs[name] = source.poll_tracker(object()) diff --git a/tests/python/examples/soma_hand_publisher/test_publisher.py b/tests/python/examples/soma_hand_publisher/test_publisher.py index 4d2a2c5a21..2599699d1f 100644 --- a/tests/python/examples/soma_hand_publisher/test_publisher.py +++ b/tests/python/examples/soma_hand_publisher/test_publisher.py @@ -15,7 +15,7 @@ from isaaccapture.retargeting_engine.utilities.soma_hand_evaluator import ( _SomaHandEvaluator, ) -from isaaccapture.schema import SomaHandedness +from isaaccapture.schema import SomaHandSide from isaaccapture_examples.soma_hand_publisher import publisher from isaaccapture_examples.soma_hand_publisher.publisher import ( create_layers, @@ -124,13 +124,13 @@ def test_publisher_pushes_each_hand_through_one_session(demo, representation, ca [demo.left, demo.right], demo.oxr_session.get_handles.return_value ) assert demo.session.update.call_count == 2 - for tracker, handedness in ( - (demo.left, SomaHandedness.LEFT), - (demo.right, SomaHandedness.RIGHT), + for tracker, hand_side in ( + (demo.left, SomaHandSide.LEFT), + (demo.right, SomaHandSide.RIGHT), ): assert tracker.push.call_count == 2 tracker.push.assert_called_with( - demo.session, publisher._payload(demo.frame, 1, representation, handedness) + demo.session, publisher._payload(demo.frame, 1, representation, hand_side) ) demo.sleep.assert_called_once_with(1 / 30) demo.session.__exit__.assert_called_once() @@ -213,8 +213,8 @@ def test_invalid_rate_is_rejected_before_loading_model(monkeypatch, rate): def test_hand_payload_constructors_preserve_side_and_arrays(): rotations = np.tile([0.0, 0.0, 0.0, 1.0], (25, 1)) - rotation_payload = soma_joint_rotations(rotations, [1, 2, 3], SomaHandedness.LEFT) - assert rotation_payload.handedness == SomaHandedness.LEFT + rotation_payload = soma_joint_rotations(rotations, [1, 2, 3], SomaHandSide.LEFT) + assert rotation_payload.hand_side == SomaHandSide.LEFT dense_rotations, rotation_valid = _dense_joint_rotations( rotation_payload.joint_rotations, 25 ) @@ -222,8 +222,8 @@ def test_hand_payload_constructors_preserve_side_and_arrays(): assert rotation_valid.all() positions = np.arange(75, dtype=np.float32).reshape(25, 3) - pose_payload = soma_joint_poses(positions, rotations, SomaHandedness.RIGHT) - assert pose_payload.handedness == SomaHandedness.RIGHT + pose_payload = soma_joint_poses(positions, rotations, SomaHandSide.RIGHT) + assert pose_payload.hand_side == SomaHandSide.RIGHT dense_positions, _, pose_valid = _dense_joint_poses(pose_payload.joint_poses, 25) np.testing.assert_array_equal(dense_positions, positions) assert pose_valid.all() @@ -233,19 +233,19 @@ def test_demo_profiles_match_upstream_hand_fk(soma_assets): body, hands = create_layers(soma_assets) frames = demo_hand_frames(soma_assets / "example_animation.npy", body, hands) - for side, handedness in ( - ("left", SomaHandedness.LEFT), - ("right", SomaHandedness.RIGHT), + for side, hand_side in ( + ("left", SomaHandSide.LEFT), + ("right", SomaHandSide.RIGHT), ): frame = frames[side] payload = soma_joint_rotations( - frame["rotations"][0], frame["translation"][0], handedness + frame["rotations"][0], frame["translation"][0], hand_side ) positions, _, valid = _SomaHandEvaluator(hands[side], side).evaluate(payload) np.testing.assert_allclose(positions, frame["positions"][0], atol=1e-5) np.testing.assert_array_equal(valid, np.ones(25, dtype=np.uint8)) evaluated = soma_joint_poses( - frame["positions"][0], frame["orientations"][0], handedness + frame["positions"][0], frame["orientations"][0], hand_side ) evaluated_positions, _, evaluated_valid = _dense_joint_poses( evaluated.joint_poses, 25 @@ -256,21 +256,21 @@ def test_demo_profiles_match_upstream_hand_fk(soma_assets): for representation in ("joint-rotations", "joint-poses"): capacity = 2048 if representation == "joint-poses" else 1024 for index in range(len(frames["left"]["positions"])): - for side, handedness in ( - ("left", SomaHandedness.LEFT), - ("right", SomaHandedness.RIGHT), + for side, hand_side in ( + ("left", SomaHandSide.LEFT), + ("right", SomaHandSide.RIGHT), ): frame = frames[side] if representation == "joint-poses": payload = soma_joint_poses( frame["positions"][index], frame["orientations"][index], - handedness, + hand_side, ) else: payload = soma_joint_rotations( frame["rotations"][index], frame["translation"][index], - handedness, + hand_side, ) assert len(payload.to_bytes()) <= capacity