35 #include <boost/date_time/posix_time/posix_time.hpp> 36 #include <boost/math/distributions/chi_squared.hpp> 52 for (
int i = 1; i < 500; i++) {
53 boost::math::chi_squared chi_squared_dist(i);
58 void UpdaterMSCKF::update(std::shared_ptr<State> state, std::vector<std::shared_ptr<Feature>> &feature_vec) {
61 if (feature_vec.empty())
65 boost::posix_time::ptime rT0, rT1, rT2, rT3, rT4, rT5;
66 rT0 = boost::posix_time::microsec_clock::local_time();
70 for (
const auto &clone_imu : state->_clones_IMU) {
71 clonetimes.emplace_back(clone_imu.first);
75 auto it0 = feature_vec.begin();
76 while (it0 != feature_vec.end()) {
79 (*it0)->clean_old_measurements(clonetimes);
83 for (
const auto &pair : (*it0)->timestamps) {
84 ct_meas += (*it0)->timestamps[pair.first].size();
89 (*it0)->to_delete =
true;
90 it0 = feature_vec.erase(it0);
95 rT1 = boost::posix_time::microsec_clock::local_time();
98 std::unordered_map<size_t, std::unordered_map<double, FeatureInitializer::ClonePose>> clones_cam;
99 for (
const auto &clone_calib : state->_calib_IMUtoCAM) {
102 std::unordered_map<double, FeatureInitializer::ClonePose> clones_cami;
103 for (
const auto &clone_imu : state->_clones_IMU) {
106 Eigen::Matrix<double, 3, 3> R_GtoCi = clone_calib.second->Rot() * clone_imu.second->Rot();
107 Eigen::Matrix<double, 3, 1> p_CioinG = clone_imu.second->pos() - R_GtoCi.transpose() * clone_calib.second->pos();
110 clones_cami.insert({clone_imu.first, FeatureInitializer::ClonePose(R_GtoCi, p_CioinG)});
114 clones_cam.insert({clone_calib.first, clones_cami});
118 auto it1 = feature_vec.begin();
119 while (it1 != feature_vec.end()) {
122 bool success_tri =
true;
130 bool success_refine =
true;
136 if (!success_tri || !success_refine) {
137 (*it1)->to_delete =
true;
138 it1 = feature_vec.erase(it1);
143 rT2 = boost::posix_time::microsec_clock::local_time();
146 size_t max_meas_size = 0;
147 for (
size_t i = 0; i < feature_vec.size(); i++) {
148 for (
const auto &pair : feature_vec.at(i)->timestamps) {
149 max_meas_size += 2 * feature_vec.at(i)->timestamps[pair.first].size();
155 size_t max_hx_size = state->max_covariance_size();
156 for (
auto &landmark : state->_features_SLAM) {
157 max_hx_size -= landmark.second->size();
161 Eigen::VectorXd res_big = Eigen::VectorXd::Zero(max_meas_size);
162 Eigen::MatrixXd Hx_big = Eigen::MatrixXd::Zero(max_meas_size, max_hx_size);
163 std::unordered_map<std::shared_ptr<Type>,
size_t> Hx_mapping;
164 std::vector<std::shared_ptr<Type>> Hx_order_big;
169 auto it2 = feature_vec.begin();
170 while (it2 != feature_vec.end()) {
174 feat.
featid = (*it2)->featid;
175 feat.
uvs = (*it2)->uvs;
181 if (state->_options.feat_rep_msckf == LandmarkRepresentation::Representation::ANCHORED_INVERSE_DEPTH_SINGLE) {
182 feat.
feat_representation = LandmarkRepresentation::Representation::ANCHORED_MSCKF_INVERSE_DEPTH;
189 feat.
p_FinA = (*it2)->p_FinA;
192 feat.
p_FinG = (*it2)->p_FinG;
200 std::vector<std::shared_ptr<Type>> Hx_order;
210 Eigen::MatrixXd S = H_x * P_marg * H_x.transpose();
212 double chi2 = res.dot(S.llt().solve(res));
216 if (res.rows() < 500) {
219 boost::math::chi_squared chi_squared_dist(res.rows());
220 chi2_check = boost::math::quantile(chi_squared_dist, 0.95);
226 (*it2)->to_delete =
true;
227 it2 = feature_vec.erase(it2);
238 for (
const auto &var : Hx_order) {
241 if (Hx_mapping.find(var) == Hx_mapping.end()) {
242 Hx_mapping.insert({var, ct_jacob});
243 Hx_order_big.push_back(var);
244 ct_jacob += var->size();
248 Hx_big.block(ct_meas, Hx_mapping[var], H_x.rows(), var->size()) = H_x.block(0, ct_hx, H_x.rows(), var->size());
249 ct_hx += var->size();
253 res_big.block(ct_meas, 0, res.rows(), 1) = res;
254 ct_meas += res.rows();
257 rT3 = boost::posix_time::microsec_clock::local_time();
261 for (
size_t f = 0;
f < feature_vec.size();
f++) {
262 feature_vec[
f]->to_delete =
true;
269 assert(ct_meas <= max_meas_size);
270 assert(ct_jacob <= max_hx_size);
271 res_big.conservativeResize(ct_meas, 1);
272 Hx_big.conservativeResize(ct_meas, ct_jacob);
276 if (Hx_big.rows() < 1) {
279 rT4 = boost::posix_time::microsec_clock::local_time();
282 Eigen::MatrixXd R_big =
_options.
sigma_pix_sq * Eigen::MatrixXd::Identity(res_big.rows(), res_big.rows());
286 rT5 = boost::posix_time::microsec_clock::local_time();
289 PRINT_ALL(
"[MSCKF-UP]: %.4f seconds to clean\n", (rT1 - rT0).total_microseconds() * 1e-6);
290 PRINT_ALL(
"[MSCKF-UP]: %.4f seconds to triangulate\n", (rT2 - rT1).total_microseconds() * 1e-6);
291 PRINT_ALL(
"[MSCKF-UP]: %.4f seconds create system (%d features)\n", (rT3 - rT2).total_microseconds() * 1e-6, (
int)feature_vec.size());
292 PRINT_ALL(
"[MSCKF-UP]: %.4f seconds compress system\n", (rT4 - rT3).total_microseconds() * 1e-6);
293 PRINT_ALL(
"[MSCKF-UP]: %.4f seconds update state (%d size)\n", (rT5 - rT4).total_microseconds() * 1e-6, (
int)res_big.rows());
294 PRINT_ALL(
"[MSCKF-UP]: %.4f seconds total\n", (rT5 - rT1).total_microseconds() * 1e-6);
static void nullspace_project_inplace(Eigen::MatrixXd &H_f, Eigen::MatrixXd &H_x, Eigen::VectorXd &res)
This will project the left nullspace of H_f onto the linear system.
static void get_feature_jacobian_full(std::shared_ptr< State > state, UpdaterHelperFeature &feature, Eigen::MatrixXd &H_f, Eigen::MatrixXd &H_x, Eigen::VectorXd &res, std::vector< std::shared_ptr< ov_type::Type >> &x_order)
Will construct the "stacked" Jacobians for a single feature from all its measurements.
double anchor_clone_timestamp
Timestamp of anchor clone.
Extended Kalman Filter estimator.
static Eigen::MatrixXd get_marginal_covariance(std::shared_ptr< State > state, const std::vector< std::shared_ptr< ov_type::Type >> &small_variables)
For a given set of variables, this will this will calculate a smaller covariance. ...
Struct which stores general updater options.
double chi2_multipler
What chi-squared multipler we should apply.
static void measurement_compress_inplace(Eigen::MatrixXd &H_x, Eigen::VectorXd &res)
This will perform measurement compression.
size_t featid
Unique ID of this feature.
Eigen::Vector3d p_FinA
Triangulated position of this feature, in the anchor frame.
ov_type::LandmarkRepresentation::Representation feat_representation
What representation our feature is in.
Eigen::Vector3d p_FinA_fej
Triangulated position of this feature, in the anchor frame first estimate.
Eigen::Vector3d p_FinG_fej
Triangulated position of this feature, in the global frame first estimate.
static void EKFUpdate(std::shared_ptr< State > state, const std::vector< std::shared_ptr< ov_type::Type >> &H_order, const Eigen::MatrixXd &H, const Eigen::VectorXd &res, const Eigen::MatrixXd &R)
Performs EKF update of the state (see Linear Measurement Update page)
Feature object that our UpdaterHelper leverages, has all measurements and means.
std::deque< double > clonetimes
void update(std::shared_ptr< State > state, std::vector< std::shared_ptr< ov_core::Feature >> &feature_vec)
Given tracked features, this will try to use them to update the state.
std::unordered_map< size_t, std::vector< Eigen::VectorXf > > uvs
UV coordinates that this feature has been seen from (mapped by camera ID)
int anchor_cam_id
What camera ID our pose is anchored in!! By default the first measurement is the anchor.
#define PRINT_WARNING(x...)
std::map< int, double > chi_squared_table
Chi squared 95th percentile table (lookup would be size of residual)
std::unordered_map< size_t, std::vector< double > > timestamps
Timestamps of each UV measurement (mapped by camera ID)
std::shared_ptr< ov_core::FeatureInitializer > initializer_feat
Feature initializer class object.
UpdaterOptions _options
Options used during update.
std::unordered_map< size_t, std::vector< Eigen::VectorXf > > uvs_norm
double sigma_pix
Noise sigma for our raw pixel measurements.
double sigma_pix_sq
Covariance for our raw pixel measurements.
Eigen::Vector3d p_FinG
Triangulated position of this feature, in the global frame.