Skip to content

Commit 7fd2cb2

Browse files
committed
Stabilize recentering with marker pose average
1 parent cb44823 commit 7fd2cb2

3 files changed

Lines changed: 100 additions & 26 deletions

File tree

alvr/client_openxr/src/extra_extensions/spatial_marker_tracking.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ impl QRCodesSpatialContext {
132132
let new = Instant::now();
133133

134134
if self.snapshot_future.is_none()
135-
//&& self.discovery_enabled.value()
135+
&& self.discovery_enabled.value()
136136
&& new > self.discovery_timeout_deadline
137137
{
138138
let snapshot_create_info = sys::SpatialDiscoverySnapshotCreateInfoEXT {
@@ -244,13 +244,12 @@ impl QRCodesSpatialContext {
244244

245245
let mut out_markers = vec![];
246246
for idx in 0..query_result.entity_id_count_output as usize {
247-
alvr_common::error!("Parsing marker");
248247
if self.entity_states[idx] != sys::SpatialEntityTrackingStateEXT::TRACKING
249248
|| self.marker_arr[idx].capability != CAPABILITY
250249
|| self.marker_arr[idx].data.buffer_id == sys::SpatialBufferIdEXT::NULL
251250
|| self.marker_arr[idx].data.buffer_type != sys::SpatialBufferTypeEXT::STRING
252251
{
253-
alvr_common::error!(
252+
alvr_common::debug!(
254253
"Parsing marker failed! {:?} {:?} {:?} {:?}",
255254
self.entity_states[idx],
256255
self.marker_arr[idx].capability,

alvr/common/src/average.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use glam::Vec2;
12
use std::{collections::VecDeque, time::Duration};
23

34
pub struct SlidingWindowAverage<T> {
@@ -38,3 +39,40 @@ impl SlidingWindowAverage<Duration> {
3839
self.history_buffer.iter().sum::<Duration>() / self.history_buffer.len() as u32
3940
}
4041
}
42+
43+
impl SlidingWindowAverage<Vec2> {
44+
pub fn get_average(&self) -> Vec2 {
45+
self.history_buffer.iter().sum::<Vec2>() / self.history_buffer.len() as f32
46+
}
47+
}
48+
49+
pub struct AngleSlidingWindowAverage {
50+
history_buffer: VecDeque<Vec2>,
51+
max_history_size: usize,
52+
}
53+
54+
impl AngleSlidingWindowAverage {
55+
pub fn new(initial_value: f32, max_history_size: usize) -> Self {
56+
Self {
57+
history_buffer: [Vec2::from_angle(initial_value)].into_iter().collect(),
58+
max_history_size,
59+
}
60+
}
61+
62+
pub fn submit_sample(&mut self, sample: f32) {
63+
if self.history_buffer.len() >= self.max_history_size {
64+
self.history_buffer.pop_front();
65+
}
66+
67+
self.history_buffer.push_back(Vec2::from_angle(sample));
68+
}
69+
70+
pub fn retain(&mut self, count: usize) {
71+
self.history_buffer
72+
.drain(0..self.history_buffer.len().saturating_sub(count));
73+
}
74+
75+
pub fn get_average(&self) -> f32 {
76+
self.history_buffer.iter().sum::<Vec2>().to_angle()
77+
}
78+
}

alvr/server_core/src/tracking/mod.rs

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ use crate::{
1313
input_mapping::ButtonMappingManager,
1414
};
1515
use alvr_common::{
16-
BODY_CHEST_ID, BODY_HIPS_ID, BODY_LEFT_ELBOW_ID, BODY_LEFT_FOOT_ID, BODY_LEFT_KNEE_ID,
17-
BODY_RIGHT_ELBOW_ID, BODY_RIGHT_FOOT_ID, BODY_RIGHT_KNEE_ID, ConnectionError,
18-
DEVICE_ID_TO_PATH, DeviceMotion, HAND_LEFT_ID, HAND_RIGHT_ID, HEAD_ID, Pose, ViewParams,
16+
AngleSlidingWindowAverage, BODY_CHEST_ID, BODY_HIPS_ID, BODY_LEFT_ELBOW_ID, BODY_LEFT_FOOT_ID,
17+
BODY_LEFT_KNEE_ID, BODY_RIGHT_ELBOW_ID, BODY_RIGHT_FOOT_ID, BODY_RIGHT_KNEE_ID,
18+
ConnectionError, DEVICE_ID_TO_PATH, DeviceMotion, HAND_LEFT_ID, HAND_RIGHT_ID, HEAD_ID, Pose,
19+
SlidingWindowAverage, ViewParams,
1920
glam::{Quat, Vec2, Vec3},
2021
parking_lot::Mutex,
2122
};
@@ -42,6 +43,12 @@ pub enum HandType {
4243
Right = 1,
4344
}
4445

46+
struct RecenteringMarker {
47+
string: String,
48+
average_angle: AngleSlidingWindowAverage,
49+
average_position: SlidingWindowAverage<Vec2>,
50+
}
51+
4552
// todo: Move this struct to Settings and use it for every tracked device
4653
#[derive(Default)]
4754
struct MotionConfig {
@@ -55,6 +62,7 @@ pub struct TrackingManager {
5562
last_head_pose: Pose, // client's reference space
5663
inverse_recentering_origin: Pose, // client's reference space
5764
device_motions_history: HashMap<u64, VecDeque<(Duration, DeviceMotion)>>,
65+
recentering_marker: Option<RecenteringMarker>,
5866
markers: HashMap<String, Pose>,
5967
hand_skeletons_history: [VecDeque<(Duration, [Pose; 26])>; 2],
6068
max_history_size: usize,
@@ -66,6 +74,7 @@ impl TrackingManager {
6674
last_head_pose: Pose::IDENTITY,
6775
inverse_recentering_origin: Pose::IDENTITY,
6876
device_motions_history: HashMap::new(),
77+
recentering_marker: None,
6978
markers: HashMap::new(),
7079
hand_skeletons_history: [VecDeque::new(), VecDeque::new()],
7180
max_history_size,
@@ -84,35 +93,61 @@ impl TrackingManager {
8493
let marker_z_axis = marker_pose.orientation * Vec3::Z;
8594
let angle_from_y = Vec3::angle_between(marker_z_axis, Vec3::Y);
8695

87-
let orientation = if (angle_from_y - FRAC_PI_2).abs() < FRAC_PI_4 {
96+
let marker_y_angle = if (angle_from_y - FRAC_PI_2).abs() < FRAC_PI_4 {
8897
// The marker is vertical
89-
let y_angle = Vec2::new(marker_z_axis.x, marker_z_axis.z)
98+
Vec2::new(marker_z_axis.x, marker_z_axis.z)
9099
.normalize()
91-
.angle_to(Vec2::Y); // (this Y is on the XZ plane -> Z)
92-
Quat::from_rotation_y(y_angle)
100+
.angle_to(Vec2::Y) // (this Y is on the XZ plane -> Z)
93101
} else {
94102
let marker_x_axis = marker_pose.orientation * Vec3::X;
95-
let y_angle = Vec2::new(marker_x_axis.x, marker_x_axis.z)
103+
Vec2::new(marker_x_axis.x, marker_x_axis.z)
96104
.normalize()
97-
.angle_to(Vec2::X);
98-
Quat::from_rotation_y(y_angle)
105+
.angle_to(Vec2::X)
106+
};
107+
let marker_floor_position =
108+
Vec2::new(marker_pose.position.x, marker_pose.position.z);
109+
110+
self.recentering_marker
111+
.take_if(|rm| rm.string != colocation_config.qr_code_string);
112+
let recentering_marker = if let Some(rm) = &mut self.recentering_marker {
113+
rm.average_angle.submit_sample(marker_y_angle);
114+
rm.average_position.submit_sample(marker_floor_position);
115+
rm
116+
} else {
117+
self.recentering_marker.insert(RecenteringMarker {
118+
string: colocation_config.qr_code_string.clone(),
119+
average_angle: AngleSlidingWindowAverage::new(
120+
marker_y_angle,
121+
self.max_history_size,
122+
),
123+
average_position: SlidingWindowAverage::new(
124+
marker_floor_position,
125+
self.max_history_size,
126+
),
127+
})
99128
};
100129

130+
let average_angle =
131+
Quat::from_rotation_y(recentering_marker.average_angle.get_average());
101132
let position = {
102-
let marker_offset_2d = Vec3::new(
133+
let marker_offset_2d = Vec2::new(
103134
colocation_config.floor_offset[0],
104-
0.0,
105135
colocation_config.floor_offset[1],
106136
);
107-
let marker_position_2d =
108-
Vec3::new(marker_pose.position.x, 0.0, marker_pose.position.z);
109137

110-
marker_position_2d - marker_offset_2d
138+
let offset_2d = recentering_marker.average_position.get_average()
139+
- marker_offset_2d;
140+
Vec3::new(offset_2d.x, 0.0, offset_2d.y)
111141
};
142+
alvr_common::debug!(
143+
"Recentering from marker. Angle: {average_angle}, Position: {position}"
144+
);
112145

113146
Pose {
114147
position,
115-
orientation,
148+
orientation: Quat::from_rotation_y(
149+
recentering_marker.average_angle.get_average(),
150+
),
116151
}
117152
} else {
118153
// In case the marker is not found, abort recentering, we still want to use
@@ -432,13 +467,15 @@ pub fn tracking_loop(
432467
&tracking.device_motions,
433468
);
434469

435-
tracking_manager_lock.report_markers(tracking.markers);
436-
if matches!(
437-
headset_config.recentering_mode,
438-
RecenteringMode::Stage { .. }
439-
) {
440-
tracking_manager_lock.recenter(&headset_config.recentering_mode);
441-
};
470+
if !tracking.markers.is_empty() {
471+
tracking_manager_lock.report_markers(tracking.markers);
472+
if matches!(
473+
headset_config.recentering_mode,
474+
RecenteringMode::Stage { .. }
475+
) {
476+
tracking_manager_lock.recenter(&headset_config.recentering_mode);
477+
};
478+
}
442479

443480
if let Some(skeleton) = tracking.hand_skeletons[0] {
444481
tracking_manager_lock.report_hand_skeleton(HandType::Left, timestamp, skeleton);

0 commit comments

Comments
 (0)