blob: de1b95154826c1b0362bb3ac7181aea445ebe480 [file] [log] [blame]
#include <log/log.h>
#include <private/dvr/linear_pose_predictor.h>
namespace android {
namespace dvr {
using AngleAxisd = Eigen::AngleAxis<double>;
void LinearPosePredictor::Add(const Sample& sample, DvrPoseAsync* out_pose) {
// If we are receiving a new sample, move the index to the next item.
// If the time stamp is the same as the last frame, we will just overwrite
// it with the new data.
if (sample.time_ns != samples_[current_index_].time_ns) {
current_index_ ^= 1;
}
// Save the sample.
samples_[current_index_] = sample;
// The previous sample we received.
const auto& previous_sample = samples_[current_index_ ^ 1];
// Ready to compute velocities.
const auto pose_delta_time =
NsToSeconds(sample.time_ns - previous_sample.time_ns);
const double inverse_dt = 1. / pose_delta_time;
if (pose_delta_time > 0.0) {
velocity_ = (sample.position - previous_sample.position) * inverse_dt;
} else {
velocity_ = vec3d::Zero();
}
quatd delta_q = sample.orientation.inverse() * previous_sample.orientation;
// Check that delta_q.w() == 1, Eigen doesn't respect this convention. If
// delta_q.w() == -1, we'll get the opposite velocity.
if (delta_q.w() < 0) {
delta_q.w() = -delta_q.w();
delta_q.vec() = -delta_q.vec();
}
rotational_velocity_ = -2.0 * delta_q.vec() * inverse_dt;
// Temporary experiment with acceleration estimate.
angular_speed_ = rotational_velocity_.norm();
angular_accel_ = 0.0;
if (forward_predict_angular_speed_) {
angular_accel_ =
pose_delta_time > 0.0
? (angular_speed_ - last_angular_speed_) / pose_delta_time
: 0.0;
}
last_angular_speed_ = angular_speed_;
rotational_axis_ = vec3d(0.0, 1.0, 0.0);
if (angular_speed_ > 0.0) {
rotational_axis_ = rotational_velocity_ / angular_speed_;
}
out_pose->orientation = {static_cast<float>(sample.orientation.vec().x()),
static_cast<float>(sample.orientation.vec().y()),
static_cast<float>(sample.orientation.vec().z()),
static_cast<float>(sample.orientation.w())};
out_pose->translation = {static_cast<float>(sample.position.x()),
static_cast<float>(sample.position.y()),
static_cast<float>(sample.position.z()), 0.0f};
out_pose->right_orientation = {
static_cast<float>(sample.orientation.vec().x()),
static_cast<float>(sample.orientation.vec().y()),
static_cast<float>(sample.orientation.vec().z()),
static_cast<float>(sample.orientation.w())};
out_pose->right_translation = {static_cast<float>(sample.position.x()),
static_cast<float>(sample.position.y()),
static_cast<float>(sample.position.z()), 0.0f};
out_pose->angular_velocity = {static_cast<float>(rotational_velocity_.x()),
static_cast<float>(rotational_velocity_.y()),
static_cast<float>(rotational_velocity_.z()),
0.0f};
out_pose->velocity = {static_cast<float>(velocity_.x()),
static_cast<float>(velocity_.y()),
static_cast<float>(velocity_.z()), 0.0f};
out_pose->timestamp_ns = sample.time_ns;
out_pose->flags = DVR_POSE_FLAG_HEAD | DVR_POSE_FLAG_VALID;
memset(out_pose->pad, 0, sizeof(out_pose->pad));
}
void LinearPosePredictor::Predict(int64_t left_time_ns, int64_t right_time_ns,
DvrPoseAsync* out_pose) const {
const auto& sample = samples_[current_index_];
double dt = NsToSeconds(left_time_ns - sample.time_ns);
double r_dt = NsToSeconds(right_time_ns - sample.time_ns);
// Temporary forward prediction code.
auto start_t_head_future = sample.position + velocity_ * dt;
auto r_start_t_head_future = sample.position + velocity_ * r_dt;
double angle = angular_speed_ * dt;
double r_angle = angular_speed_ * r_dt;
if (__builtin_expect(forward_predict_angular_speed_, 0)) {
angle += 0.5 * angular_accel_ * dt * dt;
r_angle += 0.5 * angular_accel_ * r_dt * r_dt;
}
auto start_q_head_future =
sample.orientation * quatd(AngleAxisd(angle, rotational_axis_));
auto r_start_q_head_future =
sample.orientation * quatd(AngleAxisd(r_angle, rotational_axis_));
out_pose->orientation = {static_cast<float>(start_q_head_future.x()),
static_cast<float>(start_q_head_future.y()),
static_cast<float>(start_q_head_future.z()),
static_cast<float>(start_q_head_future.w())};
out_pose->translation = {static_cast<float>(start_t_head_future.x()),
static_cast<float>(start_t_head_future.y()),
static_cast<float>(start_t_head_future.z()), 0.0f};
out_pose->right_orientation = {static_cast<float>(r_start_q_head_future.x()),
static_cast<float>(r_start_q_head_future.y()),
static_cast<float>(r_start_q_head_future.z()),
static_cast<float>(r_start_q_head_future.w())};
out_pose->right_translation = {static_cast<float>(r_start_t_head_future.x()),
static_cast<float>(r_start_t_head_future.y()),
static_cast<float>(r_start_t_head_future.z()),
0.0f};
out_pose->angular_velocity = {static_cast<float>(rotational_velocity_.x()),
static_cast<float>(rotational_velocity_.y()),
static_cast<float>(rotational_velocity_.z()),
0.0f};
out_pose->velocity = {static_cast<float>(velocity_.x()),
static_cast<float>(velocity_.y()),
static_cast<float>(velocity_.z()), 0.0f};
out_pose->timestamp_ns = left_time_ns;
out_pose->flags = DVR_POSE_FLAG_HEAD | DVR_POSE_FLAG_VALID;
memset(out_pose->pad, 0, sizeof(out_pose->pad));
}
} // namespace dvr
} // namespace android