40 void VioManager::initialize_with_gt(Eigen::Matrix<double, 17, 1> imustate) {
43 state->_imu->set_value(imustate.block(1, 0, 16, 1));
44 state->_imu->set_fej(imustate.block(1, 0, 16, 1));
48 std::vector<std::shared_ptr<ov_type::Type>> order = {state->_imu};
49 Eigen::MatrixXd Cov = std::pow(0.02, 2) * Eigen::MatrixXd::Identity(state->_imu->size(), state->_imu->size());
50 Cov.block(0, 0, 3, 3) = std::pow(0.017, 2) * Eigen::Matrix3d::Identity();
51 Cov.block(3, 3, 3, 3) = std::pow(0.05, 2) * Eigen::Matrix3d::Identity();
52 Cov.block(6, 6, 3, 3) = std::pow(0.01, 2) * Eigen::Matrix3d::Identity();
53 StateHelper::set_initial_covariance(state, Cov, order);
56 state->_timestamp = imustate(0, 0);
57 startup_time = imustate(0, 0);
58 is_initialized_vio =
true;
61 trackFEATS->get_feature_database()->cleanup_measurements(state->_timestamp);
62 if (trackARUCO !=
nullptr) {
63 trackARUCO->get_feature_database()->cleanup_measurements(state->_timestamp);
68 PRINT_DEBUG(
GREEN "[INIT]: orientation = %.4f, %.4f, %.4f, %.4f\n" RESET, state->_imu->quat()(0), state->_imu->quat()(1),
69 state->_imu->quat()(2), state->_imu->quat()(3));
70 PRINT_DEBUG(
GREEN "[INIT]: bias gyro = %.4f, %.4f, %.4f\n" RESET, state->_imu->bias_g()(0), state->_imu->bias_g()(1),
71 state->_imu->bias_g()(2));
72 PRINT_DEBUG(
GREEN "[INIT]: velocity = %.4f, %.4f, %.4f\n" RESET, state->_imu->vel()(0), state->_imu->vel()(1), state->_imu->vel()(2));
73 PRINT_DEBUG(
GREEN "[INIT]: bias accel = %.4f, %.4f, %.4f\n" RESET, state->_imu->bias_a()(0), state->_imu->bias_a()(1),
74 state->_imu->bias_a()(2));
75 PRINT_DEBUG(
GREEN "[INIT]: position = %.4f, %.4f, %.4f\n" RESET, state->_imu->pos()(0), state->_imu->pos()(1), state->_imu->pos()(2));
83 if (thread_init_running) {
84 std::lock_guard<std::mutex> lck(camera_queue_init_mtx);
85 camera_queue_init.push_back(message.
timestamp);
90 if (thread_init_success) {
95 thread_init_running =
true;
96 std::thread thread([&] {
99 Eigen::MatrixXd covariance;
100 std::vector<std::shared_ptr<ov_type::Type>> order;
101 auto init_rT1 = boost::posix_time::microsec_clock::local_time();
106 bool wait_for_jerk = (updaterZUPT ==
nullptr);
107 bool success = initializer->initialize(timestamp, covariance, order, state->_imu, wait_for_jerk);
114 StateHelper::set_initial_covariance(state, covariance, order);
117 state->_timestamp = timestamp;
118 startup_time = timestamp;
123 trackFEATS->get_feature_database()->cleanup_measurements(state->_timestamp);
124 trackFEATS->set_num_features(std::floor((
double)params.num_pts / (
double)params.state_options.num_cameras));
125 if (trackARUCO !=
nullptr) {
126 trackARUCO->get_feature_database()->cleanup_measurements(state->_timestamp);
130 if (state->_imu->vel().norm() > params.zupt_max_velocity) {
131 has_moved_since_zupt =
true;
135 auto init_rT2 = boost::posix_time::microsec_clock::local_time();
136 PRINT_INFO(
GREEN "[init]: successful initialization in %.4f seconds\n" RESET, (init_rT2 - init_rT1).total_microseconds() * 1e-6);
137 PRINT_INFO(
GREEN "[init]: orientation = %.4f, %.4f, %.4f, %.4f\n" RESET, state->_imu->quat()(0), state->_imu->quat()(1),
138 state->_imu->quat()(2), state->_imu->quat()(3));
139 PRINT_INFO(
GREEN "[init]: bias gyro = %.4f, %.4f, %.4f\n" RESET, state->_imu->bias_g()(0), state->_imu->bias_g()(1),
140 state->_imu->bias_g()(2));
141 PRINT_INFO(
GREEN "[init]: velocity = %.4f, %.4f, %.4f\n" RESET, state->_imu->vel()(0), state->_imu->vel()(1), state->_imu->vel()(2));
142 PRINT_INFO(
GREEN "[init]: bias accel = %.4f, %.4f, %.4f\n" RESET, state->_imu->bias_a()(0), state->_imu->bias_a()(1),
143 state->_imu->bias_a()(2));
144 PRINT_INFO(
GREEN "[init]: position = %.4f, %.4f, %.4f\n" RESET, state->_imu->pos()(0), state->_imu->pos()(1), state->_imu->pos()(2));
148 std::lock_guard<std::mutex> lck(camera_queue_init_mtx);
149 std::vector<double> camera_timestamps_to_init;
150 for (
size_t i = 0; i < camera_queue_init.size(); i++) {
151 if (camera_queue_init.at(i) > timestamp) {
152 camera_timestamps_to_init.push_back(camera_queue_init.at(i));
159 size_t clone_rate = (size_t)((
double)camera_timestamps_to_init.size() / (double)params.state_options.max_clone_size) + 1;
160 for (
size_t i = 0; i < camera_timestamps_to_init.size(); i += clone_rate) {
161 propagator->propagate_and_clone(state, camera_timestamps_to_init.at(i));
162 StateHelper::marginalize_old_clone(state);
164 PRINT_DEBUG(
YELLOW "[init]: moved the state forward %.2f seconds\n" RESET, state->_timestamp - timestamp);
165 thread_init_success =
true;
166 camera_queue_init.clear();
169 auto init_rT2 = boost::posix_time::microsec_clock::local_time();
170 PRINT_DEBUG(
YELLOW "[init]: failed initialization in %.4f seconds\n" RESET, (init_rT2 - init_rT1).total_microseconds() * 1e-6);
171 thread_init_success =
false;
172 std::lock_guard<std::mutex> lck(camera_queue_init_mtx);
173 camera_queue_init.clear();
177 thread_init_running =
false;
182 if (!params.use_multi_threading_subs) {
193 boost::posix_time::ptime retri_rT1, retri_rT2, retri_rT3;
194 retri_rT1 = boost::posix_time::microsec_clock::local_time();
197 assert(state->_clones_IMU.find(message.
timestamp) != state->_clones_IMU.end());
199 active_image = cv::Mat();
200 trackFEATS->display_active(active_image, 255, 255, 255, 255, 255, 255,
" ");
201 if (!active_image.empty()) {
202 active_image = active_image(cv::Rect(0, 0, message.
images.at(0).cols, message.
images.at(0).rows));
204 active_tracks_posinG.clear();
205 active_tracks_uvd.clear();
209 auto last_obs = trackFEATS->get_last_obs();
210 auto last_ids = trackFEATS->get_last_ids();
213 std::map<size_t, Eigen::Matrix3d> active_feat_linsys_A_new;
214 std::map<size_t, Eigen::Vector3d> active_feat_linsys_b_new;
215 std::map<size_t, int> active_feat_linsys_count_new;
216 std::unordered_map<size_t, Eigen::Vector3d> active_tracks_posinG_new;
219 std::map<size_t, cv::Point2f> feat_uvs_in_cam0;
220 for (
auto const &cam_id : message.
sensor_ids) {
223 Eigen::Matrix3d R_GtoI = state->_clones_IMU.at(active_tracks_time)->Rot();
224 Eigen::Vector3d p_IinG = state->_clones_IMU.at(active_tracks_time)->pos();
227 Eigen::Matrix3d R_ItoC = state->_calib_IMUtoCAM.at(cam_id)->Rot();
228 Eigen::Vector3d p_IinC = state->_calib_IMUtoCAM.at(cam_id)->pos();
231 Eigen::Matrix3d R_GtoCi = R_ItoC * R_GtoI;
232 Eigen::Vector3d p_CiinG = p_IinG - R_GtoCi.transpose() * p_IinC;
235 assert(last_obs.find(cam_id) != last_obs.end());
236 assert(last_ids.find(cam_id) != last_ids.end());
237 for (
size_t i = 0; i < last_obs.at(cam_id).size(); i++) {
240 size_t featid = last_ids.at(cam_id).at(i);
241 cv::Point2f pt_d = last_obs.at(cam_id).at(i).pt;
243 feat_uvs_in_cam0[featid] = pt_d;
247 if (state->_features_SLAM.find(featid) != state->_features_SLAM.end()) {
252 cv::Point2f pt_n = state->_cam_intrinsics_cameras.at(cam_id)->undistort_cv(pt_d);
253 Eigen::Matrix<double, 3, 1> b_i;
254 b_i << pt_n.x, pt_n.y, 1;
255 b_i = R_GtoCi.transpose() * b_i;
256 b_i = b_i / b_i.norm();
257 Eigen::Matrix3d Bperp =
skew_x(b_i);
260 Eigen::Matrix3d Ai = Bperp.transpose() * Bperp;
261 Eigen::Vector3d bi = Ai * p_CiinG;
262 if (active_feat_linsys_A.find(featid) == active_feat_linsys_A.end()) {
263 active_feat_linsys_A_new.insert({featid, Ai});
264 active_feat_linsys_b_new.insert({featid, bi});
265 active_feat_linsys_count_new.insert({featid, 1});
267 active_feat_linsys_A_new[featid] = Ai + active_feat_linsys_A[featid];
268 active_feat_linsys_b_new[featid] = bi + active_feat_linsys_b[featid];
269 active_feat_linsys_count_new[featid] = 1 + active_feat_linsys_count[featid];
273 if (active_feat_linsys_count_new.at(featid) > 3) {
276 Eigen::Matrix3d A = active_feat_linsys_A_new[featid];
277 Eigen::Vector3d b = active_feat_linsys_b_new[featid];
278 Eigen::MatrixXd p_FinG = A.colPivHouseholderQr().solve(b);
279 Eigen::MatrixXd p_FinCi = R_GtoCi * (p_FinG - p_CiinG);
282 Eigen::JacobiSVD<Eigen::Matrix3d> svd(A);
283 Eigen::MatrixXd singularValues;
284 singularValues.resize(svd.singularValues().rows(), 1);
285 singularValues = svd.singularValues();
286 double condA = singularValues(0, 0) / singularValues(singularValues.rows() - 1, 0);
290 if (std::abs(condA) <= params.featinit_options.max_cond_number && p_FinCi(2, 0) >= params.featinit_options.min_dist &&
291 p_FinCi(2, 0) <= params.featinit_options.max_dist && !std::isnan(p_FinCi.norm())) {
292 active_tracks_posinG_new[featid] = p_FinG;
297 size_t total_triangulated = active_tracks_posinG.size();
300 active_feat_linsys_A = active_feat_linsys_A_new;
301 active_feat_linsys_b = active_feat_linsys_b_new;
302 active_feat_linsys_count = active_feat_linsys_count_new;
303 active_tracks_posinG = active_tracks_posinG_new;
304 retri_rT2 = boost::posix_time::microsec_clock::local_time();
307 if (active_tracks_posinG.empty() && state->_features_SLAM.empty())
311 for (
const auto &feat : state->_features_SLAM) {
312 Eigen::Vector3d p_FinG = feat.second->get_xyz(
false);
313 if (LandmarkRepresentation::is_relative_representation(feat.second->_feat_representation)) {
315 assert(feat.second->_anchor_cam_id != -1);
317 Eigen::Matrix3d R_ItoC = state->_calib_IMUtoCAM.at(feat.second->_anchor_cam_id)->Rot();
318 Eigen::Vector3d p_IinC = state->_calib_IMUtoCAM.at(feat.second->_anchor_cam_id)->pos();
320 Eigen::Matrix3d R_GtoI = state->_clones_IMU.at(feat.second->_anchor_clone_timestamp)->Rot();
321 Eigen::Vector3d p_IinG = state->_clones_IMU.at(feat.second->_anchor_clone_timestamp)->pos();
323 p_FinG = R_GtoI.transpose() * R_ItoC.transpose() * (feat.second->get_xyz(
false) - p_IinC) + p_IinG;
325 active_tracks_posinG[feat.second->_featid] = p_FinG;
329 std::shared_ptr<Vec> distortion = state->_cam_intrinsics.at(0);
330 std::shared_ptr<PoseJPL> calibration = state->_calib_IMUtoCAM.at(0);
331 Eigen::Matrix<double, 3, 3> R_ItoC = calibration->Rot();
332 Eigen::Matrix<double, 3, 1> p_IinC = calibration->pos();
335 std::shared_ptr<PoseJPL> clone_Ii = state->_clones_IMU.at(active_tracks_time);
336 Eigen::Matrix3d R_GtoIi = clone_Ii->Rot();
337 Eigen::Vector3d p_IiinG = clone_Ii->pos();
341 for (
const auto &feat : active_tracks_posinG) {
345 if (feat_uvs_in_cam0.find(feat.first) == feat_uvs_in_cam0.end())
350 Eigen::Vector3d p_FinIi = R_GtoIi * (feat.second - p_IiinG);
351 Eigen::Vector3d p_FinCi = R_ItoC * p_FinIi + p_IinC;
352 double depth = p_FinCi(2);
353 Eigen::Vector2d uv_dist;
354 if (feat_uvs_in_cam0.find(feat.first) != feat_uvs_in_cam0.end()) {
355 uv_dist << (double)feat_uvs_in_cam0.at(feat.first).x, (double)feat_uvs_in_cam0.at(feat.first).y;
357 Eigen::Vector2d uv_norm;
358 uv_norm << p_FinCi(0) / depth, p_FinCi(1) / depth;
359 uv_dist = state->_cam_intrinsics_cameras.at(0)->distort_d(uv_norm);
368 int width = state->_cam_intrinsics_cameras.at(0)->w();
369 int height = state->_cam_intrinsics_cameras.at(0)->h();
370 if (uv_dist(0) < 0 || (
int)uv_dist(0) >= width || uv_dist(1) < 0 || (
int)uv_dist(1) >= height) {
377 uvd << uv_dist, depth;
378 active_tracks_uvd.insert({feat.first, uvd});
380 retri_rT3 = boost::posix_time::microsec_clock::local_time();
383 PRINT_ALL(
CYAN "[RETRI-TIME]: %.4f seconds for triangulation (%zu tri of %zu active)\n" RESET,
384 (retri_rT2 - retri_rT1).total_microseconds() * 1e-6, total_triangulated, active_feat_linsys_A.size());
385 PRINT_ALL(
CYAN "[RETRI-TIME]: %.4f seconds for re-projection into current\n" RESET, (retri_rT3 - retri_rT2).total_microseconds() * 1e-6);
386 PRINT_ALL(
CYAN "[RETRI-TIME]: %.4f seconds total\n" RESET, (retri_rT3 - retri_rT1).total_microseconds() * 1e-6);
389 cv::Mat VioManager::get_historical_viz_image() {
392 if (state ==
nullptr || trackFEATS ==
nullptr)
396 std::vector<size_t> highlighted_ids;
397 for (
const auto &feat : state->_features_SLAM) {
398 highlighted_ids.push_back(feat.first);
402 std::string overlay = (did_zupt_update) ?
"zvupt" :
"";
403 overlay = (!is_initialized_vio) ?
"init" : overlay;
407 trackFEATS->display_history(img_history, 255, 255, 0, 255, 255, 255, highlighted_ids, overlay);
408 if (trackARUCO !=
nullptr) {
409 trackARUCO->display_history(img_history, 0, 255, 255, 255, 255, 255, highlighted_ids, overlay);
417 std::vector<Eigen::Vector3d> VioManager::get_features_SLAM() {
418 std::vector<Eigen::Vector3d> slam_feats;
419 for (
auto &
f : state->_features_SLAM) {
420 if ((
int)
f.first <= 4 * state->_options.max_aruco_features)
424 assert(
f.second->_anchor_cam_id != -1);
426 Eigen::Matrix<double, 3, 3> R_ItoC = state->_calib_IMUtoCAM.at(
f.second->_anchor_cam_id)->Rot();
427 Eigen::Matrix<double, 3, 1> p_IinC = state->_calib_IMUtoCAM.at(
f.second->_anchor_cam_id)->pos();
429 Eigen::Matrix<double, 3, 3> R_GtoI = state->_clones_IMU.at(
f.second->_anchor_clone_timestamp)->Rot();
430 Eigen::Matrix<double, 3, 1> p_IinG = state->_clones_IMU.at(
f.second->_anchor_clone_timestamp)->pos();
432 slam_feats.push_back(R_GtoI.transpose() * R_ItoC.transpose() * (
f.second->get_xyz(
false) - p_IinC) + p_IinG);
434 slam_feats.push_back(
f.second->get_xyz(
false));
440 std::vector<Eigen::Vector3d> VioManager::get_features_ARUCO() {
441 std::vector<Eigen::Vector3d> aruco_feats;
442 for (
auto &
f : state->_features_SLAM) {
443 if ((
int)
f.first > 4 * state->_options.max_aruco_features)
447 assert(
f.second->_anchor_cam_id != -1);
449 Eigen::Matrix<double, 3, 3> R_ItoC = state->_calib_IMUtoCAM.at(
f.second->_anchor_cam_id)->Rot();
450 Eigen::Matrix<double, 3, 1> p_IinC = state->_calib_IMUtoCAM.at(
f.second->_anchor_cam_id)->pos();
452 Eigen::Matrix<double, 3, 3> R_GtoI = state->_clones_IMU.at(
f.second->_anchor_clone_timestamp)->Rot();
453 Eigen::Matrix<double, 3, 1> p_IinG = state->_clones_IMU.at(
f.second->_anchor_clone_timestamp)->pos();
455 aruco_feats.push_back(R_GtoI.transpose() * R_ItoC.transpose() * (
f.second->get_xyz(
false) - p_IinC) + p_IinG);
457 aruco_feats.push_back(
f.second->get_xyz(
false));