diff --git a/src/processor/processor_odom_icp.cpp b/src/processor/processor_odom_icp.cpp index 4ec5e9adb4de8d885f00ae012e0565e0590e8781..a362d6e7ad3bcc24deffff288cff3b25908d1a97 100644 --- a/src/processor/processor_odom_icp.cpp +++ b/src/processor/processor_odom_icp.cpp @@ -1,11 +1,14 @@ #include "laser/processor/processor_odom_icp.h" -#include "core/common/wolf.h" +#include "laser/math/laser_tools.h" + +#include <core/common/wolf.h> using namespace wolf; using namespace laserscanutils; ProcessorOdomIcp::ProcessorOdomIcp(ParamsProcessorOdomIcpPtr _params): - ProcessorTracker("ProcessorOdomIcp", "PO", 2, _params) + ProcessorTracker("ProcessorOdomIcp", "PO", 2, _params), + IsMotion("PO") { proc_params_ = _params; @@ -53,7 +56,6 @@ ProcessorOdomIcp::ProcessorOdomIcp(ParamsProcessorOdomIcpPtr _params): trf_origin_last_.res_covar = Eigen::Matrix3d::Identity(); trf_origin_incoming_.res_covar = Eigen::Matrix3d::Identity(); trf_last_incoming_.res_covar = Eigen::Matrix3d::Identity(); - setStateStructure("PO"); } ProcessorOdomIcp::~ProcessorOdomIcp() @@ -84,46 +86,12 @@ unsigned int ProcessorOdomIcp::processKnown() CaptureLaser2dPtr origin_ptr = std::static_pointer_cast<CaptureLaser2d>(origin_ptr_); CaptureLaser2dPtr incoming_ptr = std::static_pointer_cast<CaptureLaser2d>(incoming_ptr_); - // WOLF_INFO("max_correspondence_dist ", this->icp_params_.max_correspondence_dist); - // WOLF_INFO("max_iterations ", this->icp_params_.max_iterations); - // WOLF_INFO("outliers_adaptive_mult ", this->icp_params_.outliers_adaptive_mult); - // WOLF_INFO("outliers_adaptive_order ", this->icp_params_.outliers_adaptive_order); - // WOLF_INFO("outliers_maxPerc ", this->icp_params_.outliers_maxPerc); - // WOLF_INFO("use_corr_tricks ", this->icp_params_.use_corr_tricks); - // WOLF_INFO("use_point_to_line_distance ", this->icp_params_.use_point_to_line_distance); - // WOLF_INFO("angle_max_ ", this->laser_scan_params_.angle_max_); - // WOLF_INFO("angle_min_ ", this->laser_scan_params_.angle_min_); - // WOLF_INFO("angle_std_dev_ ", this->laser_scan_params_.angle_std_dev_); - // WOLF_INFO("angle_step_ ", this->laser_scan_params_.angle_step_); - // WOLF_INFO("range_max_ ", this->laser_scan_params_.range_max_); - // WOLF_INFO("range_min_ ", this->laser_scan_params_.range_min_); - // WOLF_INFO("range_std_dev_ ", this->laser_scan_params_.range_std_dev_); - // WOLF_INFO("scan_time_ ", this->laser_scan_params_.scan_time_); - - // WOLF_INFO("ODOM Icp: Aligning scans ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - // WOLF_INFO("Laser scan params\n"); - // this->laser_scan_params_.print(); - // WOLF_INFO("Icp params\n"); - // WOLF_INFO("\n max_correspondence_dist: ", this->icp_params_.max_correspondence_dist, - // "\n use_point_to_line_distance: ", this->icp_params_.use_point_to_line_distance, "\n max_iterations: ", this->icp_params_.max_iterations, - // "\n outliers_adaptive_mult: ", this->icp_params_.outliers_adaptive_mult, - // "\n outliers_adaptive_order: ", this->icp_params_.outliers_adaptive_order, "\n outliers_maxPerc: ", this->icp_params_.outliers_maxPerc, - // "\n use corr tricks: ", this->icp_params_.use_corr_tricks); trf_origin_incoming_ = icp_tools_ptr_->align(incoming_ptr->getScan(), origin_ptr->getScan(), this->laser_scan_params_, this->icp_params_, this->trf_origin_last_.res_transf); // Check order - // double score_normalized - // ((double)trf_origin_incoming_.nvalid / (double)min(incoming_ptr->getScan().ranges_raw_.size(), origin_ptr->getScan().ranges_raw_.size())); - // double mean_error = trf_origin_incoming_.error / trf_origin_incoming_.nvalid; - // WOLF_INFO("DBG ------------------------------"); - // WOLF_INFO("DBG valid? ", trf_origin_incoming_.valid, " m_er ", mean_error, " ", score_normalized * 100, "% own_id: ", incoming_ptr->id(), - // " other_id: ", origin_ptr->id()); - // WOLF_INFO("DBG own_POSE: 0 0 0 other_POSE: ", this->trf_origin_last_.res_transf.transpose(), - // " Icp_guess: ", this->trf_origin_last_.res_transf.transpose(), " Icp_trf_origin_incoming_: ", trf_origin_incoming_.res_transf.transpose()); - // WOLF_INFO("DBG odometry"); trf_origin_incoming_.valid = trf_origin_incoming_.valid && trf_origin_incoming_.error / trf_origin_incoming_.nvalid < 5e-2; } return 0; @@ -134,7 +102,6 @@ unsigned int ProcessorOdomIcp::processNew(const int& _max_features) Eigen::Vector3d t_identity; t_identity << 0, 0, 0; - // XXX: Dynamic or static? JS: static is OK. CaptureLaser2dPtr incoming_ptr = std::static_pointer_cast<CaptureLaser2d>(incoming_ptr_); CaptureLaser2dPtr last_ptr = std::static_pointer_cast<CaptureLaser2d>(last_ptr_); @@ -144,28 +111,8 @@ unsigned int ProcessorOdomIcp::processNew(const int& _max_features) this->icp_params_, t_identity); - // WOLF_INFO("ODOM Icp: Aligning scans ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - // WOLF_INFO("Laser scan params\n"); - // this->laser_scan_params_.print(); - // WOLF_INFO("Icp params\n"); - // WOLF_INFO("\n max_correspondence_dist: ", this->icp_params_.max_correspondence_dist, "\n use_point_to_line_distance: ", this->icp_params_.use_point_to_line_distance, "\n max_iterations: ", this->icp_params_.max_iterations, - // "\n outliers_adaptive_mult: ", this->icp_params_.outliers_adaptive_mult, "\n outliers_adaptive_order: ", this->icp_params_.outliers_adaptive_order, "\n outliers_maxPerc: ", - // this->icp_params_.outliers_maxPerc, "\n use corr tricks: ", this->icp_params_.use_corr_tricks); trf_last_incoming_ = icp_tools_ptr_->align(incoming_ptr->getScan(), last_ptr->getScan(), this->laser_scan_params_, this->icp_params_, t_identity); - //TEST! TO BE REMOVED - // trf_last_incoming_.res_transf = t_identity; - - // WOLF_TRACE("trf_last_incoming_: ", trf_last_incoming_.res_transf.transpose()); - // Eigen::Matrix2s R_last; - // double alphal = trf_origin_last_.res_transf(2); - // double alphali = trf_origin_incoming_.res_transf(2) - alphal; - // R_last << cos(alphal), -sin(alphal), sin(alphal), cos(alphal); - // Eigen::Vector3s trf_last_incoming_check; - // trf_last_incoming_check.head(2) = R_last.transpose() * (trf_origin_incoming_.res_transf.head(2) - trf_origin_last_.res_transf.head(2)); - // trf_last_incoming_check(2) = alphali; - // WOLF_TRACE("trf_last_incoming_check: ", trf_last_incoming_check.transpose()); - trf_last_incoming_.valid = trf_last_incoming_.valid && trf_last_incoming_.error / trf_last_incoming_.nvalid < 5e-2; return 0; @@ -236,60 +183,69 @@ void ProcessorOdomIcp::advanceDerived() // overwrite last frame's state - Isometry2d w_T_ro = Translation2d(origin_ptr_->getFrame()->getState().at('P')) * Rotation2Dd(origin_ptr_->getFrame()->getState().at('O')(0)); - Isometry2d ro_T_so = Translation2d(origin_ptr_->getSensorP()->getState()) * Rotation2Dd(origin_ptr_->getSensorO()->getState()(0)); - Isometry2d& ri_T_si = ro_T_so; // A reference just to have nice names without computing overhead + auto w_T_ro = laser::trf2isometry(origin_ptr_->getFrame()->getP()->getState(), origin_ptr_->getFrame()->getO()->getState()); + auto ro_T_so = laser::trf2isometry(origin_ptr_->getSensorP()->getState(), origin_ptr_->getSensorO()->getState()); + const auto& ri_T_si = ro_T_so; // A reference just to have nice names without computing overhead + // incoming - Isometry2d so_T_si = Translation2d(trf_origin_incoming_.res_transf.head(2)) * Rotation2Dd(trf_origin_incoming_.res_transf(2)); + auto so_T_si = laser::trf2isometry(trf_origin_incoming_.res_transf); Isometry2d w_T_ri = w_T_ro * ro_T_so * so_T_si * ri_T_si.inverse(); Vector3d x_inc; x_inc << w_T_ri.translation() , Rotation2Dd(w_T_ri.rotation()).angle(); // Put the state of incoming in last last_ptr_->getFrame()->setState(x_inc, "PO", {2,1}); + // computing odometry + auto so_T_sl = laser::trf2isometry(trf_origin_last_.res_transf); + Isometry2d sl_T_si = so_T_sl.inverse() * so_T_si; + odometry_['P'] = sl_T_si.translation(); + odometry_['O'] = Vector1d(Rotation2Dd(sl_T_si.rotation()).angle()); + + // advance transforms trf_origin_last_ = trf_origin_incoming_; } void ProcessorOdomIcp::resetDerived() { - // WOLF_INFO("NDEBUG origin ", origin_ptr_->id(), " last ", last_ptr_->id(), " error ", trf_origin_last_.error, " merror ", trf_origin_last_.error/(double) trf_origin_last_.nvalid, " nvalid ", trf_origin_last_.nvalid, " sqrt diag. ", trf_origin_last_.res_covar.diagonal().cwiseSqrt().transpose(), " trnsf ", trf_origin_last_.res_transf.transpose()); - if (origin_ptr_ != nullptr and last_ptr_ != nullptr) - { - // std::cout << "NDEBUG origin " << std::setw(4) << origin_ptr_->id() - // << " last " << std::setw(4) << last_ptr_->id() - // << " is valid? " << std::setw(4) << trf_origin_last_.valid - // << " error " << std::setw(8) << trf_origin_last_.error - // << " merror " << std::setw(10) << trf_origin_last_.error / (double)trf_origin_last_.nvalid - // << " nvalid " << std::setw(3) << trf_origin_last_.nvalid - // << " sqrt diag. " << std::setw(10) << trf_origin_last_.res_covar.diagonal().cwiseSqrt().transpose() - // << " trnsf " << std::setw(10) << trf_origin_last_.res_transf.transpose() << std::endl; - } - // Using processing_step_ to ensure that origin, last and incoming are different - if (processing_step_ != FIRST_TIME_WITH_PACK && processing_step_ != FIRST_TIME_WITHOUT_PACK) { - // Notation explanation: - // x1_R_x2: Rotation from frame x1 to frame x2 - // x1_p_y1_y2: translation vector from y1 to y2 expressed in frame x1 - - - Isometry2d w_T_ro = Translation2d(origin_ptr_->getFrame()->getP()->getState()) * Rotation2Dd(origin_ptr_->getFrame()->getO()->getState()(0)); - Isometry2d ro_T_so = Translation2d(origin_ptr_->getSensorP()->getState()) * Rotation2Dd(origin_ptr_->getSensorO()->getState()(0)); - Isometry2d &ri_T_si = ro_T_so; // A reference just to have nice names without computing overhead - - // incoming - - Isometry2d so_T_si = Translation2d(trf_origin_incoming_.res_transf.head(2)) * Rotation2Dd(trf_origin_incoming_.res_transf(2)); - Isometry2d w_T_ri = w_T_ro * ro_T_so * so_T_si * ri_T_si.inverse(); - Vector3d x_current; - x_current << w_T_ri.translation(), Rotation2Dd(w_T_ri.rotation()).angle(); - - // last - - last_ptr_->getFrame()->setState(x_current, "PO", {2,1}); - // incoming_ptr_->getFrame()->setState(x_current); - - trf_origin_last_ = trf_last_incoming_; + // WOLF_INFO("NDEBUG origin ", origin_ptr_->id(), " last ", last_ptr_->id(), " error ", trf_origin_last_.error, " merror ", trf_origin_last_.error/(double) trf_origin_last_.nvalid, " nvalid ", trf_origin_last_.nvalid, " sqrt diag. ", trf_origin_last_.res_covar.diagonal().cwiseSqrt().transpose(), " trnsf ", trf_origin_last_.res_transf.transpose()); + if (origin_ptr_ != nullptr and last_ptr_ != nullptr) + { + // + } + + // Using processing_step_ to ensure that origin, last and incoming are different + if (processing_step_ != FIRST_TIME_WITH_PACK && processing_step_ != FIRST_TIME_WITHOUT_PACK) { + // Notation explanation: + // x1_R_x2: Rotation from frame x1 to frame x2 + // x1_p_y1_y2: translation vector from y1 to y2 expressed in frame x1 + + + auto w_T_ro = laser::trf2isometry(origin_ptr_->getFrame()->getP()->getState(), origin_ptr_->getFrame()->getO()->getState()); + auto ro_T_so = laser::trf2isometry(origin_ptr_->getSensorP()->getState(), origin_ptr_->getSensorO()->getState()); + const auto &ri_T_si = ro_T_so; // A reference just to have nice names without computing overhead + + // incoming + + auto so_T_si = laser::trf2isometry(trf_origin_incoming_.res_transf); + Isometry2d w_T_ri = w_T_ro * ro_T_so * so_T_si * ri_T_si.inverse(); + Vector3d x_current; + x_current << w_T_ri.translation(), Rotation2Dd(w_T_ri.rotation()).angle(); + + // last + + last_ptr_->getFrame()->setState(x_current, "PO", {2,1}); + // incoming_ptr_->getFrame()->setState(x_current); + + // computing odometry + auto so_T_sl = laser::trf2isometry(trf_origin_last_.res_transf); + Isometry2d sl_T_si = so_T_sl.inverse() * so_T_si; + odometry_['P'] = sl_T_si.translation(); + odometry_['O'] = Vector1d(Rotation2Dd(sl_T_si.rotation()).angle()); + + // advance transforms + trf_origin_last_ = trf_last_incoming_; } } @@ -321,21 +277,17 @@ FactorBasePtr ProcessorOdomIcp::emplaceFactor(FeatureBasePtr _feature) VectorComposite ProcessorOdomIcp::getState( const StateStructure& _structure ) const { - Isometry2d w_T_ro = Translation2d(origin_ptr_->getFrame()->getP()->getState()) * Rotation2Dd(origin_ptr_->getFrame()->getO()->getState()(0)); - Isometry2d ro_T_so = Translation2d(origin_ptr_->getSensorP()->getState()) * Rotation2Dd(origin_ptr_->getSensorO()->getState()(0)); - Isometry2d &ri_T_si = ro_T_so; // A reference just to have nice names without computing overhead + auto w_T_ro = laser::trf2isometry(origin_ptr_->getFrame()->getP()->getState(), origin_ptr_->getFrame()->getO()->getState()); + auto ro_T_so = laser::trf2isometry(origin_ptr_->getSensorP()->getState(), origin_ptr_->getSensorO()->getState()); + const auto& rl_T_sl = ro_T_so; // A reference just to have nice names without computing overhead // incoming - Isometry2d so_T_si = Translation2d(trf_origin_last_.res_transf.head(2)) * Rotation2Dd(trf_origin_last_.res_transf(2)); - Isometry2d w_T_ri = w_T_ro * ro_T_so * so_T_si * ri_T_si.inverse(); + auto so_T_sl = laser::trf2isometry(trf_origin_last_.res_transf); + Isometry2d w_T_rl = w_T_ro * ro_T_so * so_T_sl * rl_T_sl.inverse(); Vector3d x_current; - VectorComposite state("PO", {w_T_ri.translation(), Vector1d(Rotation2Dd(w_T_ri.rotation()).angle())}); - -// Eigen::Vector3d state = Vector3d(0, 0, 0); -// state.head(2) << w_T_ri.translation(); -// state(2) = Rotation2Dd(w_T_ri.rotation()).angle(); + VectorComposite state("PO", {w_T_rl.translation(), Vector1d(Rotation2Dd(w_T_rl.rotation()).angle())}); return state; } diff --git a/test/gtest_processor_odom_icp.cpp b/test/gtest_processor_odom_icp.cpp index 4026584fd5ceadd57d98f5918bf3f6478eaa10e2..d4ba77e8e8a96e2ffb78bd7491272630a26aacfc 100644 --- a/test/gtest_processor_odom_icp.cpp +++ b/test/gtest_processor_odom_icp.cpp @@ -161,7 +161,6 @@ TEST_F(ProcessorOdomIcp_Test, solve) for (auto F : problem->getTrajectory()->getFrameList()) { if (F->isKey()) -// F->setState(0.5 * Vector3d::Random()); F->perturb(0.5); }