44 bool DynamicInitializer::initialize(
double ×tamp, Eigen::MatrixXd &covariance, std::vector<std::shared_ptr<ov_type::Type>> &order,
45 std::shared_ptr<ov_type::IMU> &_imu, std::map<
double, std::shared_ptr<ov_type::PoseJPL>> &_clones_IMU,
46 std::unordered_map<
size_t, std::shared_ptr<ov_type::Landmark>> &_features_SLAM) {
49 auto rT1 = boost::posix_time::microsec_clock::local_time();
50 double newest_cam_time = -1;
51 for (
auto const &feat : _db->get_internal_data()) {
52 for (
auto const &camtimepair : feat.second->timestamps) {
53 for (
auto const &time : camtimepair.second) {
54 newest_cam_time = std::max(newest_cam_time, time);
58 double oldest_time = newest_cam_time - params.init_window_time;
59 if (newest_cam_time < 0 || oldest_time < 0) {
65 _db->cleanup_measurements(oldest_time);
66 bool have_old_imu_readings =
false;
67 auto it_imu = imu_data->begin();
68 while (it_imu != imu_data->end() && it_imu->timestamp < oldest_time + params.calib_camimu_dt) {
69 have_old_imu_readings =
true;
70 it_imu = imu_data->erase(it_imu);
72 if (_db->get_internal_data().size() < 0.75 * params.init_max_features) {
73 PRINT_WARNING(
RED "[init-d]: only %zu valid features of required (%.0f thresh)!!\n" RESET, _db->get_internal_data().size(),
74 0.95 * params.init_max_features);
77 if (imu_data->size() < 2 || !have_old_imu_readings) {
86 std::unordered_map<size_t, std::shared_ptr<Feature>> features;
87 for (
const auto &feat : _db->get_internal_data()) {
88 auto feat_new = std::make_shared<Feature>();
89 feat_new->featid = feat.second->featid;
90 feat_new->uvs = feat.second->uvs;
91 feat_new->uvs_norm = feat.second->uvs_norm;
92 feat_new->timestamps = feat.second->timestamps;
93 features.insert({feat.first, feat_new});
100 const int min_num_meas_to_optimize = (int)params.init_window_time;
101 const int min_valid_features = 8;
104 bool have_stereo =
false;
105 int count_valid_features = 0;
106 std::map<size_t, int> map_features_num_meas;
107 int num_measurements = 0;
108 double oldest_camera_time = INFINITY;
109 std::map<double, bool> map_camera_times;
110 map_camera_times[newest_cam_time] =
true;
111 std::map<size_t, bool> map_camera_ids;
112 double pose_dt_avg = params.init_window_time / (
double)(params.init_dyn_num_pose + 1);
113 for (
auto const &feat : features) {
116 std::vector<double> times;
117 std::map<size_t, bool> camids;
118 for (
auto const &camtime : feat.second->timestamps) {
119 for (
double time : camtime.second) {
120 double time_dt = INFINITY;
121 for (
auto const &tmp : map_camera_times) {
122 time_dt = std::min(time_dt, std::abs(time - tmp.first));
124 for (
auto const &tmp : times) {
125 time_dt = std::min(time_dt, std::abs(time - tmp));
129 if (time_dt >= pose_dt_avg || time_dt == 0.0) {
130 times.push_back(time);
131 camids[camtime.first] =
true;
137 map_features_num_meas[feat.first] = (int)times.size();
138 if (map_features_num_meas[feat.first] < min_num_meas_to_optimize)
142 for (
auto const &tmp : times) {
143 map_camera_times[tmp] =
true;
144 oldest_camera_time = std::min(oldest_camera_time, tmp);
145 num_measurements += 2;
147 for (
auto const &tmp : camids) {
148 map_camera_ids[tmp.first] =
true;
150 if (camids.size() > 1) {
153 count_valid_features++;
158 if ((
int)map_camera_times.size() < params.init_dyn_num_pose) {
161 if (count_valid_features < min_valid_features) {
162 PRINT_WARNING(
RED "[init-d]: only %zu valid features of required %d!!\n" RESET, count_valid_features, min_valid_features);
169 Eigen::Vector3d gyroscope_bias = params.init_dyn_bias_g;
170 Eigen::Vector3d accelerometer_bias = params.init_dyn_bias_a;
173 double accel_inI_norm = 0.0;
174 double theta_inI_norm = 0.0;
175 double time0_in_imu = oldest_camera_time + params.calib_camimu_dt;
176 double time1_in_imu = newest_cam_time + params.calib_camimu_dt;
177 std::vector<ov_core::ImuData> readings = InitializerHelper::select_imu_readings(*imu_data, time0_in_imu, time1_in_imu);
178 assert(readings.size() > 2);
179 for (
size_t k = 0; k < readings.size() - 1; k++) {
180 auto imu0 = readings.at(k);
181 auto imu1 = readings.at(k + 1);
182 double dt = imu1.timestamp - imu0.timestamp;
183 Eigen::Vector3d wm = 0.5 * (imu0.wm + imu1.wm) - gyroscope_bias;
184 Eigen::Vector3d am = 0.5 * (imu0.am + imu1.am) - accelerometer_bias;
185 theta_inI_norm += (-wm * dt).norm();
186 accel_inI_norm += am.norm();
188 accel_inI_norm /= (double)(readings.size() - 1);
189 if (180.0 / M_PI * theta_inI_norm < params.init_dyn_min_deg) {
190 PRINT_WARNING(
YELLOW "[init-d]: gyroscope only %.2f degree change (%.2f thresh)\n" RESET, 180.0 / M_PI * theta_inI_norm,
191 params.init_dyn_min_deg);
194 PRINT_DEBUG(
"[init-d]: |theta_I| = %.4f deg and |accel| = %.4f\n", 180.0 / M_PI * theta_inI_norm, accel_inI_norm);
219 auto rT2 = boost::posix_time::microsec_clock::local_time();
229 const bool use_single_depth =
false;
230 int size_feature = (use_single_depth) ? 1 : 3;
231 int num_features = count_valid_features;
232 int system_size = size_feature * num_features + 3 + 3;
235 if (num_measurements < system_size) {
236 PRINT_WARNING(
YELLOW "[init-d]: not enough feature measurements (%d meas vs %d state size)!\n" RESET, num_measurements, system_size);
241 assert(oldest_camera_time < newest_cam_time);
242 double last_camera_timestamp = 0.0;
243 std::map<double, std::shared_ptr<ov_core::CpiV1>> map_camera_cpi_I0toIi, map_camera_cpi_IitoIi1;
244 for (
auto const &timepair : map_camera_times) {
247 double current_time = timepair.first;
248 if (current_time == oldest_camera_time) {
249 map_camera_cpi_I0toIi.insert({current_time,
nullptr});
250 map_camera_cpi_IitoIi1.insert({current_time,
nullptr});
251 last_camera_timestamp = current_time;
256 double cpiI0toIi1_time0_in_imu = oldest_camera_time + params.calib_camimu_dt;
257 double cpiI0toIi1_time1_in_imu = current_time + params.calib_camimu_dt;
258 auto cpiI0toIi1 = std::make_shared<ov_core::CpiV1>(params.sigma_w, params.sigma_wb, params.sigma_a, params.sigma_ab,
true);
259 cpiI0toIi1->setLinearizationPoints(gyroscope_bias, accelerometer_bias);
260 std::vector<ov_core::ImuData> cpiI0toIi1_readings =
261 InitializerHelper::select_imu_readings(*imu_data, cpiI0toIi1_time0_in_imu, cpiI0toIi1_time1_in_imu);
262 if (cpiI0toIi1_readings.size() < 2) {
263 PRINT_DEBUG(
YELLOW "[init-d]: camera %.2f in has %zu IMU readings!\n" RESET, (cpiI0toIi1_time1_in_imu - cpiI0toIi1_time0_in_imu),
264 cpiI0toIi1_readings.size());
267 double cpiI0toIi1_dt_imu = cpiI0toIi1_readings.at(cpiI0toIi1_readings.size() - 1).timestamp - cpiI0toIi1_readings.at(0).timestamp;
268 if (std::abs(cpiI0toIi1_dt_imu - (cpiI0toIi1_time1_in_imu - cpiI0toIi1_time0_in_imu)) > 0.01) {
270 (cpiI0toIi1_time1_in_imu - cpiI0toIi1_time0_in_imu));
273 for (
size_t k = 0; k < cpiI0toIi1_readings.size() - 1; k++) {
274 auto imu0 = cpiI0toIi1_readings.at(k);
275 auto imu1 = cpiI0toIi1_readings.at(k + 1);
276 cpiI0toIi1->feed_IMU(imu0.timestamp, imu1.timestamp, imu0.wm, imu0.am, imu1.wm, imu1.am);
280 double cpiIitoIi1_time0_in_imu = last_camera_timestamp + params.calib_camimu_dt;
281 double cpiIitoIi1_time1_in_imu = current_time + params.calib_camimu_dt;
282 auto cpiIitoIi1 = std::make_shared<ov_core::CpiV1>(params.sigma_w, params.sigma_wb, params.sigma_a, params.sigma_ab,
true);
283 cpiIitoIi1->setLinearizationPoints(gyroscope_bias, accelerometer_bias);
284 std::vector<ov_core::ImuData> cpiIitoIi1_readings =
285 InitializerHelper::select_imu_readings(*imu_data, cpiIitoIi1_time0_in_imu, cpiIitoIi1_time1_in_imu);
286 if (cpiIitoIi1_readings.size() < 2) {
287 PRINT_DEBUG(
YELLOW "[init-d]: camera %.2f in has %zu IMU readings!\n" RESET, (cpiIitoIi1_time1_in_imu - cpiIitoIi1_time0_in_imu),
288 cpiIitoIi1_readings.size());
291 double cpiIitoIi1_dt_imu = cpiIitoIi1_readings.at(cpiIitoIi1_readings.size() - 1).timestamp - cpiIitoIi1_readings.at(0).timestamp;
292 if (std::abs(cpiIitoIi1_dt_imu - (cpiIitoIi1_time1_in_imu - cpiIitoIi1_time0_in_imu)) > 0.01) {
294 (cpiIitoIi1_time1_in_imu - cpiIitoIi1_time0_in_imu));
297 for (
size_t k = 0; k < cpiIitoIi1_readings.size() - 1; k++) {
298 auto imu0 = cpiIitoIi1_readings.at(k);
299 auto imu1 = cpiIitoIi1_readings.at(k + 1);
300 cpiIitoIi1->feed_IMU(imu0.timestamp, imu1.timestamp, imu0.wm, imu0.am, imu1.wm, imu1.am);
304 map_camera_cpi_I0toIi.insert({current_time, cpiI0toIi1});
305 map_camera_cpi_IitoIi1.insert({current_time, cpiIitoIi1});
306 last_camera_timestamp = current_time;
311 Eigen::MatrixXd A = Eigen::MatrixXd::Zero(num_measurements, system_size);
312 Eigen::VectorXd b = Eigen::VectorXd::Zero(num_measurements);
313 PRINT_DEBUG(
"[init-d]: system of %d measurement x %d states created (%d features, %s)\n", num_measurements, system_size, num_features,
314 (have_stereo) ?
"stereo" :
"mono");
317 std::map<size_t, int> A_index_features;
318 for (
auto const &feat : features) {
319 if (map_features_num_meas[feat.first] < min_num_meas_to_optimize)
321 if (A_index_features.find(feat.first) == A_index_features.end()) {
322 A_index_features.insert({feat.first, idx_feat});
325 for (
auto const &camtime : feat.second->timestamps) {
328 size_t cam_id = camtime.first;
329 Eigen::Vector4d q_ItoC = params.camera_extrinsics.at(cam_id).block(0, 0, 4, 1);
330 Eigen::Vector3d p_IinC = params.camera_extrinsics.at(cam_id).block(4, 0, 3, 1);
334 for (
size_t i = 0; i < camtime.second.size(); i++) {
337 double time = feat.second->timestamps.at(cam_id).at(i);
338 if (map_camera_times.find(time) == map_camera_times.end())
342 Eigen::Vector2d uv_norm;
343 uv_norm << (double)feat.second->uvs_norm.at(cam_id).at(i)(0), (
double)feat.second->uvs_norm.at(cam_id).at(i)(1);
347 Eigen::MatrixXd R_I0toIk = Eigen::MatrixXd::Identity(3, 3);
348 Eigen::MatrixXd alpha_I0toIk = Eigen::MatrixXd::Zero(3, 1);
349 if (map_camera_cpi_I0toIi.find(time) != map_camera_cpi_I0toIi.end() && map_camera_cpi_I0toIi.at(time) !=
nullptr) {
350 DT = map_camera_cpi_I0toIi.at(time)->DT;
351 R_I0toIk = map_camera_cpi_I0toIi.at(time)->R_k2tau;
352 alpha_I0toIk = map_camera_cpi_I0toIi.at(time)->alpha_tau;
361 Eigen::MatrixXd H_proj = Eigen::MatrixXd::Zero(2, 3);
362 H_proj << 1, 0, -uv_norm(0), 0, 1, -uv_norm(1);
363 Eigen::MatrixXd Y = H_proj * R_ItoC * R_I0toIk;
364 Eigen::MatrixXd H_i = Eigen::MatrixXd::Zero(2, system_size);
365 Eigen::MatrixXd b_i = Y * alpha_I0toIk - H_proj * p_IinC;
366 if (size_feature == 1) {
372 H_i.block(0, size_feature * A_index_features.at(feat.first), 2, 3) = Y;
374 H_i.block(0, size_feature * num_features + 0, 2, 3) = -DT * Y;
375 H_i.block(0, size_feature * num_features + 3, 2, 3) = 0.5 * DT * DT * Y;
378 A.block(index_meas, 0, 2, A.cols()) = H_i;
379 b.block(index_meas, 0, 2, 1) = b_i;
384 auto rT3 = boost::posix_time::microsec_clock::local_time();
395 Eigen::MatrixXd A1 = A.block(0, 0, A.rows(), A.cols() - 3);
397 Eigen::MatrixXd A1A1_inv = (A1.transpose() * A1).llt().solve(Eigen::MatrixXd::Identity(A1.cols(), A1.cols()));
398 Eigen::MatrixXd A2 = A.block(0, A.cols() - 3, A.rows(), 3);
399 Eigen::MatrixXd Temp = A2.transpose() * (Eigen::MatrixXd::Identity(A1.rows(), A1.rows()) - A1 * A1A1_inv * A1.transpose());
400 Eigen::MatrixXd D = Temp * A2;
401 Eigen::MatrixXd
d = Temp * b;
402 Eigen::Matrix<double, 7, 1> coeff = InitializerHelper::compute_dongsi_coeff(D,
d, params.gravity_mag);
406 assert(coeff(0) == 1);
407 Eigen::Matrix<double, 6, 6> companion_matrix = Eigen::Matrix<double, 6, 6>::Zero(coeff.rows() - 1, coeff.rows() - 1);
408 companion_matrix.diagonal(-1).setOnes();
409 companion_matrix.col(companion_matrix.cols() - 1) = -coeff.reverse().head(coeff.rows() - 1);
410 Eigen::JacobiSVD<Eigen::Matrix<double, 6, 6>> svd0(companion_matrix);
411 Eigen::MatrixXd singularValues0 = svd0.singularValues();
412 double cond0 = singularValues0(0) / singularValues0(singularValues0.rows() - 1);
413 PRINT_DEBUG(
"[init-d]: CM cond = %.3f | rank = %d of %d (%4.3e thresh)\n", cond0, (
int)svd0.rank(), (
int)companion_matrix.cols(),
415 if (svd0.rank() != companion_matrix.rows()) {
421 Eigen::EigenSolver<Eigen::Matrix<double, 6, 6>> solver(companion_matrix,
false);
422 if (solver.info() != Eigen::Success) {
430 bool lambda_found =
false;
431 double lambda_min = -1;
432 double cost_min = INFINITY;
433 Eigen::MatrixXd I_dd = Eigen::MatrixXd::Identity(D.rows(), D.rows());
436 for (
int i = 0; i < solver.eigenvalues().size(); i++) {
437 auto val = solver.eigenvalues()(i);
438 if (val.imag() == 0) {
439 double lambda = val.real();
442 Eigen::MatrixXd D_lambdaI_inv = (D - lambda * I_dd).llt().solve(I_dd);
443 Eigen::VectorXd state_grav = D_lambdaI_inv *
d;
444 double cost = std::abs(state_grav.norm() - params.gravity_mag);
446 if (!lambda_found || cost < cost_min) {
457 PRINT_DEBUG(
"[init-d]: smallest real eigenvalue = %.5f (cost of %f)\n", lambda_min, cost_min);
461 Eigen::MatrixXd D_lambdaI_inv = (D - lambda_min * I_dd).llt().solve(I_dd);
462 Eigen::VectorXd state_grav = D_lambdaI_inv *
d;
465 Eigen::VectorXd state_feat_vel = -A1A1_inv * A1.transpose() * A2 * state_grav + A1A1_inv * A1.transpose() * b;
466 Eigen::MatrixXd x_hat = Eigen::MatrixXd::Zero(system_size, 1);
467 x_hat.block(0, 0, size_feature * num_features + 3, 1) = state_feat_vel;
468 x_hat.block(size_feature * num_features + 3, 0, 3, 1) = state_grav;
469 Eigen::Vector3d v_I0inI0 = x_hat.block(size_feature * num_features + 0, 0, 3, 1);
470 PRINT_INFO(
"[init-d]: velocity in I0 was %.3f,%.3f,%.3f and |v| = %.4f\n", v_I0inI0(0), v_I0inI0(1), v_I0inI0(2), v_I0inI0.norm());
473 Eigen::Vector3d gravity_inI0 = x_hat.block(size_feature * num_features + 3, 0, 3, 1);
474 double init_max_grav_difference = 1e-3;
475 if (std::abs(gravity_inI0.norm() - params.gravity_mag) > init_max_grav_difference) {
476 PRINT_WARNING(
YELLOW "[init-d]: gravity did not converge (%.3f > %.3f)\n" RESET, std::abs(gravity_inI0.norm() - params.gravity_mag),
477 init_max_grav_difference);
480 PRINT_INFO(
"[init-d]: gravity in I0 was %.3f,%.3f,%.3f and |g| = %.4f\n", gravity_inI0(0), gravity_inI0(1), gravity_inI0(2),
481 gravity_inI0.norm());
482 auto rT4 = boost::posix_time::microsec_clock::local_time();
488 std::map<double, Eigen::VectorXd> ori_I0toIi, pos_IiinI0, vel_IiinI0;
489 for (
auto const &timepair : map_camera_times) {
492 double time = timepair.first;
496 Eigen::MatrixXd R_I0toIk = Eigen::MatrixXd::Identity(3, 3);
497 Eigen::MatrixXd alpha_I0toIk = Eigen::MatrixXd::Zero(3, 1);
498 Eigen::MatrixXd beta_I0toIk = Eigen::MatrixXd::Zero(3, 1);
499 if (map_camera_cpi_I0toIi.find(time) != map_camera_cpi_I0toIi.end() && map_camera_cpi_I0toIi.at(time) !=
nullptr) {
500 auto cpi = map_camera_cpi_I0toIi.at(time);
502 R_I0toIk = cpi->R_k2tau;
503 alpha_I0toIk = cpi->alpha_tau;
504 beta_I0toIk = cpi->beta_tau;
508 Eigen::Vector3d p_IkinI0 = v_I0inI0 * DT - 0.5 * gravity_inI0 * DT * DT + alpha_I0toIk;
509 Eigen::Vector3d v_IkinI0 = v_I0inI0 - gravity_inI0 * DT + beta_I0toIk;
512 ori_I0toIi.insert({time,
rot_2_quat(R_I0toIk)});
513 pos_IiinI0.insert({time, p_IkinI0});
514 vel_IiinI0.insert({time, v_IkinI0});
518 count_valid_features = 0;
519 std::map<size_t, Eigen::Vector3d> features_inI0;
520 for (
auto const &feat : features) {
521 if (map_features_num_meas[feat.first] < min_num_meas_to_optimize)
523 Eigen::Vector3d p_FinI0;
524 if (size_feature == 1) {
529 p_FinI0 = x_hat.block(size_feature * A_index_features.at(feat.first), 0, 3, 1);
531 bool is_behind =
false;
532 for (
auto const &camtime : feat.second->timestamps) {
533 size_t cam_id = camtime.first;
534 Eigen::Vector4d q_ItoC = params.camera_extrinsics.at(cam_id).block(0, 0, 4, 1);
535 Eigen::Vector3d p_IinC = params.camera_extrinsics.at(cam_id).block(4, 0, 3, 1);
536 Eigen::Vector3d p_FinC0 =
quat_2_Rot(q_ItoC) * p_FinI0 + p_IinC;
537 if (p_FinC0(2) < 0) {
542 features_inI0.insert({feat.first, p_FinI0});
543 count_valid_features++;
546 if (count_valid_features < min_valid_features) {
547 PRINT_ERROR(
YELLOW "[init-d]: not enough features for our mle (%zu < %d)!\n" RESET, count_valid_features, min_valid_features);
553 Eigen::Matrix3d R_GtoI0;
554 InitializerHelper::gram_schmidt(gravity_inI0, R_GtoI0);
555 Eigen::Vector4d q_GtoI0 =
rot_2_quat(R_GtoI0);
556 Eigen::Vector3d gravity;
557 gravity << 0.0, 0.0, params.gravity_mag;
558 std::map<double, Eigen::VectorXd> ori_GtoIi, pos_IiinG, vel_IiinG;
559 std::map<size_t, Eigen::Vector3d> features_inG;
560 for (
auto const &timepair : map_camera_times) {
561 ori_GtoIi[timepair.first] =
quat_multiply(ori_I0toIi.at(timepair.first), q_GtoI0);
562 pos_IiinG[timepair.first] = R_GtoI0.transpose() * pos_IiinI0.at(timepair.first);
563 vel_IiinG[timepair.first] = R_GtoI0.transpose() * vel_IiinI0.at(timepair.first);
565 for (
auto const &feat : features_inI0) {
566 features_inG[feat.first] = R_GtoI0.transpose() * feat.second;
574 ceres::Problem problem;
577 std::map<double, int> map_states;
578 std::vector<double *> ceres_vars_ori;
579 std::vector<double *> ceres_vars_pos;
580 std::vector<double *> ceres_vars_vel;
581 std::vector<double *> ceres_vars_bias_g;
582 std::vector<double *> ceres_vars_bias_a;
585 std::map<size_t, int> map_features;
586 std::vector<double *> ceres_vars_feat;
589 std::map<size_t, int> map_calib_cam2imu;
590 std::vector<double *> ceres_vars_calib_cam2imu_ori;
591 std::vector<double *> ceres_vars_calib_cam2imu_pos;
594 std::map<size_t, int> map_calib_cam;
595 std::vector<double *> ceres_vars_calib_cam_intrinsics;
598 auto free_state_memory = [&]() {
599 for (
auto const &ptr : ceres_vars_ori)
601 for (
auto const &ptr : ceres_vars_pos)
603 for (
auto const &ptr : ceres_vars_vel)
605 for (
auto const &ptr : ceres_vars_bias_g)
607 for (
auto const &ptr : ceres_vars_bias_a)
609 for (
auto const &ptr : ceres_vars_feat)
611 for (
auto const &ptr : ceres_vars_calib_cam2imu_ori)
613 for (
auto const &ptr : ceres_vars_calib_cam2imu_pos)
615 for (
auto const &ptr : ceres_vars_calib_cam_intrinsics)
622 ceres::Solver::Options options;
623 options.linear_solver_type = ceres::DENSE_SCHUR;
624 options.trust_region_strategy_type = ceres::DOGLEG;
629 options.num_threads = params.init_dyn_mle_max_threads;
630 options.max_solver_time_in_seconds = params.init_dyn_mle_max_time;
631 options.max_num_iterations = params.init_dyn_mle_max_iter;
634 options.function_tolerance = 1e-5;
635 options.gradient_tolerance = 1e-4 * options.function_tolerance;
638 double timestamp_k = -1;
639 for (
auto const &timepair : map_camera_times) {
642 double timestamp_k1 = timepair.first;
643 std::shared_ptr<ov_core::CpiV1> cpi = map_camera_cpi_IitoIi1.at(timestamp_k1);
644 Eigen::Matrix<double, 16, 1> state_k1;
645 state_k1.block(0, 0, 4, 1) = ori_GtoIi.at(timestamp_k1);
646 state_k1.block(4, 0, 3, 1) = pos_IiinG.at(timestamp_k1);
647 state_k1.block(7, 0, 3, 1) = vel_IiinG.at(timestamp_k1);
648 state_k1.block(10, 0, 3, 1) = gyroscope_bias;
649 state_k1.block(13, 0, 3, 1) = accelerometer_bias;
656 auto *var_ori =
new double[4];
657 for (
int j = 0; j < 4; j++) {
658 var_ori[j] = state_k1(0 + j, 0);
660 auto *var_pos =
new double[3];
661 auto *var_vel =
new double[3];
662 auto *var_bias_g =
new double[3];
663 auto *var_bias_a =
new double[3];
664 for (
int j = 0; j < 3; j++) {
665 var_pos[j] = state_k1(4 + j, 0);
666 var_vel[j] = state_k1(7 + j, 0);
667 var_bias_g[j] = state_k1(10 + j, 0);
668 var_bias_a[j] = state_k1(13 + j, 0);
673 problem.AddParameterBlock(var_ori, 4, ceres_jplquat);
674 problem.AddParameterBlock(var_pos, 3);
675 problem.AddParameterBlock(var_vel, 3);
676 problem.AddParameterBlock(var_bias_g, 3);
677 problem.AddParameterBlock(var_bias_a, 3);
683 if (map_states.empty()) {
686 Eigen::MatrixXd x_lin = Eigen::MatrixXd::Zero(13, 1);
687 for (
int j = 0; j < 4; j++) {
688 x_lin(0 + j) = var_ori[j];
690 for (
int j = 0; j < 3; j++) {
691 x_lin(4 + j) = var_pos[j];
692 x_lin(7 + j) = var_bias_g[j];
693 x_lin(10 + j) = var_bias_a[j];
695 Eigen::MatrixXd prior_grad = Eigen::MatrixXd::Zero(10, 1);
696 Eigen::MatrixXd prior_Info = Eigen::MatrixXd::Identity(10, 10);
697 prior_Info.block(0, 0, 4, 4) *= 1.0 / std::pow(1e-5, 2);
698 prior_Info.block(4, 4, 3, 3) *= 1.0 / std::pow(0.05, 2);
699 prior_Info.block(7, 7, 3, 3) *= 1.0 / std::pow(0.10, 2);
702 std::vector<std::string> x_types;
703 std::vector<double *> factor_params;
704 factor_params.push_back(var_ori);
705 x_types.emplace_back(
"quat_yaw");
706 factor_params.push_back(var_pos);
707 x_types.emplace_back(
"vec3");
708 factor_params.push_back(var_bias_g);
709 x_types.emplace_back(
"vec3");
710 factor_params.push_back(var_bias_a);
711 x_types.emplace_back(
"vec3");
715 problem.AddResidualBlock(factor_prior,
nullptr, factor_params);
719 map_states.insert({timestamp_k1, (int)ceres_vars_ori.size()});
720 ceres_vars_ori.push_back(var_ori);
721 ceres_vars_pos.push_back(var_pos);
722 ceres_vars_vel.push_back(var_vel);
723 ceres_vars_bias_g.push_back(var_bias_g);
724 ceres_vars_bias_a.push_back(var_bias_a);
731 if (cpi !=
nullptr) {
732 assert(timestamp_k != -1);
733 std::vector<double *> factor_params;
734 factor_params.push_back(ceres_vars_ori.at(map_states.at(timestamp_k)));
735 factor_params.push_back(ceres_vars_bias_g.at(map_states.at(timestamp_k)));
736 factor_params.push_back(ceres_vars_vel.at(map_states.at(timestamp_k)));
737 factor_params.push_back(ceres_vars_bias_a.at(map_states.at(timestamp_k)));
738 factor_params.push_back(ceres_vars_pos.at(map_states.at(timestamp_k)));
739 factor_params.push_back(ceres_vars_ori.at(map_states.at(timestamp_k1)));
740 factor_params.push_back(ceres_vars_bias_g.at(map_states.at(timestamp_k1)));
741 factor_params.push_back(ceres_vars_vel.at(map_states.at(timestamp_k1)));
742 factor_params.push_back(ceres_vars_bias_a.at(map_states.at(timestamp_k1)));
743 factor_params.push_back(ceres_vars_pos.at(map_states.at(timestamp_k1)));
744 auto *factor_imu =
new Factor_ImuCPIv1(cpi->DT, gravity, cpi->alpha_tau, cpi->beta_tau, cpi->q_k2tau, cpi->b_a_lin, cpi->b_w_lin,
745 cpi->J_q, cpi->J_b, cpi->J_a, cpi->H_b, cpi->H_a, cpi->P_meas);
746 problem.AddResidualBlock(factor_imu,
nullptr, factor_params);
750 timestamp_k = timestamp_k1;
754 for (
auto const &idpair : map_camera_ids) {
755 size_t cam_id = idpair.first;
756 if (map_calib_cam2imu.find(cam_id) == map_calib_cam2imu.end()) {
757 auto *var_calib_ori =
new double[4];
758 for (
int j = 0; j < 4; j++) {
759 var_calib_ori[j] = params.camera_extrinsics.at(cam_id)(0 + j, 0);
761 auto *var_calib_pos =
new double[3];
762 for (
int j = 0; j < 3; j++) {
763 var_calib_pos[j] = params.camera_extrinsics.at(cam_id)(4 + j, 0);
766 problem.AddParameterBlock(var_calib_ori, 4, ceres_calib_jplquat);
767 problem.AddParameterBlock(var_calib_pos, 3);
768 map_calib_cam2imu.insert({cam_id, (int)ceres_vars_calib_cam2imu_ori.size()});
769 ceres_vars_calib_cam2imu_ori.push_back(var_calib_ori);
770 ceres_vars_calib_cam2imu_pos.push_back(var_calib_pos);
773 Eigen::MatrixXd x_lin = Eigen::MatrixXd::Zero(7, 1);
774 for (
int j = 0; j < 4; j++) {
775 x_lin(0 + j) = var_calib_ori[j];
777 for (
int j = 0; j < 3; j++) {
778 x_lin(4 + j) = var_calib_pos[j];
780 Eigen::MatrixXd prior_grad = Eigen::MatrixXd::Zero(6, 1);
781 Eigen::MatrixXd prior_Info = Eigen::MatrixXd::Identity(6, 6);
782 prior_Info.block(0, 0, 3, 3) *= 1.0 / std::pow(0.001, 2);
783 prior_Info.block(3, 3, 3, 3) *= 1.0 / std::pow(0.01, 2);
786 std::vector<std::string> x_types;
787 std::vector<double *> factor_params;
788 factor_params.push_back(var_calib_ori);
789 x_types.emplace_back(
"quat");
790 factor_params.push_back(var_calib_pos);
791 x_types.emplace_back(
"vec3");
793 problem.AddResidualBlock(factor_prior,
nullptr, factor_params);
794 if (!params.init_dyn_mle_opt_calib) {
795 problem.SetParameterBlockConstant(var_calib_ori);
796 problem.SetParameterBlockConstant(var_calib_pos);
799 if (map_calib_cam.find(cam_id) == map_calib_cam.end()) {
800 auto *var_calib_cam =
new double[8];
801 for (
int j = 0; j < 8; j++) {
802 var_calib_cam[j] = params.camera_intrinsics.at(cam_id)->get_value()(j, 0);
804 problem.AddParameterBlock(var_calib_cam, 8);
805 map_calib_cam.insert({cam_id, (int)ceres_vars_calib_cam_intrinsics.size()});
806 ceres_vars_calib_cam_intrinsics.push_back(var_calib_cam);
809 Eigen::MatrixXd x_lin = Eigen::MatrixXd::Zero(8, 1);
810 for (
int j = 0; j < 8; j++) {
811 x_lin(0 + j) = var_calib_cam[j];
813 Eigen::MatrixXd prior_grad = Eigen::MatrixXd::Zero(8, 1);
814 Eigen::MatrixXd prior_Info = Eigen::MatrixXd::Identity(8, 8);
815 prior_Info.block(0, 0, 4, 4) *= 1.0 / std::pow(1.0, 2);
816 prior_Info.block(4, 4, 4, 4) *= 1.0 / std::pow(0.005, 2);
819 std::vector<std::string> x_types;
820 std::vector<double *> factor_params;
821 factor_params.push_back(var_calib_cam);
822 x_types.emplace_back(
"vec8");
824 problem.AddResidualBlock(factor_prior,
nullptr, factor_params);
825 if (!params.init_dyn_mle_opt_calib) {
826 problem.SetParameterBlockConstant(var_calib_cam);
830 assert(map_calib_cam2imu.size() == map_calib_cam.size());
833 for (
auto const &feat : features) {
835 if (map_features_num_meas[feat.first] < min_num_meas_to_optimize)
838 if (features_inG.find(feat.first) == features_inG.end())
841 for (
auto const &camtime : feat.second->timestamps) {
844 size_t feat_id = feat.first;
845 size_t cam_id = camtime.first;
846 bool is_fisheye = (std::dynamic_pointer_cast<ov_core::CamEqui>(params.camera_intrinsics.at(cam_id)) !=
nullptr);
849 for (
size_t i = 0; i < camtime.second.size(); i++) {
852 double time = feat.second->timestamps.at(cam_id).at(i);
853 if (map_camera_times.find(time) == map_camera_times.end())
857 Eigen::Vector2d uv_raw = feat.second->uvs.at(cam_id).at(i).block(0, 0, 2, 1).cast<
double>();
861 if (map_features.find(feat_id) == map_features.end()) {
862 auto *var_feat =
new double[3];
863 for (
int j = 0; j < 3; j++) {
864 var_feat[j] = features_inG.at(feat_id)(j);
866 problem.AddParameterBlock(var_feat, 3);
867 map_features.insert({feat_id, (int)ceres_vars_feat.size()});
868 ceres_vars_feat.push_back(var_feat);
872 std::vector<double *> factor_params;
873 factor_params.push_back(ceres_vars_ori.at(map_states.at(time)));
874 factor_params.push_back(ceres_vars_pos.at(map_states.at(time)));
875 factor_params.push_back(ceres_vars_feat.at(map_features.at(feat_id)));
876 factor_params.push_back(ceres_vars_calib_cam2imu_ori.at(map_calib_cam2imu.at(cam_id)));
877 factor_params.push_back(ceres_vars_calib_cam2imu_pos.at(map_calib_cam2imu.at(cam_id)));
878 factor_params.push_back(ceres_vars_calib_cam_intrinsics.at(map_calib_cam.at(cam_id)));
881 ceres::LossFunction *loss_function =
new ceres::CauchyLoss(1.0);
882 problem.AddResidualBlock(factor_pinhole, loss_function, factor_params);
886 assert(ceres_vars_ori.size() == ceres_vars_bias_g.size());
887 assert(ceres_vars_ori.size() == ceres_vars_vel.size());
888 assert(ceres_vars_ori.size() == ceres_vars_bias_a.size());
889 assert(ceres_vars_ori.size() == ceres_vars_pos.size());
890 auto rT5 = boost::posix_time::microsec_clock::local_time();
893 ceres::Solver::Summary summary;
894 ceres::Solve(options, &problem, &summary);
895 PRINT_INFO(
"[init-d]: %d iterations | %zu states, %zu feats (%zu valid) | %d param and %d res | cost %.4e => %.4e\n",
896 (
int)summary.iterations.size(), map_states.size(), map_features.size(), count_valid_features, summary.num_parameters,
897 summary.num_residuals, summary.initial_cost, summary.final_cost);
898 auto rT6 = boost::posix_time::microsec_clock::local_time();
901 timestamp = newest_cam_time;
902 if (params.init_dyn_mle_max_iter != 0 && summary.termination_type != ceres::CONVERGENCE) {
907 PRINT_DEBUG(
"[init-d]: %s\n", summary.message.c_str());
913 auto get_pose = [&](
double timestamp) {
914 Eigen::VectorXd state_imu = Eigen::VectorXd::Zero(16);
915 for (
int i = 0; i < 4; i++) {
916 state_imu(0 + i) = ceres_vars_ori[map_states[timestamp]][i];
918 for (
int i = 0; i < 3; i++) {
919 state_imu(4 + i) = ceres_vars_pos[map_states[timestamp]][i];
920 state_imu(7 + i) = ceres_vars_vel[map_states[timestamp]][i];
921 state_imu(10 + i) = ceres_vars_bias_g[map_states[timestamp]][i];
922 state_imu(13 + i) = ceres_vars_bias_a[map_states[timestamp]][i];
928 assert(map_states.find(newest_cam_time) != map_states.end());
929 if (_imu ==
nullptr) {
930 _imu = std::make_shared<ov_type::IMU>();
932 Eigen::VectorXd imu_state = get_pose(newest_cam_time);
933 _imu->set_value(imu_state);
934 _imu->set_fej(imu_state);
937 for (
auto const &statepair : map_states) {
938 Eigen::VectorXd pose = get_pose(statepair.first);
939 if (_clones_IMU.find(statepair.first) == _clones_IMU.end()) {
940 auto _pose = std::make_shared<ov_type::PoseJPL>();
941 _pose->set_value(pose.block(0, 0, 7, 1));
942 _pose->set_fej(pose.block(0, 0, 7, 1));
943 _clones_IMU.insert({statepair.first, _pose});
945 _clones_IMU.at(statepair.first)->set_value(pose.block(0, 0, 7, 1));
946 _clones_IMU.at(statepair.first)->set_fej(pose.block(0, 0, 7, 1));
951 for (
auto const &featpair : map_features) {
952 Eigen::Vector3d feature;
953 feature << ceres_vars_feat[featpair.second][0], ceres_vars_feat[featpair.second][1], ceres_vars_feat[featpair.second][2];
954 if (_features_SLAM.find(featpair.first) == _features_SLAM.end()) {
955 auto _feature = std::make_shared<ov_type::Landmark>(3);
956 _feature->_featid = featpair.first;
957 _feature->_feat_representation = LandmarkRepresentation::Representation::GLOBAL_3D;
958 _feature->set_from_xyz(feature,
false);
959 _feature->set_from_xyz(feature,
true);
960 _features_SLAM.insert({featpair.first, _feature});
962 _features_SLAM.at(featpair.first)->_featid = featpair.first;
963 _features_SLAM.at(featpair.first)->_feat_representation = LandmarkRepresentation::Representation::GLOBAL_3D;
964 _features_SLAM.at(featpair.first)->set_from_xyz(feature,
false);
965 _features_SLAM.at(featpair.first)->set_from_xyz(feature,
true);
970 if (params.init_dyn_mle_opt_calib) {
981 std::vector<std::pair<const double *, const double *>> covariance_blocks;
982 int state_index = map_states[newest_cam_time];
984 covariance_blocks.push_back(std::make_pair(ceres_vars_ori[state_index], ceres_vars_ori[state_index]));
985 covariance_blocks.push_back(std::make_pair(ceres_vars_pos[state_index], ceres_vars_pos[state_index]));
986 covariance_blocks.push_back(std::make_pair(ceres_vars_vel[state_index], ceres_vars_vel[state_index]));
987 covariance_blocks.push_back(std::make_pair(ceres_vars_bias_g[state_index], ceres_vars_bias_g[state_index]));
988 covariance_blocks.push_back(std::make_pair(ceres_vars_bias_a[state_index], ceres_vars_bias_a[state_index]));
990 covariance_blocks.push_back(std::make_pair(ceres_vars_ori[state_index], ceres_vars_pos[state_index]));
991 covariance_blocks.push_back(std::make_pair(ceres_vars_ori[state_index], ceres_vars_vel[state_index]));
992 covariance_blocks.push_back(std::make_pair(ceres_vars_ori[state_index], ceres_vars_bias_g[state_index]));
993 covariance_blocks.push_back(std::make_pair(ceres_vars_ori[state_index], ceres_vars_bias_a[state_index]));
995 covariance_blocks.push_back(std::make_pair(ceres_vars_pos[state_index], ceres_vars_vel[state_index]));
996 covariance_blocks.push_back(std::make_pair(ceres_vars_pos[state_index], ceres_vars_bias_g[state_index]));
997 covariance_blocks.push_back(std::make_pair(ceres_vars_pos[state_index], ceres_vars_bias_a[state_index]));
999 covariance_blocks.push_back(std::make_pair(ceres_vars_vel[state_index], ceres_vars_bias_g[state_index]));
1000 covariance_blocks.push_back(std::make_pair(ceres_vars_vel[state_index], ceres_vars_bias_a[state_index]));
1002 covariance_blocks.push_back(std::make_pair(ceres_vars_bias_g[state_index], ceres_vars_bias_a[state_index]));
1005 ceres::Covariance::Options options_cov;
1006 options_cov.null_space_rank = (!params.init_dyn_mle_opt_calib) * ((
int)map_calib_cam2imu.size() * (6 + 8));
1007 options_cov.min_reciprocal_condition_number = params.init_dyn_min_rec_cond;
1009 options_cov.apply_loss_function =
true;
1010 options_cov.num_threads = params.init_dyn_mle_max_threads;
1011 ceres::Covariance problem_cov(options_cov);
1012 bool success = problem_cov.Compute(covariance_blocks, &problem);
1015 free_state_memory();
1021 order.push_back(_imu);
1022 covariance = Eigen::MatrixXd::Zero(_imu->size(), _imu->size());
1023 Eigen::Matrix<double, 3, 3, Eigen::RowMajor> covtmp = Eigen::Matrix<double, 3, 3, Eigen::RowMajor>::Zero();
1026 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_ori[state_index], ceres_vars_ori[state_index], covtmp.data()));
1027 covariance.block(0, 0, 3, 3) = covtmp.eval();
1028 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_pos[state_index], ceres_vars_pos[state_index], covtmp.data()));
1029 covariance.block(3, 3, 3, 3) = covtmp.eval();
1030 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_vel[state_index], ceres_vars_vel[state_index], covtmp.data()));
1031 covariance.block(6, 6, 3, 3) = covtmp.eval();
1032 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_bias_g[state_index], ceres_vars_bias_g[state_index], covtmp.data()));
1033 covariance.block(9, 9, 3, 3) = covtmp.eval();
1034 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_bias_a[state_index], ceres_vars_bias_a[state_index], covtmp.data()));
1035 covariance.block(12, 12, 3, 3) = covtmp.eval();
1038 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_ori[state_index], ceres_vars_pos[state_index], covtmp.data()));
1039 covariance.block(0, 3, 3, 3) = covtmp.eval();
1040 covariance.block(3, 0, 3, 3) = covtmp.transpose();
1041 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_ori[state_index], ceres_vars_vel[state_index], covtmp.data()));
1042 covariance.block(0, 6, 3, 3) = covtmp.eval();
1043 covariance.block(6, 0, 3, 3) = covtmp.transpose().eval();
1044 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_ori[state_index], ceres_vars_bias_g[state_index], covtmp.data()));
1045 covariance.block(0, 9, 3, 3) = covtmp.eval();
1046 covariance.block(9, 0, 3, 3) = covtmp.transpose().eval();
1047 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_ori[state_index], ceres_vars_bias_a[state_index], covtmp.data()));
1048 covariance.block(0, 12, 3, 3) = covtmp.eval();
1049 covariance.block(12, 0, 3, 3) = covtmp.transpose().eval();
1052 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_pos[state_index], ceres_vars_vel[state_index], covtmp.data()));
1053 covariance.block(3, 6, 3, 3) = covtmp.eval();
1054 covariance.block(6, 3, 3, 3) = covtmp.transpose().eval();
1055 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_pos[state_index], ceres_vars_bias_g[state_index], covtmp.data()));
1056 covariance.block(3, 9, 3, 3) = covtmp.eval();
1057 covariance.block(9, 3, 3, 3) = covtmp.transpose().eval();
1058 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_pos[state_index], ceres_vars_bias_a[state_index], covtmp.data()));
1059 covariance.block(3, 12, 3, 3) = covtmp.eval();
1060 covariance.block(12, 3, 3, 3) = covtmp.transpose().eval();
1063 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_vel[state_index], ceres_vars_bias_g[state_index], covtmp.data()));
1064 covariance.block(6, 9, 3, 3) = covtmp.eval();
1065 covariance.block(9, 6, 3, 3) = covtmp.transpose().eval();
1066 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_vel[state_index], ceres_vars_bias_a[state_index], covtmp.data()));
1067 covariance.block(6, 12, 3, 3) = covtmp.eval();
1068 covariance.block(12, 6, 3, 3) = covtmp.transpose().eval();
1071 CHECK(problem_cov.GetCovarianceBlockInTangentSpace(ceres_vars_bias_g[state_index], ceres_vars_bias_a[state_index], covtmp.data()));
1072 covariance.block(9, 12, 3, 3) = covtmp.eval();
1073 covariance.block(12, 9, 3, 3) = covtmp.transpose().eval();
1076 covariance.block(0, 0, 3, 3) *= params.init_dyn_inflation_orientation;
1077 covariance.block(6, 6, 3, 3) *= params.init_dyn_inflation_velocity;
1078 covariance.block(9, 9, 3, 3) *= params.init_dyn_inflation_bias_gyro;
1079 covariance.block(12, 12, 3, 3) *= params.init_dyn_inflation_bias_accel;
1082 covariance = 0.5 * (covariance + covariance.transpose());
1083 Eigen::Vector3d sigmas_vel = covariance.block(6, 6, 3, 3).diagonal().transpose().cwiseSqrt();
1084 Eigen::Vector3d sigmas_bg = covariance.block(9, 9, 3, 3).diagonal().transpose().cwiseSqrt();
1085 Eigen::Vector3d sigmas_ba = covariance.block(12, 12, 3, 3).diagonal().transpose().cwiseSqrt();
1086 PRINT_DEBUG(
"[init-d]: vel priors = %.3f, %.3f, %.3f\n", sigmas_vel(0), sigmas_vel(1), sigmas_vel(2));
1087 PRINT_DEBUG(
"[init-d]: bg priors = %.3f, %.3f, %.3f\n", sigmas_bg(0), sigmas_bg(1), sigmas_bg(2));
1088 PRINT_DEBUG(
"[init-d]: ba priors = %.3f, %.3f, %.3f\n", sigmas_ba(0), sigmas_ba(1), sigmas_ba(2));
1091 Eigen::MatrixXd x = _imu->value();
1092 x.block(4, 0, 3, 1).setZero();
1097 auto rT7 = boost::posix_time::microsec_clock::local_time();
1098 PRINT_DEBUG(
"[TIME]: %.4f sec for prelim tests\n", (rT2 - rT1).total_microseconds() * 1e-6);
1099 PRINT_DEBUG(
"[TIME]: %.4f sec for linsys setup\n", (rT3 - rT2).total_microseconds() * 1e-6);
1100 PRINT_DEBUG(
"[TIME]: %.4f sec for linsys\n", (rT4 - rT3).total_microseconds() * 1e-6);
1101 PRINT_DEBUG(
"[TIME]: %.4f sec for ceres opt setup\n", (rT5 - rT4).total_microseconds() * 1e-6);
1102 PRINT_DEBUG(
"[TIME]: %.4f sec for ceres opt\n", (rT6 - rT5).total_microseconds() * 1e-6);
1103 PRINT_DEBUG(
"[TIME]: %.4f sec for ceres covariance\n", (rT7 - rT6).total_microseconds() * 1e-6);
1104 PRINT_DEBUG(
"[TIME]: %.4f sec total for initialization\n", (rT7 - rT1).total_microseconds() * 1e-6);
1105 free_state_memory();