diff --git a/CMakeLists.txt b/CMakeLists.txt index c854988d784c23f31f2ba48544efa554b2d0d82a..abb733b77222baf486bc7009404e1934f4e8ec70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) if(COMMAND cmake_policy) - cmake_policy(SET CMP0005 NEW) + cmake_policy(SET CMP0005 NEW) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) # MAC OSX RPATH @@ -47,7 +47,6 @@ if(UNIX) endif(UNIX) - MESSAGE("Starting ${PROJECT_NAME} CMakeLists ...") CMAKE_MINIMUM_REQUIRED(VERSION 2.8) @@ -64,8 +63,18 @@ ENDIF() option(_WOLF_TRACE "Enable wolf tracing macro" ON) -# option(BUILD_EXAMPLES "Build examples" OFF) -set(BUILD_TESTS true) +IF(NOT BUILD_TESTS) + OPTION(BUILD_TESTS "Build Unit tests" ON) +ENDIF(NOT BUILD_TESTS) + +IF(NOT BUILD_DEMOS) + OPTION(BUILD_DEMOS "Build Demos" OFF) +ENDIF(NOT BUILD_DEMOS) + +IF(NOT BUILD_DOC) + OPTION(BUILD_DOC "Build Documentation" OFF) +ENDIF(NOT BUILD_DOC) + ############# ## Testing ## @@ -92,6 +101,8 @@ FIND_PACKAGE(wolf REQUIRED) FIND_PACKAGE(laser_scan_utils REQUIRED) +FIND_PACKAGE(csm QUIET) + #FIND_PATH( # Suitesparse_INCLUDE_DIRS # NAMES SuiteSparse_config.h @@ -204,9 +215,22 @@ SET(SRCS_DTASSC SET(SRCS_SOLVER ) SET(SRCS_YAML + src/yaml/processor_odom_ICP_yaml.cpp src/yaml/sensor_laser_2D_yaml.cpp ) #OPTIONALS +if(csm_FOUND) + SET(HDRS_PROCESSOR ${HDRS_PROCESSOR} + # include/laser/processor/processor_closeloop_icp.h + include/laser/processor/processor_odom_icp.h + include/laser/feature/feature_icp_align.h + ) + SET(SRCS_PROCESSOR ${SRCS_PROCESSOR} + # src/processor/processor_closeloop_icp.cpp + src/processor/processor_odom_icp.cpp + src/feature/feature_icp_align.cpp + ) +endif(csm_FOUND) #optional HDRS and SRCS # ==================EXAMPLE=============== # IF (Ceres_FOUND) @@ -216,12 +240,12 @@ SET(SRCS_YAML # include/base/ceres_wrapper/ceres_manager.h # include/base/ceres_wrapper/cost_function_wrapper.h # include/base/ceres_wrapper/create_numeric_diff_cost_function.h -# include/base/ceres_wrapper/local_parametrization_wrapper.h +# include/base/ceres_wrapper/local_parametrization_wrapper.h # ) # SET(SRCS_WRAPPER # src/solver/solver_manager.cpp # src/ceres_wrapper/ceres_manager.cpp -# src/ceres_wrapper/local_parametrization_wrapper.cpp +# src/ceres_wrapper/local_parametrization_wrapper.cpp # ) # ELSE(Ceres_FOUND) # SET(HDRS_WRAPPER) diff --git a/cmake_modules/Findcsm.cmake b/cmake_modules/Findcsm.cmake new file mode 100755 index 0000000000000000000000000000000000000000..938022e920cddb287f773480596ffe497d8a0306 --- /dev/null +++ b/cmake_modules/Findcsm.cmake @@ -0,0 +1,64 @@ +FIND_PATH( + csm_INCLUDE_DIR + NAMES algos.h + PATHS /usr/local/include/csm) +IF(csm_INCLUDE_DIR) + MESSAGE("Found csm include dirs: ${csm_INCLUDE_DIR}") +ELSE(csm_INCLUDE_DIR) + MESSAGE("Couldn't find csm include dirs") +ENDIF(csm_INCLUDE_DIR) + +FIND_LIBRARY( + csm_LIBRARY + NAMES libcsm.so libcsm.dylib + PATHS /usr/local/lib) +IF(csm_LIBRARY) + MESSAGE("Found csm lib: ${csm_LIBRARY}") +ELSE(csm_LIBRARY) + MESSAGE("Couldn't find csm lib") +ENDIF(csm_LIBRARY) + +IF (csm_INCLUDE_DIR AND csm_LIBRARY) + SET(csm_FOUND TRUE) + ELSE(csm_INCLUDE_DIR AND csm_LIBRARY) + set(csm_FOUND FALSE) +ENDIF (csm_INCLUDE_DIR AND csm_LIBRARY) + +IF (csm_FOUND) + IF (NOT csm_FIND_QUIETLY) + MESSAGE(STATUS "Found csm: ${csm_LIBRARY}") + ENDIF (NOT csm_FIND_QUIETLY) +ELSE (csm_FOUND) + IF (csm_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find csm") + ENDIF (csm_FIND_REQUIRED) +ENDIF (csm_FOUND) + + +macro(csm_report_not_found REASON_MSG) + set(csm_FOUND FALSE) + unset(csm_INCLUDE_DIR) + unset(csm_LIBRARIES) + + # Reset the CMake module path to its state when this script was called. + set(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH}) + + # Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by + # FindPackage() use the camelcase library name, not uppercase. + if (csm_FIND_QUIETLY) + message(STATUS "Failed to find csm- " ${REASON_MSG} ${ARGN}) + else (csm_FIND_REQUIRED) + message(FATAL_ERROR "Failed to find csm - " ${REASON_MSG} ${ARGN}) + else() + # Neither QUIETLY nor REQUIRED, use SEND_ERROR which emits an error + # that prevents generation, but continues configuration. + message(SEND_ERROR "Failed to find csm - " ${REASON_MSG} ${ARGN}) + endif () + return() +endmacro(csm_report_not_found) + +if(NOT csm_FOUND) + csm_report_not_found("Something went wrong while setting up csm.") +endif(NOT csm_FOUND) +# Set the include directories for csm (itself). +set(csm_FOUND TRUE) \ No newline at end of file diff --git a/include/laser/feature/feature_icp_align.h b/include/laser/feature/feature_icp_align.h new file mode 100644 index 0000000000000000000000000000000000000000..a7ee1401d41192913777075dc7123b61f053a0e6 --- /dev/null +++ b/include/laser/feature/feature_icp_align.h @@ -0,0 +1,54 @@ +#ifndef FEATURE_ICP_ALIGN_H_ +#define FEATURE_ICP_ALIGN_H_ + +//Wolf includes +#include "core/feature/feature_base.h" +#include "core/factor/factor_odom_2D.h" +#include "laser_scan_utils/icp.h" + + +//std includes + +namespace wolf { + +WOLF_PTR_TYPEDEFS(FeatureICPAlign); + +//class FeatureOdom2D +class FeatureICPAlign : public FeatureBase +{ + public: + + /** \brief Constructor from capture pointer and measure + * + * \param _measurement the measurement + * \param _meas_covariance the noise of the measurement + * + */ + FeatureICPAlign(const laserscanutils::icpOutput& _icp_align_res); + + virtual ~FeatureICPAlign(); + + /** \brief Generic interface to find factors + * + * TBD + * Generic interface to find factors between this feature and a map (static/slam) or a previous feature + * + **/ + virtual void findFactors(); + + /** \brief Constructor from capture pointer and measure + * + * \param _measurement the measurement + * \param _meas_covariance the noise of the measurement + * + */ + const laserscanutils::icpOutput& getQualityAlign() const; + + private: + laserscanutils::icpOutput icp_align_res_; + +}; + +} // namespace wolf + +#endif diff --git a/include/laser/processor/processor_closeloop_icp.h b/include/laser/processor/processor_closeloop_icp.h new file mode 100644 index 0000000000000000000000000000000000000000..e06f241b84df4f398924c3f40c3e34202932f2c3 --- /dev/null +++ b/include/laser/processor/processor_closeloop_icp.h @@ -0,0 +1,56 @@ +/************************** + * WOLF includes * + **************************/ +#include <core/processor/processor_base.h> +#include <laser/capture/capture_laser_2D.h> + +/************************** + * STD includes * + **************************/ +#include <iostream> +#include <iomanip> +#include <queue> + +namespace wolf +{ +WOLF_PTR_TYPEDEFS(ProcessorCloseLoopICP); +WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsCloseLoopICP); + + +struct ProcessorParamsCloseLoopICP : public ProcessorParamsBase +{ + int match_past_key_frame; + ProcessorParamsCloseLoopICP() = default; + ProcessorParamsCloseLoopICP(std::string _unique_name, const ParamsServer& _server): + ProcessorParamsBase(_unique_name, _server) + { + match_past_key_frame = _server.getParam<int>(_unique_name + "/match_past_key_frame"); + } + std::string print() + { + return "\n" + ProcessorParamsBase::print() + + "match_past_key_frame: " + std::to_string(match_past_key_frame) + "\n"; + } +}; + +class ProcessorCloseLoopICP : public ProcessorBase +{ + protected: + CaptureLaser2DPtr _origin_cpt; + int count = 0; + public: + ProcessorCloseLoopICP(ProcessorParamsBasePtr _params); + + virtual void configure(SensorBasePtr _sensor) override; + + virtual void process(CaptureBasePtr _capture_ptr) override; + + virtual bool voteForKeyFrame() override; + + static ProcessorBasePtr createAutoConf(const std::string& _unique_name, const ParamsServer& _server, const SensorBasePtr sensor_ptr); + + static ProcessorBasePtr create(const std::string& _unique_name, const ProcessorParamsBasePtr _params, const SensorBasePtr); + +}; + +} diff --git a/include/laser/processor/processor_odom_icp.h b/include/laser/processor/processor_odom_icp.h new file mode 100644 index 0000000000000000000000000000000000000000..221160f8fe2f3a9543f5d7eac75ed5a9186f3deb --- /dev/null +++ b/include/laser/processor/processor_odom_icp.h @@ -0,0 +1,126 @@ +#ifndef SRC_PROCESSOR_ODOM_ICP_H_ +#define SRC_PROCESSOR_ODOM_ICP_H_ + + +#include "laser/capture/capture_laser_2D.h" +#include "laser/feature/feature_icp_align.h" + +#include <core/processor/processor_tracker.h> + +#include <laser_scan_utils/laser_scan_utils.h> +#include <laser_scan_utils/icp.h> + +namespace wolf { + +WOLF_PTR_TYPEDEFS(ProcessorOdomICP); +WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsOdomICP); + +struct ProcessorParamsOdomICP : public ProcessorParamsTracker +{ + // ICP Params + int use_point_to_line_distance; + int max_correspondence_dist; + int max_iterations; + int use_corr_tricks; + double outliers_maxPerc; + double outliers_adaptive_order; + double outliers_adaptive_mult; + + // Other processor params + double vfk_min_dist; + double vfk_min_angle; + double vfk_min_time; + double vfk_min_error; + int vfk_max_points; + + ProcessorParamsOdomICP() = default; + ProcessorParamsOdomICP(std::string _unique_name, const ParamsServer &_server): + ProcessorParamsTracker(_unique_name, _server) + { + use_point_to_line_distance = _server.getParam<int> (_unique_name + "/use_point_to_line_distance"); + max_correspondence_dist = _server.getParam<int> (_unique_name + "/max_correspondence_dist"); + max_iterations = _server.getParam<int> (_unique_name + "/max_iterations"); + use_corr_tricks = _server.getParam<int> (_unique_name + "/use_corr_tricks"); + outliers_maxPerc = _server.getParam<double> (_unique_name + "/outliers_maxPerc"); + outliers_adaptive_order = _server.getParam<double> (_unique_name + "/outliers_adaptive_order"); + outliers_adaptive_mult = _server.getParam<double> (_unique_name + "/outliers_adaptive_mult"); + vfk_min_dist = _server.getParam<double> (_unique_name + "/vfk_min_dist"); + vfk_min_angle = _server.getParam<double> (_unique_name + "/vfk_min_angle"); + vfk_min_time = _server.getParam<double> (_unique_name + "/vfk_min_time"); + vfk_min_error = _server.getParam<double> (_unique_name + "/vfk_min_error"); + vfk_max_points = _server.getParam<int> (_unique_name + "/vfk_max_points"); + } + std::string print() { + return "\n" + ProcessorParamsTracker::print() + "\n" + + "use_point_to_line_distance: "+ std::to_string(use_point_to_line_distance)+ "\n" + + "max_correspondence_dist: " + std::to_string(max_correspondence_dist) + "\n" + + "max_iterations: " + std::to_string(max_iterations) + "\n" + + "use_corr_tricks: " + std::to_string(use_corr_tricks) + "\n" + + "outliers_maxPerc: " + std::to_string(outliers_maxPerc) + "\n" + + "outliers_adaptive_order: " + std::to_string(outliers_adaptive_order) + "\n" + + "outliers_adaptive_mult: " + std::to_string(outliers_adaptive_mult) + "\n" + + "vfk_min_dist: " + std::to_string(vfk_min_dist) + "\n" + + "vfk_min_angle: " + std::to_string(vfk_min_angle) + "\n" + + "vfk_min_time: " + std::to_string(vfk_min_time) + "\n" + + "vfk_min_error: " + std::to_string(vfk_min_error) + "\n" + + "vfk_max_points: " + std::to_string(vfk_max_points) + "\n"; + } +}; + +class ProcessorOdomICP : public ProcessorTracker +{ + protected: + // Useful sensor stuff + SensorLaser2DPtr sensor_laser_; // casted pointer to parent + laserscanutils::LaserScanParams laser_scan_params_; + + // ICP algorithm + std::shared_ptr<laserscanutils::ICP> icp_tools_ptr_; + + // temporary and carry-on transformations + laserscanutils::icpOutput trf_origin_last_; + laserscanutils::icpOutput trf_origin_incoming_; + laserscanutils::icpOutput trf_last_incoming_; + + public: + laserscanutils::icpParams icp_params_; + ProcessorParamsOdomICPPtr proc_params_; + + public: + ProcessorOdomICP(ProcessorParamsOdomICPPtr _params); + WOLF_PROCESSOR_CREATE(ProcessorOdomICP, ProcessorParamsOdomICP); + virtual ~ProcessorOdomICP(); + virtual void configure(SensorBasePtr _sensor) override; + + protected: + virtual void preProcess() override; + + virtual unsigned int processKnown() override; + virtual unsigned int processNew(const int& _max_features) override; + + virtual bool voteForKeyFrame() override; + + virtual void advanceDerived() override; + virtual void resetDerived() override; + + + virtual void establishFactors() override; + FeatureBasePtr emplaceFeature(CaptureBasePtr _capture_laser); + FactorBasePtr emplaceFactor(FeatureBasePtr _feature); + + inline bool voteForKeyFrameDistance(); + inline bool voteForKeyFrameAngle(); + inline bool voteForKeyFrameTime(); + inline bool voteForKeyFrameMatchQuality(); + + + + +}; + + + + +} + +#endif // SRC_PROCESSOR_ODOM_ICP_H_ diff --git a/include/laser/processor/processor_tracker_feature_polyline_2D.h b/include/laser/processor/processor_tracker_feature_polyline_2D.h index 408b75dff1fc745a2669acdfef79f2200354f9fc..f50d33fd87074be6dd234990a63ba2cc50787a33 100644 --- a/include/laser/processor/processor_tracker_feature_polyline_2D.h +++ b/include/laser/processor/processor_tracker_feature_polyline_2D.h @@ -9,7 +9,6 @@ #define PROCESSOR_TRACKER_FEATURE_POLYLINE_2D_H_ #include "laser/processor/polyline_2D_utils.h" -#include "core/processor/processor_tracker_feature.h" #include "laser/landmark/landmark_polyline_2D.h" #include "laser/landmark/landmark_match_polyline_2D.h" #include "laser/sensor/sensor_laser_2D.h" @@ -19,6 +18,9 @@ #include "laser/factor/factor_point_2D.h" #include "laser/factor/factor_point_to_line_2D.h" +#include "core/processor/processor_tracker_feature.h" +#include "core/utils/params_server.hpp" + //laser_scan_utils #include "laser_scan_utils/laser_scan.h" #include "laser_scan_utils/line_finder_iterative.h" @@ -36,6 +38,18 @@ typedef std::map<Scalar,LandmarkMatchPolyline2DPtr> LandmarkMatchPolyline2DScala struct ProcessorParamsTrackerFeaturePolyline2D : public ProcessorParamsTrackerFeature { + ProcessorParamsTrackerFeaturePolyline2D() = default; + ProcessorParamsTrackerFeaturePolyline2D(std::string _unique_name, const wolf::ParamsServer & _server) : + ProcessorParamsTrackerFeature(_unique_name, _server) + { + // TODO write parser! + } + std::string print() + { + return "\n" + ProcessorParamsTrackerFeature::print(); + // TODO write printer! + } + laserscanutils::LineFinderIterativeParams line_finder_params; Scalar match_feature_position_sq_norm_max; Scalar match_feature_orientation_sq_norm_max; @@ -81,6 +95,7 @@ class ProcessorTrackerFeaturePolyline2D : public ProcessorTrackerFeature public: ProcessorTrackerFeaturePolyline2D(ProcessorParamsTrackerFeaturePolyline2DPtr _params); + WOLF_PROCESSOR_CREATE(ProcessorTrackerFeaturePolyline2D, ProcessorParamsTrackerFeaturePolyline2D); virtual ~ProcessorTrackerFeaturePolyline2D(); @@ -242,10 +257,6 @@ class ProcessorTrackerFeaturePolyline2D : public ProcessorTrackerFeature public: - /// @brief Factory method - static ProcessorBasePtr create(const std::string& _unique_name, - const ProcessorParamsBasePtr _params); - const FeatureBasePtrList& getLastNewFeatures() const { return untracked_features_last_; diff --git a/include/laser/sensor/sensor_laser_2D.h b/include/laser/sensor/sensor_laser_2D.h index 71a152b098ab1f2654be2ea53e13b794c614d08b..3fd5c68f30c0896c4e25ae9f3e11ffa0d553ff91 100644 --- a/include/laser/sensor/sensor_laser_2D.h +++ b/include/laser/sensor/sensor_laser_2D.h @@ -20,6 +20,33 @@ struct IntrinsicsLaser2D : public IntrinsicsBase virtual ~IntrinsicsLaser2D() = default; laserscanutils::LaserScanParams scan_params; + + IntrinsicsLaser2D() = default; + IntrinsicsLaser2D(std::string _unique_name, const wolf::ParamsServer & _server) : + IntrinsicsBase(_unique_name, _server) + { + scan_params.angle_min_ = _server.getParam<double>(_unique_name + "/LaserScanParams/angle_min"); + scan_params.angle_max_ = _server.getParam<double>(_unique_name + "/LaserScanParams/angle_max"); + scan_params.angle_step_ = _server.getParam<double>(_unique_name + "/LaserScanParams/angle_step"); + scan_params.scan_time_ = _server.getParam<double>(_unique_name + "/LaserScanParams/scan_time"); + scan_params.range_min_ = _server.getParam<double>(_unique_name + "/LaserScanParams/range_min"); + scan_params.range_max_ = _server.getParam<double>(_unique_name + "/LaserScanParams/range_max"); + scan_params.range_std_dev_ = _server.getParam<double>(_unique_name + "/LaserScanParams/range_std_dev"); + scan_params.angle_std_dev_ = _server.getParam<double>(_unique_name + "/LaserScanParams/angle_std_dev"); + } + std::string print() + { + return "\n" + IntrinsicsBase::print() + "\n" + + "LaserScanParams/angle_min: " + std::to_string(scan_params.angle_min_) + "\n" + + "LaserScanParams/angle_max: " + std::to_string(scan_params.angle_max_) + "\n" + + "LaserScanParams/angle_step: " + std::to_string(scan_params.angle_step_) + "\n" + + "LaserScanParams/scan_time: " + std::to_string(scan_params.scan_time_) + "\n" + + "LaserScanParams/range_min: " + std::to_string(scan_params.range_min_) + "\n" + + "LaserScanParams/range_max: " + std::to_string(scan_params.range_max_) + "\n" + + "LaserScanParams/range_std_dev: " + std::to_string(scan_params.range_std_dev_) + "\n" + + "LaserScanParams/angle_std_dev: " + std::to_string(scan_params.angle_std_dev_) + "\n"; + } + }; WOLF_PTR_TYPEDEFS(SensorLaser2D); @@ -57,6 +84,7 @@ class SensorLaser2D : public SensorBase SensorLaser2D(StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, const IntrinsicsLaser2D& _params); SensorLaser2D(StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, IntrinsicsLaser2DPtr _params); SensorLaser2D(const Eigen::VectorXs& _extrinsics, IntrinsicsLaser2DPtr _params); + WOLF_SENSOR_CREATE(SensorLaser2D, IntrinsicsLaser2D, 3); virtual ~SensorLaser2D(); @@ -77,9 +105,7 @@ class SensorLaser2D : public SensorBase const laserscanutils::LaserScanParams & getScanParams() const; public: - static SensorBasePtr create(const std::string& _unique_name, const Eigen::VectorXs& _extrinsics_po, const IntrinsicsBasePtr _intrinsics); - static SensorBasePtr createAutoConf(const std::string& _unique_name, const ParamsServer& _server); - static IntrinsicsBasePtr createParams(const std::string& _filename_dot_yaml); +// static IntrinsicsBasePtr createParams(const std::string& _filename_dot_yaml); }; diff --git a/src/feature/feature_icp_align.cpp b/src/feature/feature_icp_align.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cbc8f8a64c97913f0ed7b12bc9920b0ddc0f45bc --- /dev/null +++ b/src/feature/feature_icp_align.cpp @@ -0,0 +1,28 @@ +#include "laser/feature/feature_icp_align.h" + +namespace wolf { + +FeatureICPAlign::FeatureICPAlign(const laserscanutils::icpOutput& _icp_align_res): + FeatureBase("ICP ALIGN", _icp_align_res.res_transf, _icp_align_res.res_covar), + icp_align_res_(_icp_align_res) +{ + +} + +FeatureICPAlign::~FeatureICPAlign() +{ + // +} + +void FeatureICPAlign::findFactors() +{ + +} + +const laserscanutils::icpOutput& FeatureICPAlign::getQualityAlign() const +{ + return icp_align_res_; +} + + +} // namespace wolf diff --git a/src/processor/processor_closeloop_icp.cpp b/src/processor/processor_closeloop_icp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4f410071df0de2110f27ad7a4878c8ee46ab519 --- /dev/null +++ b/src/processor/processor_closeloop_icp.cpp @@ -0,0 +1,80 @@ +#include "laser/processor/processor_closeloop_icp.h" +#include "laser_scan_utils/icp.h" + +using namespace wolf; + +// Constructor +ProcessorCloseLoopICP::ProcessorCloseLoopICP(ProcessorParamsBasePtr _params) : + ProcessorBase("CL ICP", _params) +{ + +} + +void ProcessorCloseLoopICP::configure(SensorBasePtr _sensor) +{ + +} + +void ProcessorCloseLoopICP::process(CaptureBasePtr _capture_ptr) +{ + // std::cout << "Am I being called?" << std::endl; + // ++count; + // CaptureLaser2DPtr cpt_ptr = std::static_pointer_cast<CaptureLaser2D>(_capture_ptr); + // SensorLaser2DPtr laser_sen = std::static_pointer_cast<SensorLaser2D>(_capture_ptr->getSensor()); + // if(_origin_cpt == nullptr) _origin_cpt = cpt_ptr; + // if(count % 10 != 0) return; + // laserscanutils::LaserScanParams scan_params = laser_sen->getScanParams(); + // laserscanutils::LaserScan& last_scan = cpt_ptr->getScan(); + // laserscanutils::LaserScan& origin_scan = _origin_cpt->getScan(); + // std::cout << "Number of ranges: " << cpt_ptr->getScan().ranges_raw_.size() << '\n'; + // Eigen::Vector3s transform_0; + // transform_0 << 0,0,0; + // laserscanutils::icp_output result = laserscanutils::ICP::matchPC(last_scan, origin_scan, scan_params, transform_0); + // std::cout << "We made it past result " << std::endl; + // std::cout << "My solution " << result.res_transf(0) << "," << result.res_transf(1) << "," << result.res_transf(2) << std::endl; + // _origin_cpt = cpt_ptr; +} + +bool ProcessorCloseLoopICP::voteForKeyFrame() +{ + return 0; +} + +ProcessorBasePtr ProcessorCloseLoopICP::create(const std::string& _unique_name, const ProcessorParamsBasePtr _params, const SensorBasePtr) +{ + ProcessorCloseLoopICPPtr prc_ptr; + + ProcessorParamsCloseLoopICPPtr params; + if (_params) + params = std::static_pointer_cast<ProcessorParamsCloseLoopICP>(_params); + else + params = std::make_shared<ProcessorParamsCloseLoopICP>(); + + prc_ptr = std::make_shared<ProcessorCloseLoopICP>(params); + prc_ptr->setName(_unique_name); + + return prc_ptr; +} + +ProcessorBasePtr ProcessorCloseLoopICP::createAutoConf(const std::string& _unique_name, const ParamsServer& _server, const SensorBasePtr sensor_ptr) +{ + ProcessorCloseLoopICPPtr prc_ptr; + auto params = std::make_shared<ProcessorParamsCloseLoopICP>(); + params->match_past_key_frame = _server.getParam<double>(_unique_name + "/match_past_key_frame", "5"); + + prc_ptr = std::make_shared<ProcessorCloseLoopICP>(params); + prc_ptr->setName(_unique_name); + + return prc_ptr; +} + + +// Register in the SensorFactory +#include "core/processor/processor_factory.h" +namespace wolf { +WOLF_REGISTER_PROCESSOR("CL ICP", ProcessorCloseLoopICP) +} /* namespace wolf */ +#include "core/processor/autoconf_processor_factory.h" +namespace wolf { + WOLF_REGISTER_PROCESSOR_AUTO("CL ICP", ProcessorCloseLoopICP) +} // namespace wolf diff --git a/src/processor/processor_odom_icp.cpp b/src/processor/processor_odom_icp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0e0102c4e628136731716b4e39be20763c08e15b --- /dev/null +++ b/src/processor/processor_odom_icp.cpp @@ -0,0 +1,229 @@ +#include "laser/processor/processor_odom_icp.h" + +using namespace wolf; +using namespace laserscanutils; + +ProcessorOdomICP::ProcessorOdomICP(ProcessorParamsOdomICPPtr _params): + ProcessorTracker("ODOM ICP", _params) +{ + proc_params_ = _params; + + + icp_params_.use_point_to_line_distance = proc_params_->use_point_to_line_distance; + icp_params_.max_correspondence_dist = proc_params_->max_correspondence_dist; + icp_params_.max_iterations = proc_params_->max_iterations; + icp_params_.use_corr_tricks = proc_params_->use_corr_tricks; + icp_params_.outliers_maxPerc = proc_params_->outliers_maxPerc; + icp_params_.outliers_adaptive_order = proc_params_->outliers_adaptive_order; + icp_params_.outliers_adaptive_mult = proc_params_->outliers_adaptive_mult; + + // ICP algorithm + icp_tools_ptr_ = std::make_shared<ICP>(); + + // Frame transforms + trf_origin_last_.res_covar = Eigen::Matrix3s::Identity(); + trf_origin_incoming_.res_covar = Eigen::Matrix3s::Identity(); + trf_last_incoming_.res_covar = Eigen::Matrix3s::Identity(); +} + +ProcessorOdomICP::~ProcessorOdomICP() +{ + +} + +void ProcessorOdomICP::preProcess() +{ + +} + + + +void ProcessorOdomICP::configure(SensorBasePtr _sensor) +{ + sensor_laser_ = std::static_pointer_cast<SensorLaser2D>(_sensor); + laser_scan_params_ = sensor_laser_->getScanParams(); +} + + + +unsigned int ProcessorOdomICP::processKnown() +{ + // Match the incoming with the origin, passing the transform from origin to last as initialization + + if (origin_ptr_) // Make sure it's not the FIRST_TIME + { + CaptureLaser2DPtr origin_ptr = std::static_pointer_cast<CaptureLaser2D>(origin_ptr_); + CaptureLaser2DPtr incoming_ptr = std::static_pointer_cast<CaptureLaser2D>(incoming_ptr_); + + 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 + } + + return 0; +} + +unsigned int ProcessorOdomICP::processNew(const int& _max_features) +{ + Eigen::Vector3s 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_); + + trf_last_incoming_ = icp_tools_ptr_->align(incoming_ptr->getScan(), + last_ptr->getScan(), + this->laser_scan_params_, + this->icp_params_, + t_identity); + return 0; +} + +bool ProcessorOdomICP::voteForKeyFrame() +{ + return (voteForKeyFrameDistance() || + voteForKeyFrameAngle() || + voteForKeyFrameTime() || + voteForKeyFrameMatchQuality()); +} + +inline bool ProcessorOdomICP::voteForKeyFrameDistance() +{ + bool vote = (trf_origin_incoming_.res_transf.head<2>().norm() > proc_params_->vfk_min_dist); + if (vote) + { + std::cout << "Distance True" << '\n'; + } + + return vote; +} + +inline bool ProcessorOdomICP::voteForKeyFrameAngle() +{ + bool vote = (fabs(trf_origin_incoming_.res_transf(2)) > proc_params_->vfk_min_angle); + if (vote) + { + std::cout << "Angle True" << '\n'; + } + + return vote; +} + +inline bool ProcessorOdomICP::voteForKeyFrameTime() +{ + Scalar secs = incoming_ptr_->getTimeStamp() - origin_ptr_->getTimeStamp(); + + bool vote = (secs > proc_params_->vfk_min_time); + + if (vote) + { + std::cout << "Time True" << '\n'; + } + + return vote; +} + +inline bool ProcessorOdomICP::voteForKeyFrameMatchQuality() +{ + bool vote = (trf_origin_incoming_.error > proc_params_->vfk_min_error || trf_origin_incoming_.nvalid < proc_params_->vfk_max_points); + if (vote) + { + std::cout << "Quality True" << '\n'; + } + return vote ; +} + + +void ProcessorOdomICP::advanceDerived() +{ + using namespace Eigen; + + // overwrite last frame's state + + Isometry2ds w_T_ro = Translation2ds(origin_ptr_->getFrame()->getState().head(2)) * Rotation2Ds(origin_ptr_->getFrame()->getState()(2)); + Isometry2ds ro_T_so = Translation2ds(origin_ptr_->getSensorP()->getState()) * Rotation2Ds(origin_ptr_->getSensorO()->getState()(0)); + Isometry2ds& ri_T_si = ro_T_so; // A reference just to have nice names without computing overhead + + // incoming + + Isometry2ds so_T_si = Translation2ds(trf_origin_incoming_.res_transf.head(2)) * Rotation2Ds(trf_origin_incoming_.res_transf(2)); + Isometry2ds w_T_ri = w_T_ro * ro_T_so * so_T_si * ri_T_si.inverse(); + Vector3s x_inc; x_inc << w_T_ri.translation() , Rotation2Ds(w_T_ri.rotation()).angle(); + + // Put the state of incoming in last + last_ptr_->getFrame()->setState(x_inc); + + trf_origin_last_ = trf_origin_incoming_; +} + +void ProcessorOdomICP::resetDerived() +{ + + // 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 + + // Rotation composition + Eigen::Rotation2D<Scalar> w_R_ro = Eigen::Rotation2D<Scalar>(origin_ptr_->getFrame()->getState()(2)); + Eigen::Rotation2D<Scalar> r_R_s = Eigen::Rotation2D<Scalar>(origin_ptr_->getSensorO()->getState()(0)); + Eigen::Rotation2D<Scalar>& ro_R_so = r_R_s; // just a ref for bettter chaining trf. names + Eigen::Rotation2D<Scalar> so_R_sl = Eigen::Rotation2D<Scalar>(trf_origin_last_.res_transf(2)); + + // Eigen::Rotation2D<Scalar> w_R_rl = w_R_ro*r_R_s*so_R_sl*r_R_s.inverse(); + // ro_R_so = rl_R_sl = r_R_s + // Planar rotations are commutative + Eigen::Rotation2D<Scalar> w_R_rl = w_R_ro * so_R_sl; + + // Translation composition + Eigen::Vector2s w_p_w_ro = origin_ptr_->getFrame()->getState().head(2); + Eigen::Vector2s w_p_ro_so = w_R_ro * origin_ptr_->getSensorP()->getState(); + Eigen::Vector2s w_p_so_sl = w_R_ro * ro_R_so * trf_origin_last_.res_transf.head(2); + Eigen::Vector2s w_p_sl_rl = w_R_rl * (-last_ptr_->getSensorP()->getState()); + + Eigen::Vector2s w_p_w_rl = w_p_w_ro + w_p_ro_so + w_p_so_sl + w_p_sl_rl; + + Eigen::Vector3s curr_state; + curr_state.head(2) = w_p_w_rl; + curr_state(2) = origin_ptr_->getFrame()->getState()(2) + trf_origin_last_.res_transf(2); + + last_ptr_->getFrame()->setState(curr_state); + + trf_origin_last_ = trf_last_incoming_; + } +} + +void ProcessorOdomICP::establishFactors() +{ + if (last_ptr_ != origin_ptr_) + { + auto ftr_ptr = emplaceFeature(last_ptr_); + emplaceFactor(ftr_ptr); + } +} + +FeatureBasePtr ProcessorOdomICP::emplaceFeature(CaptureBasePtr _capture_laser) +{ + CaptureLaser2DPtr capture_laser = std::static_pointer_cast<CaptureLaser2D>(_capture_laser); + return FeatureBase::emplace<FeatureICPAlign>(capture_laser, + trf_origin_last_); +} + +FactorBasePtr ProcessorOdomICP::emplaceFactor(FeatureBasePtr _feature) +{ + return FactorBase::emplace<FactorOdom2D>(_feature, _feature, origin_ptr_->getFrame(), + shared_from_this()); +} + + +// Register in the SensorFactory +#include "core/processor/processor_factory.h" +namespace wolf { + WOLF_REGISTER_PROCESSOR("ODOM ICP", ProcessorOdomICP); + WOLF_REGISTER_PROCESSOR_AUTO("ODOM ICP", ProcessorOdomICP); +} // namespace wolf diff --git a/src/processor/processor_tracker_feature_polyline_2D.cpp b/src/processor/processor_tracker_feature_polyline_2D.cpp index 08a5031298200a7c045f31514423f6e712d0d0a9..404889898031bf5e548ef957625c071c0b8fe08f 100644 --- a/src/processor/processor_tracker_feature_polyline_2D.cpp +++ b/src/processor/processor_tracker_feature_polyline_2D.cpp @@ -1363,22 +1363,12 @@ void ProcessorTrackerFeaturePolyline2D::computeTransformations() //std::cout << "R_last_incoming_ " << std::endl << R_last_incoming_ << std::endl; } -ProcessorBasePtr ProcessorTrackerFeaturePolyline2D::create(const std::string& _unique_name, - const ProcessorParamsBasePtr _params) -{ - auto params = std::static_pointer_cast<ProcessorParamsTrackerFeaturePolyline2D>(_params); - - auto prc_ptr = std::make_shared<ProcessorTrackerFeaturePolyline2D>(params); - - prc_ptr->setName(_unique_name); - - return prc_ptr; -} } /* namespace wolf */ // Register in the SensorFactory #include "core/processor/processor_factory.h" namespace wolf { -WOLF_REGISTER_PROCESSOR("TRACKER FEATURE POLYLINE", ProcessorTrackerFeaturePolyline2D) -} /* namespace wolf */ + WOLF_REGISTER_PROCESSOR("TRACKER FEATURE POLYLINE", ProcessorTrackerFeaturePolyline2D); + WOLF_REGISTER_PROCESSOR_AUTO("TRACKER FEATURE POLYLINE", ProcessorTrackerFeaturePolyline2D); +} // namespace wolf diff --git a/src/sensor/sensor_laser_2D.cpp b/src/sensor/sensor_laser_2D.cpp index bff07ba6ede76c6e5cd0ac762877596bd2bd2f3f..a31115ef3c51761ad991d1a79fb97022ba8bf4a1 100644 --- a/src/sensor/sensor_laser_2D.cpp +++ b/src/sensor/sensor_laser_2D.cpp @@ -1,6 +1,7 @@ #include "laser/sensor/sensor_laser_2D.h" -#include "core/state_block/state_block.h" -#include "core/state_block/state_angle.h" + +#include <core/state_block/state_block.h> +#include <core/state_block/state_angle.h> namespace wolf { @@ -31,17 +32,22 @@ SensorLaser2D::SensorLaser2D(StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, const I // } -SensorLaser2D::SensorLaser2D(StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, IntrinsicsLaser2DPtr _params) : - SensorLaser2D(_p_ptr, _o_ptr, *_params) +SensorLaser2D::SensorLaser2D(StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, const IntrinsicsLaser2DPtr _params) : + SensorBase("LASER 2D", _p_ptr, _o_ptr, nullptr, 8), + scan_params_(_params->scan_params) { // } -SensorLaser2D::SensorLaser2D(const Eigen::VectorXs& _extrinsics, IntrinsicsLaser2DPtr _params) : - SensorLaser2D(std::make_shared<StateBlock>(_extrinsics.head(2), true, nullptr), - std::make_shared<StateAngle>(_extrinsics(2), true), - _params) +SensorLaser2D::SensorLaser2D(const Eigen::VectorXs& _extrinsics, const IntrinsicsLaser2DPtr _params) : + SensorBase("LASER 2D", + std::make_shared<StateBlock>(_extrinsics.head(2), false), + std::make_shared<StateAngle>(_extrinsics(2), false), + nullptr, + 8), + scan_params_(_params->scan_params) { + // } SensorLaser2D::~SensorLaser2D() @@ -72,43 +78,11 @@ const laserscanutils::LaserScanParams& SensorLaser2D::getScanParams() const return scan_params_; } -// Define the factory method -SensorBasePtr SensorLaser2D::create(const std::string& _unique_name, const Eigen::VectorXs& _extrinsics_po, - const IntrinsicsBasePtr _intrinsics) -{ - // decode extrinsics vector - assert(_extrinsics_po.size() == 3 && "Bad extrinsics vector length. Should be 3 for 2D."); - StateBlockPtr pos_ptr = std::make_shared<StateBlock>(_extrinsics_po.head(2), true); - StateBlockPtr ori_ptr = std::make_shared<StateBlock>(_extrinsics_po.tail(1), true); - // cast intrinsics into derived type - IntrinsicsLaser2DPtr params = std::static_pointer_cast<IntrinsicsLaser2D>(_intrinsics); - SensorLaser2DPtr sen = std::make_shared<SensorLaser2D>(pos_ptr, ori_ptr, params->scan_params); - sen->setName(_unique_name); - return sen; -} - -SensorBasePtr SensorLaser2D::createAutoConf(const std::string& _unique_name, const ParamsServer& _server) -{ - // decode extrinsics vector - Eigen::VectorXs _extrinsics_po = _server.getParam<Eigen::VectorXs>(_unique_name + "/extrinsic/pos"); - assert(_extrinsics_po.size() == 3 && "Bad extrinsics vector length. Should be 3 for 2D."); - StateBlockPtr pos_ptr = std::make_shared<StateBlock>(_extrinsics_po.head(2), true); - StateBlockPtr ori_ptr = std::make_shared<StateBlock>(_extrinsics_po.tail(1), true); - - SensorLaser2DPtr sen; - IntrinsicsLaser2D params; - - sen = std::make_shared<SensorLaser2D>(pos_ptr, ori_ptr, params.scan_params); - - sen->setName(_unique_name); - return sen; -} } // namespace wolf // Register in the SensorFactory and the ParameterFactory #include "core/sensor/sensor_factory.h" -//#include "intrinsics_factory.h" namespace wolf { WOLF_REGISTER_SENSOR("LASER 2D", SensorLaser2D) WOLF_REGISTER_SENSOR_AUTO("LASER 2D", SensorLaser2D) diff --git a/src/yaml/processor_odom_ICP_yaml.cpp b/src/yaml/processor_odom_ICP_yaml.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a5557abad838122c9239b038e964f2cc66faa0d --- /dev/null +++ b/src/yaml/processor_odom_ICP_yaml.cpp @@ -0,0 +1,64 @@ +/** + * \file processor_odom_ICP_yaml.cpp + * + * Created on: Aug 6, 2019 + * \author: jsola + */ + + +// wolf +#include "laser/processor/processor_odom_icp.h" +#include "core/common/factory.h" + +// wolf yaml +#include "core/yaml/yaml_conversion.h" + +// yaml library +#include <yaml-cpp/yaml.h> + +namespace wolf +{ +namespace { +// intrinsics creator +ProcessorParamsBasePtr createProcessorParamsOdomICP(const std::string& _filename_dot_yaml) +{ + WOLF_INFO("ProcessorParamsOdomICP: Parsing file: ", _filename_dot_yaml); + + YAML::Node config = YAML::LoadFile(_filename_dot_yaml); + + if (config["type"].as<std::string>() == "ODOM ICP") + { + ProcessorParamsOdomICPPtr params = std::make_shared<ProcessorParamsOdomICP>(); + + params->voting_active = config["voting_active"] .as<bool>(); + params->voting_aux_active = config["voting_aux_active"] .as<bool>(); + params->time_tolerance = config["time_tolerance"] .as<Scalar>(); + + params->min_features_for_keyframe = config["min_features_for_keyframe"] .as<Scalar>(); + params->max_new_features = config["max_new_features"] .as<SizeEigen >(); + + params->use_point_to_line_distance = config["use_point_to_line_distance"] .as<int>(); + params->max_correspondence_dist = config["max_correspondence_dist"] .as<int>(); + params->max_iterations = config["max_iterations"] .as<int>(); + params->use_corr_tricks = config["use_corr_tricks"] .as<int>(); + params->outliers_maxPerc = config["outliers_maxPerc"] .as<Scalar>(); + params->outliers_adaptive_order = config["outliers_adaptive_order"] .as<Scalar>(); + params->outliers_adaptive_mult = config["outliers_adaptive_mult"] .as<Scalar>(); + params->vfk_min_dist = config["vfk_min_dist"] .as<Scalar>(); + params->vfk_min_angle = config["vfk_min_angle"] .as<Scalar>(); + params->vfk_min_time = config["vfk_min_time"] .as<Scalar>(); + params->vfk_min_error = config["vfk_min_error"] .as<Scalar>(); + params->vfk_max_points = config["vfk_max_points"] .as<int>(); + + return params; + } + + std::cout << "Bad configuration file. No processor type found." << std::endl; + return nullptr; +} + +// register into factory +const bool WOLF_UNUSED registered_odom_ICP_params = ProcessorParamsFactory::get().registerCreator("ODOM ICP", createProcessorParamsOdomICP); + +} // namespace [void] +} // namespace wolf diff --git a/src/yaml/sensor_laser_2D_yaml.cpp b/src/yaml/sensor_laser_2D_yaml.cpp index d741f365f3c12239074fb5350e4b269d0a23cfc2..ec1ea6692a2c5762563a3ff3bb6dfdf2491ae640 100644 --- a/src/yaml/sensor_laser_2D_yaml.cpp +++ b/src/yaml/sensor_laser_2D_yaml.cpp @@ -24,8 +24,31 @@ IntrinsicsBasePtr createIntrinsicsLaser2D(const std::string& _filename_dot_yaml) { // If required: Parse YAML - IntrinsicsLaser2DPtr params; // dummy - return params; + WOLF_INFO("IntrinsicsLaser2D: Parsing file: ", _filename_dot_yaml); + + YAML::Node config = YAML::LoadFile(_filename_dot_yaml); + + if (config["type"].as<std::string>() == "LASER 2D") + { + YAML::Node ls_params = config["LaserScanParams"]; + + IntrinsicsLaser2DPtr params = std::make_shared<IntrinsicsLaser2D>(); + + params->scan_params.angle_min_ = ls_params["angle_min"] .as<double>(); + params->scan_params.angle_max_ = ls_params["angle_max"] .as<double>(); + params->scan_params.angle_step_ = ls_params["angle_step"] .as<double>(); + params->scan_params.scan_time_ = ls_params["scan_time"] .as<double>(); + params->scan_params.range_min_ = ls_params["range_min"] .as<double>(); + params->scan_params.range_max_ = ls_params["range_max"] .as<double>(); + params->scan_params.range_std_dev_ = ls_params["range_std_dev"] .as<double>(); + params->scan_params.angle_std_dev_ = ls_params["angle_std_dev"] .as<double>(); + + return params; + } + + std::cout << "Bad configuration file " << _filename_dot_yaml << ". No processor type found." << std::endl; + return nullptr; + } // register into factory diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a973252f84fb6d0a3fce5a02b44540406fbee94d..ab4905e315a6adfcf0e27b85c6692d6e9ba7a3b0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -16,8 +16,11 @@ target_link_libraries(gtest_example ${PLUGIN_NAME}) # wolf_add_gtest(gtest_landmark_polyline gtest_landmark_polyline.cpp) target_link_libraries(gtest_landmark_polyline ${PLUGIN_NAME} ${wolf_LIBRARY}) +wolf_add_gtest(gtest_processor_odom_icp gtest_processor_odom_icp.cpp) +target_link_libraries(gtest_processor_odom_icp ${PLUGIN_NAME} ${wolf_LIBRARY}) + wolf_add_gtest(gtest_polyline_2D gtest_polyline_2D.cpp) target_link_libraries(gtest_polyline_2D ${PLUGIN_NAME} ${wolf_LIBRARY}) # wolf_add_gtest(gtest_processor_tracker_feature_polyline_2D gtest_processor_tracker_feature_polyline_2D.cpp) -# target_link_libraries(gtest_processor_tracker_feature_polyline_2D ${PLUGIN_NAME} ${wolf_LIBRARY}) \ No newline at end of file +# target_link_libraries(gtest_processor_tracker_feature_polyline_2D ${PLUGIN_NAME} ${wolf_LIBRARY}) diff --git a/test/gtest_processor_odom_icp.cpp b/test/gtest_processor_odom_icp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..008d80f3f1e417d801dab6d95cc6590a6f4d5319 --- /dev/null +++ b/test/gtest_processor_odom_icp.cpp @@ -0,0 +1,187 @@ +/** + * \file gtest_processor_odom_icp.cpp + * + * Created on: Aug 6, 2019 + * \author: jsola + */ + + +#include "laser/internal/config.h" + +#include <core/ceres_wrapper/ceres_manager.h> +#include <core/utils/utils_gtest.h> + +#include "laser/processor/processor_odom_icp.h" // THIS AT THE END OTHERWISE IT FAILS COMPILING + +using namespace wolf; +using namespace Eigen; + +std::string laser_root_dir = _WOLF_LASER_ROOT_DIR; + +class ProcessorOdomICPPublic : public ProcessorOdomICP +{ + public: + ProcessorOdomICPPublic(const ProcessorParamsOdomICPPtr& _params) : + ProcessorOdomICP(_params) + { + + } + virtual ~ProcessorOdomICPPublic(){} + + // we can add public methods here to access protected stuff in ProcessorOdomICP +}; + +WOLF_PTR_TYPEDEFS(ProcessorOdomICPPublic); + +class ProcessorOdomICP_Test : public testing::Test +{ + public: + ProblemPtr problem; + CeresManagerPtr solver; + SensorLaser2DPtr lidar; + ProcessorOdomICPPublicPtr processor; + + std::vector<float> ranges; + + TimeStamp t0; + Vector3s x0; + Matrix3s P0; + FrameBasePtr F0, F; // keyframes + + virtual void SetUp() + { + problem = Problem::create("PO", 2); + solver = std::make_shared<CeresManager>(problem); + + auto sen = problem->installSensor("LASER 2D", "lidar", Eigen::Vector3s(0,0,0), laser_root_dir + "/test/yaml/sensor_laser_2D.yaml"); + lidar = std::static_pointer_cast<SensorLaser2D>(sen); + + auto prc = problem->installProcessor("ODOM ICP", "prc icp", "lidar", laser_root_dir + "/test/yaml/processor_odom_ICP.yaml"); + processor = std::static_pointer_cast<ProcessorOdomICPPublic>(prc); + + ranges = std::vector<float>({49.97591781616211, 49.996429443359375, 49.999759674072266, 50.0, 50.0, 50.0, 49.998634338378906, 50.0, 50.0, 49.99236297607422, 49.99384307861328, 50.0, 49.9869270324707, 50.0, 49.99005889892578, 49.99773406982422, 50.0, 49.98741912841797, 50.0, 49.99842071533203, 50.0, 49.99243927001953, 49.997291564941406, 50.0, 50.0, 49.98580551147461, 49.991844177246094, 49.98896026611328, 50.0, 50.0, 49.9897346496582, 49.998111724853516, 49.99882125854492, 50.0, 50.0, 50.0, 50.0, 49.999698638916016, 50.0, 50.0, 50.0, 50.0, 49.991397857666016, 49.99360275268555, 49.999027252197266, 49.99750900268555, 49.99100112915039, 49.998714447021484, 49.98794174194336, 50.0, 50.0, 50.0, 50.0, 50.0, 49.98186492919922, 50.0, 50.0, 50.0, 49.99155807495117, 49.997196197509766, 49.98872375488281, 49.99138259887695, 50.0, 49.99021530151367, 49.99164581298828, 50.0, 49.991390228271484, 50.0, 50.0, 50.0, 49.997249603271484, 50.0, 49.991851806640625, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 49.97983169555664, 49.98630142211914, 50.0, 20.6888370513916, 49.9797477722168, 49.98846435546875, 49.99418640136719, 50.0, 50.0, 50.0, 49.99342346191406, 50.0, 49.9906005859375, 50.0, 49.99853515625, 49.989444732666016, 38.552852630615234, 38.28703689575195, 38.04865264892578, 37.78112030029297, 37.54747772216797, 37.28171157836914, 37.206565856933594, 36.835411071777344, 36.61864471435547, 36.39655685424805, 36.1579475402832, 35.95964431762695, 35.75605773925781, 35.552188873291016, 35.75926208496094, 36.27781677246094, 35.16993713378906, 34.99699401855469, 34.82910919189453, 34.6483039855957, 34.48637390136719, 34.32539749145508, 34.16202163696289, 34.232051849365234, 33.86043167114258, 33.71691131591797, 33.566650390625, 33.42384338378906, 33.2882080078125, 33.16693115234375, 33.041419982910156, 32.906009674072266, 33.008323669433594, 33.706356048583984, 34.43825149536133, 35.25088119506836, 36.05652618408203, 36.930118560791016, 37.83384704589844, 33.12321472167969, 33.02351760864258, 32.9192008972168, 32.82925796508789, 32.74382781982422, 32.64959716796875, 32.580204010009766, 32.49120330810547, 33.05714797973633, 32.343536376953125, 32.26381301879883, 32.21063232421875, 32.12488555908203, 32.06965255737305, 32.0222282409668, 31.954957962036133, 31.903532028198242, 31.83578872680664, 32.51456832885742, 34.189456939697266, 31.12668228149414, 31.076339721679688, 31.047151565551758, 30.967018127441406, 30.956220626831055, 30.924589157104492, 30.893285751342773, 30.869199752807617, 30.843050003051758, 32.791847229003906, 30.809431076049805, 30.79128074645996, 30.779237747192383, 30.776460647583008, 30.74305534362793, 30.74994468688965, 30.7137393951416, 30.734609603881836, 30.719928741455078, 30.71673011779785, 49.99970626831055, 50.0, 49.987911224365234, 33.68583679199219, 31.76846694946289, 31.8026123046875, 31.802202224731445, 31.818490982055664, 31.85223960876465, 31.86141014099121, 31.906801223754883, 31.93423843383789, 31.964210510253906, 33.567230224609375, 32.055015563964844, 32.07001876831055, 32.13076400756836, 32.16000747680664, 32.22781753540039, 32.26890563964844, 32.323944091796875, 32.36326217651367, 32.430908203125, 49.980655670166016, 34.32135772705078, 33.09465789794922, 32.27247619628906, 32.33710479736328, 32.41763687133789, 32.498661041259766, 32.57213592529297, 32.67158126831055, 32.74591827392578, 32.814476013183594, 32.93477249145508, 33.04751968383789, 33.136863708496094, 33.23999786376953, 33.34675979614258, 33.42970657348633, 33.53573226928711, 33.66716003417969, 33.78378677368164, 33.905670166015625, 34.02836608886719, 34.151817321777344, 34.2794189453125, 34.41516876220703, 34.551273345947266, 34.702728271484375, 34.84151840209961, 34.986881256103516, 35.162757873535156, 35.332794189453125, 35.47941970825195, 35.65633010864258, 35.82624435424805, 36.00060272216797, 36.17729187011719, 36.36515808105469, 36.55763626098633, 36.744773864746094, 38.46407699584961, 37.869808197021484, 37.767921447753906, 37.958900451660156, 38.20857620239258, 38.38622283935547, 38.68323516845703, 38.871334075927734, 39.151519775390625, 39.377750396728516, 39.68268966674805, 39.89873123168945, 40.197330474853516, 40.47549819946289, 40.73743438720703, 41.04566955566406, 42.33650207519531, 41.92591094970703, 41.43912124633789, 41.045528411865234, 41.32114028930664, 41.581878662109375, 41.944580078125, 42.318912506103516, 42.6725959777832, 43.07264709472656, 43.443477630615234, 43.83216094970703, 44.19996643066406, 44.63225555419922, 45.06049346923828, 45.468536376953125, 45.89896774291992, 46.330604553222656, 46.778343200683594, 47.31666946411133, 47.789310455322266, 48.26376724243164, 48.826602935791016, 49.33188247680664, 49.990909576416016, 50.0, 50.0, 50.0, 50.0, 49.995697021484375, 49.99568176269531, 49.98163986206055, 50.0, 50.0, 49.9764289855957, 50.0, 50.0, 49.98639678955078, 49.99431228637695, 50.0, 50.0, 50.0, 50.0, 49.9874267578125, 50.0, 49.98714828491211, 50.0, 49.99470901489258, 49.99113464355469, 50.0, 50.0, 50.0, 49.985504150390625, 49.99067306518555, 50.0, 49.997161865234375, 50.0, 50.0, 50.0, 49.995513916015625, 49.993038177490234, 50.0, 49.99763107299805, 50.0, 49.98752975463867, 50.0, 49.988037109375, 50.0, 50.0, 50.0, 49.9975700378418, 50.0, 49.998756408691406, 49.97819519042969, 49.99104690551758, 49.99087905883789, 49.94268798828125, 49.85968017578125, 49.786617279052734, 49.70594787597656, 49.62562561035156, 49.56686782836914, 49.50475311279297, 49.416934967041016, 49.35699462890625, 49.308589935302734, 49.990482330322266, 50.0, 49.998836517333984, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 49.980472564697266, 49.99903869628906, 50.0, 50.0, 49.989845275878906, 49.98395919799805, 50.0, 49.99302673339844, 49.99530792236328, 49.99745559692383, 50.0, 49.99560546875, 21.569303512573242}); + + t0 = 0.0; + x0 = Vector3s(0,0,0); + P0 . setIdentity(); + F0 = problem->setPrior(x0, P0, t0, 0.1); + } + virtual void TearDown(){} +}; + +TEST(ProcessorParamsOdomICP, default_construct_and_print) +{ + auto params = std::make_shared<ProcessorParamsOdomICP>(); + + ASSERT_TRUE(params); // not nullptr + + params->use_corr_tricks = 15; + + ASSERT_EQ(params->use_corr_tricks, 15); + + WOLF_INFO("params: ", params->print()); +} + +TEST(ProcessorParamsOdomICP, factory_and_print) +{ + auto params = std::static_pointer_cast<ProcessorParamsOdomICP>(ProcessorParamsFactory::get().create("ODOM ICP", laser_root_dir + "/test/yaml/processor_odom_icp.yaml")); + + ASSERT_TRUE(params); // not nullptr + + // check a couple of entries. + ASSERT_EQ (params->use_corr_tricks , 4 ); + ASSERT_DOUBLE_EQ(params->outliers_maxPerc , 5.0 ); + + WOLF_INFO("params: ", params->print()); +} + +TEST(ProcessorOdomIcp, Constructor) +{ + auto params = std::make_shared<ProcessorParamsOdomICP>(); + auto prc = std::make_shared<ProcessorOdomICP>(params); + + ASSERT_TRUE(prc); // not nullptr + ASSERT_EQ(prc->getType(), "ODOM ICP"); +} + +TEST(ProcessorOdomIcp, creator_yaml) +{ + auto params = std::static_pointer_cast<ProcessorParamsOdomICP>(ProcessorParamsFactory::get().create("ODOM ICP", laser_root_dir + "/test/yaml/processor_odom_ICP.yaml")); + auto prc = std::make_shared<ProcessorOdomICP>(params); + + ASSERT_TRUE(prc); // not nullptr + ASSERT_EQ(prc->getType(), "ODOM ICP"); +} + +TEST_F(ProcessorOdomICP_Test, full) +{ + + TimeStamp t(t0); + + + for (int i = 0; i < 7; i++) + { + std::cout << "\n========== Process " << t.getSeconds() << " sec. ==========" << std::endl; + + CaptureLaser2DPtr scan = std::make_shared<CaptureLaser2D>(t, lidar, ranges); + scan->process(); + + F = problem->getLastFrame(); + + ASSERT_MATRIX_APPROX(F->getState(), x0, 1e-6); + + WOLF_TRACE("F", F->id() , " ", F->getState().transpose()); + + if (i >= 2 && i <= 4) + { + // perturb F1 + F->setState(0.1 * Vector3s::Random()); + WOLF_TRACE("F", F->id() , " ", F->getState().transpose(), " perturbed!"); + } + + t += 1.0; + } + + ASSERT_MATRIX_APPROX(F->getState(), x0, 1e-6); +} + +TEST_F(ProcessorOdomICP_Test, solve) +{ + TimeStamp t(t0); + + for (int i = 0; i < 6; i++) + { + std::cout << "\n========== Process " << t.getSeconds() << " sec. ==========" << std::endl; + + CaptureLaser2DPtr scan = std::make_shared<CaptureLaser2D>(t, lidar, ranges); + scan->process(); + + t += 1.0; + } + + for (auto F : problem->getTrajectory()->getFrameList()) + { + if (F->isKey()) + F->setState(0.5 * Vector3s::Random()); + } + + std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); + WOLF_TRACE(report); + + for (auto F : problem->getTrajectory()->getFrameList()) + { + if (F->isKey()) + { + ASSERT_MATRIX_APPROX(F->getState() , x0 , 1e-6); + } + } +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); +// ::testing::GTEST_FLAG(filter) = "ProcessorOdomICP_Test.solve"; + return RUN_ALL_TESTS(); +} + diff --git a/test/yaml/processor_odom_ICP.yaml b/test/yaml/processor_odom_ICP.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6cd6081f72f53ae69464900bc4b482170de6a1ba --- /dev/null +++ b/test/yaml/processor_odom_ICP.yaml @@ -0,0 +1,24 @@ +type : "ODOM ICP" + +# from processor base +time_tolerance : 0.1 +voting_active : true +voting_aux_active : false + +# from processor tracker +min_features_for_keyframe : 0 +max_new_features : 0 + +# from processor odom ICP +use_point_to_line_distance : 1 +max_correspondence_dist : 2 +max_iterations : 3 +use_corr_tricks : 4 +outliers_maxPerc : 5 +outliers_adaptive_order : 6 +outliers_adaptive_mult : 7 +vfk_min_dist : 8 +vfk_min_angle : 9 +vfk_min_time : 2.5 +vfk_min_error : 11 +vfk_max_points : 12 diff --git a/test/yaml/sensor_laser_2D.yaml b/test/yaml/sensor_laser_2D.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8f6a26159078ceb368956f4df20cb8b8a6922dca --- /dev/null +++ b/test/yaml/sensor_laser_2D.yaml @@ -0,0 +1,15 @@ +type : "LASER 2D" + +# from sensor base + # no params so far + +# from sensor laser 2D +LaserScanParams: + angle_min : -1.57079994678 + angle_max : 1.57079994678 + angle_step : 0.00875097513199 + scan_time : 0.0 + range_min : 0.1 + range_max : 50.0 + range_std_dev : 0.01 + angle_std_dev : 0.001