Skip to content

Commit e9113ae

Browse files
authored
Use head and hand schema in XRIO (#18)
* Use FlatBuffer for head pose in xrio * Use FlatBuffer for hand pose in xrio
1 parent 23ad50f commit e9113ae

File tree

14 files changed

+134
-169
lines changed

14 files changed

+134
-169
lines changed

examples/oxr/cpp/oxr_session_sharing.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,13 @@ int main()
112112
{
113113
std::cout << "Frame " << i << ": "
114114
<< "Hands=" << (left.is_active ? "ACTIVE" : "INACTIVE") << " | "
115-
<< "Head=" << (head.is_valid ? "VALID" : "INVALID") << std::endl;
115+
<< "Head=" << (head.is_valid ? "VALID" : "INVALID");
116+
if (head.is_valid && head.pose)
117+
{
118+
const auto& pos = head.pose->position();
119+
std::cout << " [" << pos.x() << ", " << pos.y() << ", " << pos.z() << "]";
120+
}
121+
std::cout << std::endl;
116122
}
117123

118124
std::this_thread::sleep_for(std::chrono::milliseconds(16));

examples/oxr/cpp/oxr_simple_api_demo.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,10 @@ int main()
121121
std::cout << " Right hand: " << (right.is_active ? "ACTIVE" : "INACTIVE") << std::endl;
122122
std::cout << " Head pose: " << (head.is_valid ? "VALID" : "INVALID") << std::endl;
123123

124-
if (head.is_valid)
124+
if (head.is_valid && head.pose)
125125
{
126-
std::cout << " Position: [" << head.position[0] << ", " << head.position[1] << ", " << head.position[2]
126+
const auto& pos = head.pose->position();
127+
std::cout << " Position: [" << pos.x() << ", " << pos.y() << ", " << pos.z()
127128
<< "]" << std::endl;
128129
}
129130
std::cout << std::endl;

examples/oxr/python/modular_example.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,24 +87,24 @@ def main():
8787
# Get hand data
8888
left = hand_tracker.get_left_hand()
8989
right = hand_tracker.get_right_hand()
90-
90+
9191
print(f" Hands: Left={'ACTIVE' if left.is_active else 'INACTIVE':8s} | "
9292
f"Right={'ACTIVE' if right.is_active else 'INACTIVE':8s}")
93-
94-
if left.is_active:
95-
wrist = left.get_joint(xrio.JOINT_WRIST)
93+
94+
if left.is_active and left.joints:
95+
wrist = left.joints[xrio.JOINT_WRIST]
9696
if wrist.is_valid:
97-
pos = wrist.position
98-
print(f" Left wrist: [{pos[0]:6.3f}, {pos[1]:6.3f}, {pos[2]:6.3f}]")
99-
100-
# Get head data
97+
pos = wrist.pose.position
98+
print(f" Left wrist: [{pos.x:6.3f}, {pos.y:6.3f}, {pos.z:6.3f}]")
99+
100+
# Get head data (returns HeadPoseT from schema)
101101
head = head_tracker.get_head()
102102
print(f" Head: {'VALID' if head.is_valid else 'INVALID':8s}")
103-
104-
if head.is_valid:
105-
pos = head.position
106-
print(f" Head position: [{pos[0]:6.3f}, {pos[1]:6.3f}, {pos[2]:6.3f}]")
107-
103+
104+
if head.is_valid and head.pose:
105+
pos = head.pose.position
106+
print(f" Head position: [{pos.x:6.3f}, {pos.y:6.3f}, {pos.z:6.3f}]")
107+
108108
print()
109109

110110
frame_count += 1

examples/oxr/python/test_extensions.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import sys
1313
import teleopcore.xrio as xrio
1414
import teleopcore.oxr as oxr
15+
from teleopcore.schema import HeadPoseT
1516

1617
print("=" * 80)
1718
print("OpenXR Required Extensions Test")
@@ -107,11 +108,15 @@
107108
# Quick update test
108109
if session.update():
109110
left = hand.get_left_hand()
110-
head_pose = head.get_head()
111+
head_pose: HeadPoseT = head.get_head()
111112
print(f" ✅ Update successful")
112113
print(f" Hands: {'ACTIVE' if left.is_active else 'INACTIVE'}")
113114
print(f" Head: {'VALID' if head_pose.is_valid else 'INVALID'}")
114-
115+
116+
if head_pose.is_valid and head_pose.pose:
117+
pos = head_pose.pose.position
118+
print(f" Head position: [{pos.x:.3f}, {pos.y:.3f}, {pos.z:.3f}]")
119+
115120
# Session will be cleaned up when exiting 'with' block (RAII)
116121
else:
117122
print(" ❌ Failed to initialize")

examples/oxr/python/test_modular.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
try:
1414
import teleopcore.xrio as xrio
1515
import teleopcore.oxr as oxr
16+
import teleopcore.schema as schema
1617
except ImportError as e:
1718
print(f"Error: {e}")
1819
print("Make sure the module is built")
@@ -85,24 +86,24 @@
8586
right = hand_tracker.get_right_hand()
8687
print(f" Left hand: {'ACTIVE' if left.is_active else 'INACTIVE'}")
8788
print(f" Right hand: {'ACTIVE' if right.is_active else 'INACTIVE'}")
88-
89-
if left.is_active:
90-
wrist = left.get_joint(xrio.JOINT_WRIST)
89+
90+
if left.is_active and left.joints:
91+
wrist = left.joints[xrio.JOINT_WRIST]
9192
if wrist.is_valid:
92-
pos = wrist.position
93-
print(f" Left wrist position: [{pos[0]:.3f}, {pos[1]:.3f}, {pos[2]:.3f}]")
93+
pos = wrist.pose.position
94+
print(f" Left wrist position: [{pos.x:.3f}, {pos.y:.3f}, {pos.z:.3f}]")
9495
print()
95-
96-
# Test 7: Check head data
96+
97+
# Test 7: Check head data (returns HeadPoseT from schema)
9798
print("[Test 7] Checking head tracking data...")
98-
head = head_tracker.get_head()
99+
head: schema.HeadPoseT = head_tracker.get_head()
99100
print(f" Head: {'VALID' if head.is_valid else 'INVALID'}")
100-
101-
if head.is_valid:
102-
pos = head.position
103-
ori = head.orientation
104-
print(f" Head position: [{pos[0]:.3f}, {pos[1]:.3f}, {pos[2]:.3f}]")
105-
print(f" Head orientation: [{ori[0]:.3f}, {ori[1]:.3f}, {ori[2]:.3f}, {ori[3]:.3f}]")
101+
102+
if head.is_valid and head.pose:
103+
pos = head.pose.position
104+
ori = head.pose.orientation
105+
print(f" Head position: [{pos.x:.3f}, {pos.y:.3f}, {pos.z:.3f}]")
106+
print(f" Head orientation: [{ori.x:.3f}, {ori.y:.3f}, {ori.z:.3f}, {ori.w:.3f}]")
106107
print()
107108

108109
# Test 8: Run tracking loop

examples/oxr/python/test_session_sharing.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,17 @@
126126
print(f"[{elapsed:4.1f}s] Frame {frame_count:3d}:")
127127
print(f" Hands: {'ACTIVE' if left.is_active else 'INACTIVE':8s}")
128128
print(f" Head: {'VALID' if head.is_valid else 'INVALID':8s}")
129-
130-
if left.is_active:
131-
wrist = left.get_joint(xrio.JOINT_WRIST)
129+
130+
if left.is_active and left.joints:
131+
wrist = left.joints[xrio.JOINT_WRIST]
132132
if wrist.is_valid:
133-
pos = wrist.position
134-
print(f" Left wrist: [{pos[0]:6.3f}, {pos[1]:6.3f}, {pos[2]:6.3f}]")
135-
136-
if head.is_valid:
137-
pos = head.position
138-
print(f" Head pos: [{pos[0]:6.3f}, {pos[1]:6.3f}, {pos[2]:6.3f}]")
139-
133+
pos = wrist.pose.position
134+
print(f" Left wrist: [{pos.x:6.3f}, {pos.y:6.3f}, {pos.z:6.3f}]")
135+
136+
if head.is_valid and head.pose:
137+
pos = head.pose.position
138+
print(f" Head pos: [{pos.x:6.3f}, {pos.y:6.3f}, {pos.z:6.3f}]")
139+
140140
print()
141141

142142
frame_count += 1

examples/oxr/python/test_synthetic_hands.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,12 @@ def run_test():
117117
print(f"Frame {frame_count}:")
118118
print(f" Left Hand: {'ACTIVE' if left.is_active else 'INACTIVE'}")
119119
print(f" Right Hand: {'ACTIVE' if right.is_active else 'INACTIVE'}")
120-
121-
if left.is_active:
122-
wrist = left.get_joint(xrio.JOINT_WRIST)
120+
121+
if left.is_active and left.joints:
122+
wrist = left.joints[xrio.JOINT_WRIST]
123123
if wrist.is_valid:
124-
print(f" Left Wrist: {wrist.position}")
124+
pos = wrist.pose.position
125+
print(f" Left Wrist: [{pos.x:.3f}, {pos.y:.3f}, {pos.z:.3f}]")
125126
print()
126127

127128
frame_count += 1

src/core/xrio/cpp/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ target_link_libraries(xrio_core
4040
# oxr_utils is header-only and provides OpenXRSessionHandles struct
4141
# It also brings in OpenXR headers for base types without linking to OpenXR loader
4242
oxr::oxr_utils
43+
44+
# Schema library for FlatBuffer types
45+
teleopcore_schema
4346
)
4447

4548
# Platform-specific definitions

src/core/xrio/cpp/handtracker.cpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -117,17 +117,17 @@ bool HandTracker::Impl::update(XrTime time)
117117
return left_ok || right_ok;
118118
}
119119

120-
const HandData& HandTracker::Impl::get_left_hand() const
120+
const HandPoseT& HandTracker::Impl::get_left_hand() const
121121
{
122122
return left_hand_;
123123
}
124124

125-
const HandData& HandTracker::Impl::get_right_hand() const
125+
const HandPoseT& HandTracker::Impl::get_right_hand() const
126126
{
127127
return right_hand_;
128128
}
129129

130-
bool HandTracker::Impl::update_hand(XrHandTrackerEXT tracker, XrTime time, HandData& out_data)
130+
bool HandTracker::Impl::update_hand(XrHandTrackerEXT tracker, XrTime time, HandPoseT& out_data)
131131
{
132132
XrHandJointsLocateInfoEXT locate_info{ XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT };
133133
locate_info.baseSpace = base_space_;
@@ -150,23 +150,37 @@ bool HandTracker::Impl::update_hand(XrHandTrackerEXT tracker, XrTime time, HandD
150150
out_data.is_active = locations.isActive;
151151
out_data.timestamp = time;
152152

153-
for (uint32_t i = 0; i < 26; ++i)
153+
// Ensure joints struct is allocated
154+
if (!out_data.joints)
154155
{
155-
const auto& joint_loc = joint_locations[i];
156-
auto& joint_data = out_data.joints[i];
156+
out_data.joints = std::make_unique<HandJoints>();
157+
}
157158

158-
joint_data.position[0] = joint_loc.pose.position.x;
159-
joint_data.position[1] = joint_loc.pose.position.y;
160-
joint_data.position[2] = joint_loc.pose.position.z;
159+
// Get mutable access to the joints array
160+
auto* mutable_array = const_cast<flatbuffers::Array<HandJointPose, 26>*>(out_data.joints->poses());
161161

162-
joint_data.orientation[0] = joint_loc.pose.orientation.x;
163-
joint_data.orientation[1] = joint_loc.pose.orientation.y;
164-
joint_data.orientation[2] = joint_loc.pose.orientation.z;
165-
joint_data.orientation[3] = joint_loc.pose.orientation.w;
162+
for (uint32_t i = 0; i < 26; ++i)
163+
{
164+
const auto& joint_loc = joint_locations[i];
166165

167-
joint_data.radius = joint_loc.radius;
168-
joint_data.is_valid = (joint_loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) &&
169-
(joint_loc.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT);
166+
// Create Pose from position and orientation using FlatBuffers structs
167+
Point position(
168+
joint_loc.pose.position.x,
169+
joint_loc.pose.position.y,
170+
joint_loc.pose.position.z);
171+
Quaternion orientation(
172+
joint_loc.pose.orientation.x,
173+
joint_loc.pose.orientation.y,
174+
joint_loc.pose.orientation.z,
175+
joint_loc.pose.orientation.w);
176+
Pose pose(position, orientation);
177+
178+
bool is_valid = (joint_loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) &&
179+
(joint_loc.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT);
180+
181+
// Create HandJointPose and set it in the array
182+
HandJointPose joint_pose(pose, is_valid, joint_loc.radius);
183+
mutable_array->Mutate(i, joint_pose);
170184
}
171185

172186
return true;
@@ -190,18 +204,18 @@ std::vector<std::string> HandTracker::get_required_extensions() const
190204
return { XR_EXT_HAND_TRACKING_EXTENSION_NAME };
191205
}
192206

193-
const HandData& HandTracker::get_left_hand() const
207+
const HandPoseT& HandTracker::get_left_hand() const
194208
{
195-
static const HandData empty_data{};
209+
static const HandPoseT empty_data{};
196210
auto impl = cached_impl_.lock();
197211
if (!impl)
198212
return empty_data;
199213
return impl->get_left_hand();
200214
}
201215

202-
const HandData& HandTracker::get_right_hand() const
216+
const HandPoseT& HandTracker::get_right_hand() const
203217
{
204-
static const HandData empty_data{};
218+
static const HandPoseT empty_data{};
205219
auto impl = cached_impl_.lock();
206220
if (!impl)
207221
return empty_data;

src/core/xrio/cpp/headtracker.cpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,28 +59,28 @@ bool HeadTracker::Impl::update(XrTime time)
5959

6060
if (head_.is_valid)
6161
{
62-
// Copy position
63-
head_.position[0] = location.pose.position.x;
64-
head_.position[1] = location.pose.position.y;
65-
head_.position[2] = location.pose.position.z;
66-
67-
// Copy orientation
68-
head_.orientation[0] = location.pose.orientation.x;
69-
head_.orientation[1] = location.pose.orientation.y;
70-
head_.orientation[2] = location.pose.orientation.z;
71-
head_.orientation[3] = location.pose.orientation.w;
62+
// Create pose from position and orientation using FlatBuffers structs
63+
Point position(
64+
location.pose.position.x,
65+
location.pose.position.y,
66+
location.pose.position.z);
67+
Quaternion orientation(
68+
location.pose.orientation.x,
69+
location.pose.orientation.y,
70+
location.pose.orientation.z,
71+
location.pose.orientation.w);
72+
head_.pose = std::make_shared<Pose>(position, orientation);
7273
}
7374
else
7475
{
75-
// Invalid - zero out
76-
memset(head_.position, 0, sizeof(head_.position));
77-
memset(head_.orientation, 0, sizeof(head_.orientation));
76+
// Invalid - reset pose
77+
head_.pose.reset();
7878
}
7979

8080
return true;
8181
}
8282

83-
const HeadPose& HeadTracker::Impl::get_head() const
83+
const HeadPoseT& HeadTracker::Impl::get_head() const
8484
{
8585
return head_;
8686
}
@@ -104,9 +104,9 @@ std::vector<std::string> HeadTracker::get_required_extensions() const
104104
return {};
105105
}
106106

107-
const HeadPose& HeadTracker::get_head() const
107+
const HeadPoseT& HeadTracker::get_head() const
108108
{
109-
static const HeadPose empty_pose{};
109+
static const HeadPoseT empty_pose{};
110110
auto impl = cached_impl_.lock();
111111
if (!impl)
112112
return empty_pose;

0 commit comments

Comments
 (0)