blob: 80a3d29f0d149961b0b6d1f12c4d415f81629841 [file] [log] [blame]
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -07001/*
2 * Copyright 2021, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "SpatializerPoseController.h"
17
Ytai Ben-Tsvie9b34952021-09-10 12:48:27 -070018#define LOG_TAG "SpatializerPoseController"
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070019//#define LOG_NDEBUG 0
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -070020#include <sensor/Sensor.h>
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070021#include <utils/Log.h>
22#include <utils/SystemClock.h>
23
24namespace android {
25
26using media::createHeadTrackingProcessor;
27using media::HeadTrackingMode;
28using media::HeadTrackingProcessor;
29using media::Pose3f;
30using media::SensorPoseProvider;
31using media::Twist3f;
32
33using namespace std::chrono_literals;
34
35namespace {
36
37// This is how fast, in m/s, we allow position to shift during rate-limiting.
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -070038constexpr auto kMaxTranslationalVelocity = 2;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070039
40// This is how fast, in rad/s, we allow rotation angle to shift during rate-limiting.
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -070041constexpr auto kMaxRotationalVelocity = 4 * M_PI;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070042
43// This should be set to the typical time scale that the translation sensors used drift in. This
44// means, loosely, for how long we can trust the reading to be "accurate enough". This would
45// determine the time constants used for high-pass filtering those readings. If the value is set
46// too high, we may experience drift. If it is set too low, we may experience poses tending toward
47// identity too fast.
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080048constexpr auto kTranslationalDriftTimeConstant = 40s;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070049
50// This should be set to the typical time scale that the rotation sensors used drift in. This
51// means, loosely, for how long we can trust the reading to be "accurate enough". This would
52// determine the time constants used for high-pass filtering those readings. If the value is set
53// too high, we may experience drift. If it is set too low, we may experience poses tending toward
54// identity too fast.
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080055constexpr auto kRotationalDriftTimeConstant = 60s;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070056
57// This is how far into the future we predict the head pose, using linear extrapolation based on
58// twist (velocity). It should be set to a value that matches the characteristic durations of moving
59// one's head. The higher we set this, the more latency we are able to reduce, but setting this too
60// high will result in high prediction errors whenever the head accelerates (changes velocity).
61constexpr auto kPredictionDuration = 10ms;
62
63// After losing this many consecutive samples from either sensor, we would treat the measurement as
64// stale;
65constexpr auto kMaxLostSamples = 4;
66
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080067// Auto-recenter kicks in after the head has been still for this long.
68constexpr auto kAutoRecenterWindowDuration = 10s;
69
70// Auto-recenter considers head not still if translated by this much (in meters, approx).
71constexpr float kAutoRecenterTranslationThreshold = 0.1f;
72
73// Auto-recenter considers head not still if rotated by this much (in radians, approx).
74constexpr float kAutoRecenterRotationThreshold = 5.0f / 180 * M_PI;
75
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080076// Screen is considered to be unstable (not still) if it has moved significantly within the last
77// time window of this duration.
78constexpr auto kScreenStillnessWindowDuration = 10s;
79
80// Screen is considered to have moved significantly if translated by this much (in meter, approx).
81constexpr float kScreenStillnessTranslationThreshold = 0.1f;
82
83// Screen is considered to have moved significantly if rotated by this much (in radians, approx).
84constexpr float kScreenStillnessRotationThreshold = 5.0f / 180 * M_PI;
85
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070086// Time units for system clock ticks. This is what the Sensor Framework timestamps represent and
87// what we use for pose filtering.
88using Ticks = std::chrono::nanoseconds;
89
90// How many ticks in a second.
91constexpr auto kTicksPerSecond = Ticks::period::den;
92
93} // namespace
94
95SpatializerPoseController::SpatializerPoseController(Listener* listener,
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -070096 std::chrono::microseconds sensorPeriod,
97 std::chrono::microseconds maxUpdatePeriod)
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070098 : mListener(listener),
99 mSensorPeriod(sensorPeriod),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700100 mProcessor(createHeadTrackingProcessor(HeadTrackingProcessor::Options{
101 .maxTranslationalVelocity = kMaxTranslationalVelocity / kTicksPerSecond,
102 .maxRotationalVelocity = kMaxRotationalVelocity / kTicksPerSecond,
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -0800103 .translationalDriftTimeConstant =
104 double(Ticks(kTranslationalDriftTimeConstant).count()),
105 .rotationalDriftTimeConstant = double(Ticks(kRotationalDriftTimeConstant).count()),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700106 .freshnessTimeout = Ticks(sensorPeriod * kMaxLostSamples).count(),
107 .predictionDuration = Ticks(kPredictionDuration).count(),
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800108 .autoRecenterWindowDuration = Ticks(kAutoRecenterWindowDuration).count(),
109 .autoRecenterTranslationalThreshold = kAutoRecenterTranslationThreshold,
110 .autoRecenterRotationalThreshold = kAutoRecenterRotationThreshold,
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -0800111 .screenStillnessWindowDuration = Ticks(kScreenStillnessWindowDuration).count(),
112 .screenStillnessTranslationalThreshold = kScreenStillnessTranslationThreshold,
113 .screenStillnessRotationalThreshold = kScreenStillnessRotationThreshold,
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700114 })),
Ytai Ben-Tsvi8b6fe3a2021-09-13 15:55:44 -0700115 mPoseProvider(SensorPoseProvider::create("headtracker", this)),
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700116 mThread([this, maxUpdatePeriod] {
117 while (true) {
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700118 Pose3f headToStage;
119 std::optional<HeadTrackingMode> modeIfChanged;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700120 {
121 std::unique_lock lock(mMutex);
122 mCondVar.wait_for(lock, maxUpdatePeriod,
123 [this] { return mShouldExit || mShouldCalculate; });
124 if (mShouldExit) {
125 ALOGV("Exiting thread");
126 return;
127 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700128
129 // Calculate.
130 std::tie(headToStage, modeIfChanged) = calculate_l();
131 }
132
133 // Invoke the callbacks outside the lock.
134 mListener->onHeadToStagePose(headToStage);
135 if (modeIfChanged) {
136 mListener->onActualModeChange(modeIfChanged.value());
137 }
138
139 {
140 std::lock_guard lock(mMutex);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700141 if (!mCalculated) {
142 mCalculated = true;
143 mCondVar.notify_all();
144 }
145 mShouldCalculate = false;
146 }
147 }
148 }) {}
149
150SpatializerPoseController::~SpatializerPoseController() {
151 {
152 std::unique_lock lock(mMutex);
153 mShouldExit = true;
154 mCondVar.notify_all();
155 }
156 mThread.join();
157}
158
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700159void SpatializerPoseController::setHeadSensor(int32_t sensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700160 std::lock_guard lock(mMutex);
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700161 // Stop current sensor, if valid and different from the other sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700162 if (mHeadSensor != INVALID_SENSOR && mHeadSensor != mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700163 mPoseProvider->stopSensor(mHeadSensor);
164 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700165
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700166 if (sensor != INVALID_SENSOR) {
167 if (sensor != mScreenSensor) {
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700168 // Start new sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700169 mHeadSensor =
170 mPoseProvider->startSensor(sensor, mSensorPeriod) ? sensor : INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700171 } else {
172 // Sensor is already enabled.
173 mHeadSensor = mScreenSensor;
174 }
175 } else {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700176 mHeadSensor = INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700177 }
178
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700179 mProcessor->recenter(true, false);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700180}
181
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700182void SpatializerPoseController::setScreenSensor(int32_t sensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700183 std::lock_guard lock(mMutex);
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700184 // Stop current sensor, if valid and different from the other sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700185 if (mScreenSensor != INVALID_SENSOR && mScreenSensor != mHeadSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700186 mPoseProvider->stopSensor(mScreenSensor);
187 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700188
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700189 if (sensor != INVALID_SENSOR) {
190 if (sensor != mHeadSensor) {
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700191 // Start new sensor.
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700192 mScreenSensor =
193 mPoseProvider->startSensor(sensor, mSensorPeriod) ? sensor : INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700194 } else {
195 // Sensor is already enabled.
196 mScreenSensor = mHeadSensor;
197 }
198 } else {
Ytai Ben-Tsvi9f12f172021-09-23 16:47:25 -0700199 mScreenSensor = INVALID_SENSOR;
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700200 }
201
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700202 mProcessor->recenter(false, true);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700203}
204
205void SpatializerPoseController::setDesiredMode(HeadTrackingMode mode) {
206 std::lock_guard lock(mMutex);
207 mProcessor->setDesiredMode(mode);
208}
209
210void SpatializerPoseController::setScreenToStagePose(const Pose3f& screenToStage) {
211 std::lock_guard lock(mMutex);
212 mProcessor->setScreenToStagePose(screenToStage);
213}
214
215void SpatializerPoseController::setDisplayOrientation(float physicalToLogicalAngle) {
216 std::lock_guard lock(mMutex);
217 mProcessor->setDisplayOrientation(physicalToLogicalAngle);
218}
219
220void SpatializerPoseController::calculateAsync() {
221 std::lock_guard lock(mMutex);
222 mShouldCalculate = true;
223 mCondVar.notify_all();
224}
225
226void SpatializerPoseController::waitUntilCalculated() {
227 std::unique_lock lock(mMutex);
228 mCondVar.wait(lock, [this] { return mCalculated; });
229}
230
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700231std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>>
232SpatializerPoseController::calculate_l() {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700233 Pose3f headToStage;
234 HeadTrackingMode mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700235 std::optional<media::HeadTrackingMode> modeIfChanged;
236
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700237 mProcessor->calculate(elapsedRealtimeNano());
238 headToStage = mProcessor->getHeadToStagePose();
239 mode = mProcessor->getActualMode();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700240 if (!mActualMode.has_value() || mActualMode.value() != mode) {
241 mActualMode = mode;
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700242 modeIfChanged = mode;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700243 }
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700244 return std::make_tuple(headToStage, modeIfChanged);
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700245}
246
247void SpatializerPoseController::recenter() {
248 std::lock_guard lock(mMutex);
249 mProcessor->recenter();
250}
251
252void SpatializerPoseController::onPose(int64_t timestamp, int32_t sensor, const Pose3f& pose,
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700253 const std::optional<Twist3f>& twist, bool isNewReference) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700254 std::lock_guard lock(mMutex);
255 if (sensor == mHeadSensor) {
256 mProcessor->setWorldToHeadPose(timestamp, pose, twist.value_or(Twist3f()));
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700257 if (isNewReference) {
258 mProcessor->recenter(true, false);
259 }
Ytai Ben-Tsvi9bae7422021-08-27 16:13:19 -0700260 }
261 if (sensor == mScreenSensor) {
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700262 mProcessor->setWorldToScreenPose(timestamp, pose);
Ytai Ben-Tsvi2c694be2021-10-06 17:12:49 -0700263 if (isNewReference) {
264 mProcessor->recenter(false, true);
265 }
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700266 }
267}
268
269} // namespace android