StaticInitializer.cpp
Go to the documentation of this file.
1 /*
2  * OpenVINS: An Open Platform for Visual-Inertial Research
3  * Copyright (C) 2018-2023 Patrick Geneva
4  * Copyright (C) 2018-2023 Guoquan Huang
5  * Copyright (C) 2018-2023 OpenVINS Contributors
6  * Copyright (C) 2018-2019 Kevin Eckenhoff
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "StaticInitializer.h"
23 
24 #include "utils/helper.h"
25 
26 #include "feat/FeatureHelper.h"
27 #include "types/IMU.h"
28 #include "utils/colors.h"
29 #include "utils/print.h"
30 #include "utils/quat_ops.h"
31 #include "utils/sensor_data.h"
32 
33 using namespace ov_core;
34 using namespace ov_type;
35 using namespace ov_init;
36 
37 bool StaticInitializer::initialize(double &timestamp, Eigen::MatrixXd &covariance, std::vector<std::shared_ptr<Type>> &order,
38  std::shared_ptr<IMU> t_imu, bool wait_for_jerk) {
39 
40  // Return if we don't have any measurements
41  if (imu_data->size() < 2) {
42  return false;
43  }
44 
45  // Newest and oldest imu timestamp
46  double newesttime = imu_data->at(imu_data->size() - 1).timestamp;
47  double oldesttime = imu_data->at(0).timestamp;
48 
49  // Return if we don't have enough for two windows
50  if (newesttime - oldesttime < params.init_window_time) {
51  PRINT_INFO(YELLOW "[init-s]: unable to select window of IMU readings, not enough readings\n" RESET);
52  return false;
53  }
54 
55  // First lets collect a window of IMU readings from the newest measurement to the oldest
56  std::vector<ImuData> window_1to0, window_2to1;
57  for (const ImuData &data : *imu_data) {
58  if (data.timestamp > newesttime - 0.5 * params.init_window_time && data.timestamp <= newesttime - 0.0 * params.init_window_time) {
59  window_1to0.push_back(data);
60  }
61  if (data.timestamp > newesttime - 1.0 * params.init_window_time && data.timestamp <= newesttime - 0.5 * params.init_window_time) {
62  window_2to1.push_back(data);
63  }
64  }
65 
66  // Return if both of these failed
67  if (window_1to0.size() < 2 || window_2to1.size() < 2) {
68  PRINT_INFO(YELLOW "[init-s]: unable to select window of IMU readings, not enough readings\n" RESET);
69  return false;
70  }
71 
72  // Calculate the sample variance for the newest window from 1 to 0
73  Eigen::Vector3d a_avg_1to0 = Eigen::Vector3d::Zero();
74  for (const ImuData &data : window_1to0) {
75  a_avg_1to0 += data.am;
76  }
77  a_avg_1to0 /= (int)window_1to0.size();
78  double a_var_1to0 = 0;
79  for (const ImuData &data : window_1to0) {
80  a_var_1to0 += (data.am - a_avg_1to0).dot(data.am - a_avg_1to0);
81  }
82  a_var_1to0 = std::sqrt(a_var_1to0 / ((int)window_1to0.size() - 1));
83 
84  // Calculate the sample variance for the second newest window from 2 to 1
85  Eigen::Vector3d a_avg_2to1 = Eigen::Vector3d::Zero();
86  Eigen::Vector3d w_avg_2to1 = Eigen::Vector3d::Zero();
87  for (const ImuData &data : window_2to1) {
88  a_avg_2to1 += data.am;
89  w_avg_2to1 += data.wm;
90  }
91  a_avg_2to1 = a_avg_2to1 / window_2to1.size();
92  w_avg_2to1 = w_avg_2to1 / window_2to1.size();
93  double a_var_2to1 = 0;
94  for (const ImuData &data : window_2to1) {
95  a_var_2to1 += (data.am - a_avg_2to1).dot(data.am - a_avg_2to1);
96  }
97  a_var_2to1 = std::sqrt(a_var_2to1 / ((int)window_2to1.size() - 1));
98  PRINT_DEBUG(YELLOW "[init-s]: IMU excitation stats: %.3f,%.3f\n" RESET, a_var_2to1, a_var_1to0);
99 
100  // If it is below the threshold and we want to wait till we detect a jerk
101  if (a_var_1to0 < params.init_imu_thresh && wait_for_jerk) {
102  PRINT_INFO(YELLOW "[init-s]: no IMU excitation, below threshold %.3f < %.3f\n" RESET, a_var_1to0, params.init_imu_thresh);
103  return false;
104  }
105 
106  // We should also check that the old state was below the threshold!
107  // This is the case when we have started up moving, and thus we need to wait for a period of stationary motion
108  if (a_var_2to1 > params.init_imu_thresh && wait_for_jerk) {
109  PRINT_INFO(YELLOW "[init-s]: to much IMU excitation, above threshold %.3f > %.3f\n" RESET, a_var_2to1, params.init_imu_thresh);
110  return false;
111  }
112 
113  // If it is above the threshold and we are not waiting for a jerk
114  // Then we are not stationary (i.e. moving) so we should wait till we are
115  if ((a_var_1to0 > params.init_imu_thresh || a_var_2to1 > params.init_imu_thresh) && !wait_for_jerk) {
116  PRINT_INFO(YELLOW "[init-s]: to much IMU excitation, above threshold %.3f,%.3f > %.3f\n" RESET, a_var_2to1, a_var_1to0,
117  params.init_imu_thresh);
118  return false;
119  }
120 
121  // Get rotation with z axis aligned with -g (z_in_G=0,0,1)
122  Eigen::Vector3d z_axis = a_avg_2to1 / a_avg_2to1.norm();
123  Eigen::Matrix3d Ro;
124  InitializerHelper::gram_schmidt(z_axis, Ro);
125  Eigen::Vector4d q_GtoI = rot_2_quat(Ro);
126 
127  // Set our biases equal to our noise (subtract our gravity from accelerometer bias)
128  Eigen::Vector3d gravity_inG;
129  gravity_inG << 0.0, 0.0, params.gravity_mag;
130  Eigen::Vector3d bg = w_avg_2to1;
131  Eigen::Vector3d ba = a_avg_2to1 - quat_2_Rot(q_GtoI) * gravity_inG;
132 
133  // Set our state variables
134  timestamp = window_2to1.at(window_2to1.size() - 1).timestamp;
135  Eigen::VectorXd imu_state = Eigen::VectorXd::Zero(16);
136  imu_state.block(0, 0, 4, 1) = q_GtoI;
137  imu_state.block(10, 0, 3, 1) = bg;
138  imu_state.block(13, 0, 3, 1) = ba;
139  assert(t_imu != nullptr);
140  t_imu->set_value(imu_state);
141  t_imu->set_fej(imu_state);
142 
143  // Create base covariance and its covariance ordering
144  order.clear();
145  order.push_back(t_imu);
146  covariance = std::pow(0.02, 2) * Eigen::MatrixXd::Identity(t_imu->size(), t_imu->size());
147  covariance.block(0, 0, 3, 3) = std::pow(0.02, 2) * Eigen::Matrix3d::Identity(); // q
148  covariance.block(3, 3, 3, 3) = std::pow(0.05, 2) * Eigen::Matrix3d::Identity(); // p
149  covariance.block(6, 6, 3, 3) = std::pow(0.01, 2) * Eigen::Matrix3d::Identity(); // v (static)
150 
151  // A VIO system has 4dof unobservable directions which can be arbitrarily picked.
152  // This means that on startup, we can fix the yaw and position to be 100 percent known.
153  // TODO: why can't we set these to zero and get a good NEES realworld result?
154  // Thus, after determining the global to current IMU orientation after initialization, we can propagate the global error
155  // into the new IMU pose. In this case the position is directly equivalent, but the orientation needs to be propagated.
156  // We propagate the global orientation into the current local IMU frame
157  // R_GtoI = R_GtoI*R_GtoG -> H = R_GtoI
158  // Eigen::Matrix3d R_GtoI = quat_2_Rot(q_GtoI);
159  // covariance(2, 2) = std::pow(1e-4, 2);
160  // covariance.block(0, 0, 3, 3) = R_GtoI * covariance.block(0, 0, 3, 3) * R_GtoI.transpose();
161  // covariance.block(3, 3, 3, 3) = std::pow(1e-3, 2) * Eigen::Matrix3d::Identity();
162 
163  // Return :D
164  return true;
165 }
quat_ops.h
IMU.h
YELLOW
YELLOW
PRINT_DEBUG
#define PRINT_DEBUG(x...)
sensor_data.h
FeatureHelper.h
ov_init
State initialization code.
Definition: Factor_GenericPrior.h:27
ov_core::ImuData
ov_core::rot_2_quat
Eigen::Matrix< double, 4, 1 > rot_2_quat(const Eigen::Matrix< double, 3, 3 > &rot)
ov_core::quat_2_Rot
Eigen::Matrix< double, 3, 3 > quat_2_Rot(const Eigen::Matrix< double, 4, 1 > &q)
print.h
colors.h
PRINT_INFO
#define PRINT_INFO(x...)
ov_type
RESET
#define RESET
helper.h
ov_core
StaticInitializer.h


ov_init
Author(s): Patrick Geneva , Kevin Eckenhoff , Guoquan Huang
autogenerated on Mon Dec 16 2024 03:06:51