diff --git a/CMakeLists.txt b/CMakeLists.txt index cab800a231b74a05eb9c466e0ec5d508ca561918..1f1f99f4c4bfb71389afc7fe1695355ad801f3c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,6 @@ if(UNIX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=all -Werror=extra -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-parameter -Wno-missing-field-initializers") endif(UNIX) - IF(NOT BUILD_TESTS) OPTION(BUILD_TESTS "Build Unit tests" ON) ENDIF(NOT BUILD_TESTS) @@ -147,8 +146,8 @@ IF(EXISTS "${WOLF_CONFIG_DIR}" AND NOT IS_DIRECTORY "${WOLF_CONFIG_DIR}") ENDIF() # Configure config.h configure_file(${CMAKE_CURRENT_SOURCE_DIR}/internal/config.h.in "${WOLF_CONFIG_DIR}/config.h") -message("WOLF CONFIG ${WOLF_CONFIG_DIR}/config.h") -message("CONFIG DIRECTORY ${PROJECT_BINARY_DIR}") +message(STATUS "WOLF CONFIG DIRECTORY ${WOLF_CONFIG_DIR}") +message(STATUS "WOLF CONFIG FILE ${WOLF_CONFIG_DIR}/config.h") include_directories("${PROJECT_BINARY_DIR}/conf") # include spdlog (logging library) @@ -209,6 +208,7 @@ SET(HDRS_FRAME include/core/frame/frame_base.h ) SET(HDRS_STATE_BLOCK + include/core/state_block/factory_state_block.h include/core/state_block/has_state_blocks.h include/core/state_block/local_parametrization_angle.h include/core/state_block/local_parametrization_base.h @@ -216,6 +216,7 @@ SET(HDRS_STATE_BLOCK include/core/state_block/local_parametrization_quaternion.h include/core/state_block/state_angle.h include/core/state_block/state_block.h + include/core/state_block/state_composite.h include/core/state_block/state_homogeneous_3d.h include/core/state_block/state_quaternion.h ) @@ -226,7 +227,6 @@ SET(HDRS_CAPTURE include/core/capture/capture_odom_2d.h include/core/capture/capture_odom_3d.h include/core/capture/capture_pose.h - include/core/capture/capture_velocity.h include/core/capture/capture_void.h include/core/capture/capture_diff_drive.h ) @@ -246,6 +246,7 @@ SET(HDRS_FACTOR include/core/factor/factor_pose_3d.h include/core/factor/factor_quaternion_absolute.h include/core/factor/factor_relative_2d_analytic.h + include/core/factor/factor_relative_pose_2d_with_extrinsics.h ) SET(HDRS_FEATURE include/core/feature/feature_base.h @@ -263,7 +264,7 @@ SET(HDRS_PROCESSOR include/core/processor/motion_buffer.h include/core/processor/processor_base.h include/core/processor/processor_diff_drive.h - include/core/processor/processor_factory.h + include/core/processor/factory_processor.h include/core/processor/processor_logging.h include/core/processor/processor_loopclosure.h include/core/processor/processor_motion.h @@ -277,15 +278,19 @@ SET(HDRS_PROCESSOR SET(HDRS_SENSOR include/core/sensor/sensor_base.h include/core/sensor/sensor_diff_drive.h - include/core/sensor/sensor_factory.h + include/core/sensor/factory_sensor.h include/core/sensor/sensor_odom_2d.h include/core/sensor/sensor_odom_3d.h ) SET(HDRS_SOLVER include/core/solver/solver_manager.h - include/core/solver/solver_factory.h + include/core/solver/factory_solver.h + ) +SET(HDRS_TREE_MANAGER + include/core/tree_manager/factory_tree_manager.h + include/core/tree_manager/tree_manager_base.h + include/core/tree_manager/tree_manager_sliding_window.h ) - SET(HDRS_YAML include/core/yaml/parser_yaml.h include/core/yaml/yaml_conversion.h @@ -312,6 +317,7 @@ SET(SRCS_STATE_BLOCK src/state_block/local_parametrization_homogeneous.cpp src/state_block/local_parametrization_quaternion.cpp src/state_block/state_block.cpp + src/state_block/state_composite.cpp ) SET(SRCS_COMMON src/common/node_base.cpp @@ -332,7 +338,6 @@ SET(SRCS_CAPTURE src/capture/capture_odom_2d.cpp src/capture/capture_odom_3d.cpp src/capture/capture_pose.cpp - src/capture/capture_velocity.cpp src/capture/capture_void.cpp src/capture/capture_diff_drive.cpp ) @@ -350,6 +355,7 @@ SET(SRCS_LANDMARK src/landmark/landmark_base.cpp ) SET(SRCS_PROCESSOR + src/processor/is_motion.cpp src/processor/motion_buffer.cpp src/processor/processor_base.cpp src/processor/processor_diff_drive.cpp @@ -371,6 +377,9 @@ SET(SRCS_SENSOR SET(SRCS_SOLVER src/solver/solver_manager.cpp ) +SET(SRCS_TREE_MANAGER + src/tree_manager/tree_manager_sliding_window.cpp + ) SET(SRCS_YAML src/yaml/parser_yaml.cpp src/yaml/processor_odom_3d_yaml.cpp @@ -400,8 +409,6 @@ ELSE(Ceres_FOUND) SET(SRCS_WRAPPER) ENDIF(Ceres_FOUND) -#SUBDIRECTORIES -add_subdirectory(hello_wolf) IF (cereal_FOUND) ADD_SUBDIRECTORY(serialization/cereal) ENDIF(cereal_FOUND) @@ -431,10 +438,23 @@ ADD_LIBRARY(${PROJECT_NAME} ${SRCS_SOLVER} ${SRCS_STATE_BLOCK} ${SRCS_TRAJECTORY} + ${SRCS_TREE_MANAGER} ${SRCS_UTILS} ${SRCS_WRAPPER} ${SRCS_YAML} ) + +# Set compiler options +# ==================== +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + message(STATUS "Using C++ compiler clang") + target_compile_options(${PROJECT_NAME} PRIVATE -Winconsistent-missing-override) + # using Clang +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + message(STATUS "Using C++ compiler gnu") + target_compile_options(${PROJECT_NAME} PRIVATE -Wsuggest-override) + # using GCC +endif() #Link the created libraries #============================================================= @@ -471,44 +491,46 @@ INSTALL(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets install(EXPORT ${PROJECT_NAME}Targets DESTINATION lib/cmake/${PROJECT_NAME}) #install headers -INSTALL(FILES ${HDRS_MATH} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/math) -INSTALL(FILES ${HDRS_UTILS} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/utils) -INSTALL(FILES ${HDRS_PROBLEM} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/problem) -INSTALL(FILES ${HDRS_HARDWARE} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/hardware) -INSTALL(FILES ${HDRS_TRAJECTORY} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/trajectory) -INSTALL(FILES ${HDRS_MAP} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/map) -INSTALL(FILES ${HDRS_FRAME} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/frame) -INSTALL(FILES ${HDRS_STATE_BLOCK} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/state_block) -INSTALL(FILES ${HDRS_COMMON} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/common) INSTALL(FILES ${HDRS_CAPTURE} DESTINATION include/iri-algorithms/wolf/plugin_core/core/capture) +INSTALL(FILES ${HDRS_COMMON} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/common) INSTALL(FILES ${HDRS_FACTOR} DESTINATION include/iri-algorithms/wolf/plugin_core/core/factor) INSTALL(FILES ${HDRS_FEATURE} DESTINATION include/iri-algorithms/wolf/plugin_core/core/feature) -INSTALL(FILES ${HDRS_SENSOR} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/sensor) -INSTALL(FILES ${HDRS_PROCESSOR} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/processor) +INSTALL(FILES ${HDRS_FRAME} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/frame) +INSTALL(FILES ${HDRS_HARDWARE} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/hardware) INSTALL(FILES ${HDRS_LANDMARK} DESTINATION include/iri-algorithms/wolf/plugin_core/core/landmark) -INSTALL(FILES ${HDRS_WRAPPER} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/ceres_wrapper) -INSTALL(FILES ${HDRS_SOLVER_SUITESPARSE} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/solver_suitesparse) -INSTALL(FILES ${HDRS_SOLVER} - DESTINATION include/iri-algorithms/wolf/plugin_core/core/solver) +INSTALL(FILES ${HDRS_MAP} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/map) +INSTALL(FILES ${HDRS_MATH} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/math) +INSTALL(FILES ${HDRS_PROBLEM} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/problem) +INSTALL(FILES ${HDRS_PROCESSOR} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/processor) +INSTALL(FILES ${HDRS_SENSOR} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/sensor) INSTALL(FILES ${HDRS_SERIALIZATION} DESTINATION include/iri-algorithms/wolf/plugin_core/core/serialization) +INSTALL(FILES ${HDRS_SOLVER} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/solver) +INSTALL(FILES ${HDRS_SOLVER_SUITESPARSE} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/solver_suitesparse) +INSTALL(FILES ${HDRS_STATE_BLOCK} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/state_block) +INSTALL(FILES ${HDRS_TRAJECTORY} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/trajectory) +INSTALL(FILES ${HDRS_TREE_MANAGER} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/tree_manager) +INSTALL(FILES ${HDRS_UTILS} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/utils) +INSTALL(FILES ${HDRS_WRAPPER} + DESTINATION include/iri-algorithms/wolf/plugin_core/core/ceres_wrapper) INSTALL(FILES ${HDRS_YAML} DESTINATION include/iri-algorithms/wolf/plugin_core/core/yaml) diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e6b2bb11cbe6b95dceba4095af5c57b2c76f16c0 --- /dev/null +++ b/demos/CMakeLists.txt @@ -0,0 +1,2 @@ +#Add hello_wolf demo +add_subdirectory(hello_wolf) diff --git a/demos/demo_map_yaml.cpp b/demos/demo_map_yaml.cpp deleted file mode 100644 index 87023e52856c9e3ba937882cd5311e05260b507b..0000000000000000000000000000000000000000 --- a/demos/demo_map_yaml.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/** - * \file test_map_yaml.cpp - * - * Created on: Jul 27, 2016 - * \author: jsola - */ - -#include "core/common/wolf.h" -#include "core/problem/problem.h" -#include "core/map/map_base.h" -#include "core/landmark/landmark_polyline_2d.h" -#include "core/landmark/landmark_AHP.h" -#include "core/state_block/state_block.h" -#include "core/yaml/yaml_conversion.h" - -#include <iostream> -using namespace wolf; - -void print(MapBase& _map) -{ - for (auto lmk_ptr : _map.getLandmarkList()) - { - std::cout << "Lmk ID: " << lmk_ptr->id(); - std::cout << "\nLmk type: " << lmk_ptr->getType(); - if (lmk_ptr->getType() == "POLYLINE 2d") - { - LandmarkPolyline2dPtr poly_ptr = std::static_pointer_cast<LandmarkPolyline2d>(lmk_ptr); - std::cout << "\npos: " << poly_ptr->getP()->getState().transpose() << " -- fixed: " << poly_ptr->getP()->isFixed(); - std::cout << "\nori: " << poly_ptr->getO()->getState().transpose() << " -- fixed: " << poly_ptr->getO()->isFixed(); - std::cout << "\nn points: " << poly_ptr->getNPoints(); - std::cout << "\nFirst idx: " << poly_ptr->getFirstId(); - std::cout << "\nFirst def: " << poly_ptr->isFirstDefined(); - std::cout << "\nLast def: " << poly_ptr->isLastDefined(); - for (int idx = poly_ptr->getFirstId(); idx <= poly_ptr->getLastId(); idx++) - std::cout << "\n point: " << idx << ": " << poly_ptr->getPointStateBlock(idx)->getState().transpose(); - break; - } - else if (lmk_ptr->getType() == "AHP") - { - LandmarkAHPPtr ahp_ptr = std::static_pointer_cast<LandmarkAHP>(lmk_ptr); - std::cout << "\npos: " << ahp_ptr->getP()->getState().transpose() << " -- fixed: " << ahp_ptr->getP()->isFixed(); - std::cout << "\ndescript: " << ahp_ptr->getCvDescriptor().t(); - break; - } - else - break; - - std::cout << std::endl; - } -} - -int main() -{ - using namespace Eigen; - - std::cout << "\nTesting Lmk creator and node saving..." << std::endl; - Vector4d v; - v << 1, 2, 3, 4; - cv::Mat d = (cv::Mat_<int>(8,1) << 1, 2, 3, 4, 5, 6, 7, 8); - LandmarkAHP lmk_1(v, nullptr, nullptr, d); - std::cout << "Pos 1 = " << lmk_1.getP()->getState().transpose() << std::endl; - std::cout << "Des 1 = " << lmk_1.getCvDescriptor().t() << std::endl; - - YAML::Node n = lmk_1.saveToYaml(); - std::cout << "Pos n = " << n["position"].as<VectorXd>().transpose() << std::endl; - std::cout << "Des n = " << n["descriptor"].as<VectorXd>().transpose() << std::endl; - - LandmarkAHP lmk_2 = *(std::static_pointer_cast<LandmarkAHP>(LandmarkAHP::create(n))); - std::cout << "Pos 2 = " << lmk_2.getP()->getState().transpose() << std::endl; - std::cout << "Des 2 = " << lmk_2.getCvDescriptor().t() << std::endl; - - std::string filename; - - std::string wolf_root = _WOLF_ROOT_DIR; - std::string wolf_config = wolf_root + "/src/examples"; - std::cout << "\nWolf directory for configuration files: " << wolf_config << std::endl; - - ProblemPtr problem = Problem::create("PO", 2); - filename = wolf_config + "/map_polyline_example.yaml"; - std::cout << "Reading map from file: " << filename << std::endl; - problem->loadMap(filename); - - std::cout << "Printing map..." << std::endl; - print(*(problem->getMap())); - - filename = wolf_config + "/map_polyline_example_write.yaml"; - std::cout << "Writing map to file: " << filename << std::endl; - std::string thisfile = __FILE__; - problem->getMap()->save(filename, "Example generated by test file " + thisfile); - - std::cout << "Clearing map... " << std::endl; - problem->getMap()->getLandmarkList().clear(); - - std::cout << "Re-reading map from file: " << filename << std::endl; - problem->loadMap(filename); - - std::cout << "Printing map..." << std::endl; - print(*(problem->getMap())); - - return 0; -} diff --git a/hello_wolf/CMakeLists.txt b/demos/hello_wolf/CMakeLists.txt similarity index 100% rename from hello_wolf/CMakeLists.txt rename to demos/hello_wolf/CMakeLists.txt diff --git a/hello_wolf/capture_range_bearing.cpp b/demos/hello_wolf/capture_range_bearing.cpp similarity index 89% rename from hello_wolf/capture_range_bearing.cpp rename to demos/hello_wolf/capture_range_bearing.cpp index a2d44a101085ea0ad3aa4ae7d68af68370ea5024..9ead1c183b8b08a64f709faea5236d5dbb056231 100644 --- a/hello_wolf/capture_range_bearing.cpp +++ b/demos/hello_wolf/capture_range_bearing.cpp @@ -11,7 +11,7 @@ namespace wolf { CaptureRangeBearing::CaptureRangeBearing(const TimeStamp& _ts, const SensorBasePtr& _scanner, const Eigen::VectorXi& _ids, const Eigen::VectorXd& _ranges, const Eigen::VectorXd& _bearings) : - CaptureBase("RANGE BEARING", _ts, _scanner), + CaptureBase("CaptureRangeBearing", _ts, _scanner), ids_(_ids), ranges_(_ranges), bearings_(_bearings) diff --git a/hello_wolf/capture_range_bearing.h b/demos/hello_wolf/capture_range_bearing.h similarity index 100% rename from hello_wolf/capture_range_bearing.h rename to demos/hello_wolf/capture_range_bearing.h diff --git a/hello_wolf/factor_bearing.h b/demos/hello_wolf/factor_bearing.h similarity index 92% rename from hello_wolf/factor_bearing.h rename to demos/hello_wolf/factor_bearing.h index 6975a798db580e1c127b0215609f49904b29ae40..f5c5dd95887add0562377c360e7087a8f975665d 100644 --- a/hello_wolf/factor_bearing.h +++ b/demos/hello_wolf/factor_bearing.h @@ -68,9 +68,8 @@ inline bool FactorBearing::operator ()(const T* const _p1, const T* const _o1, // 3. Get the expected bearing of the point T bearing = atan2(point_r(1), point_r(0)); - // 4. Get the measured range-and-bearing to the point, and its covariance + // 4. Get the measured range-and-bearing to the point Matrix<T, 2, 1> range_bearing = getMeasurement(); - Matrix<T, 2, 2> range_bearing_cov = getMeasurementCovariance(); // 5. Get the bearing error by comparing against the bearing measurement T er = range_bearing(1) - bearing; @@ -80,8 +79,7 @@ inline bool FactorBearing::operator ()(const T* const _p1, const T* const _o1, er -= T(2*M_PI); // 6. Compute the residual by scaling according to the standard deviation of the bearing part - T sigma = sqrt(range_bearing_cov(1,1)); - *_res = er / sigma; + *_res = er * T(getMeasurementSquareRootInformationUpper()(1,1)); return true; } diff --git a/hello_wolf/factor_range_bearing.h b/demos/hello_wolf/factor_range_bearing.h similarity index 98% rename from hello_wolf/factor_range_bearing.h rename to demos/hello_wolf/factor_range_bearing.h index 436b79e4a0eee67aa8ddd97de34ec14127251d01..226a6335e7966a0d3bdd7042c017913bc64b419b 100644 --- a/hello_wolf/factor_range_bearing.h +++ b/demos/hello_wolf/factor_range_bearing.h @@ -21,12 +21,14 @@ class FactorRangeBearing : public FactorAutodiff<FactorRangeBearing, 2, 2, 1, 2, { public: FactorRangeBearing(const CaptureBasePtr& _capture_own, // own capture's pointer + const FeatureBasePtr& _feature_ptr, const LandmarkBasePtr& _landmark_other_ptr, // other landmark's pointer const ProcessorBasePtr& _processor_ptr, // processor having created this bool _apply_loss_function, // apply loss function to residual? FactorStatus _status) : // active factor? FactorAutodiff<FactorRangeBearing, 2, 2, 1, 2, 1, 2>( // sizes of: residual, rob pos, rob ori, sen pos, sen ori, lmk pos "RANGE BEARING", // factor type enum (see wolf.h) + _feature_ptr, nullptr, // other frame's pointer nullptr, // other capture's pointer nullptr, // other feature's pointer diff --git a/hello_wolf/feature_range_bearing.cpp b/demos/hello_wolf/feature_range_bearing.cpp similarity index 82% rename from hello_wolf/feature_range_bearing.cpp rename to demos/hello_wolf/feature_range_bearing.cpp index 4d47cc5539f5fcfe2cc011ea4c4e6e11d2685f90..ea584a419aa21c1d7e462824d6872f7d57bd818c 100644 --- a/hello_wolf/feature_range_bearing.cpp +++ b/demos/hello_wolf/feature_range_bearing.cpp @@ -11,7 +11,7 @@ namespace wolf { FeatureRangeBearing::FeatureRangeBearing(const Eigen::VectorXd& _measurement, const Eigen::MatrixXd& _meas_covariance) : - FeatureBase("RANGE BEARING", _measurement, _meas_covariance) + FeatureBase("FeatureRangeBearing", _measurement, _meas_covariance) { // } diff --git a/hello_wolf/feature_range_bearing.h b/demos/hello_wolf/feature_range_bearing.h similarity index 100% rename from hello_wolf/feature_range_bearing.h rename to demos/hello_wolf/feature_range_bearing.h diff --git a/hello_wolf/hello_wolf.cpp b/demos/hello_wolf/hello_wolf.cpp similarity index 92% rename from hello_wolf/hello_wolf.cpp rename to demos/hello_wolf/hello_wolf.cpp index ac33da83c3fece5dce946e9c808869edd511e6f4..e51f7a33658bf1c3afb9f2d20e8118825886ebf6 100644 --- a/hello_wolf/hello_wolf.cpp +++ b/demos/hello_wolf/hello_wolf.cpp @@ -115,7 +115,7 @@ int main() SensorBasePtr sensor_odo = problem->installSensor("SensorOdom2d", "sensor odo", Vector3d(0,0,0), intrinsics_odo); // processor odometer 2d - ProcessorParamsOdom2dPtr params_odo = std::make_shared<ProcessorParamsOdom2d>(); + ParamsProcessorOdom2dPtr params_odo = std::make_shared<ParamsProcessorOdom2d>(); params_odo->voting_active = true; params_odo->time_tolerance = 0.1; params_odo->max_time_span = 999; @@ -132,16 +132,19 @@ int main() SensorBasePtr sensor_rb = problem->installSensor("SensorRangeBearing", "sensor RB", Vector3d(1,1,0), intrinsics_rb); // processor Range and Bearing - ProcessorParamsRangeBearingPtr params_rb = std::make_shared<ProcessorParamsRangeBearing>(); + ParamsProcessorRangeBearingPtr params_rb = std::make_shared<ParamsProcessorRangeBearing>(); params_rb->voting_active = false; params_rb->time_tolerance = 0.01; ProcessorBasePtr processor_rb = problem->installProcessor("ProcessorRangeBearing", "processor RB", sensor_rb, params_rb); // initialize TimeStamp t(0.0); // t : 0.0 - Vector3d x(0,0,0); - Matrix3d P = Matrix3d::Identity() * 0.1; - problem->setPrior(x, P, t, 0.5); // KF1 : (0,0,0) + // Vector3d x(0,0,0); + VectorComposite x(Vector3d(0,0,0), "PO", {2,1}); + // Matrix3d P = Matrix3d::Identity() * 0.1; + VectorComposite P(Vector3d(sqrt(0.1),sqrt(0.1),sqrt(0.1)), "PO", {2,1}); + FrameBasePtr KF1 = problem->setPriorFactor(x, P, t, 0.5); // KF1 : (0,0,0) + std::static_pointer_cast<ProcessorMotion>(processor)->setOrigin(KF1); // SELF CALIBRATION =================================================== @@ -220,19 +223,7 @@ int main() // PERTURB initial guess WOLF_TRACE("======== PERTURB PROBLEM PRIORS =======") - for (auto& sen : problem->getHardware()->getSensorList()) - for (auto& sb : sen->getStateBlockVec()) - if (sb && !sb->isFixed()) - sb->setState(sb->getState() + VectorXd::Random(sb->getSize()) * 0.5); // We perturb A LOT ! - for (auto& kf : problem->getTrajectory()->getFrameList()) - if (kf->isKeyOrAux()) - for (auto& pair_key_sb : kf->getStateBlockMap()) - if (!pair_key_sb.second->isFixed()) - pair_key_sb.second->setState(pair_key_sb.second->getState() + VectorXd::Random(pair_key_sb.second->getSize()) * 0.5); // We perturb A LOT ! - for (auto lmk : problem->getMap()->getLandmarkList()) - for (auto& pair_key_sb : lmk->getStateBlockMap()) - if (!pair_key_sb.second->isFixed()) - pair_key_sb.second->setState(pair_key_sb.second->getState() + VectorXd::Random(pair_key_sb.second->getSize()) * 0.5); // We perturb A LOT ! + problem->perturb(0.5); // Perturb all state blocks that are not fixed problem->print(1,0,1,0); // SOLVE again @@ -260,7 +251,7 @@ int main() std::cout << std::endl; WOLF_TRACE("======== FINAL PRINT FOR INTERPRETATION =======") - problem->print(4,1,1,1); + problem->print(4,0,1,0); /* * ============= FIRST COMMENT ON THE RESULTS ================== diff --git a/hello_wolf/hello_wolf_autoconf.cpp b/demos/hello_wolf/hello_wolf_autoconf.cpp similarity index 69% rename from hello_wolf/hello_wolf_autoconf.cpp rename to demos/hello_wolf/hello_wolf_autoconf.cpp index a387adfe9656523c37d025bb3a74f0f198281b3d..bff8afd133c97f83f16f35fbcd35ab3db011f17f 100644 --- a/hello_wolf/hello_wolf_autoconf.cpp +++ b/demos/hello_wolf/hello_wolf_autoconf.cpp @@ -9,6 +9,7 @@ // wolf core includes #include "core/common/wolf.h" #include "core/capture/capture_odom_2d.h" +#include "core/processor/processor_motion.h" #include "core/yaml/parser_yaml.h" #include "core/ceres_wrapper/ceres_manager.h" @@ -98,7 +99,7 @@ int main() WOLF_TRACE("======== CONFIGURE PROBLEM ======="); // Config file to parse. Here is where all the problem is defined: - std::string config_file = "hello_wolf/yaml/hello_wolf_config.yaml"; + std::string config_file = "demos/hello_wolf/yaml/hello_wolf_config.yaml"; std::string wolf_path = std::string(_WOLF_ROOT_DIR); // parse file into params server: each param will be retrievable from this params server: @@ -118,9 +119,11 @@ int main() // recover sensor pointers and other stuff for later use (access by sensor name) SensorBasePtr sensor_odo = problem->getSensor("sen odom"); SensorBasePtr sensor_rb = problem->getSensor("sen rb"); - TimeStamp t = problem->getTrajectory()->getFrameList().front()->getTimeStamp(); - + // APPLY PRIOR and SET PROCESSOR ODOM ORIGIN =================================================== + TimeStamp t(0.0); + FrameBasePtr KF1 = problem->applyPriorOptions(t); + std::static_pointer_cast<ProcessorMotion>(problem->getProcessorIsMotion())->setOrigin(KF1); // SELF CALIBRATION =================================================== // These few lines control whether we calibrate some sensor parameters or not. @@ -203,19 +206,7 @@ int main() // PERTURB initial guess WOLF_TRACE("======== PERTURB PROBLEM PRIORS =======") - for (auto& sen : problem->getHardware()->getSensorList()) - for (auto& sb : sen->getStateBlockVec()) - if (sb && !sb->isFixed()) - sb->setState(sb->getState() + VectorXd::Random(sb->getSize()) * 0.5); // We perturb A LOT ! - for (auto& kf : problem->getTrajectory()->getFrameList()) - if (kf->isKeyOrAux()) - for (auto& pair_key_sb : kf->getStateBlockMap()) - if (pair_key_sb.second && !pair_key_sb.second->isFixed()) - pair_key_sb.second->setState(pair_key_sb.second->getState() + VectorXd::Random(pair_key_sb.second->getSize()) * 0.5); // We perturb A LOT ! - for (auto lmk : problem->getMap()->getLandmarkList()) - for (auto& pair_key_sb : lmk->getStateBlockMap()) - if (!pair_key_sb.second->isFixed()) - pair_key_sb.second->setState(pair_key_sb.second->getState() + VectorXd::Random(pair_key_sb.second->getSize()) * 0.5); // We perturb A LOT ! + problem->perturb(0.5); // Perturb all state blocks that are not fixed problem->print(1,0,1,0); // SOLVE again @@ -250,9 +241,8 @@ int main() * * IF YOU SEE at the end of the printed problem the estimate for Lmk 3 as: * - * L3 POINT 2d <-- c8 - * Est, x = ( 3 2 ) - * sb: Est + * Lmk3 LandmarkPoint2d <-- Fac9 + * P[Est] = ( 1 2 ) * * it means WOLF SOLVED SUCCESSFULLY (L3 is effectively at location (3,2) ) ! * @@ -271,73 +261,80 @@ int main() * The full message is explained below. * * P: wolf tree status --------------------- - Hardware - S1 ODOM 2d // Sensor 1, type ODOMETRY 2d. - Extr [Sta] = [ Fix( 0 0 ) Fix( 0 ) ] // Static extrinsics, fixed position, fixed orientation (See notes 1 and 2 below) - Intr [Sta] = [ ] // Static intrinsics, but no intrinsics anyway - pm1 ODOM 2d // Processor 1, type ODOMETRY 2d - o: C7 - F3 // origin at Capture 7, Frame 3 - l: C10 - F4 // last at Capture 10, frame 4 - S2 RANGE BEARING // Sensor 2, type RANGE and BEARING. - Extr [Sta] = [ Fix( 1 1 ) Est( 0 ) ] // Static extrinsics, fixed position, estimated orientation (See notes 1 and 2 below) - Intr [Sta] = [ ] // Static intrinsics, but no intrinsics anyway - pt2 RANGE BEARING // Processor 2: type Range and Bearing - Trajectory - KF1 <-- c3 // KeyFrame 1, constrained by Factor 3 - Est, ts=0, x = ( -1.6e-13 9.4e-11 1.4e-10 ) // State is estimated; time stamp and state vector - sb: Est Est // State's pos and orient are estimated - C1 FIX -> S- [ <-- // Capture 1, type FIX or Absolute - f1 FIX <-- // Feature 1, type Fix - m = ( 0 0 0 ) // The absolute measurement for this frame is (0,0,0) --> origin - c1 FIX --> A // Factor 1, type FIX, it is Absolute - CM2 ODOM 2d -> S1 [Sta, Sta] <-- // Capture 2, type ODOM, from Sensor 1 (static extr and intr) - C5 RANGE BEARING -> S2 [Sta, Sta] <-- // Capture 5, type R+B, from Sensor 2 (static extr and intr) - f2 RANGE BEARING <-- // Feature 2, type R+B - m = ( 1 1.57 ) // The feature's measurement is 1m, 1.57rad - c2 RANGE BEARING --> L1 // Factor 2 against Landmark 1 - KF2 <-- c6 - Est, ts=1, x = ( 1 2.5e-10 1.6e-10 ) - sb: Est Est - CM3 ODOM 2d -> S1 [Sta, Sta] <-- - f3 ODOM 2d <-- - m = ( 1 0 0 ) - c3 ODOM 2d --> F1 // Factor 3, type ODOM, against Frame 1 - C9 RANGE BEARING -> S2 [Sta, Sta] <-- - f4 RANGE BEARING <-- - m = ( 1.41 2.36 ) - c4 RANGE BEARING --> L1 - f5 RANGE BEARING <-- - m = ( 1 1.57 ) - c5 RANGE BEARING --> L2 - KF3 <-- - Est, ts=2, x = ( 2 4.1e-10 1.7e-10 ) - sb: Est Est - CM7 ODOM 2d -> S1 [Sta, Sta] <-- - f6 ODOM 2d <-- - m = ( 1 0 0 ) - c6 ODOM 2d --> F2 - C12 RANGE BEARING -> S2 [Sta, Sta] <-- - f7 RANGE BEARING <-- - m = ( 1.41 2.36 ) - c7 RANGE BEARING --> L2 - f8 RANGE BEARING <-- - m = ( 1 1.57 ) - c8 RANGE BEARING --> L3 - F4 <-- - Est, ts=2, x = ( 0.11 -0.045 0.26 ) - sb: Est Est - CM10 ODOM 2d -> S1 [Sta, Sta] <-- - Map - L1 POINT 2d <-- c2 c4 // Landmark 1, constrained by Factors 2 and 4 - Est, x = ( 1 2 ) // L4 state is estimated, state vector - sb: Est // L4 has 1 state block estimated - L2 POINT 2d <-- c5 c7 - Est, x = ( 2 2 ) - sb: Est - L3 POINT 2d <-- c8 - Est, x = ( 3 2 ) - sb: Est - ----------------------------------------- + Hardware + Sen1 SensorOdom2d "sen odom" // Sensor 1, type odometry 2D + sb: P[Sta,Fix] = ( 0 0 ); O[Sta,Fix] = ( 0 ); // Static extrinsics, fixed position, fixed orientation (See notes 1 and 2 below) + PrcM1 ProcessorOdom2d "prc odom" // Processor 1, type odometry 2D + o: Cap6 - KFrm3 // origin at Capture 6, Frame 3 + l: Cap8 - Frm4 // last at Capture 8, Frame 4 + Sen2 SensorRangeBearing "sen rb" // Sensor 2, type range and bearing + sb: P[Sta,Fix] = ( 1 1 ); O[Sta,Fix] = ( 0 ); // Static extrinsics, fixed position, estimated orientation (See notes 1 and 2 below) + Prc2 ProcessorRangeBearing "prc rb" // Processor 2, type range and bearing + Trajectory + KFrm1 <-- Fac4 // KeyFrame 1, constrained by Factor 4 + P[Est] = ( -4.4e-12 1.5e-09 ) // Position is estimated + O[Est] = ( 2.6e-09 ) // Orientation is estimated + Cap1 CaptureVoid -> Sen- <-- // This is an "artificial" capture used to hold the features relative to the prior + Ftr1 trk0 prior <-- // Position prior + m = ( 0 0 ) + Fac1 FactorBlockAbsolute --> Abs + Ftr2 trk0 prior <-- // Orientation prior + m = ( 0 ) + Fac2 FactorBlockAbsolute --> Abs + CapM2 CaptureOdom2d -> Sen1 <-- // Capture 2 of type motion odom 2d from sensor 1. + buffer size : 0 + Cap4 CaptureRangeBearing -> Sen2 <-- + Ftr3 trk0 FeatureRangeBearing <-- + m = ( 1 1.6 ) + Fac3 RANGE BEARING --> Lmk1 + KFrm2 <-- Fac7 + P[Est] = ( 1 5.7e-09 ) + O[Est] = ( 5.7e-09 ) + CapM3 CaptureOdom2d -> Sen1 -> OCap2 ; OFrm1 <--// Capture 3 of type motion odom2d from sensor 1. + // Its origin is at Capture 2; Frame 1 + buffer size : 2 + delta preint : (1 0 0) + Ftr4 trk0 ProcessorOdom2d <-- + m = ( 1 0 0 ) + Fac4 FactorOdom2d --> Frm1 + Cap7 CaptureRangeBearing -> Sen2 <-- + Ftr5 trk0 FeatureRangeBearing <-- + m = ( 1.4 2.4 ) + Fac5 RANGE BEARING --> Lmk1 + Ftr6 trk0 FeatureRangeBearing <-- + m = ( 1 1.6 ) + Fac6 RANGE BEARING --> Lmk2 + KFrm3 <-- + P[Est] = ( 2 1.2e-08 ) + O[Est] = ( 6.6e-09 ) + CapM6 CaptureOdom2d -> Sen1 -> OCap3 ; OFrm2 <-- + buffer size : 2 + delta preint : (1 0 0) + Ftr7 trk0 ProcessorOdom2d <-- + m = ( 1 0 0 ) + Fac7 FactorOdom2d --> Frm2 + Cap9 CaptureRangeBearing -> Sen2 <-- + Ftr8 trk0 FeatureRangeBearing <-- + m = ( 1.4 2.4 ) + Fac8 RANGE BEARING --> Lmk2 + Ftr9 trk0 FeatureRangeBearing <-- + m = ( 1 1.6 ) + Fac9 RANGE BEARING --> Lmk3 + Frm4 <-- + P[Est] = ( 2 0 ) + O[Est] = ( 0 ) + CapM8 CaptureOdom2d -> Sen1 -> OCap6 ; OFrm3 <-- + buffer size : 1 + delta preint : (0 0 0) + Map + Lmk1 LandmarkPoint2d <-- Fac3 Fac5 // Landmark 1 constrained by factors 3 & 5 + P[Est] = ( 1 2 ) + Lmk2 LandmarkPoint2d <-- Fac6 Fac8 + P[Est] = ( 2 2 ) + Lmk3 LandmarkPoint2d <-- Fac9 + P[Est] = ( 3 2 ) + ----------------------------------------- + * * ============= GENERAL WOLF NOTES ================== * diff --git a/hello_wolf/landmark_point_2d.cpp b/demos/hello_wolf/landmark_point_2d.cpp similarity index 80% rename from hello_wolf/landmark_point_2d.cpp rename to demos/hello_wolf/landmark_point_2d.cpp index 835c4fb04e4f7b1e5695958ca9db3cbb810c5ec5..8b2ad4c0e8a9b576f67e9d8d56e41d932abedef8 100644 --- a/hello_wolf/landmark_point_2d.cpp +++ b/demos/hello_wolf/landmark_point_2d.cpp @@ -11,7 +11,7 @@ namespace wolf { LandmarkPoint2d::LandmarkPoint2d(int _id, const Eigen::Vector2d& _xy) : - LandmarkBase("POINT 2d", std::make_shared<StateBlock>(_xy)) + LandmarkBase("LandmarkPoint2d", std::make_shared<StateBlock>(_xy)) { setId(_id); } diff --git a/hello_wolf/landmark_point_2d.h b/demos/hello_wolf/landmark_point_2d.h similarity index 100% rename from hello_wolf/landmark_point_2d.h rename to demos/hello_wolf/landmark_point_2d.h diff --git a/hello_wolf/processor_range_bearing.cpp b/demos/hello_wolf/processor_range_bearing.cpp similarity index 92% rename from hello_wolf/processor_range_bearing.cpp rename to demos/hello_wolf/processor_range_bearing.cpp index 89b3d7775e3c5b79dca8de4a0d2f6f5ad91d17e7..08e77f76c8d7d2ec70c9b1ac6689e724a67e5c7c 100644 --- a/hello_wolf/processor_range_bearing.cpp +++ b/demos/hello_wolf/processor_range_bearing.cpp @@ -14,7 +14,7 @@ namespace wolf { -ProcessorRangeBearing::ProcessorRangeBearing(ProcessorParamsBasePtr _params) : +ProcessorRangeBearing::ProcessorRangeBearing(ParamsProcessorBasePtr _params) : ProcessorBase("ProcessorRangeBearing", 2, _params) { // @@ -91,6 +91,7 @@ void ProcessorRangeBearing::processCapture(CaptureBasePtr _capture) auto prc = shared_from_this(); auto ctr = FactorBase::emplace<FactorRangeBearing>(ftr, capture_rb, + ftr, lmk, prc, false, @@ -125,14 +126,14 @@ ProcessorRangeBearing::Trf ProcessorRangeBearing::transform(const Eigen::Vector2 Eigen::Vector2d ProcessorRangeBearing::fromSensor(const Eigen::Vector2d& lmk_s) const { - Trf H_w_r = transform(getProblem()->getCurrentState()); + Trf H_w_r = transform(getProblem()->getState().vector("PO")); return H_w_r * H_r_s * lmk_s; } Eigen::Vector2d ProcessorRangeBearing::toSensor(const Eigen::Vector2d& lmk_w) const { // Trf H_w_r = transform(getSensor()->getP()->getState(), getSensor()->getO()->getState()); - Trf H_w_r = transform(getProblem()->getCurrentState()); + Trf H_w_r = transform(getProblem()->getState().vector("PO")); return (H_w_r * H_r_s).inverse() * lmk_w; } @@ -160,10 +161,10 @@ bool ProcessorRangeBearing::storeCapture(CaptureBasePtr _cap_ptr) } /* namespace wolf */ // Register in the SensorFactory -#include "core/processor/processor_factory.h" +#include "core/processor/factory_processor.h" namespace wolf { -WOLF_REGISTER_PROCESSOR("ProcessorRangeBearing", ProcessorRangeBearing) -WOLF_REGISTER_PROCESSOR_AUTO("ProcessorRangeBearing", ProcessorRangeBearing) +WOLF_REGISTER_PROCESSOR(ProcessorRangeBearing) +WOLF_REGISTER_PROCESSOR_AUTO(ProcessorRangeBearing) } // namespace wolf diff --git a/hello_wolf/processor_range_bearing.h b/demos/hello_wolf/processor_range_bearing.h similarity index 87% rename from hello_wolf/processor_range_bearing.h rename to demos/hello_wolf/processor_range_bearing.h index ec1d8619835f1169a192639db09d8be93087cdae..1203b217e4f07c3e02a287f63b0bace4ba46ede2 100644 --- a/hello_wolf/processor_range_bearing.h +++ b/demos/hello_wolf/processor_range_bearing.h @@ -17,23 +17,23 @@ namespace wolf { -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsRangeBearing); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorRangeBearing); -struct ProcessorParamsRangeBearing : public ProcessorParamsBase +struct ParamsProcessorRangeBearing : public ParamsProcessorBase { // We do not need special parameters, but in case you need they should be defined here. - ProcessorParamsRangeBearing() + ParamsProcessorRangeBearing() { //DEFINED FOR COMPATIBILITY PURPOSES. TO BE REMOVED IN THE FUTURE. } - ProcessorParamsRangeBearing(std::string _unique_name, const ParamsServer& _server) : - ProcessorParamsBase(_unique_name, _server) + ParamsProcessorRangeBearing(std::string _unique_name, const ParamsServer& _server) : + ParamsProcessorBase(_unique_name, _server) { // } std::string print() const { - return "\n" + ProcessorParamsBase::print(); + return "\n" + ParamsProcessorBase::print(); } }; @@ -45,12 +45,12 @@ class ProcessorRangeBearing : public ProcessorBase public: typedef Eigen::Transform<double, 2, Eigen::Isometry> Trf; - ProcessorRangeBearing(ProcessorParamsBasePtr _params); + ProcessorRangeBearing(ParamsProcessorBasePtr _params); virtual ~ProcessorRangeBearing() {/* empty */} virtual void configure(SensorBasePtr _sensor) override; // Factory method for high level API - WOLF_PROCESSOR_CREATE(ProcessorRangeBearing, ProcessorParamsRangeBearing); + WOLF_PROCESSOR_CREATE(ProcessorRangeBearing, ParamsProcessorRangeBearing); protected: // Implementation of pure virtuals from ProcessorBase diff --git a/hello_wolf/sensor_range_bearing.cpp b/demos/hello_wolf/sensor_range_bearing.cpp similarity index 86% rename from hello_wolf/sensor_range_bearing.cpp rename to demos/hello_wolf/sensor_range_bearing.cpp index 3eea032b2ba632cf3343805446a98d0805e56f3c..54507f9ac53771523b9db8716089113686bc1ca0 100644 --- a/hello_wolf/sensor_range_bearing.cpp +++ b/demos/hello_wolf/sensor_range_bearing.cpp @@ -38,9 +38,9 @@ SensorRangeBearing::~SensorRangeBearing() } /* namespace wolf */ // Register in the SensorFactory -#include "core/sensor/sensor_factory.h" +#include "core/sensor/factory_sensor.h" namespace wolf { -WOLF_REGISTER_SENSOR("SensorRangeBearing", SensorRangeBearing) -WOLF_REGISTER_SENSOR_AUTO("SensorRangeBearing", SensorRangeBearing) +WOLF_REGISTER_SENSOR(SensorRangeBearing) +WOLF_REGISTER_SENSOR_AUTO(SensorRangeBearing) } // namespace wolf diff --git a/hello_wolf/sensor_range_bearing.h b/demos/hello_wolf/sensor_range_bearing.h similarity index 100% rename from hello_wolf/sensor_range_bearing.h rename to demos/hello_wolf/sensor_range_bearing.h diff --git a/hello_wolf/yaml/hello_wolf_config.yaml b/demos/hello_wolf/yaml/hello_wolf_config.yaml similarity index 59% rename from hello_wolf/yaml/hello_wolf_config.yaml rename to demos/hello_wolf/yaml/hello_wolf_config.yaml index b84d7776622264f96a4597ade146d64bcec86438..f2e4f8db31f97ef8059b4d59483a747456e6d19c 100644 --- a/hello_wolf/yaml/hello_wolf_config.yaml +++ b/demos/hello_wolf/yaml/hello_wolf_config.yaml @@ -2,12 +2,23 @@ config: problem: + tree_manager: + type: "TreeManagerSlidingWindow" + n_key_frames: -1 + fix_first_key_frame: false + viral_remove_empty_parent: true frame_structure: "PO" # keyframes have position and orientation dimension: 2 # space is 2d prior: - timestamp: 0.0 - state: [0,0,0] - cov: [[3,3],.01,0,0,0,.01,0,0,0,.01] + mode: "factor" + # state: [0,0,0] + $state: + P: [0,0] + O: [0] + # cov: [[3,3],.01,0,0,0,.01,0,0,0,.01] + $sigma: + P: [0.31, 0.31] + O: [0.31] time_tolerance: 0.1 sensors: @@ -17,7 +28,7 @@ config: name: "sen odom" extrinsic: pose: [0,0, 0] - follow: "hello_wolf/yaml/sensor_odom_2d.yaml" # config parameters in this file + follow: "demos/hello_wolf/yaml/sensor_odom_2d.yaml" # config parameters in this file - type: "SensorRangeBearing" plugin: "core" @@ -25,7 +36,7 @@ config: extrinsic: pose: [1,1, 0] noise_range_metres_std: 0.2 # parser only considers first appearence so the following file parsing will not overwrite this param - follow: hello_wolf/yaml/sensor_range_bearing.yaml # config parameters in this file + follow: demos/hello_wolf/yaml/sensor_range_bearing.yaml # config parameters in this file processors: @@ -33,10 +44,10 @@ config: plugin: "core" name: "prc odom" sensor_name: "sen odom" # attach processor to this sensor - follow: hello_wolf/yaml/processor_odom_2d.yaml # config parameters in this file + follow: demos/hello_wolf/yaml/processor_odom_2d.yaml # config parameters in this file - type: "ProcessorRangeBearing" plugin: "core" name: "prc rb" sensor_name: "sen rb" # attach processor to this sensor - follow: hello_wolf/yaml/processor_range_bearing.yaml # config parameters in this file + follow: demos/hello_wolf/yaml/processor_range_bearing.yaml # config parameters in this file diff --git a/hello_wolf/yaml/processor_odom_2d.yaml b/demos/hello_wolf/yaml/processor_odom_2d.yaml similarity index 92% rename from hello_wolf/yaml/processor_odom_2d.yaml rename to demos/hello_wolf/yaml/processor_odom_2d.yaml index bee82ff9ad905a72dc6c1ffd46ac6d7267ae8870..7e345ef211f52897b17267065e28feec0bf4b143 100644 --- a/hello_wolf/yaml/processor_odom_2d.yaml +++ b/demos/hello_wolf/yaml/processor_odom_2d.yaml @@ -10,3 +10,4 @@ keyframe_vote: angle_turned: 999 max_buff_length: 999 cov_det: 999 +apply_loss_function: true diff --git a/hello_wolf/yaml/processor_range_bearing.yaml b/demos/hello_wolf/yaml/processor_range_bearing.yaml similarity index 84% rename from hello_wolf/yaml/processor_range_bearing.yaml rename to demos/hello_wolf/yaml/processor_range_bearing.yaml index 61efbf8e31ee32ab9a348133a67037c5fbbdafee..3c257678c9a73eeb3b415e976b55eeddb3a79edd 100644 --- a/hello_wolf/yaml/processor_range_bearing.yaml +++ b/demos/hello_wolf/yaml/processor_range_bearing.yaml @@ -5,3 +5,5 @@ time_tolerance: 0.1 keyframe_vote: voting_active: true voting_aux_active: false + +apply_loss_function: true diff --git a/hello_wolf/yaml/sensor_odom_2d.yaml b/demos/hello_wolf/yaml/sensor_odom_2d.yaml similarity index 64% rename from hello_wolf/yaml/sensor_odom_2d.yaml rename to demos/hello_wolf/yaml/sensor_odom_2d.yaml index 3ad7204855cae5c1e8e00cfdc011ff27d2725692..65ac28219471ad65180538e526521d7866391a01 100644 --- a/hello_wolf/yaml/sensor_odom_2d.yaml +++ b/demos/hello_wolf/yaml/sensor_odom_2d.yaml @@ -1,4 +1,5 @@ -type: "SensorOdom2d" # This must match the KEY used in the SensorFactory. Otherwise it is an error. +type: "SensorOdom2d" # This must match the KEY used in the FactorySensor. Otherwise it is an error. k_disp_to_disp: 0.1 # m^2 / m k_rot_to_rot: 0.1 # rad^2 / rad +apply_loss_function: true diff --git a/hello_wolf/yaml/sensor_range_bearing.yaml b/demos/hello_wolf/yaml/sensor_range_bearing.yaml similarity index 58% rename from hello_wolf/yaml/sensor_range_bearing.yaml rename to demos/hello_wolf/yaml/sensor_range_bearing.yaml index 40a2387a041f8a34a41c5669218dd4a4eb00c0bf..d1625337dfc0b0d323d662a727c1ac298117a455 100644 --- a/hello_wolf/yaml/sensor_range_bearing.yaml +++ b/demos/hello_wolf/yaml/sensor_range_bearing.yaml @@ -1,4 +1,5 @@ type: "SensorRangeBearing" noise_range_metres_std: 0.1 -noise_bearing_degrees_std: 0.5 +noise_bearing_degrees_std: 0.5 +apply_loss_function: true diff --git a/include/core/capture/capture_base.h b/include/core/capture/capture_base.h index 2491d5a6a5afbdc4d3b52a3e86003c3794b6cd81..d4e215e47cd576b48797c4e9f028be5a5a64edf1 100644 --- a/include/core/capture/capture_base.h +++ b/include/core/capture/capture_base.h @@ -29,7 +29,6 @@ class CaptureBase : public NodeBase, public HasStateBlocks, public std::enable_s FeatureBasePtrList feature_list_; FactorBasePtrList constrained_by_list_; SensorBaseWPtr sensor_ptr_; ///< Pointer to sensor - SizeEigen calib_size_; ///< size of the calibration parameters (dynamic or static sensor params that are not fixed) static unsigned int capture_id_count_; @@ -83,7 +82,7 @@ class CaptureBase : public NodeBase, public HasStateBlocks, public std::enable_s // State blocks - const std::string& getStructure() const; + const StateStructure& getStructure() const; StateBlockPtr getStateBlock(const std::string& _key) const; StateBlockPtr getStateBlock(const char _key) const { return getStateBlock(std::string(1, _key)); } StateBlockPtr getSensorP() const; @@ -93,24 +92,31 @@ class CaptureBase : public NodeBase, public HasStateBlocks, public std::enable_s virtual void fix() override; virtual void unfix() override; - bool hasCalibration() {return calib_size_ > 0;} - SizeEigen getCalibSize() const; - virtual Eigen::VectorXd getCalibration() const; - void setCalibration(const Eigen::VectorXd& _calib); void move(FrameBasePtr); void link(FrameBasePtr); template<typename classType, typename... T> static std::shared_ptr<classType> emplace(FrameBasePtr _frm_ptr, T&&... all); - protected: - virtual SizeEigen computeCalibSize() const; + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const; + + void print(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream = std::cout, + std::string _tabs = "") const; + + virtual CheckLog localCheck(bool _verbose, CaptureBasePtr _cap_ptr, std::ostream& _stream, std::string _tabs = "") const; + bool check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs = "") const; private: FeatureBasePtr addFeature(FeatureBasePtr _ft_ptr); void removeFeature(FeatureBasePtr _ft_ptr); - - private: - void updateCalibSize(); }; } @@ -130,16 +136,6 @@ std::shared_ptr<classType> CaptureBase::emplace(FrameBasePtr _frm_ptr, T&&... al return cpt; } -inline SizeEigen CaptureBase::getCalibSize() const -{ - return calib_size_; -} - -inline void CaptureBase::updateCalibSize() -{ - calib_size_ = computeCalibSize(); -} - inline StateBlockPtr CaptureBase::getSensorP() const { return getStateBlock("P"); diff --git a/include/core/capture/capture_diff_drive.h b/include/core/capture/capture_diff_drive.h index 2300a65b2a203ccc6bb9ca155fab6dbb6b2bdd96..52e865da7d6d3e441643480d9a5e6acc0014aa89 100644 --- a/include/core/capture/capture_diff_drive.h +++ b/include/core/capture/capture_diff_drive.h @@ -38,9 +38,6 @@ public: StateBlockPtr _intr_ptr = nullptr); virtual ~CaptureDiffDrive() = default; - - virtual Eigen::VectorXd correctDelta(const VectorXd& _delta, const VectorXd& _delta_error) const override; - }; } // namespace wolf diff --git a/include/core/capture/capture_motion.h b/include/core/capture/capture_motion.h index d78cd5169f3dfc523c9435c11dc65b41ef6b3591..fca231eeb7142aa456171c95438d0b322927a88d 100644 --- a/include/core/capture/capture_motion.h +++ b/include/core/capture/capture_motion.h @@ -50,8 +50,6 @@ class CaptureMotion : public CaptureBase const TimeStamp& _ts, SensorBasePtr _sensor_ptr, const Eigen::VectorXd& _data, - SizeEigen _delta_size, - SizeEigen _delta_cov_size, CaptureBasePtr _capture_origin_ptr); CaptureMotion(const std::string & _type, @@ -59,8 +57,6 @@ class CaptureMotion : public CaptureBase SensorBasePtr _sensor_ptr, const Eigen::VectorXd& _data, const Eigen::MatrixXd& _data_cov, - SizeEigen _delta_size, - SizeEigen _delta_cov_size, CaptureBasePtr _capture_origin_ptr, StateBlockPtr _p_ptr = nullptr, StateBlockPtr _o_ptr = nullptr, @@ -88,18 +84,25 @@ class CaptureMotion : public CaptureBase MatrixXd getJacobianCalib(const TimeStamp& _ts) const; // Get delta preintegrated, and corrected for changes on calibration params - VectorXd getDeltaCorrected(const VectorXd& _calib_current) const; - VectorXd getDeltaCorrected(const VectorXd& _calib_current, const TimeStamp& _ts) const; VectorXd getDeltaPreint() const; VectorXd getDeltaPreint(const TimeStamp& _ts) const; MatrixXd getDeltaPreintCov() const; MatrixXd getDeltaPreintCov(const TimeStamp& _ts) const; - virtual VectorXd correctDelta(const VectorXd& _delta, const VectorXd& _delta_error) const; // Origin frame and capture CaptureBasePtr getOriginCapture(); + CaptureBasePtr getOriginCapture() const; void setOriginCapture(CaptureBasePtr _capture_origin_ptr); + bool containsTimeStamp(const TimeStamp& _ts, double _time_tolerance); + + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const override; + // member data: private: Eigen::VectorXd data_; ///< Motion data in form of vector mandatory @@ -144,7 +147,7 @@ inline MotionBuffer& CaptureMotion::getBuffer() inline Eigen::MatrixXd CaptureMotion::getJacobianCalib() const { - return getBuffer().get().back().jacobian_calib_; + return getBuffer().back().jacobian_calib_; } inline Eigen::MatrixXd CaptureMotion::getJacobianCalib(const TimeStamp& _ts) const @@ -152,13 +155,12 @@ inline Eigen::MatrixXd CaptureMotion::getJacobianCalib(const TimeStamp& _ts) con return getBuffer().getMotion(_ts).jacobian_calib_; } -inline Eigen::VectorXd CaptureMotion::correctDelta(const VectorXd& _delta, const VectorXd& _delta_error) const +inline wolf::CaptureBasePtr CaptureMotion::getOriginCapture() { - WOLF_DEBUG("WARNING: using Cartesian sum for delta correction. \nIf your deltas lie on a manifold, derive this function and implement the proper delta correction!") - return _delta + _delta_error; + return capture_origin_ptr_.lock(); } -inline wolf::CaptureBasePtr CaptureMotion::getOriginCapture() +inline wolf::CaptureBasePtr CaptureMotion::getOriginCapture() const { return capture_origin_ptr_.lock(); } @@ -180,7 +182,7 @@ inline void CaptureMotion::setCalibrationPreint(const VectorXd& _calib_preint) inline VectorXd CaptureMotion::getDeltaPreint() const { - return getBuffer().get().back().delta_integr_; + return getBuffer().back().delta_integr_; } inline VectorXd CaptureMotion::getDeltaPreint(const TimeStamp& _ts) const @@ -190,7 +192,7 @@ inline VectorXd CaptureMotion::getDeltaPreint(const TimeStamp& _ts) const inline MatrixXd CaptureMotion::getDeltaPreintCov() const { - return getBuffer().get().back().delta_integr_cov_; + return getBuffer().back().delta_integr_cov_; } inline MatrixXd CaptureMotion::getDeltaPreintCov(const TimeStamp& _ts) const diff --git a/include/core/capture/capture_odom_2d.h b/include/core/capture/capture_odom_2d.h index d18217279601157c9a1b2eb3c4e7f4ba4dae6cbb..8856c363a7f576413a3428fa7b206ab6bd17f824 100644 --- a/include/core/capture/capture_odom_2d.h +++ b/include/core/capture/capture_odom_2d.h @@ -33,17 +33,8 @@ class CaptureOdom2d : public CaptureMotion virtual ~CaptureOdom2d(); - virtual VectorXd correctDelta(const VectorXd& _delta, const VectorXd& _delta_error) const override; - }; -inline Eigen::VectorXd CaptureOdom2d::correctDelta(const VectorXd& _delta, const VectorXd& _delta_error) const -{ - Vector3d delta = _delta + _delta_error; - delta(2) = pi2pi(delta(2)); - return delta; -} - } /* namespace wolf */ #endif /* CAPTURE_ODOM_2d_H_ */ diff --git a/include/core/capture/capture_odom_3d.h b/include/core/capture/capture_odom_3d.h index 7e4ee02c8b694cc6ae2b8e8b6d9e6803d7587c65..b4a293f8c4059b9346a334c31e017a967267a902 100644 --- a/include/core/capture/capture_odom_3d.h +++ b/include/core/capture/capture_odom_3d.h @@ -33,8 +33,6 @@ class CaptureOdom3d : public CaptureMotion virtual ~CaptureOdom3d(); - virtual VectorXd correctDelta(const VectorXd& _delta, const VectorXd& _delta_error) const override; - }; } /* namespace wolf */ diff --git a/include/core/capture/capture_velocity.h b/include/core/capture/capture_velocity.h deleted file mode 100644 index d2d1c686dfd84c0d8d9ca3c4fbe0a1b7d17091e1..0000000000000000000000000000000000000000 --- a/include/core/capture/capture_velocity.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * \file capture_velocity.h - * - * Created on: Oct 20, 2016 - * \author: Jeremie Deray - */ - -#ifndef _WOLF_CAPTURE_VELOCITY_H_ -#define _WOLF_CAPTURE_VELOCITY_H_ - -//wolf includes -#include "core/capture/capture_motion.h" - -namespace wolf { - -WOLF_PTR_TYPEDEFS(CaptureVelocity); - -/** - * @brief The CaptureVelocity class - * - * Represents a velocity. - */ -class CaptureVelocity : public CaptureMotion -{ -protected: - - using NodeBase::node_type_; - -public: - - /** - * \brief Constructor - **/ - CaptureVelocity(const TimeStamp& _ts, - const SensorBasePtr& _sensor_ptr, - const Eigen::VectorXd& _velocity, - SizeEigen _delta_size, SizeEigen _delta_cov_size, - CaptureBasePtr _capture_origin_ptr); - - CaptureVelocity(const TimeStamp& _ts, - const SensorBasePtr& _sensor_ptr, - const Eigen::VectorXd& _velocity, - const Eigen::MatrixXd& _velocity_cov, - SizeEigen _delta_size, SizeEigen _delta_cov_size, - CaptureBasePtr _capture_origin_ptr, - StateBlockPtr _p_ptr = nullptr, - StateBlockPtr _o_ptr = nullptr, - StateBlockPtr _intr_ptr = nullptr); - - virtual ~CaptureVelocity() = default; - - const Eigen::VectorXd& getVelocity() const; - - const Eigen::MatrixXd& getVelocityCov() const; -}; - -} // namespace wolf - -#endif /* _WOLF_CAPTURE_VELOCITY_H_ */ diff --git a/include/core/ceres_wrapper/ceres_manager.h b/include/core/ceres_wrapper/ceres_manager.h index 802ab7b49dabf93455f8f93fc8c30745415fe33e..0841f7421ef37f039b2fa77449ffafefd52b7118 100644 --- a/include/core/ceres_wrapper/ceres_manager.h +++ b/include/core/ceres_wrapper/ceres_manager.h @@ -62,10 +62,7 @@ class CeresManager : public SolverManager ceres::Solver::Summary getSummary(); - std::unique_ptr<ceres::Problem>& getCeresProblem() - { - return ceres_problem_; - } + std::unique_ptr<ceres::Problem>& getCeresProblem(); virtual void computeCovariances(CovarianceBlocksToBeComputed _blocks = CovarianceBlocksToBeComputed::ROBOT_LANDMARKS) override; @@ -82,25 +79,26 @@ class CeresManager : public SolverManager ceres::Solver::Options& getSolverOptions(); - void check(); const Eigen::SparseMatrixd computeHessian() const; protected: - std::string solveImpl(const ReportVerbosity report_level) override; + virtual bool checkDerived(std::string prefix="") const override; - void addFactor(const FactorBasePtr& fac_ptr) override; + virtual std::string solveDerived(const ReportVerbosity report_level) override; - void removeFactor(const FactorBasePtr& fac_ptr) override; + virtual void addFactorDerived(const FactorBasePtr& fac_ptr) override; - void addStateBlock(const StateBlockPtr& state_ptr) override; + virtual void removeFactorDerived(const FactorBasePtr& fac_ptr) override; - void removeStateBlock(const StateBlockPtr& state_ptr) override; + virtual void addStateBlockDerived(const StateBlockPtr& state_ptr) override; - void updateStateBlockStatus(const StateBlockPtr& state_ptr) override; + virtual void removeStateBlockDerived(const StateBlockPtr& state_ptr) override; - void updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr) override; + virtual void updateStateBlockStatusDerived(const StateBlockPtr& state_ptr) override; + + virtual void updateStateBlockLocalParametrizationDerived(const StateBlockPtr& state_ptr) override; ceres::CostFunctionPtr createCostFunction(const FactorBasePtr& _fac_ptr); @@ -114,6 +112,11 @@ inline ceres::Solver::Summary CeresManager::getSummary() return summary_; } +inline std::unique_ptr<ceres::Problem>& CeresManager::getCeresProblem() +{ + return ceres_problem_; +} + inline ceres::Solver::Options& CeresManager::getSolverOptions() { return ceres_options_; diff --git a/include/core/common/factory.h b/include/core/common/factory.h index 810871e64fd3ed645d3412a21836ea8d3e6b93cc..70f66f6e5f39a7525bcf8d5cccbf762c4ca9f2c0 100644 --- a/include/core/common/factory.h +++ b/include/core/common/factory.h @@ -112,9 +112,9 @@ namespace wolf * The first thing to know is that we have defined typedefs for the templates that we are using. For example: * * \code - * typedef Factory<ParamsSensorBase, std::string> ParamsSensorFactory; - * typedef Factory<ProcessorParamsBase, std::string> ProcessorParamsFactory; - * typedef Factory<LandmarkBase, YAML::Node> LandmarkFactory; + * typedef Factory<ParamsSensorBase, std::string> FactoryParamsSensor; + * typedef Factory<ParamsProcessorBase, std::string> FactoryParamsProcessor; + * typedef Factory<LandmarkBase, YAML::Node> FactoryLandmark; * \endcode * * Second to know, the Factory class is a <a href="http://stackoverflow.com/questions/1008019/c-singleton-design-pattern#1008289">singleton</a>: it can only exist once in your application. @@ -129,7 +129,7 @@ namespace wolf * You can then call the methods you like, e.g. to create a landmark, you use: * * \code - * LandmarkFactory::get().create(TYPE, args...); // see below for creating objects ... + * FactoryLandmark::get().create(TYPE, args...); // see below for creating objects ... * \endcode * * #### Write creator methods (in your derived object classes) @@ -164,7 +164,7 @@ namespace wolf * that knows how to create your specific object, e.g.: * * \code - * LandmarkFactory::get().registerCreator("POLYLINE 2d", LandmarkPolyline2d::create); + * FactoryLandmark::get().registerCreator("POLYLINE 2d", LandmarkPolyline2d::create); * \endcode * * #### Automatic registration @@ -172,7 +172,7 @@ namespace wolf * For example, in sensor_camera_yaml.cpp we find the line: * * \code - * const bool registered_camera_intr = ParamsSensorFactory::get().registerCreator("CAMERA", createParamsSensorCamera); + * const bool registered_camera_intr = FactoryParamsSensor::get().registerCreator("CAMERA", createParamsSensorCamera); * \endcode * * which is a static invocation (i.e., it is placed at global scope outside of the ParamsSensorCamera class). @@ -199,7 +199,7 @@ namespace wolf * or even better, make use of the convenient typedefs: * * \code - * LandmarkBasePtr lmk_ptr = LandmarkFactory::get().create("POLYLINE 2d", lmk_yaml_node); + * LandmarkBasePtr lmk_ptr = FactoryLandmark::get().create("POLYLINE 2d", lmk_yaml_node); * \endcode * * ### Examples @@ -239,21 +239,21 @@ namespace wolf * // Register landmark creator (put the register code inside an unnamed namespace): * namespace * { - * const bool registered_lmk_polyline_2d = LandmarkFactory::get().registerCreator("POLYLINE 2d", LandmarkPolyline2d::create); + * const bool registered_lmk_polyline_2d = FactoryLandmark::get().registerCreator("POLYLINE 2d", LandmarkPolyline2d::create); * } * * \endcode * * ### More information - * - ParamsSensorFactory: typedef of this template to create intrinsic structs deriving from ParamsSensorBase directly from YAML files. - * - ProcessorParamsFactory: typedef of this template to create processor params structs deriving from ProcessorParamsBase directly from YAML files. - * - LandmarkFactory: typedef of this template to create landmarks deriving from LandmarkBase directly from YAML nodes. + * - FactoryParamsSensor: typedef of this template to create intrinsic structs deriving from ParamsSensorBase directly from YAML files. + * - FactoryParamsProcessor: typedef of this template to create processor params structs deriving from ParamsProcessorBase directly from YAML files. + * - FactoryLandmark: typedef of this template to create landmarks deriving from LandmarkBase directly from YAML nodes. * - Problem::loadMap() : to load a maps directly from YAML files. * - You can also check the code in the example file ````src/examples/test_map_yaml.cpp````. * * #### See also - * - SensorFactory: to create sensors - * - ProcessorFactory: to create processors. + * - FactorySensor: to create sensors + * - FactoryProcessor: to create processors. * - Problem::installSensor() : to install sensors in WOLF Problem. * - Problem::installProcessor() : to install processors in WOLF Problem. * @@ -275,7 +275,7 @@ class Factory bool registerCreator(const std::string& _type, CreatorCallback createFn); bool unregisterCreator(const std::string& _type); TypeBasePtr create(const std::string& _type, TypeInput... _input); - std::string getClass(); + std::string getClass() const; private: CallbackMap callbacks_; @@ -332,7 +332,7 @@ inline Factory<TypeBase, TypeInput...>& Factory<TypeBase, TypeInput...>::get() } template<class TypeBase, typename... TypeInput> -inline std::string Factory<TypeBase, TypeInput...>::getClass() +inline std::string Factory<TypeBase, TypeInput...>::getClass() const { return "Factory<class TypeBase>"; } @@ -348,11 +348,11 @@ namespace wolf // Landmarks from YAML class LandmarkBase; typedef Factory<LandmarkBase, - const YAML::Node&> LandmarkFactory; + const YAML::Node&> FactoryLandmark; template<> -inline std::string LandmarkFactory::getClass() +inline std::string FactoryLandmark::getClass() const { - return "LandmarkFactory"; + return "FactoryLandmark"; } diff --git a/include/core/common/node_base.h b/include/core/common/node_base.h index 4488ab30ec274eeb84e49b7dcd600de9a93acf5e..dcd7d37176c2eb4c36aea7c8b342aa064b43a896 100644 --- a/include/core/common/node_base.h +++ b/include/core/common/node_base.h @@ -3,6 +3,7 @@ // Wolf includes #include "core/common/wolf.h" +#include "core/utils/check_log.h" namespace wolf { @@ -27,8 +28,8 @@ namespace wolf { * - "LANDMARK" * * - A unique type, which is a subcategory of the above. The list here cannot be exhaustive, but a few examples follow: - * - "SesorCamera" - * - "SesorLaser2d" + * - "SensorCamera" + * - "SensorLaser2d" * - "LandmarkPoint3d" * - "ProcessorLaser2d" * diff --git a/include/core/common/wolf.h b/include/core/common/wolf.h index 64a4741c518ecd0f75bf029aa4e3267b1e3f8c4e..319b2df0bf0d0ed464ca8a55647a63594a1bb4a3 100644 --- a/include/core/common/wolf.h +++ b/include/core/common/wolf.h @@ -212,6 +212,10 @@ WOLF_PTR_TYPEDEFS(NodeBase); // Problem WOLF_PTR_TYPEDEFS(Problem); +// Tree Manager +WOLF_PTR_TYPEDEFS(TreeManagerBase); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsTreeManagerBase); + // Hardware WOLF_PTR_TYPEDEFS(HardwareBase); @@ -230,7 +234,7 @@ WOLF_LIST_TYPEDEFS(ProcessorBase); WOLF_PTR_TYPEDEFS(ProcessorMotion); // - - Processor params -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsBase); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorBase); // Trajectory WOLF_PTR_TYPEDEFS(TrajectoryBase); @@ -279,7 +283,6 @@ inline bool file_exists(const std::string& _name) inline const Eigen::Vector3d gravity(void) { return Eigen::Vector3d(0,0,-9.806); } - } // namespace wolf #endif /* WOLF_H_ */ diff --git a/include/core/factor/factor_analytic.h b/include/core/factor/factor_analytic.h index f1f9f02e617be2046471b7cecb26959bfe610143..34fd699a7b1461f9ab147c9d5d9f6ef2496b2f97 100644 --- a/include/core/factor/factor_analytic.h +++ b/include/core/factor/factor_analytic.h @@ -19,6 +19,7 @@ class FactorAnalytic: public FactorBase public: FactorAnalytic(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, diff --git a/include/core/factor/factor_autodiff.h b/include/core/factor/factor_autodiff.h index d5e86d2f168acce03feb9085420de1c6ad901ab8..dce0203c894704953ff3001732f418b2636343a3 100644 --- a/include/core/factor/factor_autodiff.h +++ b/include/core/factor/factor_autodiff.h @@ -15,7 +15,7 @@ namespace wolf { //template class FactorAutodiff -template <class FacT, unsigned int RES, unsigned int B0, unsigned int B1 = 0, unsigned int B2 = 0, unsigned int B3 = 0, unsigned int B4 = 0, unsigned int B5 = 0, unsigned int B6 = 0, unsigned int B7 = 0, unsigned int B8 = 0, unsigned int B9 = 0> +template <class FacT, unsigned int RES, unsigned int B0, unsigned int B1 = 0, unsigned int B2 = 0, unsigned int B3 = 0, unsigned int B4 = 0, unsigned int B5 = 0, unsigned int B6 = 0, unsigned int B7 = 0, unsigned int B8 = 0, unsigned int B9 = 0, unsigned int B10 = 0, unsigned int B11 = 0> class FactorAutodiff : public FactorBase { public: @@ -31,34 +31,40 @@ class FactorAutodiff : public FactorBase static const unsigned int block7Size = B7; static const unsigned int block8Size = B8; static const unsigned int block9Size = B9; - static const unsigned int n_blocks = 10; + static const unsigned int block10Size = B10; + static const unsigned int block11Size = B11; + static const unsigned int n_blocks = 12; static const std::vector<unsigned int> state_block_sizes_; typedef ceres::Jet<double, B0 + B1 + B2 + B3 + B4 + - B5 + B6 + B7 + B8 + B9> WolfJet; + B5 + B6 + B7 + B8 + B9 + + B10 + B11> WolfJet; protected: std::vector<StateBlockPtr> state_ptrs_; static const std::vector<unsigned int> jacobian_locations_; - std::array<WolfJet, RES>* residuals_jets_; - std::array<WolfJet, B0>* jets_0_; - std::array<WolfJet, B1>* jets_1_; - std::array<WolfJet, B2>* jets_2_; - std::array<WolfJet, B3>* jets_3_; - std::array<WolfJet, B4>* jets_4_; - std::array<WolfJet, B5>* jets_5_; - std::array<WolfJet, B6>* jets_6_; - std::array<WolfJet, B7>* jets_7_; - std::array<WolfJet, B8>* jets_8_; - std::array<WolfJet, B9>* jets_9_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; + mutable std::array<WolfJet, B2> jets_2_; + mutable std::array<WolfJet, B3> jets_3_; + mutable std::array<WolfJet, B4> jets_4_; + mutable std::array<WolfJet, B5> jets_5_; + mutable std::array<WolfJet, B6> jets_6_; + mutable std::array<WolfJet, B7> jets_7_; + mutable std::array<WolfJet, B8> jets_8_; + mutable std::array<WolfJet, B9> jets_9_; + mutable std::array<WolfJet, B10> jets_10_; + mutable std::array<WolfJet, B11> jets_11_; public: /** \brief Constructor valid for all categories (ABSOLUTE, FRAME, FEATURE, LANDMARK) **/ FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -75,58 +81,56 @@ class FactorAutodiff : public FactorBase StateBlockPtr _state6Ptr, StateBlockPtr _state7Ptr, StateBlockPtr _state8Ptr, - StateBlockPtr _state9Ptr) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), - state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr}), - residuals_jets_(new std::array<WolfJet, RES>), - jets_0_(new std::array<WolfJet, B0>), - jets_1_(new std::array<WolfJet, B1>), - jets_2_(new std::array<WolfJet, B2>), - jets_3_(new std::array<WolfJet, B3>), - jets_4_(new std::array<WolfJet, B4>), - jets_5_(new std::array<WolfJet, B5>), - jets_6_(new std::array<WolfJet, B6>), - jets_7_(new std::array<WolfJet, B7>), - jets_8_(new std::array<WolfJet, B8>), - jets_9_(new std::array<WolfJet, B9>) + StateBlockPtr _state9Ptr, + StateBlockPtr _state10Ptr, + StateBlockPtr _state11Ptr) : + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr,_state10Ptr,_state11Ptr}) { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + assert(_state2Ptr != nullptr && "nullptr state block"); + assert(_state3Ptr != nullptr && "nullptr state block"); + assert(_state4Ptr != nullptr && "nullptr state block"); + assert(_state5Ptr != nullptr && "nullptr state block"); + assert(_state6Ptr != nullptr && "nullptr state block"); + assert(_state7Ptr != nullptr && "nullptr state block"); + assert(_state8Ptr != nullptr && "nullptr state block"); + assert(_state9Ptr != nullptr && "nullptr state block"); + assert(_state10Ptr != nullptr && "nullptr state block"); + assert(_state11Ptr != nullptr && "nullptr state block"); + // initialize jets unsigned int last_jet_idx = 0; for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i] = WolfJet(0, last_jet_idx++); + jets_0_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i] = WolfJet(0, last_jet_idx++); + jets_1_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i] = WolfJet(0, last_jet_idx++); + jets_2_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i] = WolfJet(0, last_jet_idx++); + jets_3_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i] = WolfJet(0, last_jet_idx++); + jets_4_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B5; i++) - (*jets_5_)[i] = WolfJet(0, last_jet_idx++); + jets_5_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B6; i++) - (*jets_6_)[i] = WolfJet(0, last_jet_idx++); + jets_6_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B7; i++) - (*jets_7_)[i] = WolfJet(0, last_jet_idx++); + jets_7_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B8; i++) - (*jets_8_)[i] = WolfJet(0, last_jet_idx++); + jets_8_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B9; i++) - (*jets_9_)[i] = WolfJet(0, last_jet_idx++); + jets_9_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B10; i++) + jets_10_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B11; i++) + jets_11_[i] = WolfJet(0, last_jet_idx++); } virtual ~FactorAutodiff() { - delete jets_0_; - delete jets_1_; - delete jets_2_; - delete jets_3_; - delete jets_4_; - delete jets_5_; - delete jets_6_; - delete jets_7_; - delete jets_8_; - delete jets_9_; - delete residuals_jets_; } virtual JacobianMethod getJacobianMethod() const @@ -154,6 +158,8 @@ class FactorAutodiff : public FactorBase parameters[7], parameters[8], parameters[9], + parameters[10], + parameters[11], residuals); } // also compute jacobians @@ -165,28 +171,30 @@ class FactorAutodiff : public FactorBase updateJetsRealPart(param_vec); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - jets_5_->data(), - jets_6_->data(), - jets_7_->data(), - jets_8_->data(), - jets_9_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + jets_7_.data(), + jets_8_.data(), + jets_9_.data(), + jets_10_.data(), + jets_11_.data(), + residuals_jets_.data()); // fill the residual array for (unsigned int i = 0; i < RES; i++) - residuals[i] = (*residuals_jets_)[i].a; + residuals[i] = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) if (jacobians[i] != nullptr) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), jacobians[i] + row * state_block_sizes_.at(i)); } return true; @@ -199,25 +207,29 @@ class FactorAutodiff : public FactorBase { // update jets real part for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i].a = parameters[0][i]; + jets_0_[i].a = parameters[0][i]; for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i].a = parameters[1][i]; + jets_1_[i].a = parameters[1][i]; for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i].a = parameters[2][i]; + jets_2_[i].a = parameters[2][i]; for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i].a = parameters[3][i]; + jets_3_[i].a = parameters[3][i]; for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i].a = parameters[4][i]; + jets_4_[i].a = parameters[4][i]; for (unsigned int i = 0; i < B5; i++) - (*jets_5_)[i].a = parameters[5][i]; + jets_5_[i].a = parameters[5][i]; for (unsigned int i = 0; i < B6; i++) - (*jets_6_)[i].a = parameters[6][i]; + jets_6_[i].a = parameters[6][i]; for (unsigned int i = 0; i < B7; i++) - (*jets_7_)[i].a = parameters[7][i]; + jets_7_[i].a = parameters[7][i]; for (unsigned int i = 0; i < B8; i++) - (*jets_8_)[i].a = parameters[8][i]; + jets_8_[i].a = parameters[8][i]; for (unsigned int i = 0; i < B9; i++) - (*jets_9_)[i].a = parameters[9][i]; + jets_9_[i].a = parameters[9][i]; + for (unsigned int i = 0; i < B10; i++) + jets_10_[i].a = parameters[10][i]; + for (unsigned int i = 0; i < B11; i++) + jets_11_[i].a = parameters[11][i]; } /** \brief Returns a vector of Jacobian matrix corresponding to each state block evaluated in the point provided in _states_ptr @@ -234,21 +246,23 @@ class FactorAutodiff : public FactorBase updateJetsRealPart(_states_ptr); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - jets_5_->data(), - jets_6_->data(), - jets_7_->data(), - jets_8_->data(), - jets_9_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + jets_7_.data(), + jets_8_.data(), + jets_9_.data(), + jets_10_.data(), + jets_11_.data(), + residuals_jets_.data()); // fill the residual vector for (unsigned int i = 0; i < RES; i++) - residual_(i) = (*residuals_jets_)[i].a; + residual_(i) = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) @@ -258,8 +272,8 @@ class FactorAutodiff : public FactorBase // Fill Jacobian rows from jets if (!state_ptrs_[i]->isFixed()) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), Ji.data() + row * state_block_sizes_.at(i)); // add to the Jacobians vector jacobians_.push_back(Ji); @@ -299,10 +313,531 @@ class FactorAutodiff : public FactorBase } }; + +////////////////// SPECIALIZATION 11 BLOCKS //////////////////////////////////////////////////////////////////////// + +template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8,unsigned int B9,unsigned int B10> +class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,0> : public FactorBase +{ + public: + + static const unsigned int residualSize = RES; + static const unsigned int block0Size = B0; + static const unsigned int block1Size = B1; + static const unsigned int block2Size = B2; + static const unsigned int block3Size = B3; + static const unsigned int block4Size = B4; + static const unsigned int block5Size = B5; + static const unsigned int block6Size = B6; + static const unsigned int block7Size = B7; + static const unsigned int block8Size = B8; + static const unsigned int block9Size = B9; + static const unsigned int block10Size = B10; + static const unsigned int block11Size = 0; + static const unsigned int n_blocks = 11; + + static const std::vector<unsigned int> state_block_sizes_; + + typedef ceres::Jet<double, B0 + B1 + B2 + B3 + B4 + + B5 + B6 + B7 + B8 + B9 + B10> WolfJet; + + protected: + + std::vector<StateBlockPtr> state_ptrs_; + + static const std::vector<unsigned int> jacobian_locations_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; + mutable std::array<WolfJet, B2> jets_2_; + mutable std::array<WolfJet, B3> jets_3_; + mutable std::array<WolfJet, B4> jets_4_; + mutable std::array<WolfJet, B5> jets_5_; + mutable std::array<WolfJet, B6> jets_6_; + mutable std::array<WolfJet, B7> jets_7_; + mutable std::array<WolfJet, B8> jets_8_; + mutable std::array<WolfJet, B9> jets_9_; + mutable std::array<WolfJet, B10> jets_10_; + + public: + + FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, + const FrameBasePtr& _frame_other_ptr, + const CaptureBasePtr& _capture_other_ptr, + const FeatureBasePtr& _feature_other_ptr, + const LandmarkBasePtr& _landmark_other_ptr, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status, + StateBlockPtr _state0Ptr, + StateBlockPtr _state1Ptr, + StateBlockPtr _state2Ptr, + StateBlockPtr _state3Ptr, + StateBlockPtr _state4Ptr, + StateBlockPtr _state5Ptr, + StateBlockPtr _state6Ptr, + StateBlockPtr _state7Ptr, + StateBlockPtr _state8Ptr, + StateBlockPtr _state9Ptr, + StateBlockPtr _state10Ptr) : + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr,_state10Ptr}) + { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + assert(_state2Ptr != nullptr && "nullptr state block"); + assert(_state3Ptr != nullptr && "nullptr state block"); + assert(_state4Ptr != nullptr && "nullptr state block"); + assert(_state5Ptr != nullptr && "nullptr state block"); + assert(_state6Ptr != nullptr && "nullptr state block"); + assert(_state7Ptr != nullptr && "nullptr state block"); + assert(_state8Ptr != nullptr && "nullptr state block"); + assert(_state9Ptr != nullptr && "nullptr state block"); + assert(_state10Ptr != nullptr && "nullptr state block"); + + // initialize jets + unsigned int last_jet_idx = 0; + for (unsigned int i = 0; i < B0; i++) + jets_0_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B1; i++) + jets_1_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B2; i++) + jets_2_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B3; i++) + jets_3_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B4; i++) + jets_4_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B5; i++) + jets_5_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B6; i++) + jets_6_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B7; i++) + jets_7_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B8; i++) + jets_8_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B9; i++) + jets_9_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B10; i++) + jets_10_[i] = WolfJet(0, last_jet_idx++); + state_ptrs_.resize(n_blocks); + } + + virtual ~FactorAutodiff() + { + } + + virtual JacobianMethod getJacobianMethod() const + { + return JAC_AUTO; + } + + virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const + { + // only residuals + if (jacobians == nullptr) + { + (*static_cast<FacT const*>(this))(parameters[0], + parameters[1], + parameters[2], + parameters[3], + parameters[4], + parameters[5], + parameters[6], + parameters[7], + parameters[8], + parameters[9], + parameters[10], + residuals); + } + // also compute jacobians + else + { + // update jets real part + std::vector<double const*> param_vec; + param_vec.assign(parameters,parameters+n_blocks); + updateJetsRealPart(param_vec); + + // call functor + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + jets_7_.data(), + jets_8_.data(), + jets_9_.data(), + jets_10_.data(), + residuals_jets_.data()); + + // fill the residual array + for (unsigned int i = 0; i < RES; i++) + residuals[i] = residuals_jets_[i].a; + + // fill the jacobian matrices + for (unsigned int i = 0; i<n_blocks; i++) + if (jacobians[i] != nullptr) + for (unsigned int row = 0; row < RES; row++) + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + jacobians[i] + row * state_block_sizes_.at(i)); + } + return true; + } + + void updateJetsRealPart(const std::vector<double const*>& parameters) const + { + // update jets real part + for (unsigned int i = 0; i < B0; i++) + jets_0_[i].a = parameters[0][i]; + for (unsigned int i = 0; i < B1; i++) + jets_1_[i].a = parameters[1][i]; + for (unsigned int i = 0; i < B2; i++) + jets_2_[i].a = parameters[2][i]; + for (unsigned int i = 0; i < B3; i++) + jets_3_[i].a = parameters[3][i]; + for (unsigned int i = 0; i < B4; i++) + jets_4_[i].a = parameters[4][i]; + for (unsigned int i = 0; i < B5; i++) + jets_5_[i].a = parameters[5][i]; + for (unsigned int i = 0; i < B6; i++) + jets_6_[i].a = parameters[6][i]; + for (unsigned int i = 0; i < B7; i++) + jets_7_[i].a = parameters[7][i]; + for (unsigned int i = 0; i < B8; i++) + jets_8_[i].a = parameters[8][i]; + for (unsigned int i = 0; i < B9; i++) + jets_9_[i].a = parameters[9][i]; + for (unsigned int i = 0; i < B10; i++) + jets_10_[i].a = parameters[10][i]; + } + + virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const + { + assert(residual_.size() == RES); + jacobians_.clear(); + + assert(_states_ptr.size() == n_blocks); + + // update jets real part + updateJetsRealPart(_states_ptr); + + // call functor + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + jets_7_.data(), + jets_8_.data(), + jets_9_.data(), + jets_10_.data(), + residuals_jets_.data()); + + // fill the residual vector + for (unsigned int i = 0; i < RES; i++) + residual_(i) = residuals_jets_[i].a; + + // fill the jacobian matrices + for (unsigned int i = 0; i<n_blocks; i++) + { + // Create a row major Jacobian + Eigen::MatrixRowXd Ji(Eigen::MatrixRowXd::Zero(RES, state_block_sizes_[i])); + // Fill Jacobian rows from jets + if (!state_ptrs_[i]->isFixed()) + for (unsigned int row = 0; row < RES; row++) + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + Ji.data() + row * state_block_sizes_.at(i)); + // add to the Jacobians vector + jacobians_.push_back(Ji); + } + + // print jacobian matrices +// for (unsigned int i = 0; i < n_blocks; i++) +// std::cout << jacobians_[i] << std::endl << std::endl; + } + + virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const + { + return state_ptrs_; + } + + virtual std::vector<unsigned int> getStateSizes() const + { + return state_block_sizes_; + } + + virtual unsigned int getSize() const + { + return RES; + } +}; + +////////////////// SPECIALIZATION 10 BLOCKS //////////////////////////////////////////////////////////////////////// + +template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8,unsigned int B9> +class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,0,0> : public FactorBase +{ + public: + + static const unsigned int residualSize = RES; + static const unsigned int block0Size = B0; + static const unsigned int block1Size = B1; + static const unsigned int block2Size = B2; + static const unsigned int block3Size = B3; + static const unsigned int block4Size = B4; + static const unsigned int block5Size = B5; + static const unsigned int block6Size = B6; + static const unsigned int block7Size = B7; + static const unsigned int block8Size = B8; + static const unsigned int block9Size = B9; + static const unsigned int block10Size = 0; + static const unsigned int block11Size = 0; + static const unsigned int n_blocks = 10; + + static const std::vector<unsigned int> state_block_sizes_; + + typedef ceres::Jet<double, B0 + B1 + B2 + B3 + B4 + + B5 + B6 + B7 + B8 + B9> WolfJet; + + protected: + + std::vector<StateBlockPtr> state_ptrs_; + + static const std::vector<unsigned int> jacobian_locations_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; + mutable std::array<WolfJet, B2> jets_2_; + mutable std::array<WolfJet, B3> jets_3_; + mutable std::array<WolfJet, B4> jets_4_; + mutable std::array<WolfJet, B5> jets_5_; + mutable std::array<WolfJet, B6> jets_6_; + mutable std::array<WolfJet, B7> jets_7_; + mutable std::array<WolfJet, B8> jets_8_; + mutable std::array<WolfJet, B9> jets_9_; + + public: + + FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, + const FrameBasePtr& _frame_other_ptr, + const CaptureBasePtr& _capture_other_ptr, + const FeatureBasePtr& _feature_other_ptr, + const LandmarkBasePtr& _landmark_other_ptr, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status, + StateBlockPtr _state0Ptr, + StateBlockPtr _state1Ptr, + StateBlockPtr _state2Ptr, + StateBlockPtr _state3Ptr, + StateBlockPtr _state4Ptr, + StateBlockPtr _state5Ptr, + StateBlockPtr _state6Ptr, + StateBlockPtr _state7Ptr, + StateBlockPtr _state8Ptr, + StateBlockPtr _state9Ptr) : + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr}) + { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + assert(_state2Ptr != nullptr && "nullptr state block"); + assert(_state3Ptr != nullptr && "nullptr state block"); + assert(_state4Ptr != nullptr && "nullptr state block"); + assert(_state5Ptr != nullptr && "nullptr state block"); + assert(_state6Ptr != nullptr && "nullptr state block"); + assert(_state7Ptr != nullptr && "nullptr state block"); + assert(_state8Ptr != nullptr && "nullptr state block"); + assert(_state9Ptr != nullptr && "nullptr state block"); + + // initialize jets + unsigned int last_jet_idx = 0; + for (unsigned int i = 0; i < B0; i++) + jets_0_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B1; i++) + jets_1_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B2; i++) + jets_2_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B3; i++) + jets_3_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B4; i++) + jets_4_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B5; i++) + jets_5_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B6; i++) + jets_6_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B7; i++) + jets_7_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B8; i++) + jets_8_[i] = WolfJet(0, last_jet_idx++); + for (unsigned int i = 0; i < B9; i++) + jets_9_[i] = WolfJet(0, last_jet_idx++); + state_ptrs_.resize(n_blocks); + } + + virtual ~FactorAutodiff() + { + } + + virtual JacobianMethod getJacobianMethod() const + { + return JAC_AUTO; + } + + virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const + { + // only residuals + if (jacobians == nullptr) + { + (*static_cast<FacT const*>(this))(parameters[0], + parameters[1], + parameters[2], + parameters[3], + parameters[4], + parameters[5], + parameters[6], + parameters[7], + parameters[8], + parameters[9], + residuals); + } + // also compute jacobians + else + { + // update jets real part + std::vector<double const*> param_vec; + param_vec.assign(parameters,parameters+n_blocks); + updateJetsRealPart(param_vec); + + // call functor + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + jets_7_.data(), + jets_8_.data(), + jets_9_.data(), + residuals_jets_.data()); + + // fill the residual array + for (unsigned int i = 0; i < RES; i++) + residuals[i] = residuals_jets_[i].a; + + // fill the jacobian matrices + for (unsigned int i = 0; i<n_blocks; i++) + if (jacobians[i] != nullptr) + for (unsigned int row = 0; row < RES; row++) + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + jacobians[i] + row * state_block_sizes_.at(i)); + } + return true; + } + + void updateJetsRealPart(const std::vector<double const*>& parameters) const + { + // update jets real part + for (unsigned int i = 0; i < B0; i++) + jets_0_[i].a = parameters[0][i]; + for (unsigned int i = 0; i < B1; i++) + jets_1_[i].a = parameters[1][i]; + for (unsigned int i = 0; i < B2; i++) + jets_2_[i].a = parameters[2][i]; + for (unsigned int i = 0; i < B3; i++) + jets_3_[i].a = parameters[3][i]; + for (unsigned int i = 0; i < B4; i++) + jets_4_[i].a = parameters[4][i]; + for (unsigned int i = 0; i < B5; i++) + jets_5_[i].a = parameters[5][i]; + for (unsigned int i = 0; i < B6; i++) + jets_6_[i].a = parameters[6][i]; + for (unsigned int i = 0; i < B7; i++) + jets_7_[i].a = parameters[7][i]; + for (unsigned int i = 0; i < B8; i++) + jets_8_[i].a = parameters[8][i]; + for (unsigned int i = 0; i < B9; i++) + jets_9_[i].a = parameters[9][i]; + } + + virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const + { + assert(residual_.size() == RES); + jacobians_.clear(); + + assert(_states_ptr.size() == n_blocks); + + // update jets real part + updateJetsRealPart(_states_ptr); + + // call functor + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + jets_7_.data(), + jets_8_.data(), + jets_9_.data(), + residuals_jets_.data()); + + // fill the residual vector + for (unsigned int i = 0; i < RES; i++) + residual_(i) = residuals_jets_[i].a; + + // fill the jacobian matrices + for (unsigned int i = 0; i<n_blocks; i++) + { + // Create a row major Jacobian + Eigen::MatrixRowXd Ji(Eigen::MatrixRowXd::Zero(RES, state_block_sizes_[i])); + // Fill Jacobian rows from jets + if (!state_ptrs_[i]->isFixed()) + for (unsigned int row = 0; row < RES; row++) + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + Ji.data() + row * state_block_sizes_.at(i)); + // add to the Jacobians vector + jacobians_.push_back(Ji); + } + + // print jacobian matrices +// for (unsigned int i = 0; i < n_blocks; i++) +// std::cout << jacobians_[i] << std::endl << std::endl; + } + + virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const + { + return state_ptrs_; + } + + virtual std::vector<unsigned int> getStateSizes() const + { + return state_block_sizes_; + } + + virtual unsigned int getSize() const + { + return RES; + } +}; + ////////////////// SPECIALIZATION 9 BLOCKS //////////////////////////////////////////////////////////////////////// template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8> -class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase +class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0,0,0> : public FactorBase { public: @@ -317,6 +852,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase static const unsigned int block7Size = B7; static const unsigned int block8Size = B8; static const unsigned int block9Size = 0; + static const unsigned int block10Size = 0; + static const unsigned int block11Size = 0; static const unsigned int n_blocks = 9; static const std::vector<unsigned int> state_block_sizes_; @@ -329,21 +866,21 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase std::vector<StateBlockPtr> state_ptrs_; static const std::vector<unsigned int> jacobian_locations_; - std::array<WolfJet, RES>* residuals_jets_; - - std::array<WolfJet, B0>* jets_0_; - std::array<WolfJet, B1>* jets_1_; - std::array<WolfJet, B2>* jets_2_; - std::array<WolfJet, B3>* jets_3_; - std::array<WolfJet, B4>* jets_4_; - std::array<WolfJet, B5>* jets_5_; - std::array<WolfJet, B6>* jets_6_; - std::array<WolfJet, B7>* jets_7_; - std::array<WolfJet, B8>* jets_8_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; + mutable std::array<WolfJet, B2> jets_2_; + mutable std::array<WolfJet, B3> jets_3_; + mutable std::array<WolfJet, B4> jets_4_; + mutable std::array<WolfJet, B5> jets_5_; + mutable std::array<WolfJet, B6> jets_6_; + mutable std::array<WolfJet, B7> jets_7_; + mutable std::array<WolfJet, B8> jets_8_; public: FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -360,54 +897,45 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase StateBlockPtr _state6Ptr, StateBlockPtr _state7Ptr, StateBlockPtr _state8Ptr) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), - state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr}), - residuals_jets_(new std::array<WolfJet, RES>), - jets_0_(new std::array<WolfJet, B0>), - jets_1_(new std::array<WolfJet, B1>), - jets_2_(new std::array<WolfJet, B2>), - jets_3_(new std::array<WolfJet, B3>), - jets_4_(new std::array<WolfJet, B4>), - jets_5_(new std::array<WolfJet, B5>), - jets_6_(new std::array<WolfJet, B6>), - jets_7_(new std::array<WolfJet, B7>), - jets_8_(new std::array<WolfJet, B8>) - { + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr}) + { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + assert(_state2Ptr != nullptr && "nullptr state block"); + assert(_state3Ptr != nullptr && "nullptr state block"); + assert(_state4Ptr != nullptr && "nullptr state block"); + assert(_state5Ptr != nullptr && "nullptr state block"); + assert(_state6Ptr != nullptr && "nullptr state block"); + assert(_state7Ptr != nullptr && "nullptr state block"); + assert(_state8Ptr != nullptr && "nullptr state block"); + // initialize jets unsigned int last_jet_idx = 0; for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i] = WolfJet(0, last_jet_idx++); + jets_0_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i] = WolfJet(0, last_jet_idx++); + jets_1_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i] = WolfJet(0, last_jet_idx++); + jets_2_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i] = WolfJet(0, last_jet_idx++); + jets_3_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i] = WolfJet(0, last_jet_idx++); + jets_4_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B5; i++) - (*jets_5_)[i] = WolfJet(0, last_jet_idx++); + jets_5_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B6; i++) - (*jets_6_)[i] = WolfJet(0, last_jet_idx++); + jets_6_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B7; i++) - (*jets_7_)[i] = WolfJet(0, last_jet_idx++); + jets_7_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B8; i++) - (*jets_8_)[i] = WolfJet(0, last_jet_idx++); + jets_8_[i] = WolfJet(0, last_jet_idx++); state_ptrs_.resize(n_blocks); } virtual ~FactorAutodiff() { - delete jets_0_; - delete jets_1_; - delete jets_2_; - delete jets_3_; - delete jets_4_; - delete jets_5_; - delete jets_6_; - delete jets_7_; - delete jets_8_; - delete residuals_jets_; } virtual JacobianMethod getJacobianMethod() const @@ -440,27 +968,27 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase updateJetsRealPart(param_vec); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - jets_5_->data(), - jets_6_->data(), - jets_7_->data(), - jets_8_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + jets_7_.data(), + jets_8_.data(), + residuals_jets_.data()); // fill the residual array for (unsigned int i = 0; i < RES; i++) - residuals[i] = (*residuals_jets_)[i].a; + residuals[i] = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) if (jacobians[i] != nullptr) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), jacobians[i] + row * state_block_sizes_.at(i)); } return true; @@ -470,23 +998,23 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase { // update jets real part for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i].a = parameters[0][i]; + jets_0_[i].a = parameters[0][i]; for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i].a = parameters[1][i]; + jets_1_[i].a = parameters[1][i]; for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i].a = parameters[2][i]; + jets_2_[i].a = parameters[2][i]; for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i].a = parameters[3][i]; + jets_3_[i].a = parameters[3][i]; for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i].a = parameters[4][i]; + jets_4_[i].a = parameters[4][i]; for (unsigned int i = 0; i < B5; i++) - (*jets_5_)[i].a = parameters[5][i]; + jets_5_[i].a = parameters[5][i]; for (unsigned int i = 0; i < B6; i++) - (*jets_6_)[i].a = parameters[6][i]; + jets_6_[i].a = parameters[6][i]; for (unsigned int i = 0; i < B7; i++) - (*jets_7_)[i].a = parameters[7][i]; + jets_7_[i].a = parameters[7][i]; for (unsigned int i = 0; i < B8; i++) - (*jets_8_)[i].a = parameters[8][i]; + jets_8_[i].a = parameters[8][i]; } virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const @@ -500,20 +1028,20 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase updateJetsRealPart(_states_ptr); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - jets_5_->data(), - jets_6_->data(), - jets_7_->data(), - jets_8_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + jets_7_.data(), + jets_8_.data(), + residuals_jets_.data()); // fill the residual vector for (unsigned int i = 0; i < RES; i++) - residual_(i) = (*residuals_jets_)[i].a; + residual_(i) = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) @@ -523,8 +1051,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase // Fill Jacobian rows from jets if (!state_ptrs_[i]->isFixed()) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), Ji.data() + row * state_block_sizes_.at(i)); // add to the Jacobians vector jacobians_.push_back(Ji); @@ -554,7 +1082,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase ////////////////// SPECIALIZATION 8 BLOCKS //////////////////////////////////////////////////////////////////////// template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7> -class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase +class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0,0,0> : public FactorBase { public: @@ -569,6 +1097,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase static const unsigned int block7Size = B7; static const unsigned int block8Size = 0; static const unsigned int block9Size = 0; + static const unsigned int block10Size = 0; + static const unsigned int block11Size = 0; static const unsigned int n_blocks = 8; static const std::vector<unsigned int> state_block_sizes_; @@ -581,20 +1111,20 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase std::vector<StateBlockPtr> state_ptrs_; static const std::vector<unsigned int> jacobian_locations_; - std::array<WolfJet, RES>* residuals_jets_; - - std::array<WolfJet, B0>* jets_0_; - std::array<WolfJet, B1>* jets_1_; - std::array<WolfJet, B2>* jets_2_; - std::array<WolfJet, B3>* jets_3_; - std::array<WolfJet, B4>* jets_4_; - std::array<WolfJet, B5>* jets_5_; - std::array<WolfJet, B6>* jets_6_; - std::array<WolfJet, B7>* jets_7_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; + mutable std::array<WolfJet, B2> jets_2_; + mutable std::array<WolfJet, B3> jets_3_; + mutable std::array<WolfJet, B4> jets_4_; + mutable std::array<WolfJet, B5> jets_5_; + mutable std::array<WolfJet, B6> jets_6_; + mutable std::array<WolfJet, B7> jets_7_; public: FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -610,50 +1140,42 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase StateBlockPtr _state5Ptr, StateBlockPtr _state6Ptr, StateBlockPtr _state7Ptr) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), - state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr}), - residuals_jets_(new std::array<WolfJet, RES>), - jets_0_(new std::array<WolfJet, B0>), - jets_1_(new std::array<WolfJet, B1>), - jets_2_(new std::array<WolfJet, B2>), - jets_3_(new std::array<WolfJet, B3>), - jets_4_(new std::array<WolfJet, B4>), - jets_5_(new std::array<WolfJet, B5>), - jets_6_(new std::array<WolfJet, B6>), - jets_7_(new std::array<WolfJet, B7>) - { + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr}) + { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + assert(_state2Ptr != nullptr && "nullptr state block"); + assert(_state3Ptr != nullptr && "nullptr state block"); + assert(_state4Ptr != nullptr && "nullptr state block"); + assert(_state5Ptr != nullptr && "nullptr state block"); + assert(_state6Ptr != nullptr && "nullptr state block"); + assert(_state7Ptr != nullptr && "nullptr state block"); + // initialize jets unsigned int last_jet_idx = 0; for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i] = WolfJet(0, last_jet_idx++); + jets_0_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i] = WolfJet(0, last_jet_idx++); + jets_1_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i] = WolfJet(0, last_jet_idx++); + jets_2_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i] = WolfJet(0, last_jet_idx++); + jets_3_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i] = WolfJet(0, last_jet_idx++); + jets_4_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B5; i++) - (*jets_5_)[i] = WolfJet(0, last_jet_idx++); + jets_5_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B6; i++) - (*jets_6_)[i] = WolfJet(0, last_jet_idx++); + jets_6_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B7; i++) - (*jets_7_)[i] = WolfJet(0, last_jet_idx++); + jets_7_[i] = WolfJet(0, last_jet_idx++); state_ptrs_.resize(n_blocks); } virtual ~FactorAutodiff() { - delete jets_0_; - delete jets_1_; - delete jets_2_; - delete jets_3_; - delete jets_4_; - delete jets_5_; - delete jets_6_; - delete jets_7_; - delete residuals_jets_; } virtual JacobianMethod getJacobianMethod() const @@ -685,26 +1207,26 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase updateJetsRealPart(param_vec); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - jets_5_->data(), - jets_6_->data(), - jets_7_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + jets_7_.data(), + residuals_jets_.data()); // fill the residual array for (unsigned int i = 0; i < RES; i++) - residuals[i] = (*residuals_jets_)[i].a; + residuals[i] = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) if (jacobians[i] != nullptr) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), jacobians[i] + row * state_block_sizes_.at(i)); } return true; @@ -714,21 +1236,21 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase { // update jets real part for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i].a = parameters[0][i]; + jets_0_[i].a = parameters[0][i]; for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i].a = parameters[1][i]; + jets_1_[i].a = parameters[1][i]; for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i].a = parameters[2][i]; + jets_2_[i].a = parameters[2][i]; for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i].a = parameters[3][i]; + jets_3_[i].a = parameters[3][i]; for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i].a = parameters[4][i]; + jets_4_[i].a = parameters[4][i]; for (unsigned int i = 0; i < B5; i++) - (*jets_5_)[i].a = parameters[5][i]; + jets_5_[i].a = parameters[5][i]; for (unsigned int i = 0; i < B6; i++) - (*jets_6_)[i].a = parameters[6][i]; + jets_6_[i].a = parameters[6][i]; for (unsigned int i = 0; i < B7; i++) - (*jets_7_)[i].a = parameters[7][i]; + jets_7_[i].a = parameters[7][i]; } virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const @@ -742,19 +1264,19 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase updateJetsRealPart(_states_ptr); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - jets_5_->data(), - jets_6_->data(), - jets_7_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + jets_7_.data(), + residuals_jets_.data()); // fill the residual vector for (unsigned int i = 0; i < RES; i++) - residual_(i) = (*residuals_jets_)[i].a; + residual_(i) = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) @@ -764,8 +1286,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase // Fill Jacobian rows from jets if (!state_ptrs_[i]->isFixed()) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), Ji.data() + row * state_block_sizes_.at(i)); // add to the Jacobians vector jacobians_.push_back(Ji); @@ -795,7 +1317,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase ////////////////// SPECIALIZATION 7 BLOCKS //////////////////////////////////////////////////////////////////////// template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6> -class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase +class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0,0,0> : public FactorBase { public: @@ -810,6 +1332,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase static const unsigned int block7Size = 0; static const unsigned int block8Size = 0; static const unsigned int block9Size = 0; + static const unsigned int block10Size = 0; + static const unsigned int block11Size = 0; static const unsigned int n_blocks = 7; static const std::vector<unsigned int> state_block_sizes_; @@ -822,19 +1346,19 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase std::vector<StateBlockPtr> state_ptrs_; static const std::vector<unsigned int> jacobian_locations_; - std::array<WolfJet, RES>* residuals_jets_; - - std::array<WolfJet, B0>* jets_0_; - std::array<WolfJet, B1>* jets_1_; - std::array<WolfJet, B2>* jets_2_; - std::array<WolfJet, B3>* jets_3_; - std::array<WolfJet, B4>* jets_4_; - std::array<WolfJet, B5>* jets_5_; - std::array<WolfJet, B6>* jets_6_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; + mutable std::array<WolfJet, B2> jets_2_; + mutable std::array<WolfJet, B3> jets_3_; + mutable std::array<WolfJet, B4> jets_4_; + mutable std::array<WolfJet, B5> jets_5_; + mutable std::array<WolfJet, B6> jets_6_; public: FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -849,46 +1373,39 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase StateBlockPtr _state4Ptr, StateBlockPtr _state5Ptr, StateBlockPtr _state6Ptr) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), - state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr}), - residuals_jets_(new std::array<WolfJet, RES>), - jets_0_(new std::array<WolfJet, B0>), - jets_1_(new std::array<WolfJet, B1>), - jets_2_(new std::array<WolfJet, B2>), - jets_3_(new std::array<WolfJet, B3>), - jets_4_(new std::array<WolfJet, B4>), - jets_5_(new std::array<WolfJet, B5>), - jets_6_(new std::array<WolfJet, B6>) - { + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr}) + { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + assert(_state2Ptr != nullptr && "nullptr state block"); + assert(_state3Ptr != nullptr && "nullptr state block"); + assert(_state4Ptr != nullptr && "nullptr state block"); + assert(_state5Ptr != nullptr && "nullptr state block"); + assert(_state6Ptr != nullptr && "nullptr state block"); + // initialize jets unsigned int last_jet_idx = 0; for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i] = WolfJet(0, last_jet_idx++); + jets_0_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i] = WolfJet(0, last_jet_idx++); + jets_1_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i] = WolfJet(0, last_jet_idx++); + jets_2_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i] = WolfJet(0, last_jet_idx++); + jets_3_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i] = WolfJet(0, last_jet_idx++); + jets_4_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B5; i++) - (*jets_5_)[i] = WolfJet(0, last_jet_idx++); + jets_5_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B6; i++) - (*jets_6_)[i] = WolfJet(0, last_jet_idx++); + jets_6_[i] = WolfJet(0, last_jet_idx++); state_ptrs_.resize(n_blocks); } virtual ~FactorAutodiff() { - delete jets_0_; - delete jets_1_; - delete jets_2_; - delete jets_3_; - delete jets_4_; - delete jets_5_; - delete jets_6_; - delete residuals_jets_; } virtual JacobianMethod getJacobianMethod() const @@ -919,25 +1436,25 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase updateJetsRealPart(param_vec); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - jets_5_->data(), - jets_6_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + residuals_jets_.data()); // fill the residual array for (unsigned int i = 0; i < RES; i++) - residuals[i] = (*residuals_jets_)[i].a; + residuals[i] = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) if (jacobians[i] != nullptr) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), jacobians[i] + row * state_block_sizes_.at(i)); } return true; @@ -947,19 +1464,19 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase { // update jets real part for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i].a = parameters[0][i]; + jets_0_[i].a = parameters[0][i]; for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i].a = parameters[1][i]; + jets_1_[i].a = parameters[1][i]; for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i].a = parameters[2][i]; + jets_2_[i].a = parameters[2][i]; for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i].a = parameters[3][i]; + jets_3_[i].a = parameters[3][i]; for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i].a = parameters[4][i]; + jets_4_[i].a = parameters[4][i]; for (unsigned int i = 0; i < B5; i++) - (*jets_5_)[i].a = parameters[5][i]; + jets_5_[i].a = parameters[5][i]; for (unsigned int i = 0; i < B6; i++) - (*jets_6_)[i].a = parameters[6][i]; + jets_6_[i].a = parameters[6][i]; } virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const @@ -973,18 +1490,18 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase updateJetsRealPart(_states_ptr); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - jets_5_->data(), - jets_6_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + jets_6_.data(), + residuals_jets_.data()); // fill the residual vector for (unsigned int i = 0; i < RES; i++) - residual_(i) = (*residuals_jets_)[i].a; + residual_(i) = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) @@ -994,8 +1511,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase // Fill Jacobian rows from jets if (!state_ptrs_[i]->isFixed()) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), Ji.data() + row * state_block_sizes_.at(i)); // add to the Jacobians vector jacobians_.push_back(Ji); @@ -1025,7 +1542,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase ////////////////// SPECIALIZATION 6 BLOCKS //////////////////////////////////////////////////////////////////////// template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5> -class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase +class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0,0,0> : public FactorBase { public: @@ -1040,6 +1557,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase static const unsigned int block7Size = 0; static const unsigned int block8Size = 0; static const unsigned int block9Size = 0; + static const unsigned int block10Size = 0; + static const unsigned int block11Size = 0; static const unsigned int n_blocks = 6; static const std::vector<unsigned int> state_block_sizes_; @@ -1052,18 +1571,18 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase std::vector<StateBlockPtr> state_ptrs_; static const std::vector<unsigned int> jacobian_locations_; - std::array<WolfJet, RES>* residuals_jets_; - - std::array<WolfJet, B0>* jets_0_; - std::array<WolfJet, B1>* jets_1_; - std::array<WolfJet, B2>* jets_2_; - std::array<WolfJet, B3>* jets_3_; - std::array<WolfJet, B4>* jets_4_; - std::array<WolfJet, B5>* jets_5_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; + mutable std::array<WolfJet, B2> jets_2_; + mutable std::array<WolfJet, B3> jets_3_; + mutable std::array<WolfJet, B4> jets_4_; + mutable std::array<WolfJet, B5> jets_5_; public: FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -1077,42 +1596,36 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase StateBlockPtr _state3Ptr, StateBlockPtr _state4Ptr, StateBlockPtr _state5Ptr) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), - state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr}), - residuals_jets_(new std::array<WolfJet, RES>), - jets_0_(new std::array<WolfJet, B0>), - jets_1_(new std::array<WolfJet, B1>), - jets_2_(new std::array<WolfJet, B2>), - jets_3_(new std::array<WolfJet, B3>), - jets_4_(new std::array<WolfJet, B4>), - jets_5_(new std::array<WolfJet, B5>) + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr}) { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + assert(_state2Ptr != nullptr && "nullptr state block"); + assert(_state3Ptr != nullptr && "nullptr state block"); + assert(_state4Ptr != nullptr && "nullptr state block"); + assert(_state5Ptr != nullptr && "nullptr state block"); + // initialize jets unsigned int last_jet_idx = 0; for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i] = WolfJet(0, last_jet_idx++); + jets_0_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i] = WolfJet(0, last_jet_idx++); + jets_1_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i] = WolfJet(0, last_jet_idx++); + jets_2_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i] = WolfJet(0, last_jet_idx++); + jets_3_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i] = WolfJet(0, last_jet_idx++); + jets_4_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B5; i++) - (*jets_5_)[i] = WolfJet(0, last_jet_idx++); + jets_5_[i] = WolfJet(0, last_jet_idx++); state_ptrs_.resize(n_blocks); } virtual ~FactorAutodiff() { - delete jets_0_; - delete jets_1_; - delete jets_2_; - delete jets_3_; - delete jets_4_; - delete jets_5_; - delete residuals_jets_; } virtual JacobianMethod getJacobianMethod() const @@ -1142,24 +1655,24 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase updateJetsRealPart(param_vec); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - jets_5_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + residuals_jets_.data()); // fill the residual array for (unsigned int i = 0; i < RES; i++) - residuals[i] = (*residuals_jets_)[i].a; + residuals[i] = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) if (jacobians[i] != nullptr) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), jacobians[i] + row * state_block_sizes_.at(i)); } return true; @@ -1169,17 +1682,17 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase { // update jets real part for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i].a = parameters[0][i]; + jets_0_[i].a = parameters[0][i]; for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i].a = parameters[1][i]; + jets_1_[i].a = parameters[1][i]; for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i].a = parameters[2][i]; + jets_2_[i].a = parameters[2][i]; for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i].a = parameters[3][i]; + jets_3_[i].a = parameters[3][i]; for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i].a = parameters[4][i]; + jets_4_[i].a = parameters[4][i]; for (unsigned int i = 0; i < B5; i++) - (*jets_5_)[i].a = parameters[5][i]; + jets_5_[i].a = parameters[5][i]; } virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const @@ -1193,17 +1706,17 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase updateJetsRealPart(_states_ptr); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - jets_5_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + jets_5_.data(), + residuals_jets_.data()); // fill the residual vector for (unsigned int i = 0; i < RES; i++) - residual_(i) = (*residuals_jets_)[i].a; + residual_(i) = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) @@ -1213,8 +1726,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase // Fill Jacobian rows from jets if (!state_ptrs_[i]->isFixed()) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), Ji.data() + row * state_block_sizes_.at(i)); // add to the Jacobians vector jacobians_.push_back(Ji); @@ -1240,7 +1753,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase ////////////////// SPECIALIZATION 5 BLOCKS //////////////////////////////////////////////////////////////////////// template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4> -class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase +class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0,0,0> : public FactorBase { public: @@ -1255,6 +1768,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase static const unsigned int block7Size = 0; static const unsigned int block8Size = 0; static const unsigned int block9Size = 0; + static const unsigned int block10Size = 0; + static const unsigned int block11Size = 0; static const unsigned int n_blocks = 5; static const std::vector<unsigned int> state_block_sizes_; @@ -1266,17 +1781,17 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase std::vector<StateBlockPtr> state_ptrs_; static const std::vector<unsigned int> jacobian_locations_; - std::array<WolfJet, RES>* residuals_jets_; - - std::array<WolfJet, B0>* jets_0_; - std::array<WolfJet, B1>* jets_1_; - std::array<WolfJet, B2>* jets_2_; - std::array<WolfJet, B3>* jets_3_; - std::array<WolfJet, B4>* jets_4_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; + mutable std::array<WolfJet, B2> jets_2_; + mutable std::array<WolfJet, B3> jets_3_; + mutable std::array<WolfJet, B4> jets_4_; public: FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -1289,38 +1804,33 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase StateBlockPtr _state2Ptr, StateBlockPtr _state3Ptr, StateBlockPtr _state4Ptr) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), - state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr}), - residuals_jets_(new std::array<WolfJet, RES>), - jets_0_(new std::array<WolfJet, B0>), - jets_1_(new std::array<WolfJet, B1>), - jets_2_(new std::array<WolfJet, B2>), - jets_3_(new std::array<WolfJet, B3>), - jets_4_(new std::array<WolfJet, B4>) + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr}) { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + assert(_state2Ptr != nullptr && "nullptr state block"); + assert(_state3Ptr != nullptr && "nullptr state block"); + assert(_state4Ptr != nullptr && "nullptr state block"); + // initialize jets unsigned int last_jet_idx = 0; for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i] = WolfJet(0, last_jet_idx++); + jets_0_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i] = WolfJet(0, last_jet_idx++); + jets_1_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i] = WolfJet(0, last_jet_idx++); + jets_2_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i] = WolfJet(0, last_jet_idx++); + jets_3_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i] = WolfJet(0, last_jet_idx++); + jets_4_[i] = WolfJet(0, last_jet_idx++); state_ptrs_.resize(n_blocks); } virtual ~FactorAutodiff() { - delete jets_0_; - delete jets_1_; - delete jets_2_; - delete jets_3_; - delete jets_4_; - delete residuals_jets_; } virtual JacobianMethod getJacobianMethod() const @@ -1349,23 +1859,23 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase updateJetsRealPart(param_vec); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + residuals_jets_.data()); // fill the residual array for (unsigned int i = 0; i < RES; i++) - residuals[i] = (*residuals_jets_)[i].a; + residuals[i] = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) if (jacobians[i] != nullptr) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), jacobians[i] + row * state_block_sizes_.at(i)); } return true; @@ -1375,15 +1885,15 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase { // update jets real part for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i].a = parameters[0][i]; + jets_0_[i].a = parameters[0][i]; for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i].a = parameters[1][i]; + jets_1_[i].a = parameters[1][i]; for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i].a = parameters[2][i]; + jets_2_[i].a = parameters[2][i]; for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i].a = parameters[3][i]; + jets_3_[i].a = parameters[3][i]; for (unsigned int i = 0; i < B4; i++) - (*jets_4_)[i].a = parameters[4][i]; + jets_4_[i].a = parameters[4][i]; } virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const @@ -1397,16 +1907,16 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase updateJetsRealPart(_states_ptr); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - jets_4_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + jets_4_.data(), + residuals_jets_.data()); // fill the residual vector for (unsigned int i = 0; i < RES; i++) - residual_(i) = (*residuals_jets_)[i].a; + residual_(i) = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) @@ -1416,8 +1926,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase // Fill Jacobian rows from jets if (!state_ptrs_[i]->isFixed()) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), Ji.data() + row * state_block_sizes_.at(i)); // add to the Jacobians vector jacobians_.push_back(Ji); @@ -1443,7 +1953,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase ////////////////// SPECIALIZATION 4 BLOCKS //////////////////////////////////////////////////////////////////////// template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3> -class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase +class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0,0,0> : public FactorBase { public: @@ -1458,6 +1968,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase static const unsigned int block7Size = 0; static const unsigned int block8Size = 0; static const unsigned int block9Size = 0; + static const unsigned int block10Size = 0; + static const unsigned int block11Size = 0; static const unsigned int n_blocks = 4; static const std::vector<unsigned int> state_block_sizes_; @@ -1469,16 +1981,16 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase std::vector<StateBlockPtr> state_ptrs_; static const std::vector<unsigned int> jacobian_locations_; - std::array<WolfJet, RES>* residuals_jets_; - - std::array<WolfJet, B0>* jets_0_; - std::array<WolfJet, B1>* jets_1_; - std::array<WolfJet, B2>* jets_2_; - std::array<WolfJet, B3>* jets_3_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; + mutable std::array<WolfJet, B2> jets_2_; + mutable std::array<WolfJet, B3> jets_3_; public: FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -1490,34 +2002,30 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase StateBlockPtr _state1Ptr, StateBlockPtr _state2Ptr, StateBlockPtr _state3Ptr) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), - state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr}), - residuals_jets_(new std::array<WolfJet, RES>), - jets_0_(new std::array<WolfJet, B0>), - jets_1_(new std::array<WolfJet, B1>), - jets_2_(new std::array<WolfJet, B2>), - jets_3_(new std::array<WolfJet, B3>) + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr}) { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + assert(_state2Ptr != nullptr && "nullptr state block"); + assert(_state3Ptr != nullptr && "nullptr state block"); + // initialize jets unsigned int last_jet_idx = 0; for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i] = WolfJet(0, last_jet_idx++); + jets_0_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i] = WolfJet(0, last_jet_idx++); + jets_1_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i] = WolfJet(0, last_jet_idx++); + jets_2_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i] = WolfJet(0, last_jet_idx++); + jets_3_[i] = WolfJet(0, last_jet_idx++); state_ptrs_.resize(n_blocks); } virtual ~FactorAutodiff() { - delete jets_0_; - delete jets_1_; - delete jets_2_; - delete jets_3_; - delete residuals_jets_; } virtual JacobianMethod getJacobianMethod() const @@ -1545,22 +2053,22 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase updateJetsRealPart(param_vec); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + residuals_jets_.data()); // fill the residual array for (unsigned int i = 0; i < RES; i++) - residuals[i] = (*residuals_jets_)[i].a; + residuals[i] = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) if (jacobians[i] != nullptr) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), jacobians[i] + row * state_block_sizes_.at(i)); } return true; @@ -1570,13 +2078,13 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase { // update jets real part for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i].a = parameters[0][i]; + jets_0_[i].a = parameters[0][i]; for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i].a = parameters[1][i]; + jets_1_[i].a = parameters[1][i]; for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i].a = parameters[2][i]; + jets_2_[i].a = parameters[2][i]; for (unsigned int i = 0; i < B3; i++) - (*jets_3_)[i].a = parameters[3][i]; + jets_3_[i].a = parameters[3][i]; } virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const @@ -1590,15 +2098,15 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase updateJetsRealPart(_states_ptr); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - jets_3_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + jets_3_.data(), + residuals_jets_.data()); // fill the residual vector for (unsigned int i = 0; i < RES; i++) - residual_(i) = (*residuals_jets_)[i].a; + residual_(i) = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) @@ -1608,8 +2116,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase // Fill Jacobian rows from jets if (!state_ptrs_[i]->isFixed()) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), Ji.data() + row * state_block_sizes_.at(i)); // add to the Jacobians vector jacobians_.push_back(Ji); @@ -1639,7 +2147,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase ////////////////// SPECIALIZATION 3 BLOCKS //////////////////////////////////////////////////////////////////////// template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2> -class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase +class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0,0,0> : public FactorBase { public: @@ -1654,6 +2162,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase static const unsigned int block7Size = 0; static const unsigned int block8Size = 0; static const unsigned int block9Size = 0; + static const unsigned int block10Size = 0; + static const unsigned int block11Size = 0; static const unsigned int n_blocks = 3; static const std::vector<unsigned int> state_block_sizes_; @@ -1665,15 +2175,15 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase std::vector<StateBlockPtr> state_ptrs_; static const std::vector<unsigned int> jacobian_locations_; - std::array<WolfJet, RES>* residuals_jets_; - - std::array<WolfJet, B0>* jets_0_; - std::array<WolfJet, B1>* jets_1_; - std::array<WolfJet, B2>* jets_2_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; + mutable std::array<WolfJet, B2> jets_2_; public: FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -1684,30 +2194,27 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase StateBlockPtr _state0Ptr, StateBlockPtr _state1Ptr, StateBlockPtr _state2Ptr) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), - state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr}), - residuals_jets_(new std::array<WolfJet, RES>), - jets_0_(new std::array<WolfJet, B0>), - jets_1_(new std::array<WolfJet, B1>), - jets_2_(new std::array<WolfJet, B2>) + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr}) { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + assert(_state2Ptr != nullptr && "nullptr state block"); + // initialize jets unsigned int last_jet_idx = 0; for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i] = WolfJet(0, last_jet_idx++); + jets_0_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i] = WolfJet(0, last_jet_idx++); + jets_1_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i] = WolfJet(0, last_jet_idx++); + jets_2_[i] = WolfJet(0, last_jet_idx++); state_ptrs_.resize(n_blocks); } virtual ~FactorAutodiff() { - delete jets_0_; - delete jets_1_; - delete jets_2_; - delete residuals_jets_; } virtual JacobianMethod getJacobianMethod() const @@ -1734,21 +2241,21 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase updateJetsRealPart(param_vec); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + residuals_jets_.data()); // fill the residual array for (unsigned int i = 0; i < RES; i++) - residuals[i] = (*residuals_jets_)[i].a; + residuals[i] = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) if (jacobians[i] != nullptr) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), jacobians[i] + row * state_block_sizes_.at(i)); } return true; @@ -1758,11 +2265,11 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase { // update jets real part for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i].a = parameters[0][i]; + jets_0_[i].a = parameters[0][i]; for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i].a = parameters[1][i]; + jets_1_[i].a = parameters[1][i]; for (unsigned int i = 0; i < B2; i++) - (*jets_2_)[i].a = parameters[2][i]; + jets_2_[i].a = parameters[2][i]; } virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const @@ -1776,14 +2283,14 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase updateJetsRealPart(_states_ptr); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - jets_2_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + jets_2_.data(), + residuals_jets_.data()); // fill the residual vector for (unsigned int i = 0; i < RES; i++) - residual_(i) = (*residuals_jets_)[i].a; + residual_(i) = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) @@ -1793,8 +2300,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase // Fill Jacobian rows from jets if (!state_ptrs_[i]->isFixed()) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), Ji.data() + row * state_block_sizes_.at(i)); // add to the Jacobians vector jacobians_.push_back(Ji); @@ -1824,7 +2331,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase ////////////////// SPECIALIZATION 2 BLOCKS //////////////////////////////////////////////////////////////////////// template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1> -class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase +class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0,0,0> : public FactorBase { public: @@ -1839,6 +2346,8 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase static const unsigned int block7Size = 0; static const unsigned int block8Size = 0; static const unsigned int block9Size = 0; + static const unsigned int block10Size = 0; + static const unsigned int block11Size = 0; static const unsigned int n_blocks = 2; static const std::vector<unsigned int> state_block_sizes_; @@ -1850,14 +2359,14 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase std::vector<StateBlockPtr> state_ptrs_; static const std::vector<unsigned int> jacobian_locations_; - std::array<WolfJet, RES>* residuals_jets_; - - std::array<WolfJet, B0>* jets_0_; - std::array<WolfJet, B1>* jets_1_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; + mutable std::array<WolfJet, B1> jets_1_; public: FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -1867,26 +2376,24 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase FactorStatus _status, StateBlockPtr _state0Ptr, StateBlockPtr _state1Ptr) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), - state_ptrs_({_state0Ptr,_state1Ptr}), - residuals_jets_(new std::array<WolfJet, RES>), - jets_0_(new std::array<WolfJet, B0>), - jets_1_(new std::array<WolfJet, B1>) + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr,_state1Ptr}) { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + assert(_state1Ptr != nullptr && "nullptr state block"); + // initialize jets unsigned int last_jet_idx = 0; for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i] = WolfJet(0, last_jet_idx++); + jets_0_[i] = WolfJet(0, last_jet_idx++); for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i] = WolfJet(0, last_jet_idx++); + jets_1_[i] = WolfJet(0, last_jet_idx++); state_ptrs_.resize(n_blocks); } virtual ~FactorAutodiff() { - delete jets_0_; - delete jets_1_; - delete residuals_jets_; } virtual JacobianMethod getJacobianMethod() const @@ -1912,20 +2419,20 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase updateJetsRealPart(param_vec); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + residuals_jets_.data()); // fill the residual array for (unsigned int i = 0; i < RES; i++) - residuals[i] = (*residuals_jets_)[i].a; + residuals[i] = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) if (jacobians[i] != nullptr) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), jacobians[i] + row * state_block_sizes_.at(i)); } return true; @@ -1935,9 +2442,9 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase { // update jets real part for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i].a = parameters[0][i]; + jets_0_[i].a = parameters[0][i]; for (unsigned int i = 0; i < B1; i++) - (*jets_1_)[i].a = parameters[1][i]; + jets_1_[i].a = parameters[1][i]; } virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const @@ -1951,13 +2458,13 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase updateJetsRealPart(_states_ptr); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - jets_1_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + jets_1_.data(), + residuals_jets_.data()); // fill the residual vector for (unsigned int i = 0; i < RES; i++) - residual_(i) = (*residuals_jets_)[i].a; + residual_(i) = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) @@ -1967,8 +2474,8 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase // Fill Jacobian rows from jets if (!state_ptrs_[i]->isFixed()) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), Ji.data() + row * state_block_sizes_.at(i)); // add to the Jacobians vector jacobians_.push_back(Ji); @@ -1998,7 +2505,7 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase ////////////////// SPECIALIZATION 1 BLOCK //////////////////////////////////////////////////////////////////////// template <class FacT,unsigned int RES,unsigned int B0> -class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase +class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0,0,0> : public FactorBase { public: @@ -2013,6 +2520,8 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase static const unsigned int block7Size = 0; static const unsigned int block8Size = 0; static const unsigned int block9Size = 0; + static const unsigned int block10Size = 0; + static const unsigned int block11Size = 0; static const unsigned int n_blocks = 1; static const std::vector<unsigned int> state_block_sizes_; @@ -2024,13 +2533,13 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase std::vector<StateBlockPtr> state_ptrs_; static const std::vector<unsigned int> jacobian_locations_; - std::array<WolfJet, RES>* residuals_jets_; - - std::array<WolfJet, B0>* jets_0_; + mutable std::array<WolfJet, RES> residuals_jets_; + mutable std::array<WolfJet, B0> jets_0_; public: FactorAutodiff(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -2039,22 +2548,21 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase bool _apply_loss_function, FactorStatus _status, StateBlockPtr _state0Ptr) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), - state_ptrs_({_state0Ptr}), - residuals_jets_(new std::array<WolfJet, RES>), - jets_0_(new std::array<WolfJet, B0>) + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + state_ptrs_({_state0Ptr}) { + // asserts for null states + assert(_state0Ptr != nullptr && "nullptr state block"); + // initialize jets unsigned int last_jet_idx = 0; for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i] = WolfJet(0, last_jet_idx++); + jets_0_[i] = WolfJet(0, last_jet_idx++); state_ptrs_.resize(n_blocks); } virtual ~FactorAutodiff() { - delete jets_0_; - delete residuals_jets_; } virtual JacobianMethod getJacobianMethod() const @@ -2079,19 +2587,19 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase updateJetsRealPart(param_vec); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + residuals_jets_.data()); // fill the residual array for (unsigned int i = 0; i < RES; i++) - residuals[i] = (*residuals_jets_)[i].a; + residuals[i] = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) if (jacobians[i] != nullptr) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), jacobians[i] + row * state_block_sizes_.at(i)); } return true; @@ -2101,7 +2609,7 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase { // update jets real part for (unsigned int i = 0; i < B0; i++) - (*jets_0_)[i].a = parameters[0][i]; + jets_0_[i].a = parameters[0][i]; } virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const @@ -2115,12 +2623,12 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase updateJetsRealPart(_states_ptr); // call functor - (*static_cast<FacT const*>(this))(jets_0_->data(), - residuals_jets_->data()); + (*static_cast<FacT const*>(this))(jets_0_.data(), + residuals_jets_.data()); // fill the residual vector for (unsigned int i = 0; i < RES; i++) - residual_(i) = (*residuals_jets_)[i].a; + residual_(i) = residuals_jets_[i].a; // fill the jacobian matrices for (unsigned int i = 0; i<n_blocks; i++) @@ -2130,8 +2638,8 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase // Fill Jacobian rows from jets if (!state_ptrs_[i]->isFixed()) for (unsigned int row = 0; row < RES; row++) - std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i), - (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), + std::copy(residuals_jets_[row].v.data() + jacobian_locations_.at(i), + residuals_jets_[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i), Ji.data() + row * state_block_sizes_.at(i)); // add to the Jacobians vector jacobians_.push_back(Ji); @@ -2162,113 +2670,146 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase // STATIC CONST VECTORS INITIALIZATION //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // state_block_sizes_ +// 12 BLOCKS +template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8,unsigned int B9,unsigned int B10,unsigned int B11> +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11}; +// 11 BLOCKS +template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8,unsigned int B9,unsigned int B10> +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10}; // 10 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8,unsigned int B9> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8,B9}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8,B9}; // 9 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8}; // 8 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7}; // 7 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6}; // 6 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5}; // 5 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4}; // 4 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3}; // 3 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2}; // 2 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1}; // 1 BLOCK template <class FacT,unsigned int RES,unsigned int B0> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0}; // jacobian_locations_ +// 12 BLOCKS +template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8,unsigned int B9,unsigned int B10,unsigned int B11> +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11>::jacobian_locations_ = {0, + B0, + B0+B1, + B0+B1+B2, + B0+B1+B2+B3, + B0+B1+B2+B3+B4, + B0+B1+B2+B3+B4+B5, + B0+B1+B2+B3+B4+B5+B6, + B0+B1+B2+B3+B4+B5+B6+B7, + B0+B1+B2+B3+B4+B5+B6+B7+B8, + B0+B1+B2+B3+B4+B5+B6+B7+B8+B9, + B0+B1+B2+B3+B4+B5+B6+B7+B8+B9+B10}; +// 10 BLOCKS +template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8,unsigned int B9,unsigned int B10> +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,0>::jacobian_locations_ = {0, + B0, + B0+B1, + B0+B1+B2, + B0+B1+B2+B3, + B0+B1+B2+B3+B4, + B0+B1+B2+B3+B4+B5, + B0+B1+B2+B3+B4+B5+B6, + B0+B1+B2+B3+B4+B5+B6+B7, + B0+B1+B2+B3+B4+B5+B6+B7+B8, + B0+B1+B2+B3+B4+B5+B6+B7+B8+B9}; // 10 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8,unsigned int B9> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9>::jacobian_locations_ = {0, - B0, - B0+B1, - B0+B1+B2, - B0+B1+B2+B3, - B0+B1+B2+B3+B4, - B0+B1+B2+B3+B4+B5, - B0+B1+B2+B3+B4+B5+B6, - B0+B1+B2+B3+B4+B5+B6+B7, - B0+B1+B2+B3+B4+B5+B6+B7+B8}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,0,0>::jacobian_locations_ = {0, + B0, + B0+B1, + B0+B1+B2, + B0+B1+B2+B3, + B0+B1+B2+B3+B4, + B0+B1+B2+B3+B4+B5, + B0+B1+B2+B3+B4+B5+B6, + B0+B1+B2+B3+B4+B5+B6+B7, + B0+B1+B2+B3+B4+B5+B6+B7+B8}; // 9 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0>::jacobian_locations_ = {0, - B0, - B0+B1, - B0+B1+B2, - B0+B1+B2+B3, - B0+B1+B2+B3+B4, - B0+B1+B2+B3+B4+B5, - B0+B1+B2+B3+B4+B5+B6, - B0+B1+B2+B3+B4+B5+B6+B7}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0,0,0>::jacobian_locations_ = {0, + B0, + B0+B1, + B0+B1+B2, + B0+B1+B2+B3, + B0+B1+B2+B3+B4, + B0+B1+B2+B3+B4+B5, + B0+B1+B2+B3+B4+B5+B6, + B0+B1+B2+B3+B4+B5+B6+B7}; // 8 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0>::jacobian_locations_ = {0, - B0, - B0+B1, - B0+B1+B2, - B0+B1+B2+B3, - B0+B1+B2+B3+B4, - B0+B1+B2+B3+B4+B5, - B0+B1+B2+B3+B4+B5+B6}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0,0,0>::jacobian_locations_ = {0, + B0, + B0+B1, + B0+B1+B2, + B0+B1+B2+B3, + B0+B1+B2+B3+B4, + B0+B1+B2+B3+B4+B5, + B0+B1+B2+B3+B4+B5+B6}; // 7 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0>::jacobian_locations_ = {0, - B0, - B0+B1, - B0+B1+B2, - B0+B1+B2+B3, - B0+B1+B2+B3+B4, - B0+B1+B2+B3+B4+B5}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0,0,0>::jacobian_locations_ = {0, + B0, + B0+B1, + B0+B1+B2, + B0+B1+B2+B3, + B0+B1+B2+B3+B4, + B0+B1+B2+B3+B4+B5}; // 6 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0>::jacobian_locations_ = {0, - B0, - B0+B1, - B0+B1+B2, - B0+B1+B2+B3, - B0+B1+B2+B3+B4}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0,0,0>::jacobian_locations_ = {0, + B0, + B0+B1, + B0+B1+B2, + B0+B1+B2+B3, + B0+B1+B2+B3+B4}; // 5 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0>::jacobian_locations_ = {0, - B0, - B0+B1, - B0+B1+B2, - B0+B1+B2+B3}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0,0,0>::jacobian_locations_ = {0, + B0, + B0+B1, + B0+B1+B2, + B0+B1+B2+B3}; // 4 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0>::jacobian_locations_ = {0, - B0, - B0+B1, - B0+B1+B2}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0, + B0, + B0+B1, + B0+B1+B2}; // 3 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0>::jacobian_locations_ = {0, - B0, - B0+B1}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0, + B0, + B0+B1}; // 2 BLOCKS template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0, - B0}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0, + B0}; // 1 BLOCK template <class FacT,unsigned int RES,unsigned int B0> -const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0}; +const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0}; } // namespace wolf diff --git a/include/core/factor/factor_autodiff_distance_3d.h b/include/core/factor/factor_autodiff_distance_3d.h index 8dc182d6f92ec60d7ba310ed1e7f94e27a9281fc..320f7ac270cdd151f078c520561e509f108296d8 100644 --- a/include/core/factor/factor_autodiff_distance_3d.h +++ b/include/core/factor/factor_autodiff_distance_3d.h @@ -23,8 +23,9 @@ class FactorAutodiffDistance3d : public FactorAutodiff<FactorAutodiffDistance3d, const ProcessorBasePtr& _processor_ptr, bool _apply_loss_function, FactorStatus _status) : - FactorAutodiff("DISTANCE 3d", - _frm_other, + FactorAutodiff("FactorAutodiffDistance3d", + _feat, + _frm_other, nullptr, nullptr, nullptr, diff --git a/include/core/factor/factor_base.h b/include/core/factor/factor_base.h index cd1439f96e437dc39dde137dd1014f37abee10db..acbe45ec5d827c247376a130d0f5de5591c1bed3 100644 --- a/include/core/factor/factor_base.h +++ b/include/core/factor/factor_base.h @@ -52,7 +52,9 @@ class FactorBase : public NodeBase, public std::enable_shared_from_this<FactorBa CaptureBaseWPtrList capture_other_list_; ///< CaptureBase pointer list FeatureBaseWPtrList feature_other_list_; ///< FeatureBase pointer list LandmarkBaseWPtrList landmark_other_list_; ///< LandmarkBase pointer list - ProcessorBaseWPtr processor_ptr_; ///< ProcessorBase pointer list + ProcessorBaseWPtr processor_ptr_; ///< Processor pointer + Eigen::VectorXd measurement_; ///< the measurement vector + Eigen::MatrixXd measurement_sqrt_information_upper_;///< the squared root information matrix ///< ProcessorBase pointer list virtual void setProblem(ProblemPtr) final; public: @@ -64,6 +66,7 @@ class FactorBase : public NodeBase, public std::enable_shared_from_this<FactorBa * that does not located in the same branch. **/ FactorBase(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -73,6 +76,7 @@ class FactorBase : public NodeBase, public std::enable_shared_from_this<FactorBa FactorStatus _status = FAC_ACTIVE); FactorBase(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtrList& _frame_other_list, const CaptureBasePtrList& _capture_other_list, const FeatureBasePtrList& _feature_other_list, @@ -124,15 +128,11 @@ class FactorBase : public NodeBase, public std::enable_shared_from_this<FactorBa **/ virtual std::vector<unsigned int> getStateSizes() const = 0; - /** \brief Returns a reference to the feature measurement + /** \brief Returns a reference to the measurement **/ virtual const Eigen::VectorXd& getMeasurement() const; - /** \brief Returns a reference to the feature measurement covariance - **/ - virtual const Eigen::MatrixXd& getMeasurementCovariance() const; - - /** \brief Returns a reference to the feature measurement square root information + /** \brief Returns a reference to the measurement square root information **/ virtual const Eigen::MatrixXd& getMeasurementSquareRootInformationUpper() const; @@ -206,6 +206,23 @@ class FactorBase : public NodeBase, public std::enable_shared_from_this<FactorBa template<typename classType, typename... T> static std::shared_ptr<classType> emplace(FeatureBasePtr _oth_ptr, T&&... all); + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const; + + void print(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream = std::cout, + std::string _tabs = "") const; + + virtual CheckLog localCheck(bool _verbose, FactorBasePtr _fac_ptr, std::ostream& _stream, std::string _tabs = "") const; + bool check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs = "") const; + private: void setFeature(const FeatureBasePtr _ft_ptr){feature_ptr_ = _ft_ptr;} @@ -237,7 +254,6 @@ std::shared_ptr<classType> FactorBase::emplace(FeatureBasePtr _ftr_ptr, T&&... a return ctr; } - inline unsigned int FactorBase::id() const { return factor_id_; @@ -290,7 +306,6 @@ inline LandmarkBasePtr FactorBase::getLandmarkOther() const return landmark_other_list_.front().lock(); } - inline ProcessorBasePtr FactorBase::getProcessor() const { return processor_ptr_.lock(); @@ -301,5 +316,15 @@ inline void FactorBase::setProcessor(const ProcessorBasePtr& _processor_ptr) processor_ptr_ = _processor_ptr; } +inline const Eigen::VectorXd& FactorBase::getMeasurement() const +{ + return measurement_; +} + +inline const Eigen::MatrixXd& FactorBase::getMeasurementSquareRootInformationUpper() const +{ + return measurement_sqrt_information_upper_; +} + } // namespace wolf #endif diff --git a/include/core/factor/factor_block_absolute.h b/include/core/factor/factor_block_absolute.h index 0743548b7b4aad0517ecdd2590955c4cdf7c023c..143308af2988a74d754f865c305e1ba089f4f778 100644 --- a/include/core/factor/factor_block_absolute.h +++ b/include/core/factor/factor_block_absolute.h @@ -31,17 +31,49 @@ class FactorBlockAbsolute : public FactorAnalytic /** \brief Constructor * * \param _sb_ptr the constrained state block - * \param _start_idx (default=0) the index of the first state element that is constrained - * \param _start_idx (default=-1) the size of the state segment that is constrained, -1 = all the * */ - FactorBlockAbsolute(StateBlockPtr _sb_ptr, - unsigned int _start_idx = 0, - int _size = -1, - ProcessorBasePtr _processor_ptr = nullptr, - bool _apply_loss_function = false, + FactorBlockAbsolute(FeatureBasePtr _feature_ptr, + StateBlockPtr _sb_ptr, + ProcessorBasePtr _processor_ptr, + bool _apply_loss_function, FactorStatus _status = FAC_ACTIVE) : FactorAnalytic("FactorBlockAbsolute", + _feature_ptr, + nullptr, + nullptr, + nullptr, + nullptr, + _processor_ptr, + _apply_loss_function, + _status, + _sb_ptr), + sb_size_(_sb_ptr->getSize()), + sb_constrained_start_(0), + sb_constrained_size_(sb_size_) + { + assert(sb_constrained_size_+sb_constrained_start_ <= sb_size_); + + // precompute Jacobian (Identity) + J_ = Eigen::MatrixXd::Identity(sb_constrained_size_, sb_size_); + } + + /** \brief Constructor for segment of state block + * + * \param _sb_ptr the constrained state block + * \param _start_idx the index of the first state element that is constrained + * \param _start_idx the size of the state segment that is constrained, -1 = all the + * + */ + FactorBlockAbsolute(FeatureBasePtr _feature_ptr, + StateBlockPtr _sb_ptr, + unsigned int _start_idx, + int _size, + ProcessorBasePtr _processor_ptr, + bool _apply_loss_function, + FactorStatus _status = FAC_ACTIVE) : + FactorAnalytic("FactorBlockAbsolute", + _feature_ptr, nullptr, nullptr, nullptr, diff --git a/include/core/factor/factor_block_difference.h b/include/core/factor/factor_block_difference.h index d3558ef21aa6e6577fc54d26015db3f9e3193312..ebaf8bc7be42c444f74588599e5b18d7135a5a88 100644 --- a/include/core/factor/factor_block_difference.h +++ b/include/core/factor/factor_block_difference.h @@ -36,21 +36,22 @@ class FactorBlockDifference : public FactorAnalytic * \param _sb_ptr the constrained state block * */ - FactorBlockDifference( - const StateBlockPtr& _sb1_ptr, - const StateBlockPtr& _sb2_ptr, - const FrameBasePtr& _frame_other = nullptr, - const CaptureBasePtr& _cap_other = nullptr, - const FeatureBasePtr& _feat_other = nullptr, - const LandmarkBasePtr& _lmk_other = nullptr, - unsigned int _start_idx1 = 0, - int _size1 = -1, - unsigned int _start_idx2 = 0, - int _size2 = -1, - ProcessorBasePtr _processor_ptr = nullptr, - bool _apply_loss_function = false, - FactorStatus _status = FAC_ACTIVE) : + FactorBlockDifference(const FeatureBasePtr& _feature_ptr, + const StateBlockPtr& _sb1_ptr, + const StateBlockPtr& _sb2_ptr, + const FrameBasePtr& _frame_other = nullptr, + const CaptureBasePtr& _cap_other = nullptr, + const FeatureBasePtr& _feat_other = nullptr, + const LandmarkBasePtr& _lmk_other = nullptr, + unsigned int _start_idx1 = 0, + int _size1 = -1, + unsigned int _start_idx2 = 0, + int _size2 = -1, + ProcessorBasePtr _processor_ptr = nullptr, + bool _apply_loss_function = false, + FactorStatus _status = FAC_ACTIVE) : FactorAnalytic("FactorBlockDifference", + _feature_ptr, _frame_other, _cap_other, _feat_other, @@ -129,8 +130,8 @@ inline Eigen::VectorXd FactorBlockDifference::evaluateResiduals(const std::vecto { // Check measurement and cov sizes assert(_st_vector.size() == 2 && "Wrong number of state blocks!"); - assert(getMeasurement().size() == getMeasurementCovariance().cols()); - assert(getMeasurement().size() == getMeasurementCovariance().rows()); + assert(getMeasurement().size() == getMeasurementSquareRootInformationUpper().cols()); + assert(getMeasurement().size() == getMeasurementSquareRootInformationUpper().rows()); assert(getMeasurement().size() == sb1_constrained_size_); assert(getMeasurement().size() == sb2_constrained_size_); diff --git a/include/core/factor/factor_diff_drive.h b/include/core/factor/factor_diff_drive.h index d936a99d6c1d64f29fda2c5aeca1806e0065c4d1..e267fb507ebfd811a0c17b1b6446267223510198 100644 --- a/include/core/factor/factor_diff_drive.h +++ b/include/core/factor/factor_diff_drive.h @@ -14,6 +14,7 @@ #include "core/factor/factor_autodiff.h" #include "core/frame/frame_base.h" #include "core/feature/feature_motion.h" +#include "core/math/rotations.h" namespace { @@ -31,20 +32,20 @@ namespace wolf WOLF_PTR_TYPEDEFS(FactorDiffDrive); class FactorDiffDrive : public FactorAutodiff<FactorDiffDrive, - RESIDUAL_SIZE, - POSITION_SIZE, - ORIENTATION_SIZE, - POSITION_SIZE, - ORIENTATION_SIZE, - INTRINSICS_SIZE> + RESIDUAL_SIZE, + POSITION_SIZE, + ORIENTATION_SIZE, + POSITION_SIZE, + ORIENTATION_SIZE, + INTRINSICS_SIZE> { using Base = FactorAutodiff<FactorDiffDrive, // @suppress("Type cannot be resolved") - RESIDUAL_SIZE, - POSITION_SIZE, - ORIENTATION_SIZE, - POSITION_SIZE, - ORIENTATION_SIZE, - INTRINSICS_SIZE>; + RESIDUAL_SIZE, + POSITION_SIZE, + ORIENTATION_SIZE, + POSITION_SIZE, + ORIENTATION_SIZE, + INTRINSICS_SIZE>; public: @@ -54,6 +55,7 @@ class FactorDiffDrive : public FactorAutodiff<FactorDiffDrive, const bool _apply_loss_function, const FactorStatus _status = FAC_ACTIVE) : Base("FactorDiffDrive", + _ftr_ptr, _capture_origin_ptr->getFrame(), _capture_origin_ptr, nullptr, @@ -126,10 +128,7 @@ inline bool FactorDiffDrive::operator ()(const T* const _p1, const T* const _o1, residuals = delta_corrected - delta_predicted; // angle remapping - while (residuals(2) > T(M_PI)) - residuals(2) = residuals(2) - T(2. * M_PI); - while (residuals(2) <= T(-M_PI)) - residuals(2) = residuals(2) + T(2. * M_PI); + pi2pi(residuals(2)); // weighted residual residuals = getMeasurementSquareRootInformationUpper() * residuals; diff --git a/include/core/factor/factor_odom_2d.h b/include/core/factor/factor_odom_2d.h index e20f0f50f158b7ed04e2d09054fafee9300a6f29..d8cfa08a9a9bf70c8b580f407f0983f60e791566 100644 --- a/include/core/factor/factor_odom_2d.h +++ b/include/core/factor/factor_odom_2d.h @@ -4,6 +4,7 @@ //Wolf includes #include "core/factor/factor_autodiff.h" #include "core/frame/frame_base.h" +#include "core/math/rotations.h" //#include "ceres/jet.h" @@ -16,18 +17,19 @@ class FactorOdom2d : public FactorAutodiff<FactorOdom2d, 3, 2, 1, 2, 1> { public: FactorOdom2d(const FeatureBasePtr& _ftr_ptr, - const FrameBasePtr& _frame_other_ptr, - const ProcessorBasePtr& _processor_ptr, - bool _apply_loss_function, - FactorStatus _status = FAC_ACTIVE) : + const FrameBasePtr& _frame_other_ptr, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status = FAC_ACTIVE) : FactorAutodiff<FactorOdom2d, 3, 2, 1, 2, 1>("FactorOdom2d", - _frame_other_ptr, nullptr, nullptr, nullptr, - _processor_ptr, - _apply_loss_function, _status, - _frame_other_ptr->getP(), - _frame_other_ptr->getO(), - _ftr_ptr->getFrame()->getP(), - _ftr_ptr->getFrame()->getO()) + _ftr_ptr, + _frame_other_ptr, nullptr, nullptr, nullptr, + _processor_ptr, + _apply_loss_function, _status, + _frame_other_ptr->getP(), + _frame_other_ptr->getO(), + _ftr_ptr->getFrame()->getP(), + _ftr_ptr->getFrame()->getO()) { // } @@ -72,10 +74,7 @@ inline bool FactorOdom2d::operator ()(const T* const _p1, const T* const _o1, co // Error er = expected_measurement - getMeasurement(); - while (er(2) > T( M_PI )) - er(2) -= T( 2 * M_PI ); - while (er(2) < T( -M_PI )) - er(2) += T( 2 * M_PI ); + er(2) = pi2pi(er(2)); // Residuals res = getMeasurementSquareRootInformationUpper() * er; diff --git a/include/core/factor/factor_odom_2d_analytic.h b/include/core/factor/factor_odom_2d_analytic.h index c7eec32a1778b9f1ad69da6c3c0087e50509a904..52ea04ccd817f2a6c914d771737c284bca4ce664 100644 --- a/include/core/factor/factor_odom_2d_analytic.h +++ b/include/core/factor/factor_odom_2d_analytic.h @@ -18,7 +18,7 @@ class FactorOdom2dAnalytic : public FactorRelative2dAnalytic const ProcessorBasePtr& _processor_ptr, bool _apply_loss_function, FactorStatus _status = FAC_ACTIVE) : - FactorRelative2dAnalytic("ODOM_2d", + FactorRelative2dAnalytic("FactorOdom2dAnalytic", _ftr_ptr, _frame_ptr, _processor_ptr, diff --git a/include/core/factor/factor_odom_2d_closeloop.h b/include/core/factor/factor_odom_2d_closeloop.h index e7d35aefa48b549174d060668cbee540edb6e9e2..a4ea7b1dff8484a89885edd424a6ac899331d3d7 100644 --- a/include/core/factor/factor_odom_2d_closeloop.h +++ b/include/core/factor/factor_odom_2d_closeloop.h @@ -4,6 +4,7 @@ //Wolf includes #include "core/factor/factor_autodiff.h" #include "core/frame/frame_base.h" +#include "core/math/rotations.h" //#include "ceres/jet.h" @@ -20,13 +21,14 @@ class FactorOdom2dCloseloop : public FactorAutodiff<FactorOdom2dCloseloop, 3, 2, const ProcessorBasePtr& _processor_ptr = nullptr, bool _apply_loss_function = false, FactorStatus _status = FAC_ACTIVE) : FactorAutodiff<FactorOdom2dCloseloop, 3, 2, 1, 2, 1>("FactorOdom2dCloseloop", - _frame_other_ptr, nullptr, nullptr, nullptr, - _processor_ptr, - _apply_loss_function, _status, - _frame_other_ptr->getP(), - _frame_other_ptr->getO(), - _ftr_ptr->getFrame()->getP(), - _ftr_ptr->getFrame()->getO()) + _ftr_ptr, + _frame_other_ptr, nullptr, nullptr, nullptr, + _processor_ptr, + _apply_loss_function, _status, + _frame_other_ptr->getP(), + _frame_other_ptr->getO(), + _ftr_ptr->getFrame()->getP(), + _ftr_ptr->getFrame()->getO()) { // } @@ -71,10 +73,7 @@ inline bool FactorOdom2dCloseloop::operator ()(const T* const _p1, const T* cons // Error er = expected_measurement - getMeasurement().cast<T>(); - while (er(2) > T( M_PI )) - er(2) -= T( 2 * M_PI ); - while (er(2) < T( -M_PI )) - er(2) += T( 2 * M_PI ); + er(2)=pi2pi(er(2)); // Residuals res = getMeasurementSquareRootInformationUpper().cast<T>() * er; diff --git a/include/core/factor/factor_odom_3d.h b/include/core/factor/factor_odom_3d.h index 2e49daf216906b4e96d92e9c195cbff579fd6545..4e32efe4067d52c23bfe978cea7ef792214e00c9 100644 --- a/include/core/factor/factor_odom_3d.h +++ b/include/core/factor/factor_odom_3d.h @@ -21,10 +21,10 @@ class FactorOdom3d : public FactorAutodiff<FactorOdom3d,6,3,4,3,4> { public: FactorOdom3d(const FeatureBasePtr& _ftr_current_ptr, - const FrameBasePtr& _frame_past_ptr, - const ProcessorBasePtr& _processor_ptr, - bool _apply_loss_function, - FactorStatus _status = FAC_ACTIVE); + const FrameBasePtr& _frame_past_ptr, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status = FAC_ACTIVE); virtual ~FactorOdom3d() = default; @@ -81,18 +81,19 @@ inline FactorOdom3d::FactorOdom3d(const FeatureBasePtr& _ftr_current_ptr, const ProcessorBasePtr& _processor_ptr, bool _apply_loss_function, FactorStatus _status) : - FactorAutodiff<FactorOdom3d, 6, 3, 4, 3, 4>("FactorOdom3d", // type - _frame_past_ptr, // frame other - nullptr, // capture other - nullptr, // feature other - nullptr, // landmark other - _processor_ptr, // processor - _apply_loss_function, - _status, - _ftr_current_ptr->getFrame()->getP(), // current frame P - _ftr_current_ptr->getFrame()->getO(), // current frame Q - _frame_past_ptr->getP(), // past frame P - _frame_past_ptr->getO()) // past frame Q + FactorAutodiff<FactorOdom3d, 6, 3, 4, 3, 4>("FactorOdom3d", // type + _ftr_current_ptr, // feature + _frame_past_ptr, // frame other + nullptr, // capture other + nullptr, // feature other + nullptr, // landmark other + _processor_ptr, // processor + _apply_loss_function, + _status, + _ftr_current_ptr->getFrame()->getP(), // current frame P + _ftr_current_ptr->getFrame()->getO(), // current frame Q + _frame_past_ptr->getP(), // past frame P + _frame_past_ptr->getO()) // past frame Q { // WOLF_TRACE("Constr ODOM 3d (f", _ftr_current_ptr->id(), // " F", _ftr_current_ptr->getCapture()->getFrame()->id(), @@ -105,8 +106,12 @@ inline FactorOdom3d::FactorOdom3d(const FeatureBasePtr& _ftr_current_ptr, } template<typename T> -inline bool FactorOdom3d::expectation(const T* const _p_current, const T* const _q_current, const T* const _p_past, - const T* const _q_past, T* _expectation_dp, T* _expectation_dq) const +inline bool FactorOdom3d::expectation(const T* const _p_current, + const T* const _q_current, + const T* const _p_past, + const T* const _q_past, + T* _expectation_dp, + T* _expectation_dq) const { Eigen::Map<const Eigen::Matrix<T,3,1> > p_current(_p_current); Eigen::Map<const Eigen::Quaternion<T> > q_current(_q_current); @@ -168,8 +173,11 @@ inline Eigen::VectorXd FactorOdom3d::expectation() const } template<typename T> -inline bool FactorOdom3d::operator ()(const T* const _p_current, const T* const _q_current, const T* const _p_past, - const T* const _q_past, T* _residuals) const +inline bool FactorOdom3d::operator ()(const T* const _p_current, + const T* const _q_current, + const T* const _p_past, + const T* const _q_past, + T* _residuals) const { /* Residual expression diff --git a/include/core/factor/factor_pose_2d.h b/include/core/factor/factor_pose_2d.h index ce63c806017117e67d18c2e79c34468e6b16a61c..a054c11673b75e69fe413afa9c5a161ac42d0778 100644 --- a/include/core/factor/factor_pose_2d.h +++ b/include/core/factor/factor_pose_2d.h @@ -22,6 +22,7 @@ class FactorPose2d: public FactorAutodiff<FactorPose2d,3,2,1> bool _apply_loss_function, FactorStatus _status = FAC_ACTIVE) : FactorAutodiff<FactorPose2d, 3, 2, 1>("FactorPose2d", + _ftr_ptr, nullptr, nullptr, nullptr, nullptr, _processor_ptr, _apply_loss_function, @@ -54,15 +55,11 @@ inline bool FactorPose2d::operator ()(const T* const _p, const T* const _o, T* _ Eigen::Matrix<T,3,1> er; er(0) = meas(0) - _p[0]; er(1) = meas(1) - _p[1]; - er(2) = meas(2) - _o[0]; - while (er[2] > T(M_PI)) - er(2) = er(2) - T(2*M_PI); - while (er(2) <= T(-M_PI)) - er(2) = er(2) + T(2*M_PI); + er(2) = pi2pi(meas(2) - _o[0]); // residual Eigen::Map<Eigen::Matrix<T,3,1>> res(_residuals); - res = getFeature()->getMeasurementSquareRootInformationUpper() * er; + res = getMeasurementSquareRootInformationUpper() * er; //////////////////////////////////////////////////////// // print Jacobian. Uncomment this as you wish (remember to uncomment #include "ceres/jet.h" above): diff --git a/include/core/factor/factor_pose_3d.h b/include/core/factor/factor_pose_3d.h index 9a46cbab24101a69faaad78ea190f1823406dd35..0390ab6401f782ed30921e9090bc2e5ed796589a 100644 --- a/include/core/factor/factor_pose_3d.h +++ b/include/core/factor/factor_pose_3d.h @@ -21,6 +21,7 @@ class FactorPose3d: public FactorAutodiff<FactorPose3d,6,3,4> bool _apply_loss_function, FactorStatus _status = FAC_ACTIVE) : FactorAutodiff<FactorPose3d,6,3,4>("FactorPose3d", + _ftr_ptr, nullptr, nullptr, nullptr, nullptr, _processor_ptr, _apply_loss_function, @@ -61,7 +62,7 @@ inline bool FactorPose3d::operator ()(const T* const _p, const T* const _o, T* _ // residual Eigen::Map<Eigen::Matrix<T, 6, 1>> res(_residuals); - res = getFeature()->getMeasurementSquareRootInformationUpper() * er; + res = getMeasurementSquareRootInformationUpper() * er; return true; } diff --git a/include/core/factor/factor_quaternion_absolute.h b/include/core/factor/factor_quaternion_absolute.h index 6533bd414d54a9eb45da8c92336ba3d1f0e07739..8cb37c39234d4ae47c05453179f0354380c824e9 100644 --- a/include/core/factor/factor_quaternion_absolute.h +++ b/include/core/factor/factor_quaternion_absolute.h @@ -23,11 +23,13 @@ class FactorQuaternionAbsolute: public FactorAutodiff<FactorQuaternionAbsolute,3 { public: - FactorQuaternionAbsolute(StateBlockPtr _sb_ptr, - ProcessorBasePtr _processor_ptr = nullptr, - bool _apply_loss_function = false, + FactorQuaternionAbsolute(FeatureBasePtr _ftr_ptr, + StateBlockPtr _sb_ptr, + ProcessorBasePtr _processor_ptr, + bool _apply_loss_function, FactorStatus _status = FAC_ACTIVE) : - FactorAutodiff<FactorQuaternionAbsolute,3,4>("QUATERNION ABS", + FactorAutodiff<FactorQuaternionAbsolute,3,4>("FactorQuaternionAbsolute", + _ftr_ptr, nullptr, nullptr, nullptr, @@ -78,7 +80,7 @@ inline bool FactorQuaternionAbsolute::operator ()(const T* const _o, T* _residua // residual Eigen::Map<Eigen::Matrix<T, 3, 1>> res(_residuals); - res = getFeature()->getMeasurementSquareRootInformationUpper() * er; + res = getMeasurementSquareRootInformationUpper() * er; return true; } diff --git a/include/core/factor/factor_relative_2d_analytic.h b/include/core/factor/factor_relative_2d_analytic.h index 5a67da1ff6c0e17614902ebc3195dd8124ec0ed6..e4ccf958c00e0e6185e0cf97a20c8072517c2756 100644 --- a/include/core/factor/factor_relative_2d_analytic.h +++ b/include/core/factor/factor_relative_2d_analytic.h @@ -4,6 +4,7 @@ //Wolf includes #include "core/factor/factor_analytic.h" #include "core/landmark/landmark_base.h" +#include "core/math/rotations.h" #include <Eigen/StdVector> namespace wolf { @@ -18,12 +19,24 @@ class FactorRelative2dAnalytic : public FactorAnalytic /** \brief Constructor of category FAC_FRAME **/ FactorRelative2dAnalytic(const std::string& _tp, - const FeatureBasePtr& _ftr_ptr, - const FrameBasePtr& _frame_ptr, - const ProcessorBasePtr& _processor_ptr, - bool _apply_loss_function, - FactorStatus _status = FAC_ACTIVE) : - FactorAnalytic(_tp, _frame_ptr, nullptr, nullptr, nullptr, _processor_ptr, _apply_loss_function, _status, _frame_ptr->getP(), _frame_ptr->getO(), _ftr_ptr->getFrame()->getP(), _ftr_ptr->getFrame()->getO()) + const FeatureBasePtr& _ftr_ptr, + const FrameBasePtr& _frame_other_ptr, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status = FAC_ACTIVE) : + FactorAnalytic(_tp, + _ftr_ptr, + _frame_other_ptr, + nullptr, + nullptr, + nullptr, + _processor_ptr, + _apply_loss_function, + _status, + _frame_other_ptr->getP(), + _frame_other_ptr->getO(), + _ftr_ptr->getFrame()->getP(), + _ftr_ptr->getFrame()->getO()) { // } @@ -31,12 +44,24 @@ class FactorRelative2dAnalytic : public FactorAnalytic /** \brief Constructor of category FAC_FEATURE **/ FactorRelative2dAnalytic(const std::string& _tp, - const FeatureBasePtr& _ftr_ptr, - const FeatureBasePtr& _ftr_other_ptr, - const ProcessorBasePtr& _processor_ptr, - bool _apply_loss_function, - FactorStatus _status = FAC_ACTIVE) : - FactorAnalytic(_tp, nullptr, nullptr, _ftr_other_ptr, nullptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFrame()->getP(), _ftr_ptr->getFrame()->getO(), _ftr_other_ptr->getFrame()->getP(), _ftr_other_ptr->getFrame()->getO() ) + const FeatureBasePtr& _ftr_ptr, + const FeatureBasePtr& _ftr_other_ptr, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status = FAC_ACTIVE) : + FactorAnalytic(_tp, + _ftr_ptr, + nullptr, + nullptr, + _ftr_other_ptr, + nullptr, + _processor_ptr, + _apply_loss_function, + _status, + _ftr_ptr->getFrame()->getP(), + _ftr_ptr->getFrame()->getO(), + _ftr_other_ptr->getFrame()->getP(), + _ftr_other_ptr->getFrame()->getO() ) { // } @@ -44,12 +69,24 @@ class FactorRelative2dAnalytic : public FactorAnalytic /** \brief Constructor of category FAC_LANDMARK **/ FactorRelative2dAnalytic(const std::string& _tp, - const FeatureBasePtr& _ftr_ptr, - const LandmarkBasePtr& _landmark_ptr, - const ProcessorBasePtr& _processor_ptr, - bool _apply_loss_function, - FactorStatus _status = FAC_ACTIVE) : - FactorAnalytic(_tp, nullptr, nullptr, nullptr, _landmark_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFrame()->getP(), _ftr_ptr->getFrame()->getO(), _landmark_ptr->getP(), _landmark_ptr->getO()) + const FeatureBasePtr& _ftr_ptr, + const LandmarkBasePtr& _landmark_other_ptr, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status = FAC_ACTIVE) : + FactorAnalytic(_tp, + _ftr_ptr, + nullptr, + nullptr, + nullptr, + _landmark_other_ptr, + _processor_ptr, + _apply_loss_function, + _status, + _ftr_ptr->getFrame()->getP(), + _ftr_ptr->getFrame()->getO(), + _landmark_other_ptr->getP(), + _landmark_other_ptr->getO()) { // } @@ -113,10 +150,7 @@ inline Eigen::VectorXd FactorRelative2dAnalytic::evaluateResiduals( expected_measurement(2) = _st_vector[3](0) - _st_vector[1](0); // Residual residual = expected_measurement - getMeasurement(); - while (residual(2) > M_PI) - residual(2) = residual(2) - 2 * M_PI; - while (residual(2) <= -M_PI) - residual(2) = residual(2) + 2 * M_PI; + residual(2) = pi2pi(residual(2)); residual = getMeasurementSquareRootInformationUpper() * residual; return residual; } diff --git a/include/core/factor/factor_relative_pose_2d_with_extrinsics.h b/include/core/factor/factor_relative_pose_2d_with_extrinsics.h new file mode 100644 index 0000000000000000000000000000000000000000..704cc3e7bc906a84a6702b6e8fdcad38766562ee --- /dev/null +++ b/include/core/factor/factor_relative_pose_2d_with_extrinsics.h @@ -0,0 +1,130 @@ +#ifndef FACTOR_RELATIVE_POSE_2D_WITH_EXTRINSICS_THETA_H_ +#define FACTOR_RELATIVE_POSE_2D_WITH_EXTRINSICS_THETA_H_ + +//Wolf includes +#include "core/factor/factor_autodiff.h" +#include "core/frame/frame_base.h" +#include "core/math/rotations.h" + +//#include "ceres/jet.h" + +namespace wolf { + +WOLF_PTR_TYPEDEFS(FactorRelativePose2dWithExtrinsics); + +//class +class FactorRelativePose2dWithExtrinsics : public FactorAutodiff<FactorRelativePose2dWithExtrinsics, 3, 2, 1, 2, 1, 2, 1> +{ + public: + FactorRelativePose2dWithExtrinsics(const FeatureBasePtr& _ftr_ptr, + const FrameBasePtr& _frame_other_ptr, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status = FAC_ACTIVE) : + FactorAutodiff<FactorRelativePose2dWithExtrinsics, 3, 2, 1, 2, 1, 2, 1>("FactorRelativePose2dWithExtrinsics", + _ftr_ptr, + _frame_other_ptr, nullptr, nullptr, nullptr, + _processor_ptr, + _apply_loss_function, + _status, + _frame_other_ptr->getP(), + _frame_other_ptr->getO(), + _ftr_ptr->getFrame()->getP(), + _ftr_ptr->getFrame()->getO(), + _ftr_ptr->getCapture()->getSensorP(), + _ftr_ptr->getCapture()->getSensorO()) + { + assert(_ftr_ptr->getCapture()->getSensorP() != nullptr && "No extrinsics found!"); + assert(_ftr_ptr->getCapture()->getSensorO() != nullptr && "No extrinsics found!"); + // + } + + virtual ~FactorRelativePose2dWithExtrinsics() = default; + + virtual std::string getTopology() const override + { + return std::string("MOTION"); + } + + template<typename T> + bool operator ()(const T* const _p1, + const T* const _o1, + const T* const _p2, + const T* const _o2, + const T* const _sp, + const T* const _so, + T* _residuals) const; +}; + +template<typename T> +inline bool FactorRelativePose2dWithExtrinsics::operator ()(const T* const _p1, + const T* const _o1, + const T* const _p2, + const T* const _o2, + const T* const _ps, + const T* const _os, + T* _residuals) const +{ + + // MAPS + Eigen::Map<Eigen::Matrix<T,3,1> > res(_residuals); + Eigen::Map<const Eigen::Matrix<T,2,1> > p1(_p1); + Eigen::Map<const Eigen::Matrix<T,2,1> > p2(_p2); + Eigen::Map<const Eigen::Matrix<T,2,1> > ps(_ps); + T o1 = _o1[0]; + T o2 = _o2[0]; + T os = _os[0]; + + Eigen::Matrix<T, 3, 1> expected_measurement; + Eigen::Matrix<T, 3, 1> er; // error + + // Expected measurement + // r1_p_r1_s1 = ps + // r2_p_r2_s2 = ps + // r1_R_s1 = R(os) + // r2_R_s2 = R(os) + // w_R_r1 = R(o1) + // w_R_r2 = R(o2) + // ---------------------------------------- + + // s1_p_s1_s2 = s1_R_r1*r1_p_s1_r1 + + // s1_R_r1*r1_R_w*w_p_r1_w + + // s1_R_r1*r1_R_w*w_p_w_r2 + + // s1_R_r1*r1_R_w*w_R_r2*r2_p_r2_s2 + + // s1_p_s1_s2 = s1_R_r1*(r1_p_s1_r1 + r1_R_w*(w_p_r1_w + w_p_w_r2 + w_R_r2*r2_p_r2_s2)) + + expected_measurement.head(2) = Eigen::Rotation2D<T>(-os)*(-ps + Eigen::Rotation2D<T>(-o1)*(-p1 + p2 + Eigen::Rotation2D<T>(o2)*ps)); + expected_measurement(2) = o2 - o1; + + // Error + er = expected_measurement - getMeasurement().cast<T>(); + er(2) = pi2pi(er(2)); + + // Residuals + res = getMeasurementSquareRootInformationUpper().cast<T>() * er; + + //////////////////////////////////////////////////////// + // print Jacobian. Uncomment this as you wish (remember to uncomment #include "ceres/jet.h" above): +// using ceres::Jet; +// Eigen::MatrixXs J(3,6); +// J.row(0) = ((Jet<Scalar, 6>)(er(0))).v; +// J.row(1) = ((Jet<Scalar, 6>)(er(1))).v; +// J.row(2) = ((Jet<Scalar, 6>)(er(2))).v; +// J.row(0) = ((Jet<Scalar, 6>)(res(0))).v; +// J.row(1) = ((Jet<Scalar, 6>)(res(1))).v; +// J.row(2) = ((Jet<Scalar, 6>)(res(2))).v; +// if (sizeof(er(0)) != sizeof(double)) +// { +// std::cout << "FactorRelativePose2dWithExtrinsics::Jacobian(c" << id() << ") = \n " << J << std::endl; +// std::cout << "FactorRelativePose2dWithExtrinsics::Weighted Jacobian(c" << id() << ") = \n " << J << std::endl; +// std::cout << "FactorRelativePose2dWithExtrinsics::Sqrt Info(c" << id() << ") = \n" << getMeasurementSquareRootInformationUpper() << std::endl; +// } + //////////////////////////////////////////////////////// + + return true; +} + +} // namespace wolf + +#endif diff --git a/include/core/feature/feature_base.h b/include/core/feature/feature_base.h index a2ba3bc60f5d0db16d6c486099ac5e3e9b3116ec..f412fd3688e114e6116cd17db7de724e0fb7fa85 100644 --- a/include/core/feature/feature_base.h +++ b/include/core/feature/feature_base.h @@ -76,9 +76,17 @@ class FeatureBase : public NodeBase, public std::enable_shared_from_this<Feature */ double getMeasurement(unsigned int _ii) const; const Eigen::VectorXd& getMeasurement() const; + + private: + /* \brief Set the measurement and its noise + * + * WARNING: To be used once in the constructor only. + */ void setMeasurement(const Eigen::VectorXd& _meas); void setMeasurementCovariance(const Eigen::MatrixXd & _meas_cov); void setMeasurementInformation(const Eigen::MatrixXd & _meas_info); + + public: const Eigen::MatrixXd& getMeasurementCovariance() const; Eigen::MatrixXd getMeasurementInformation() const; const Eigen::MatrixXd& getMeasurementSquareRootInformationUpper() const; @@ -106,6 +114,21 @@ class FeatureBase : public NodeBase, public std::enable_shared_from_this<Feature template<typename classType, typename... T> static std::shared_ptr<classType> emplace(CaptureBasePtr _cpt_ptr, T&&... all); + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const; + void print(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream = std::cout, + std::string _tabs = "") const; + + virtual CheckLog localCheck(bool _verbose, FeatureBasePtr _feature_ptr, std::ostream& _stream, std::string _tabs = "") const; + bool check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs = "") const; private: void setCapture(CaptureBasePtr _cap_ptr){capture_ptr_ = _cap_ptr;} @@ -176,11 +199,6 @@ inline const Eigen::MatrixXd& FeatureBase::getMeasurementSquareRootInformationUp return measurement_sqrt_information_upper_; } -inline void FeatureBase::setMeasurement(const Eigen::VectorXd& _meas) -{ - measurement_ = _meas; -} - inline const Eigen::VectorXd& FeatureBase::getExpectation() const { return expectation_; diff --git a/include/core/frame/frame_base.h b/include/core/frame/frame_base.h index eea8873b3e804743f4cd224bffd6442d4c17febf..6c73ad933f4b305fca0c71af6db5a47792cab574 100644 --- a/include/core/frame/frame_base.h +++ b/include/core/frame/frame_base.h @@ -48,16 +48,6 @@ class FrameBase : public NodeBase, public HasStateBlocks, public std::enable_sha TimeStamp time_stamp_; ///< frame time stamp public: - /** \brief Constructor of non-key Frame with only time stamp - * - * Constructor with only time stamp - * \param _ts is the time stamp associated to this frame, provided in seconds - * \param _p_ptr StateBlock pointer to the position (default: nullptr) - * \param _o_ptr StateBlock pointer to the orientation (default: nullptr). Pass a StateQuaternion if needed. - * \param _v_ptr StateBlock pointer to the velocity (default: nullptr). - **/ - FrameBase(const TimeStamp& _ts, StateBlockPtr _p_ptr, StateBlockPtr _o_ptr = nullptr, StateBlockPtr _v_ptr = nullptr); - /** \brief Constructor with type, time stamp and state pointer * * Constructor with type, time stamp and state pointer @@ -67,9 +57,27 @@ class FrameBase : public NodeBase, public HasStateBlocks, public std::enable_sha * \param _o_ptr StateBlock pointer to the orientation (default: nullptr) * \param _v_ptr StateBlock pointer to the velocity (default: nullptr). **/ - FrameBase(const FrameType & _tp, const TimeStamp& _ts, StateBlockPtr _p_ptr, StateBlockPtr _o_ptr = nullptr, StateBlockPtr _v_ptr = nullptr); - - FrameBase(const std::string _frame_structure, const SizeEigen _dim, const FrameType & _tp, const TimeStamp& _ts, const Eigen::VectorXd& _x); + FrameBase(const FrameType & _tp, + const TimeStamp& _ts, + StateBlockPtr _p_ptr, + StateBlockPtr _o_ptr = nullptr, + StateBlockPtr _v_ptr = nullptr); + + FrameBase(const FrameType & _tp, + const TimeStamp& _ts, + const std::string _frame_structure, + const SizeEigen _dim, + const Eigen::VectorXd& _x); + + FrameBase(const FrameType & _tp, + const TimeStamp& _ts, + const std::string _frame_structure, + const VectorComposite& _state); + + FrameBase(const FrameType & _tp, + const TimeStamp& _ts, + const std::string _frame_structure, + const std::list<VectorXd>& _vectors); virtual ~FrameBase(); virtual void remove(bool viral_remove_empty_parent=false); @@ -131,6 +139,23 @@ class FrameBase : public NodeBase, public HasStateBlocks, public std::enable_sha template<typename classType, typename... T> static std::shared_ptr<classType> emplace(TrajectoryBasePtr _ptr, T&&... all); + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const; + + void print(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream = std::cout, + std::string _tabs = "") const; + + virtual CheckLog localCheck(bool _verbose, FrameBasePtr _frm_ptr, std::ostream& _stream, std::string _tabs = "") const; + bool check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs = "") const; + private: CaptureBasePtr addCapture(CaptureBasePtr _capt_ptr); diff --git a/include/core/hardware/hardware_base.h b/include/core/hardware/hardware_base.h index a309e7a03c8a5e27f459b772ce6bff5b0994f714..fba575b0b8ea55a15b8bbe4972d0bc12984ae62b 100644 --- a/include/core/hardware/hardware_base.h +++ b/include/core/hardware/hardware_base.h @@ -27,6 +27,22 @@ class HardwareBase : public NodeBase, public std::enable_shared_from_this<Hardwa const SensorBasePtrList& getSensorList() const; + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const; + void print(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream = std::cout, + std::string _tabs = "") const; + + virtual CheckLog localCheck(bool _verbose, HardwareBasePtr _hwd_ptr, std::ostream& _stream, std::string _tabs = "") const; + bool check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs = "") const; + private: virtual SensorBasePtr addSensor(SensorBasePtr _sensor_ptr); }; diff --git a/include/core/landmark/landmark_base.h b/include/core/landmark/landmark_base.h index 254e03e480f8471029c38c8f59626b230dc962f9..3d177d79c972b1e072fb86d5d7790e686cd387ff 100644 --- a/include/core/landmark/landmark_base.h +++ b/include/core/landmark/landmark_base.h @@ -85,6 +85,23 @@ class LandmarkBase : public NodeBase, public HasStateBlocks, public std::enable_ */ static LandmarkBasePtr create(const YAML::Node& _node); + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const; + + void print(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream = std::cout, + std::string _tabs = "") const; + + virtual CheckLog localCheck(bool _verbose, LandmarkBasePtr _lmk_ptr, std::ostream& _stream, std::string _tabs = "") const; + bool check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs = "") const; + private: void setMap(const MapBasePtr _map_ptr); diff --git a/include/core/map/map_base.h b/include/core/map/map_base.h index 6d09191e54619d5a00fce39e1ecf002aace66d3a..e609298014d8b68ca9e686a877ea80b041b34214 100644 --- a/include/core/map/map_base.h +++ b/include/core/map/map_base.h @@ -38,6 +38,21 @@ class MapBase : public NodeBase, public std::enable_shared_from_this<MapBase> void load(const std::string& _map_file_yaml); void save(const std::string& _map_file_yaml, const std::string& _map_name = "Map automatically saved by Wolf"); + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const; + void print(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream = std::cout, + std::string _tabs = "") const; + + virtual CheckLog localCheck(bool _verbose, MapBasePtr _map_ptr, std::ostream& _stream, std::string _tabs = "") const; + bool check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs = "") const; private: std::string dateTimeNow(); }; diff --git a/include/core/math/SE2.h b/include/core/math/SE2.h index 00f570faed8c0542a1e0312a5ad1bc7c2ab710e3..4ac32d2ded2923f212937cfa88a0994fb0dca5b4 100644 --- a/include/core/math/SE2.h +++ b/include/core/math/SE2.h @@ -10,6 +10,7 @@ #include "core/common/wolf.h" #include "core/math/rotations.h" +#include "core/state_block/state_composite.h" #include <Eigen/Geometry> #include <Eigen/Dense> @@ -25,17 +26,26 @@ namespace wolf namespace SO2{ template<typename T> -Eigen::Matrix<T, 2, 2> exp(const T theta) +inline Eigen::Matrix<T, 2, 2> exp(const T theta) { return Eigen::Rotation2D<T>(theta).matrix(); } + } // namespace SO2 namespace SE2{ +/** \brief Compute [1]_x * t = (-t.y ; t.x) + */ +template<class D> +inline Eigen::Matrix<typename D::Scalar, 2, 1> skewed(const MatrixBase<D>& t) +{ + return Eigen::Matrix<typename D::Scalar, 2, 1>(-t(1), t(0)); +} + template<typename T> -Eigen::Matrix2d V_helper(const T theta) +inline Eigen::Matrix2d V_helper(const T theta) { T s; // sin(theta) / theta T c_1; // (1-cos(theta)) / theta @@ -56,8 +66,17 @@ Eigen::Matrix2d V_helper(const T theta) return (Matrix<T, 2, 2>() << s, -c_1, c_1, s).finished(); } +inline VectorComposite identity() +{ + VectorComposite v; + v["P"] = Vector2d::Zero(); + v["O"] = Vector1d::Zero(); + + return v; +} + template<class D1, class D2> -void exp(const Eigen::MatrixBase<D1>& _tau, Eigen::MatrixBase<D2>& _delta) +inline void exp(const Eigen::MatrixBase<D1>& _tau, Eigen::MatrixBase<D2>& _delta) { MatrixSizeCheck<3, 1>::check(_tau); MatrixSizeCheck<3, 1>::check(_delta); @@ -68,7 +87,7 @@ void exp(const Eigen::MatrixBase<D1>& _tau, Eigen::MatrixBase<D2>& _delta) } template<class D, typename T> -Eigen::Matrix<T, 2, 1> J_Vp_theta(const Eigen::MatrixBase<D>& p, const T theta) +inline Eigen::Matrix<T, 2, 1> J_Vp_theta(const Eigen::MatrixBase<D>& p, const T theta) { MatrixSizeCheck<2, 1>::check (p); @@ -95,7 +114,7 @@ Eigen::Matrix<T, 2, 1> J_Vp_theta(const Eigen::MatrixBase<D>& p, const T theta) } template<class D1, class D2, class D3> -void exp(const MatrixBase<D1>& _tau, MatrixBase<D2>& _delta, MatrixBase<D3>& _J_delta_tau) +inline void exp(const MatrixBase<D1>& _tau, MatrixBase<D2>& _delta, MatrixBase<D3>& _J_delta_tau) { MatrixSizeCheck<3, 1>::check(_tau); MatrixSizeCheck<3, 1>::check(_delta); @@ -116,6 +135,254 @@ void exp(const MatrixBase<D1>& _tau, MatrixBase<D2>& _delta, MatrixBase<D3>& _J_ _J_delta_tau << V, J_Vp_theta(_tau.template head<2>(), theta), 0.0, 0.0, 1.0; } +inline void exp(const VectorComposite& _tau, VectorComposite& _delta) +{ + // [1] eq. 156 + const auto &p = _tau.at("P"); + const auto &theta = pi2pi(_tau.at("O")(0)); + Matrix2d V = V_helper(theta); + + _delta["P"] = V * p; + _delta["O"] = Matrix1d(theta); +} + +inline VectorComposite exp(const VectorComposite& tau) +{ + VectorComposite res("PO", {2,1}); + + exp(tau, res); + + return res; +} + +inline void exp(const VectorComposite& _tau, VectorComposite& _delta, MatrixComposite& _J_delta_tau) +{ + // [1] eq. 156 + const auto &p = _tau.at("P"); + const auto &theta = pi2pi(_tau.at("O")(0)); + Matrix2d V = V_helper(theta); + + _delta["P"] = V * p; + _delta["O"] = Matrix1d(theta); + + // Jacobian follows the composite definition in [1] eq. 89, with jacobian blocks: + // J_Vp_p = V: see V_helper, eq. 158 + // J_Vp_theta: see fcn helper + // J_theta_theta = 1; eq. 126 + _J_delta_tau.clear(); + _J_delta_tau.emplace("P", "P", V); + _J_delta_tau.emplace("P", "O", J_Vp_theta(p, theta)); + _J_delta_tau.emplace("O", "P", RowVector2d(0.0, 0.0)); + _J_delta_tau.emplace("O", "O", Matrix1d(1)); +} + +template<class D1, class D2, class D3> +inline void compose(const MatrixBase<D1> &_delta1, MatrixBase<D2> &_delta2, MatrixBase<D3> &_delta1_compose_delta2) +{ + MatrixSizeCheck<3, 1>::check(_delta1); + MatrixSizeCheck<3, 1>::check(_delta2); + MatrixSizeCheck<3, 1>::check(_delta1_compose_delta2); + + _delta1_compose_delta2.template head<2>() = _delta1.template head<2>() + + SO2::exp(_delta1(2)) * _delta2.template head<2>(); + _delta1_compose_delta2(2) = pi2pi(_delta1(2) + _delta2(2)); +} + +template<class D1, class D2, class D3, class D4, class D5> +inline void compose(const MatrixBase<D1>& _delta1, + const MatrixBase<D2>& _delta2, + MatrixBase<D3>& _delta1_compose_delta2, + MatrixBase<D4>& _J_compose_delta1, + MatrixBase<D5>& _J_compose_delta2) +{ + MatrixSizeCheck<3, 1>::check(_delta1); + MatrixSizeCheck<3, 1>::check(_delta2); + MatrixSizeCheck<3, 1>::check(_delta1_compose_delta2); + MatrixSizeCheck<3, 3>::check(_J_compose_delta1); + MatrixSizeCheck<3, 3>::check(_J_compose_delta2); + + Matrix2d R1 = SO2::exp(_delta1(2)); // need temporary + + // tc = t1 + R1 t2 + _delta1_compose_delta2.template head<2>() = _delta1.template head<2>() + R1 * _delta2.template head<2>(); + + // Rc = R1 R2 --> theta = theta1 + theta2 + _delta1_compose_delta2(2) = pi2pi(_delta1(2) + _delta2(2)); + + /* Jacobians in composite form [1] see eqs. (89, 125, 129, 130) + * + * resulting delta is: + * + * tc = t1 + R1 t2 (*) + * Rc = R1 R2 (**) + * + * Jacobians have the form: + * + * [ J_t_t J_t_R ] + * [ J_r_t J_R_R ] + * + * Jacobian blocks are: + * + * J_tc_t1 = I trivial from (*) + * J_tc_R1 = R1 [1]x t2 = R1 (-t2.y ; t2.x) see [1]: eq. (129) + * + * J_Rc_t1 = (0 0) trivial from (**) + * J_Rc_R1 = 1 see [1]: eq. (125) + * + * J_tc_t2 = R1 see [1]: eq. (130) + * J_tc_R2 = 0 trivial from (*) + * + * J_Rc_t2 = 0 trivial from (**) + * J_Rc_R2 = 1 see [1]: eq. (125) + */ + + _J_compose_delta1.setIdentity(); + _J_compose_delta1.template block<2, 1>(0, 2) = R1 * skewed(_delta2.template head<2>()); + + _J_compose_delta2.setIdentity(3, 3); + _J_compose_delta2.template block<2, 2>(0, 0) = R1; +} + +inline void compose(const VectorComposite& _x1, + const VectorComposite& _x2, + VectorComposite& _c) +{ + const auto& p1 = _x1.at("P"); + const auto& a1 = _x1.at("O")(0); // angle + const auto& R1 = SO2::exp(a1); + + const auto& p2 = _x2.at("P"); + const auto& a2 = _x2.at("O")(0); // angle + + // tc = t1 + R1 t2 + _c["P"] = p1 + R1 * p2; + + // Rc = R1 R2 --> theta = theta1 + theta2 + _c["O"] = Matrix1d( pi2pi(a1 + a2) ) ; +} + +inline void compose(const VectorComposite& _x1, + const VectorComposite& _x2, + VectorComposite& _c, + MatrixComposite& _J_c_x1, + MatrixComposite& _J_c_x2) +{ + const auto& p1 = _x1.at("P"); + const auto& a1 = _x1.at("O")(0); // angle + Matrix2d R1 = SO2::exp(a1); // need temporary + + const auto& p2 = _x2.at("P"); + const auto& a2 = _x2.at("O")(0); // angle + + /* Jacobians in composite form [1] see eqs. (89, 125, 129, 130) + * + * resulting delta is: + * + * tc = t1 + R1 t2 (*) + * Rc = R1 R2 (**) + * + * Jacobians have the form: + * + * [ J_t_t J_t_R ] + * [ J_r_t J_R_R ] + * + * Jacobian blocks are: + * + * J_tc_t1 = I trivial from (*) + * J_tc_R1 = R1 [1]x t2 = R1 (-t2.y ; t2.x) see [1]: eq. (129) + * + * J_Rc_t1 = (0 0) trivial from (**) + * J_Rc_R1 = 1 see [1]: eq. (125) + * + * J_tc_t2 = R1 see [1]: eq. (130) + * J_tc_R2 = 0 trivial from (*) + * + * J_Rc_t2 = 0 trivial from (**) + * J_Rc_R2 = 1 see [1]: eq. (125) + */ + + _J_c_x1.clear(); + _J_c_x1.emplace("P", "P", Matrix2d::Identity()); + _J_c_x1.emplace("P", "O", MatrixXd(R1 * skewed(p2)) ); + _J_c_x1.emplace("O", "P", RowVector2d(0,0)); + _J_c_x1.emplace("O", "O", Matrix1d(1)); + + _J_c_x2.clear(); + _J_c_x2.emplace("P", "P", R1); + _J_c_x2.emplace("P", "O", Vector2d(0,0)); + _J_c_x2.emplace("O", "P", RowVector2d(0,0)); + _J_c_x2.emplace("O", "O", Matrix1d(1)); + + + // Actually compose the vectors here. This avoids aliasing in case this is called with 'c' coinciding with 'x1' or 'x2'. + + // tc = t1 + R1 t2 + _c["P"] = p1 + R1 * p2; + + // Rc = R1 R2 --> theta = theta1 + theta2 + _c["O"] = Matrix1d( pi2pi(a1 + a2) ) ; + +} + +template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8> +inline void plus(const MatrixBase<D1>& p1, const MatrixBase<D2>& q1, + const MatrixBase<D4>& p2, const MatrixBase<D5>& o2, + MatrixBase<D7>& plus_p, MatrixBase<D8>& plus_q) +{ + MatrixSizeCheck<2, 1>::check(p1); + MatrixSizeCheck<1, 1>::check(q1); + MatrixSizeCheck<2, 1>::check(p2); + MatrixSizeCheck<1, 1>::check(o2); + MatrixSizeCheck<2, 1>::check(plus_p); + MatrixSizeCheck<1, 1>::check(plus_q); + + plus_p = p1 + p2; + plus_q(0) = pi2pi(q1(0) + o2(0)); +} + +template<typename D1, typename D2, typename D3> +inline void plus(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2, + MatrixBase<D3>& d_plus) +{ + Map<const Matrix<typename D1::Scalar, 2, 1> > p1 ( & d1(0) ); + Map<const Matrix<typename D1::Scalar, 1, 1> > q1 ( & d1(2) ); + Map<const Matrix<typename D2::Scalar, 2, 1> > p2 ( & d2(0) ); + Map<const Matrix<typename D2::Scalar, 1, 1> > o2 ( & d2(2) ); + Map<Matrix<typename D3::Scalar, 2, 1> > p_p ( & d_plus(0) ); + Map<Matrix<typename D1::Scalar, 1, 1> > q_p ( & d_plus(2) ); + + plus(p1, q1, p2, o2, p_p, q_p); +} + +template<typename D1, typename D2> +inline Matrix<typename D1::Scalar, 3, 1> plus(const MatrixBase<D1>& d1, + const MatrixBase<D2>& d2) +{ + Matrix<typename D1::Scalar, 3, 1> d_plus; + plus(d1, d2, d_plus); + return d_plus; +} + +inline void plus(const VectorComposite& x, const VectorComposite& tau, VectorComposite& res) +{ + plus(x.at("P"), x.at("O"), tau.at("P"), tau.at("O"), res.at("P"), res.at("O")); +} + +inline VectorComposite plus(const VectorComposite& x, const VectorComposite& tau) +{ + VectorComposite res; + + res["P"] = Vector2d(); + res["O"] = Vector1d(); + + plus(x, tau, res); + + return res; +} + + + } // namespace SE2 } // namespacs wolf diff --git a/include/core/math/SE3.h b/include/core/math/SE3.h index 701c5bab7a5ec5ecc6401def52ad9ca6d0f26856..4b000889c59320e8c7e819725c415dd19308d077 100644 --- a/include/core/math/SE3.h +++ b/include/core/math/SE3.h @@ -10,6 +10,7 @@ #include "core/common/wolf.h" #include "core/math/rotations.h" +#include "core/state_block/state_composite.h" /* * The functions in this file are related to manipulations of Delta motion magnitudes used in 3d motion. @@ -26,11 +27,17 @@ * - identity: I = Delta at the origin, with Dp = [0,0,0]; Dq = [0,0,0,1], so that D (+) I = I (+) D = D * - inverse: so that D (+) D.inv = D.inv (+) D = I * - between: Db = D2 (-) D1 := D1.inv (+) D2, so that D2 = D1 (+) Db - * - log_SE3: go from Delta manifold to tangent space (equivalent to log() in rotations) - * - exp_SE3: go from tangent space to delta manifold (equivalent to exp() in rotations) - * - plus: D2 = D1 * exp_SE3(d) - * - minus: d = log_SE3( D1.inv() * D2 ) + * - log: go from Delta manifold to tangent space (equivalent to log() in rotations) + * - exp: go from tangent space to delta manifold (equivalent to exp() in rotations) + * - plus: D2 = D1 * exp(d) + * - minus: d = log( D1.inv() * D2 ) * - interpolate: dd = D1 * exp ( log( D1.inv() * D2 ) * t ) = D1 (+) ( (D2 (-) D1) * t) + * + * ------------------------------------------------------------------------------------------ + * + * Some of the functions below are based on: + * + * [1] J. Sola et. al. "A micro Lie theory for state estimation in robotics", tech rep. IRI 2018, https://arxiv.org/pdf/1812.01537.pdf */ namespace wolf @@ -57,6 +64,13 @@ inline void identity(MatrixBase<D1>& p, MatrixBase<D2>& q) q << T2(0), T2(0), T2(0), T2(1); } +inline void identity(VectorComposite& v) +{ + v.clear(); + v["P"] = Vector3d::Zero(); + v["O"] = Quaterniond::Identity().coeffs(); +} + template<typename T = double> inline Matrix<T, 7, 1> identity() { @@ -67,14 +81,14 @@ inline Matrix<T, 7, 1> identity() } template<typename D1, typename D2, typename D4, typename D5> -inline void inverse(const MatrixBase<D1>& dp, const QuaternionBase<D2>& dq, - MatrixBase<D4>& idp, QuaternionBase<D5>& idq) +inline void inverse(const MatrixBase<D1>& p, const QuaternionBase<D2>& q, + MatrixBase<D4>& ip, QuaternionBase<D5>& iq) { - MatrixSizeCheck<3, 1>::check(dp); - MatrixSizeCheck<3, 1>::check(idp); + MatrixSizeCheck<3, 1>::check(p); + MatrixSizeCheck<3, 1>::check(ip); - idp = - dq.conjugate() * dp ; - idq = dq.conjugate() ; + ip = - q.conjugate() * p ; + iq = q.conjugate() ; } template<typename D1, typename D2> @@ -84,12 +98,12 @@ inline void inverse(const MatrixBase<D1>& d, MatrixSizeCheck<7, 1>::check(d); MatrixSizeCheck<7, 1>::check(id); - Map<const Matrix<typename D1::Scalar, 3, 1> > dp ( & d( 0 ) ); - Map<const Quaternion<typename D1::Scalar> > dq ( & d( 3 ) ); - Map<Matrix<typename D2::Scalar, 3, 1> > idp ( & id( 0 ) ); - Map<Quaternion<typename D2::Scalar> > idq ( & id( 3 ) ); + Map<const Matrix<typename D1::Scalar, 3, 1> > p ( & d( 0 ) ); + Map<const Quaternion<typename D1::Scalar> > q ( & d( 3 ) ); + Map<Matrix<typename D2::Scalar, 3, 1> > ip ( & id( 0 ) ); + Map<Quaternion<typename D2::Scalar> > iq ( & id( 3 ) ); - inverse(dp, dq, idp, idq); + inverse(p, q, ip, iq); } template<typename D> @@ -101,16 +115,35 @@ inline Matrix<typename D::Scalar, 7, 1> inverse(const MatrixBase<D>& d) } template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8> -inline void compose(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, - const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, - MatrixBase<D7>& sum_p, QuaternionBase<D8>& sum_q ) +inline void compose(const MatrixBase<D1>& p1, const QuaternionBase<D2>& q1, + const MatrixBase<D4>& p2, const QuaternionBase<D5>& q2, + MatrixBase<D7>& pc, QuaternionBase<D8>& qc ) { - MatrixSizeCheck<3, 1>::check(dp1); - MatrixSizeCheck<3, 1>::check(dp2); - MatrixSizeCheck<3, 1>::check(sum_p); + MatrixSizeCheck<3, 1>::check(p1); + MatrixSizeCheck<3, 1>::check(p2); + MatrixSizeCheck<3, 1>::check(pc); - sum_p = dp1 + dq1*dp2; - sum_q = dq1*dq2; // dq here to avoid possible aliasing between d1 and sum + pc = p1 + q1 * p2; + qc = q1 * q2; // q here to avoid possible aliasing between d1 and sum +} + +template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8> +inline void compose(const MatrixBase<D1>& p1, const MatrixBase<D2>& q1, + const MatrixBase<D4>& p2, const MatrixBase<D5>& q2, + MatrixBase<D7>& pc, MatrixBase<D8>& qc ) +{ + MatrixSizeCheck<3, 1>::check(p1); + MatrixSizeCheck<4, 1>::check(q1); + MatrixSizeCheck<3, 1>::check(p2); + MatrixSizeCheck<4, 1>::check(q2); + MatrixSizeCheck<3, 1>::check(pc); + MatrixSizeCheck<4, 1>::check(qc); + + Map<const Quaternion<typename D2::Scalar> > mq1 ( & q1( 0 ) ); + Map<const Quaternion<typename D5::Scalar> > mq2 ( & q2( 0 ) ); + Map< Quaternion<typename D8::Scalar> > mqc ( & qc( 0 ) ); + + compose(p1, mq1, p2, mq2, pc, mqc); } template<typename D1, typename D2, typename D3> @@ -122,14 +155,14 @@ inline void compose(const MatrixBase<D1>& d1, MatrixSizeCheck<7, 1>::check(d2); MatrixSizeCheck<7, 1>::check(sum); - Map<const Matrix<typename D1::Scalar, 3, 1> > dp1 ( & d1( 0 ) ); - Map<const Quaternion<typename D1::Scalar> > dq1 ( & d1( 3 ) ); - Map<const Matrix<typename D2::Scalar, 3, 1> > dp2 ( & d2( 0 ) ); - Map<const Quaternion<typename D2::Scalar> > dq2 ( & d2( 3 ) ); - Map<Matrix<typename D3::Scalar, 3, 1> > sum_p ( & sum( 0 ) ); - Map<Quaternion<typename D3::Scalar> > sum_q ( & sum( 3 ) ); + Map<const Matrix<typename D1::Scalar, 3, 1> > p1 ( & d1( 0 ) ); + Map<const Quaternion<typename D1::Scalar> > q1 ( & d1( 3 ) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > p2 ( & d2( 0 ) ); + Map<const Quaternion<typename D2::Scalar> > q2 ( & d2( 3 ) ); + Map<Matrix<typename D3::Scalar, 3, 1> > pc ( & sum( 0 ) ); + Map<Quaternion<typename D3::Scalar> > qc ( & sum( 3 ) ); - compose(dp1, dq1, dp2, dq2, sum_p, sum_q); + compose(p1, q1, p2, q2, pc, qc); } template<typename D1, typename D2> @@ -155,8 +188,8 @@ inline void compose(const MatrixBase<D1>& d1, MatrixSizeCheck< 6, 6>::check(J_sum_d2); // Some useful temporaries - Matrix<typename D1::Scalar, 3, 3> dR1 = q2R(d1.segment(3,4)); //dq1.matrix(); // First Delta, DR - Matrix<typename D2::Scalar, 3, 3> dR2 = q2R(d2.segment(3,4)); //dq2.matrix(); // Second delta, dR + Matrix<typename D1::Scalar, 3, 3> dR1 = q2R(d1.segment(3,4)); //q1.matrix(); // First Delta, DR + Matrix<typename D2::Scalar, 3, 3> dR2 = q2R(d2.segment(3,4)); //q2.matrix(); // Second delta, dR // Jac wrt first delta J_sum_d1.setIdentity(); // dDp'/dDp = dDv'/dDv = I @@ -165,43 +198,75 @@ inline void compose(const MatrixBase<D1>& d1, // Jac wrt second delta J_sum_d2.setIdentity(); // - J_sum_d2.block(0,0,3,3) = dR1; // dDp'/ddp + J_sum_d2.block(0,0,3,3) = dR1; // dDp'/p // J_sum_d2.block(3,3,3,3) = Matrix3d::Identity(); // dDo'/ddo = I // compose deltas -- done here to avoid aliasing when calling with input `d1` and result `sum` referencing the same variable compose(d1, d2, sum); } +inline void compose(const VectorComposite& x1, const VectorComposite& x2, VectorComposite& c) +{ + compose(x1.at("P"), x1.at("O"), x2.at("P"), x2.at("O"), c["P"], c["O"]); +} + +inline void compose(const VectorComposite& x1, + const VectorComposite& x2, + VectorComposite& c, + MatrixComposite& J_c_x1, + MatrixComposite& J_c_x2) +{ + + // Some useful temporaries + const auto R1 = q2R(x1.at("O")); //q1.matrix(); // make temporary + const auto& R2 = q2R(x2.at("O")); //q2.matrix(); // do not make temporary, only reference + + // Jac wrt first delta + J_c_x1.emplace("P", "P", Matrix3d::Identity() ) ; + J_c_x1.emplace("P", "O", - R1 * skew(x2.at("P")) ) ; + J_c_x1.emplace("O", "P", Matrix3d::Zero() ) ; + J_c_x1.emplace("O", "O", R2.transpose() ) ; + + // Jac wrt second delta + J_c_x2.emplace("P", "P", R1 ); + J_c_x2.emplace("P", "O", Matrix3d::Zero() ); + J_c_x2.emplace("O", "P", Matrix3d::Zero() ); + J_c_x2.emplace("O", "O", Matrix3d::Identity() ); + + // compose deltas -- done here to avoid aliasing when calling with input `x1` and result `c` referencing the same variable + compose(x1, x2, c); +} + template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8> -inline void between(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, - const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, - MatrixBase<D7>& dp12, QuaternionBase<D8>& dq12) +inline void between(const MatrixBase<D1>& p1, const QuaternionBase<D2>& q1, + const MatrixBase<D4>& p2, const QuaternionBase<D5>& q2, + MatrixBase<D7>& p12, QuaternionBase<D8>& q12) { - MatrixSizeCheck<3, 1>::check(dp1); - MatrixSizeCheck<3, 1>::check(dp2); - MatrixSizeCheck<3, 1>::check(dp12); + MatrixSizeCheck<3, 1>::check(p1); + MatrixSizeCheck<3, 1>::check(p2); + MatrixSizeCheck<3, 1>::check(p12); - dp12 = dq1.conjugate() * ( dp2 - dp1 ); - dq12 = dq1.conjugate() * dq2; + p12 = q1.conjugate() * ( p2 - p1 ); + q12 = q1.conjugate() * q2; } template<typename D1, typename D2, typename D3> inline void between(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2, - MatrixBase<D3>& d2_minus_d1) + MatrixBase<D3>& d12) { MatrixSizeCheck<7, 1>::check(d1); MatrixSizeCheck<7, 1>::check(d2); - MatrixSizeCheck<7, 1>::check(d2_minus_d1); + MatrixSizeCheck<7, 1>::check(d12); - Map<const Matrix<typename D1::Scalar, 3, 1> > dp1 ( & d1(0) ); - Map<const Quaternion<typename D1::Scalar> > dq1 ( & d1(3) ); - Map<const Matrix<typename D2::Scalar, 3, 1> > dp2 ( & d2(0) ); - Map<const Quaternion<typename D2::Scalar> > dq2 ( & d2(3) ); - Map<Matrix<typename D3::Scalar, 3, 1> > dp12 ( & d2_minus_d1(0) ); - Map<Quaternion<typename D3::Scalar> > dq12 ( & d2_minus_d1(3) ); + Map<const Matrix<typename D1::Scalar, 3, 1> > p1 ( & d1(0) ); + Map<const Quaternion<typename D1::Scalar> > q1 ( & d1(3) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > p2 ( & d2(0) ); + Map<const Quaternion<typename D2::Scalar> > q2 ( & d2(3) ); + Map<Matrix<typename D3::Scalar, 3, 1> > p12 ( & d12(0) ); + Map<Quaternion<typename D3::Scalar> > q12 ( & d12(3) ); - between(dp1, dq1, dp2, dq2, dp12, dq12); + between(p1, q1, p2, q2, p12, q12); } template<typename D1, typename D2> @@ -216,28 +281,28 @@ inline Matrix<typename D1::Scalar, 7, 1> between(const MatrixBase<D1>& d1, } template<typename Derived> -Matrix<typename Derived::Scalar, 6, 1> log_SE3(const MatrixBase<Derived>& delta_in) +inline Matrix<typename Derived::Scalar, 6, 1> log(const MatrixBase<Derived>& delta_in) { MatrixSizeCheck<7, 1>::check(delta_in); Matrix<typename Derived::Scalar, 6, 1> ret; - Map<const Matrix<typename Derived::Scalar, 3, 1> > dp_in ( & delta_in(0) ); - Map<const Quaternion<typename Derived::Scalar> > dq_in ( & delta_in(3) ); - Map<Matrix<typename Derived::Scalar, 3, 1> > dp_ret ( & ret(0) ); + Map<const Matrix<typename Derived::Scalar, 3, 1> > p_in ( & delta_in(0) ); + Map<const Quaternion<typename Derived::Scalar> > q_in ( & delta_in(3) ); + Map<Matrix<typename Derived::Scalar, 3, 1> > p_ret ( & ret(0) ); Map<Matrix<typename Derived::Scalar, 3, 1> > do_ret ( & ret(3) ); Matrix<typename Derived::Scalar, 3, 3> V_inv; - do_ret = log_q(dq_in); + do_ret = log_q(q_in); V_inv = jac_SO3_left_inv(do_ret); - dp_ret = V_inv * dp_in; + p_ret = V_inv * p_in; return ret; } template<typename Derived> -Matrix<typename Derived::Scalar, 7, 1> exp_SE3(const MatrixBase<Derived>& d_in) +inline Matrix<typename Derived::Scalar, 7, 1> exp(const MatrixBase<Derived>& d_in) { MatrixSizeCheck<6, 1>::check(d_in); @@ -247,27 +312,58 @@ Matrix<typename Derived::Scalar, 7, 1> exp_SE3(const MatrixBase<Derived>& d_in) V = jac_SO3_left(d_in.template tail<3>()); - Map<const Matrix<typename Derived::Scalar, 3, 1> > dp_in ( & d_in(0) ); - Map<const Matrix<typename Derived::Scalar, 3, 1> > do_in ( & d_in(3) ); - Map<Matrix<typename Derived::Scalar, 3, 1> > dp ( & ret(0) ); - Map<Quaternion<typename Derived::Scalar> > dq ( & ret(3) ); + Map<const Matrix<typename Derived::Scalar, 3, 1> > p_in ( & d_in(0) ); + Map<const Matrix<typename Derived::Scalar, 3, 1> > o_in ( & d_in(3) ); + Map<Matrix<typename Derived::Scalar, 3, 1> > p ( & ret(0) ); + Map<Quaternion<typename Derived::Scalar> > q ( & ret(3) ); - dp = V * dp_in; - dq = exp_q(do_in); + p = V * p_in; + q = exp_q(o_in); return ret; } +inline VectorComposite exp(const VectorComposite& tau) +{ + const auto& p = tau.at("P"); + const auto& theta = tau.at("O"); + + Matrix3d V = jac_SO3_left(theta); // see [1] eqs. (174) and (145) + + VectorComposite res; + + res["P"] = V * p ; + res["O"] = exp_q(theta).coeffs() ; + + return res; +} + template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8> -inline void plus(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, - const MatrixBase<D4>& dp2, const MatrixBase<D5>& do2, +inline void plus(const MatrixBase<D1>& p1, const QuaternionBase<D2>& q1, + const MatrixBase<D4>& p2, const MatrixBase<D5>& o2, MatrixBase<D7>& plus_p, QuaternionBase<D8>& plus_q) { - MatrixSizeCheck<3, 1>::check(dp1); - MatrixSizeCheck<3, 1>::check(dp2); + MatrixSizeCheck<3, 1>::check(p1); + MatrixSizeCheck<3, 1>::check(p2); + MatrixSizeCheck<3, 1>::check(o2); MatrixSizeCheck<3, 1>::check(plus_p); - plus_p = dp1 + dp2; - plus_q = dq1 * exp_q(do2); + + plus_p = p1 + p2; + plus_q = q1 * exp_q(o2); +} + +template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8> +inline void plus(const MatrixBase<D1>& p1, const MatrixBase<D2>& q1, + const MatrixBase<D4>& p2, const MatrixBase<D5>& o2, + MatrixBase<D7>& plus_p, MatrixBase<D8>& plus_q) +{ + MatrixSizeCheck<4, 1>::check(q1); + MatrixSizeCheck<4, 1>::check(plus_q); + + Map<const Quaterniond> q1m ( & q1 (0) ); + Map<Quaterniond> plus_qm ( & plus_q(0) ); + + plus(p1, q1m, p2, o2, plus_p, plus_qm); } template<typename D1, typename D2, typename D3> @@ -275,14 +371,14 @@ inline void plus(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2, MatrixBase<D3>& d_plus) { - Map<const Matrix<typename D1::Scalar, 3, 1> > dp1 ( & d1(0) ); - Map<const Quaternion<typename D1::Scalar> > dq1 ( & d1(3) ); - Map<const Matrix<typename D2::Scalar, 3, 1> > dp2 ( & d2(0) ); - Map<const Matrix<typename D2::Scalar, 3, 1> > do2 ( & d2(3) ); - Map<Matrix<typename D3::Scalar, 3, 1> > dp_p ( & d_plus(0) ); - Map<Quaternion<typename D3::Scalar> > dq_p ( & d_plus(3) ); - - plus(dp1, dq1, dp2, do2, dp_p, dq_p); + Map<const Matrix<typename D1::Scalar, 3, 1> > p1 ( & d1(0) ); + Map<const Quaternion<typename D1::Scalar> > q1 ( & d1(3) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > p2 ( & d2(0) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > o2 ( & d2(3) ); + Map<Matrix<typename D3::Scalar, 3, 1> > p_p ( & d_plus(0) ); + Map<Quaternion<typename D3::Scalar> > q_p ( & d_plus(3) ); + + plus(p1, q1, p2, o2, p_p, q_p); } template<typename D1, typename D2> @@ -294,25 +390,42 @@ inline Matrix<typename D1::Scalar, 7, 1> plus(const MatrixBase<D1>& d1, return d_plus; } +inline void plus(const VectorComposite& x, const VectorComposite& tau, VectorComposite& res) +{ + plus(x.at("P"), x.at("O"), tau.at("P"), tau.at("O"), res.at("P"), res.at("O")); +} + +inline VectorComposite plus(const VectorComposite& x, const VectorComposite& tau) +{ + VectorComposite res; + + res["P"] = Vector3d(); + res["O"] = Vector4d(); + + plus(x, tau, res); + + return res; +} + template<typename D1, typename D2, typename D4, typename D5, typename D7, typename D8> -inline void minus(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, - const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, - MatrixBase<D7>& diff_p, MatrixBase<D8>& diff_o ) +inline void minus(const MatrixBase<D1>& p1, const QuaternionBase<D2>& q1, + const MatrixBase<D4>& p2, const QuaternionBase<D5>& q2, + MatrixBase<D7>& pd, MatrixBase<D8>& od ) { - diff_p = dp2 - dp1; - diff_o = log_q(dq1.conjugate() * dq2); + pd = p2 - p1; + od = log_q(q1.conjugate() * q2); } template<typename D1, typename D2, typename D4, typename D5, typename D6, typename D7, typename D8, typename D9> -inline void minus(const MatrixBase<D1>& dp1, const QuaternionBase<D2>& dq1, - const MatrixBase<D4>& dp2, const QuaternionBase<D5>& dq2, - MatrixBase<D6>& diff_p, MatrixBase<D7>& diff_o, - MatrixBase<D8>& J_do_dq1, MatrixBase<D9>& J_do_dq2) +inline void minus(const MatrixBase<D1>& p1, const QuaternionBase<D2>& q1, + const MatrixBase<D4>& p2, const QuaternionBase<D5>& q2, + MatrixBase<D6>& pd, MatrixBase<D7>& od, + MatrixBase<D8>& J_do_q1, MatrixBase<D9>& J_do_q2) { - minus(dp1, dq1, dp2, dq2, diff_p, diff_o); + minus(p1, q1, p2, q2, pd, od); - J_do_dq1 = - jac_SO3_left_inv(diff_o); - J_do_dq2 = jac_SO3_right_inv(diff_o); + J_do_q1 = - jac_SO3_left_inv(od); + J_do_q2 = jac_SO3_right_inv(od); } template<typename D1, typename D2, typename D3> @@ -320,14 +433,14 @@ inline void minus(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2, MatrixBase<D3>& err) { - Map<const Matrix<typename D1::Scalar, 3, 1> > dp1 ( & d1(0) ); - Map<const Quaternion<typename D1::Scalar> > dq1 ( & d1(3) ); - Map<const Matrix<typename D2::Scalar, 3, 1> > dp2 ( & d2(0) ); - Map<const Quaternion<typename D2::Scalar> > dq2 ( & d2(3) ); - Map<Matrix<typename D3::Scalar, 3, 1> > diff_p ( & err(0) ); - Map<Matrix<typename D3::Scalar, 3, 1> > diff_o ( & err(3) ); - - minus(dp1, dq1, dp2, dq2, diff_p, diff_o); + Map<const Matrix<typename D1::Scalar, 3, 1> > p1 ( & d1(0) ); + Map<const Quaternion<typename D1::Scalar> > q1 ( & d1(3) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > p2 ( & d2(0) ); + Map<const Quaternion<typename D2::Scalar> > q2 ( & d2(3) ); + Map<Matrix<typename D3::Scalar, 3, 1> > pd ( & err(0) ); + Map<Matrix<typename D3::Scalar, 3, 1> > od ( & err(3) ); + + minus(p1, q1, p2, q2, pd, od); } template<typename D1, typename D2, typename D3, typename D4, typename D5> @@ -337,35 +450,30 @@ inline void minus(const MatrixBase<D1>& d1, MatrixBase<D4>& J_diff_d1, MatrixBase<D5>& J_diff_d2) { - Map<const Matrix<typename D1::Scalar, 3, 1> > dp1 ( & d1(0) ); - Map<const Quaternion<typename D1::Scalar> > dq1 ( & d1(3) ); - Map<const Matrix<typename D1::Scalar, 3, 1> > dv1 ( & d1(7) ); - Map<const Matrix<typename D2::Scalar, 3, 1> > dp2 ( & d2(0) ); - Map<const Quaternion<typename D2::Scalar> > dq2 ( & d2(3) ); - Map<const Matrix<typename D2::Scalar, 3, 1> > dv2 ( & d2(7) ); - Map<Matrix<typename D3::Scalar, 3, 1> > diff_p ( & dif(0) ); - Map<Matrix<typename D3::Scalar, 3, 1> > diff_o ( & dif(3) ); - Map<Matrix<typename D3::Scalar, 3, 1> > diff_v ( & dif(6) ); + Map<const Matrix<typename D1::Scalar, 3, 1> > p1 ( & d1(0) ); + Map<const Quaternion<typename D1::Scalar> > q1 ( & d1(3) ); + Map<const Matrix<typename D2::Scalar, 3, 1> > p2 ( & d2(0) ); + Map<const Quaternion<typename D2::Scalar> > q2 ( & d2(3) ); + Map<Matrix<typename D3::Scalar, 3, 1> > pd ( & dif(0) ); + Map<Matrix<typename D3::Scalar, 3, 1> > od ( & dif(3) ); - Matrix<typename D4::Scalar, 3, 3> J_do_dq1, J_do_dq2; + Matrix<typename D4::Scalar, 3, 3> J_do_q1, J_do_q2; - minus(dp1, dq1, dv1, dp2, dq2, dv2, diff_p, diff_o, diff_v, J_do_dq1, J_do_dq2); + minus(p1, q1, p2, q2, pd, od, J_do_q1, J_do_q2); /* d = minus(d1, d2) is - * dp = dp2 - dp1 - * do = Log(dq1.conj * dq2) - * dv = dv2 - dv1 + * pd = p2 - p1 + * od = Log(q1.conj * q2) * - * With trivial Jacobians for dp and dv, and: - * J_do_dq1 = - J_l_inv(theta) - * J_do_dq2 = J_r_inv(theta) + * With trivial Jacobians for p and dv, and: + * J_do_q1 = - J_l_inv(theta) + * J_do_q2 = J_r_inv(theta) */ - J_diff_d1 = - Matrix<typename D4::Scalar, 6, 6>::Identity();// d(p2 - p1) / d(p1) = - Identity - J_diff_d1.block(3,3,3,3) = J_do_dq1; // d(R1.tr*R2) / d(R1) = - J_l_inv(theta) + J_diff_d1.block(3,3,3,3) = J_do_q1; // d(R1.tr*R2) / d(R1) = - J_l_inv(theta) J_diff_d2.setIdentity(6,6); // d(R1.tr*R2) / d(R2) = Identity - J_diff_d2.block(3,3,3,3) = J_do_dq2; // d(R1.tr*R2) / d(R1) = J_r_inv(theta) + J_diff_d2.block(3,3,3,3) = J_do_q2; // d(R1.tr*R2) / d(R1) = J_r_inv(theta) } template<typename D1, typename D2> @@ -385,9 +493,9 @@ inline void interpolate(const MatrixBase<D1>& d1, { Matrix<typename D1::Scalar, 7, 1> dd = between(d1, d2); - Matrix<typename D1::Scalar, 6, 1> tau = t * log_SE3(dd); + Matrix<typename D1::Scalar, 6, 1> tau = t * log(dd); - ret = compose(d1, exp_SE3(tau)); + ret = compose(d1, exp(tau)); } template<typename D1, typename D2> diff --git a/include/core/math/rotations.h b/include/core/math/rotations.h index 7c2ede927a796adfd35e7dd9240e0128f1192c11..a0a86c6ee4c3ef095725a2df2230c2fdb8de751f 100644 --- a/include/core/math/rotations.h +++ b/include/core/math/rotations.h @@ -27,7 +27,7 @@ pi2pi(const T _angle) T angle = _angle; while (angle > T( M_PI )) angle -= T( 2 * M_PI ); - while (angle < T( -M_PI )) + while (angle <= T( -M_PI )) angle += T( 2 * M_PI ); return angle; diff --git a/include/core/problem/problem.h b/include/core/problem/problem.h index f2b19ef05c22f7a4c6777f889031dbda45d80a5b..f64f629056e3c5c52abc41818f049dc14b876438 100644 --- a/include/core/problem/problem.h +++ b/include/core/problem/problem.h @@ -11,7 +11,7 @@ class ProcessorMotion; class StateBlock; class TimeStamp; struct ParamsSensorBase; -struct ProcessorParamsBase; +struct ParamsProcessorBase; } //wolf includes @@ -19,9 +19,10 @@ struct ProcessorParamsBase; #include "core/frame/frame_base.h" #include "core/state_block/state_block.h" #include "core/utils/params_server.h" -#include "core/sensor/sensor_factory.h" -#include "core/processor/processor_factory.h" +#include "core/sensor/factory_sensor.h" +#include "core/processor/factory_processor.h" #include "core/processor/is_motion.h" +#include "core/state_block/state_composite.h" // std includes #include <mutex> @@ -34,6 +35,15 @@ enum Notification REMOVE }; +struct PriorOptions +{ + std::string mode = ""; + VectorComposite state; + MatrixComposite cov; + double time_tolerance; +}; +WOLF_STRUCT_PTR_TYPEDEFS(PriorOptions); + /** \brief Wolf problem node element in the Wolf Tree */ class Problem : public std::enable_shared_from_this<Problem> @@ -41,8 +51,10 @@ class Problem : public std::enable_shared_from_this<Problem> friend SolverManager; // Enable SolverManager to acces protected functions (consumeXXXNotificationMap()) friend ProcessorBase; friend ProcessorMotion; + friend IsMotion; protected: + TreeManagerBasePtr tree_manager_; HardwareBasePtr hardware_ptr_; TrajectoryBasePtr trajectory_ptr_; MapBasePtr map_ptr_; @@ -51,11 +63,10 @@ class Problem : public std::enable_shared_from_this<Problem> SizeEigen state_size_, state_cov_size_, dim_; std::map<FactorBasePtr, Notification> factor_notification_map_; std::map<StateBlockPtr, Notification> state_block_notification_map_; - mutable std::mutex mut_factor_notifications_; - mutable std::mutex mut_state_block_notifications_; + mutable std::mutex mut_notifications_; mutable std::mutex mut_covariances_; - bool prior_is_set_; - std::string frame_structure_; + StateStructure frame_structure_; + PriorOptionsPtr prior_options_; private: // CAUTION: THESE METHODS ARE PRIVATE, DO NOT MAKE THEM PUBLIC !! Problem(const std::string& _frame_structure); // USE create() below !! @@ -67,11 +78,26 @@ class Problem : public std::enable_shared_from_this<Problem> static ProblemPtr autoSetup(ParamsServer &_server); virtual ~Problem(); + + // Properties ----------------------------------------- - SizeEigen getFrameStructureSize() const; - void getFrameStructureSize(SizeEigen& _x_size, SizeEigen& _cov_size) const; + public: SizeEigen getDim() const; - std::string getFrameStructure() const; + StateStructure getFrameStructure() const; + + protected: + void appendToStructure(const StateStructure& _structure); + + + + + // Tree manager -------------------------------------- + public: + void setTreeManager(TreeManagerBasePtr _gm); + TreeManagerBasePtr getTreeManager() const; + + + // Hardware branch ------------------------------------ HardwareBasePtr getHardware() const; @@ -91,7 +117,7 @@ class Problem : public std::enable_shared_from_this<Problem> * \param _sen_type type of sensor * \param _unique_sensor_name unique sensor name, used to identify the particular instance of the sensor * \param _extrinsics a vector of extrinsic parameters: size 2 for 2d position, 3 for 2d pose, 3 for 3d position, 7 for 3d pose. - * \param _intrinsics_filename the name of a file containing the intrinsic parameters in a format compatible with the intrinsics creator registered in ParamsSensorFactory under the key _sen_type. + * \param _intrinsics_filename the name of a file containing the intrinsic parameters in a format compatible with the intrinsics creator registered in FactoryParamsSensor under the key _sen_type. */ SensorBasePtr installSensor(const std::string& _sen_type, // const std::string& _unique_sensor_name, // @@ -119,7 +145,7 @@ class Problem : public std::enable_shared_from_this<Problem> ProcessorBasePtr installProcessor(const std::string& _prc_type, // const std::string& _unique_processor_name, // SensorBasePtr _corresponding_sensor_ptr, // - ProcessorParamsBasePtr _prc_params = nullptr); + ParamsProcessorBasePtr _prc_params = nullptr); /** \brief Factory method to install (create, and add to sensor) processors only from its properties * @@ -155,51 +181,91 @@ class Problem : public std::enable_shared_from_this<Problem> IsMotionPtr getProcessorIsMotion(); std::list<IsMotionPtr> getProcessorIsMotionList(); + + + // Trajectory branch ---------------------------------- TrajectoryBasePtr getTrajectory() const; - virtual FrameBasePtr setPrior(const Eigen::VectorXd& _prior_state, // - const Eigen::MatrixXd& _prior_cov, // - const TimeStamp& _ts, - const double _time_tolerance); - /** \brief Emplace frame from string frame_structure + // Prior + bool isPriorSet() const; + void setPriorOptions(const std::string& _mode, + const double _time_tolerance = 0, + const VectorComposite& _state = VectorComposite(), + const VectorComposite& _cov = VectorComposite()); + FrameBasePtr applyPriorOptions(const TimeStamp& _ts); + FrameBasePtr setPriorFactor(const VectorComposite &_state, + const VectorComposite &_sigma, + const TimeStamp &_ts, + const double &_time_tol); + FrameBasePtr setPriorFix(const VectorComposite &_state, + const TimeStamp &_ts, + const double &_time_tol); + FrameBasePtr setPriorInitialGuess(const VectorComposite &_state, + const TimeStamp &_ts, + const double &_time_tol); + + /** \brief Emplace frame from string frame_structure, dimension and vector + * \param _frame_key_type Either KEY, AUXILIARY or NON_ESTIMATED + * \param _time_stamp Time stamp of the frame * \param _frame_structure String indicating the frame structure. * \param _dim variable indicating the dimension of the problem - * \param _frame_key_type Either KEY, AUXILIARY or NON_ESTIMATED * \param _frame_state State vector; must match the size and format of the chosen frame structure - * \param _time_stamp Time stamp of the frame * * This acts as a Frame factory, but also takes care to update related lists in WolfProblem: * - Create a Frame * - Add it to Trajectory * - If it is key-frame, update state-block lists in Problem */ - FrameBasePtr emplaceFrame(const std::string& _frame_structure, // + FrameBasePtr emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const StateStructure& _frame_structure, // const SizeEigen _dim, // - FrameType _frame_key_type, // - const Eigen::VectorXd& _frame_state, // - const TimeStamp& _time_stamp); + const Eigen::VectorXd& _frame_state); - /** \brief Emplace frame from string frame_structure without state + /** \brief Emplace frame from string frame_structure and state + * \param _frame_key_type Either KEY, AUXILIARY or NON_ESTIMATED + * \param _time_stamp Time stamp of the frame * \param _frame_structure String indicating the frame structure. - * \param _dim variable indicating the dimension of the problem + * \param _frame_state State vector; must match the size and format of the chosen frame structure + * + * - The dimension is taken from Problem + * + * This acts as a Frame factory, but also takes care to update related lists in WolfProblem: + * - Create a Frame + * - Add it to Trajectory + * - If it is key-frame, update state-block lists in Problem + */ + FrameBasePtr emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const StateStructure& _frame_structure, // + const VectorComposite& _frame_state); + + /** \brief Emplace frame from state * \param _frame_key_type Either KEY, AUXILIARY or NON_ESTIMATED * \param _time_stamp Time stamp of the frame + * \param _frame_state State; must be part of the problem's frame structure + * + * - The structure is taken from Problem + * - The dimension is taken from Problem * * This acts as a Frame factory, but also takes care to update related lists in WolfProblem: * - Create a Frame * - Add it to Trajectory * - If it is key-frame, update state-block lists in Problem */ - FrameBasePtr emplaceFrame(const std::string& _frame_structure, // - const SizeEigen _dim, // - FrameType _frame_key_type, // - const TimeStamp& _time_stamp); + FrameBasePtr emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const VectorComposite& _frame_state); - /** \brief Emplace frame from string frame_structure without structure + /** \brief Emplace frame from string frame_structure and dimension * \param _frame_key_type Either KEY, AUXILIARY or NON_ESTIMATED - * \param _frame_state State vector; must match the size and format of the chosen frame structure * \param _time_stamp Time stamp of the frame + * \param _frame_structure String indicating the frame structure. + * \param _dim variable indicating the dimension of the problem + * + * - The dimension is taken from Problem + * - The state is taken from Problem * * This acts as a Frame factory, but also takes care to update related lists in WolfProblem: * - Create a Frame @@ -207,12 +273,34 @@ class Problem : public std::enable_shared_from_this<Problem> * - If it is key-frame, update state-block lists in Problem */ FrameBasePtr emplaceFrame(FrameType _frame_key_type, // - const Eigen::VectorXd& _frame_state, // - const TimeStamp& _time_stamp); + const TimeStamp& _time_stamp, // + const StateStructure& _frame_structure, // + const SizeEigen _dim); - /** \brief Emplace frame from string frame_structure without structure nor state + /** \brief Emplace frame from state vector * \param _frame_key_type Either KEY, AUXILIARY or NON_ESTIMATED * \param _time_stamp Time stamp of the frame + * \param _frame_state State vector; must match the size and format of the chosen frame structure + * + * - The structure is taken from Problem + * - The dimension is taken from Problem + * + * This acts as a Frame factory, but also takes care to update related lists in WolfProblem: + * - Create a Frame + * - Add it to Trajectory + * - If it is key-frame, update state-block lists in Problem + */ + FrameBasePtr emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const Eigen::VectorXd& _frame_state); + + /** \brief Emplace frame, guess all values + * \param _frame_key_type Either KEY, AUXILIARY or NON_ESTIMATED + * \param _time_stamp Time stamp of the frame + * + * - The structure is taken from Problem + * - The dimension is taken from Problem + * - The state is taken from Problem * * This acts as a Frame factory, but also takes care to update related lists in WolfProblem: * - Create a Frame @@ -262,17 +350,15 @@ class Problem : public std::enable_shared_from_this<Problem> const double& _time_tolerance); // State getters - Eigen::VectorXd getCurrentState ( ) const; - void getCurrentState (Eigen::VectorXd& _state) const; - void getCurrentStateAndStamp (Eigen::VectorXd& _state, TimeStamp& _ts) const; - Eigen::VectorXd getState (const TimeStamp& _ts) const; - void getState (const TimeStamp& _ts, Eigen::VectorXd& _state) const; + TimeStamp getTimeStamp ( ) const; + VectorComposite getState ( const StateStructure& _structure = "" ) const; + VectorComposite getState ( const TimeStamp& _ts, const StateStructure& _structure = "" ) const; + // Zero state provider - Eigen::VectorXd zeroState ( ) const; - bool priorIsSet() const; - void setPriorIsSet(bool _prior_is_set); - // Perturb state - void perturb(double amplitude = 0.01); + VectorComposite stateZero ( const StateStructure& _structure = "" ) const; + + + // Map branch ----------------------------------------- MapBasePtr getMap() const; @@ -280,7 +366,13 @@ class Problem : public std::enable_shared_from_this<Problem> void saveMap(const std::string& _filename_dot_yaml, // const std::string& _map_name = "Map automatically saved by Wolf"); - // Covariances ------------------------------------------- + + + // All branches ------------------------------------------- + // perturb states + void perturb(double amplitude = 0.01); + + // Covariances void clearCovariance(); void addCovarianceBlock(StateBlockPtr _state1, StateBlockPtr _state2, const Eigen::MatrixXd& _cov); void addCovarianceBlock(StateBlockPtr _state1, const Eigen::MatrixXd& _cov); @@ -292,6 +384,8 @@ class Problem : public std::enable_shared_from_this<Problem> bool getLastKeyOrAuxFrameCovariance(Eigen::MatrixXd& _covariance) const; bool getLandmarkCovariance(LandmarkBaseConstPtr _landmark_ptr, Eigen::MatrixXd& _covariance) const; + + // Solver management ---------------------------------------- /** \brief Notifies a new/removed state block to update the solver manager @@ -319,6 +413,11 @@ class Problem : public std::enable_shared_from_this<Problem> bool getFactorNotification(const FactorBasePtr& fac_ptr, Notification& notif) const; protected: + /** \brief Returns the map of state block notification to be handled by the solver (the map stored in this is emptied) + */ + void consumeNotifications(std::map<StateBlockPtr,Notification>&, + std::map<FactorBasePtr,Notification>&); + /** \brief Returns the map of state block notification to be handled by the solver (the map stored in this is emptied) */ std::map<StateBlockPtr,Notification> consumeStateBlockNotificationMap(); @@ -329,11 +428,6 @@ class Problem : public std::enable_shared_from_this<Problem> public: // Print and check --------------------------------------- - void print(int depth, // - std::ostream& stream , - bool constr_by, // - bool metric, // - bool state_blocks) const; /** * \brief print wolf tree * \param depth : levels to show ( 0: H, T, M : 1: H:S:p, T:F, M:L ; 2: T:F:C ; 3: T:F:C:f ; 4: T:F:C:f:c ) @@ -344,11 +438,8 @@ class Problem : public std::enable_shared_from_this<Problem> void print(int depth = 4, // bool constr_by = false, // bool metric = true, // - bool state_blocks = false) const; - void print(const std::string& depth, // - bool constr_by = false, // - bool metric = true, // - bool state_blocks = false) const; + bool state_blocks = false, + std::ostream& stream = std::cout) const; bool check(int verbose_level = 0) const; bool check(bool verbose, std::ostream& stream) const; @@ -361,14 +452,14 @@ class Problem : public std::enable_shared_from_this<Problem> namespace wolf { -inline bool Problem::priorIsSet() const +inline TreeManagerBasePtr Problem::getTreeManager() const { - return prior_is_set_; + return tree_manager_; } -inline void Problem::setPriorIsSet(bool _prior_is_set) +inline bool Problem::isPriorSet() const { - prior_is_set_ = _prior_is_set; + return prior_options_ == nullptr; } inline IsMotionPtr Problem::getProcessorIsMotion() @@ -384,28 +475,25 @@ inline std::list<IsMotionPtr> Problem::getProcessorIsMotionList() return processor_is_motion_list_; } -inline std::map<StateBlockPtr,Notification> Problem::consumeStateBlockNotificationMap() -{ - std::lock_guard<std::mutex> lock(mut_state_block_notifications_); - return std::move(state_block_notification_map_); -} - inline SizeStd Problem::getStateBlockNotificationMapSize() const { - std::lock_guard<std::mutex> lock(mut_state_block_notifications_); + std::lock_guard<std::mutex> lock(mut_notifications_); return state_block_notification_map_.size(); } -inline std::map<FactorBasePtr,Notification> Problem::consumeFactorNotificationMap() +inline wolf::SizeStd Problem::getFactorNotificationMapSize() const { - std::lock_guard<std::mutex> lock(mut_factor_notifications_); - return std::move(factor_notification_map_); + std::lock_guard<std::mutex> lock(mut_notifications_); + return factor_notification_map_.size(); } -inline wolf::SizeStd Problem::getFactorNotificationMapSize() const +inline void Problem::consumeNotifications(std::map<StateBlockPtr,Notification>& _sb_notification_map, + std::map<FactorBasePtr,Notification>& _fac_notification_map) { - std::lock_guard<std::mutex> lock(mut_factor_notifications_); - return factor_notification_map_.size(); + std::lock_guard<std::mutex> lock(mut_notifications_); + + _sb_notification_map = std::move(state_block_notification_map_); + _fac_notification_map = std::move(factor_notification_map_); } } // namespace wolf diff --git a/include/core/processor/processor_factory.h b/include/core/processor/factory_processor.h similarity index 74% rename from include/core/processor/processor_factory.h rename to include/core/processor/factory_processor.h index c14f3daa364678ef6f549fa04f65eddb4885e1fd..5fc2f8f14ccffc52653c6f43fa0c07fdb03be825 100644 --- a/include/core/processor/processor_factory.h +++ b/include/core/processor/factory_processor.h @@ -1,17 +1,17 @@ /** - * \file processor_factory.h + * \file factory_processor.h * * Created on: May 4, 2016 * \author: jsola */ -#ifndef PROCESSOR_FACTORY_H_ -#define PROCESSOR_FACTORY_H_ +#ifndef FACTORY_PROCESSOR_H_ +#define FACTORY_PROCESSOR_H_ namespace wolf { class ProcessorBase; -struct ProcessorParamsBase; +struct ParamsProcessorBase; } // wolf @@ -47,17 +47,17 @@ namespace wolf * - Write a processor creator for ProcessorOdom2d (example). * * #### Accessing the Factory - * The ProcessorFactory class is a singleton: it can only exist once in your application. + * The FactoryProcessor class is a singleton: it can only exist once in your application. * To obtain an instance of it, use the static method get(), * * \code - * ProcessorFactory::get() + * FactoryProcessor::get() * \endcode * * You can then call the methods you like, e.g. to create a processor, you type: * * \code - * ProcessorFactory::get().create(...); // see below for creating processors ... + * FactoryProcessor::get().create(...); // see below for creating processors ... * \endcode * * #### Registering processor creators @@ -69,21 +69,21 @@ namespace wolf * that knows how to create your specific processor, e.g.: * * \code - * ProcessorFactory::get().registerCreator("ProcessorOdom2d", ProcessorOdom2d::create); + * FactoryProcessor::get().registerCreator("ProcessorOdom2d", ProcessorOdom2d::create); * \endcode * * The method ProcessorOdom2d::create() exists in the ProcessorOdom2d class as a static method. * All these ProcessorXxx::create() methods need to have exactly the same API, regardless of the processor type. - * This API includes a processor name, and a pointer to a base struct of parameters, ProcessorParamsBasePtr, + * This API includes a processor name, and a pointer to a base struct of parameters, ParamsProcessorBasePtr, * that can be derived for each derived processor. * * Here is an example of ProcessorOdom2d::create() extracted from processor_odom_2d.h: * * \code - * static ProcessorBasePtr create(const std::string& _name, ProcessorParamsBasePtr _params) + * static ProcessorBasePtr create(const std::string& _name, ParamsProcessorBasePtr _params) * { * // cast _params to good type - * ProcessorParamsOdom2d* params = (ProcessorParamsOdom2d*)_params; + * ParamsProcessorOdom2d* params = (ParamsProcessorOdom2d*)_params; * * ProcessorBasePtr prc = new ProcessorOdom2d(params); * prc->setName(_name); // pass the name to the created ProcessorOdom2d. @@ -96,7 +96,7 @@ namespace wolf * For example, in processor_odom_2d.cpp we find the line: * * \code - * const bool registered_odom_2d = ProcessorFactory::get().registerCreator("ProcessorOdom2d", ProcessorOdom2d::create); + * const bool registered_odom_2d = FactoryProcessor::get().registerCreator("ProcessorOdom2d", ProcessorOdom2d::create); * \endcode * * which is a static invocation (i.e., it is placed at global scope outside of the ProcessorOdom2d class). @@ -107,7 +107,7 @@ namespace wolf * It only needs to be passed the string of the processor type. * * \code - * ProcessorFactory::get().unregisterCreator("ProcessorOdom2d"); + * FactoryProcessor::get().unregisterCreator("ProcessorOdom2d"); * \endcode * * #### Creating processors @@ -117,7 +117,7 @@ namespace wolf * To create a ProcessorOdom2d, you type: * * \code - * ProcessorFactory::get().create("ProcessorOdom2d", "main odometry", params_ptr); + * FactoryProcessor::get().create("ProcessorOdom2d", "main odometry", params_ptr); * \endcode * * #### Example 1 : using the Factories alone @@ -125,21 +125,21 @@ namespace wolf * and bind it to a SensorOdom2d: * * \code - * #include "core/sensor/sensor_odom_2d.h" // provides SensorOdom2d and SensorFactory - * #include "core/processor/processor_odom_2d.h" // provides ProcessorOdom2d and ProcessorFactory + * #include "core/sensor/sensor_odom_2d.h" // provides SensorOdom2d and FactorySensor + * #include "core/processor/processor_odom_2d.h" // provides ProcessorOdom2d and FactoryProcessor * * // Note: SensorOdom2d::create() is already registered, automatically. * // Note: ProcessorOdom2d::create() is already registered, automatically. * - * // First create the sensor (See SensorFactory for details) - * SensorBasePtr sensor_ptr = SensorFactory::get().create ( "FactorOdom2d" , "Main odometer" , extrinsics , &intrinsics ); + * // First create the sensor (See FactorySensor for details) + * SensorBasePtr sensor_ptr = FactorySensor::get().create ( "FactorOdom2d" , "Main odometer" , extrinsics , &intrinsics ); * * // To create a odometry integrator, provide a type="ODOM 2d", a name="main odometry", and a pointer to the parameters struct: * - * ProcessorParamsOdom2d params({...}); // fill in the derived struct (note: ProcessorOdom2d actually has no input params) + * ParamsProcessorOdom2d params({...}); // fill in the derived struct (note: ProcessorOdom2d actually has no input params) * * ProcessorBasePtr processor_ptr = - * ProcessorFactory::get().create ( "ProcessorOdom2d" , "main odometry" , ¶ms ); + * FactoryProcessor::get().create ( "ProcessorOdom2d" , "main odometry" , ¶ms ); * * // Bind processor to sensor * sensor_ptr->addProcessor(processor_ptr); @@ -165,43 +165,43 @@ namespace wolf * You can also check the code in the example file ````src/examples/test_wolf_factories.cpp````. */ -// ProcessorParams factory -struct ProcessorParamsBase; -typedef Factory<ProcessorParamsBase, - const std::string&> ProcessorParamsFactory; +// ParamsProcessor factory +struct ParamsProcessorBase; +typedef Factory<ParamsProcessorBase, + const std::string&> FactoryParamsProcessor; template<> -inline std::string ProcessorParamsFactory::getClass() +inline std::string FactoryParamsProcessor::getClass() const { - return "ProcessorParamsFactory"; + return "FactoryParamsProcessor"; } // Processor factory typedef Factory<ProcessorBase, const std::string&, - const ProcessorParamsBasePtr> ProcessorFactory; + const ParamsProcessorBasePtr> FactoryProcessor; template<> -inline std::string ProcessorFactory::getClass() +inline std::string FactoryProcessor::getClass() const { - return "ProcessorFactory"; + return "FactoryProcessor"; } -#define WOLF_REGISTER_PROCESSOR(ProcessorType, ProcessorName) \ - namespace{ const bool WOLF_UNUSED ProcessorName##Registered = \ - wolf::ProcessorFactory::get().registerCreator(ProcessorType, ProcessorName::create); } \ +#define WOLF_REGISTER_PROCESSOR(ProcessorType) \ + namespace{ const bool WOLF_UNUSED ProcessorType##Registered = \ + wolf::FactoryProcessor::get().registerCreator(#ProcessorType, ProcessorType::create); } \ typedef Factory<ProcessorBase, const std::string&, - const ParamsServer&> AutoConfProcessorFactory; + const ParamsServer&> AutoConfFactoryProcessor; template<> -inline std::string AutoConfProcessorFactory::getClass() +inline std::string AutoConfFactoryProcessor::getClass() const { - return "AutoConfProcessorFactory"; + return "AutoConfFactoryProcessor"; } -#define WOLF_REGISTER_PROCESSOR_AUTO(ProcessorType, ProcessorName) \ - namespace{ const bool WOLF_UNUSED ProcessorName##AutoConfRegistered = \ - wolf::AutoConfProcessorFactory::get().registerCreator(ProcessorType, ProcessorName::create); } \ +#define WOLF_REGISTER_PROCESSOR_AUTO(ProcessorType) \ + namespace{ const bool WOLF_UNUSED ProcessorType##AutoConfRegistered = \ + wolf::AutoConfFactoryProcessor::get().registerCreator(#ProcessorType, ProcessorType::create); } \ } /* namespace wolf */ diff --git a/include/core/processor/is_motion.h b/include/core/processor/is_motion.h index 8c99fe72e37698a2210e35a3af0c14bf9168f65e..2f725e18d723463e810441c83f7fc81acc206785 100644 --- a/include/core/processor/is_motion.h +++ b/include/core/processor/is_motion.h @@ -9,6 +9,7 @@ #define PROCESSOR_IS_MOTION_H_ #include "core/common/wolf.h" +#include "core/state_block/state_composite.h" namespace wolf { @@ -24,28 +25,14 @@ class IsMotion virtual ~IsMotion(); // Queries to the processor: - - /** \brief Fill a reference to the state integrated so far - * \param _x the returned state vector - */ - virtual void getCurrentState(Eigen::VectorXd& _x) const = 0; - virtual void getCurrentTimeStamp(TimeStamp& _ts) const = 0; - /** \brief Fill the state corresponding to the provided time-stamp - * \param _ts the time stamp - * \param _x the returned state - * \return if state in the provided time-stamp could be resolved - */ - virtual bool getState(const TimeStamp& _ts, Eigen::VectorXd& _x) const = 0; - - - // Overloaded getters - Eigen::VectorXd getCurrentState() const; - TimeStamp getCurrentTimeStamp() const; - Eigen::VectorXd getState(const TimeStamp& _ts) const; + virtual TimeStamp getTimeStamp() const = 0; + virtual VectorComposite getState() const = 0; + virtual VectorComposite getState(const TimeStamp& _ts) const = 0; std::string getStateStructure(){return state_structure_;}; void setStateStructure(std::string _state_structure){state_structure_ = _state_structure;}; - + void addToProblem(ProblemPtr _prb_ptr, IsMotionPtr _motion_ptr); + protected: std::string state_structure_; ///< The structure of the state vector (to retrieve state blocks from frames) @@ -62,29 +49,6 @@ inline IsMotion::~IsMotion() { } -inline Eigen::VectorXd IsMotion::getCurrentState() const -{ - Eigen::VectorXd x; - getCurrentState(x); - return x; -} - -inline TimeStamp IsMotion::getCurrentTimeStamp() const -{ - TimeStamp ts; - getCurrentTimeStamp(ts); - return ts; -} - -inline Eigen::VectorXd IsMotion::getState(const TimeStamp& _ts) const -{ - Eigen::VectorXd x; - getState(_ts, x); - return x; -} - - - } /* namespace wolf */ #endif /* PROCESSOR_IS_MOTION_H_ */ diff --git a/include/core/processor/motion_buffer.h b/include/core/processor/motion_buffer.h index a5b41ebfe3ebf77f269148d42781b7dd96cd36a2..548fcf6e1e4f99b9d020784b226f4f1df75e4b98 100644 --- a/include/core/processor/motion_buffer.h +++ b/include/core/processor/motion_buffer.h @@ -72,30 +72,16 @@ struct Motion * - If the query time stamp does not match any time stamp in the buffer, * the returned motion-integral or delta-integral is the one immediately before the query time stamp. */ -class MotionBuffer{ +class MotionBuffer : public std::list<Motion> +{ public: MotionBuffer() ; - std::list<Motion>& get(); - const std::list<Motion>& get() const; const Motion& getMotion(const TimeStamp& _ts) const; void getMotion(const TimeStamp& _ts, Motion& _motion) const; void split(const TimeStamp& _ts, MotionBuffer& _oldest_buffer); void print(bool show_data = 0, bool show_delta = 0, bool show_delta_int = 0, bool show_jacs = 0); - - private: - std::list<Motion> container_; }; -inline std::list<Motion>& MotionBuffer::get() -{ - return container_; -} - -inline const std::list<Motion>& MotionBuffer::get() const -{ - return container_; -} - } // namespace wolf #endif /* SRC_MOTIONBUFFER_H_ */ diff --git a/include/core/processor/processor_base.h b/include/core/processor/processor_base.h index dc62abcac8375fc238f7c93617a33ccb8662d246..4182e762db050a3f36e714d453b73fb63568f5bc 100644 --- a/include/core/processor/processor_base.h +++ b/include/core/processor/processor_base.h @@ -30,13 +30,13 @@ namespace wolf { * In order to use this macro, the derived processor class, ProcessorClass, * must have a constructor available with the API: * - * ProcessorClass(const ProcessorParamsClassPtr _params); + * ProcessorClass(const ParamsProcessorClassPtr _params); */ -#define WOLF_PROCESSOR_CREATE(ProcessorClass, ProcessorParamsClass) \ +#define WOLF_PROCESSOR_CREATE(ProcessorClass, ParamsProcessorClass) \ static ProcessorBasePtr create(const std::string& _unique_name, \ const ParamsServer& _server) \ { \ - auto params = std::make_shared<ProcessorParamsClass>(_unique_name, _server); \ + auto params = std::make_shared<ParamsProcessorClass>(_unique_name, _server); \ \ auto processor = std::make_shared<ProcessorClass>(params); \ \ @@ -44,9 +44,9 @@ static ProcessorBasePtr create(const std::string& _unique_name, \ return processor; \ } \ -static ProcessorBasePtr create(const std::string& _unique_name, const ProcessorParamsBasePtr _params) \ +static ProcessorBasePtr create(const std::string& _unique_name, const ParamsProcessorBasePtr _params) \ { \ - auto params = std::static_pointer_cast<ProcessorParamsClass>(_params); \ + auto params = std::static_pointer_cast<ParamsProcessorClass>(_params); \ \ auto processor = std::make_shared<ProcessorClass>(params); \ \ @@ -208,11 +208,11 @@ class BufferCapture : public Buffer<CaptureBasePtr> {}; * * Derive from this struct to create structs of processor parameters. */ -struct ProcessorParamsBase : public ParamsBase +struct ParamsProcessorBase : public ParamsBase { std::string prefix = "processor/"; - ProcessorParamsBase() = default; - ProcessorParamsBase(std::string _unique_name, const ParamsServer& _server): + ParamsProcessorBase() = default; + ParamsProcessorBase(std::string _unique_name, const ParamsServer& _server): ParamsBase(_unique_name, _server) { time_tolerance = _server.getParam<double>(prefix + _unique_name + "/time_tolerance"); @@ -221,7 +221,7 @@ struct ProcessorParamsBase : public ParamsBase apply_loss_function = _server.getParam<bool>(prefix + _unique_name + "/apply_loss_function"); } - virtual ~ProcessorParamsBase() = default; + virtual ~ParamsProcessorBase() = default; /** maximum time difference between a Keyframe time stamp and * a particular Capture of this processor to allow assigning @@ -248,7 +248,7 @@ class ProcessorBase : public NodeBase, public std::enable_shared_from_this<Proce friend SensorBase; protected: unsigned int processor_id_; - ProcessorParamsBasePtr params_; + ParamsProcessorBasePtr params_; BufferPackKeyFrame buffer_pack_kf_; BufferCapture buffer_capture_; int dim_; @@ -258,7 +258,7 @@ class ProcessorBase : public NodeBase, public std::enable_shared_from_this<Proce static unsigned int processor_id_count_; public: - ProcessorBase(const std::string& _type, int _dim, ProcessorParamsBasePtr _params); + ProcessorBase(const std::string& _type, int _dim, ParamsProcessorBasePtr _params); virtual ~ProcessorBase(); virtual void configure(SensorBasePtr _sensor) = 0; virtual void remove(); @@ -326,6 +326,8 @@ class ProcessorBase : public NodeBase, public std::enable_shared_from_this<Proce virtual bool permittedAuxFrame() final; + virtual void setProblem(ProblemPtr) override; + public: /**\brief notify a new keyframe made by another processor * @@ -361,6 +363,23 @@ class ProcessorBase : public NodeBase, public std::enable_shared_from_this<Proce template<typename classType, typename... T> static std::shared_ptr<classType> emplace(SensorBasePtr _sen_ptr, T&&... all); void setVotingAuxActive(bool _voting_active = true); + + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const; + + void print(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream = std::cout, + std::string _tabs = "") const; + + virtual CheckLog localCheck(bool _verbose, ProcessorBasePtr _prc_ptr, std::ostream& _stream, std::string _tabs = "") const; + bool check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs = "") const; }; inline bool ProcessorBase::isVotingActive() const diff --git a/include/core/processor/processor_diff_drive.h b/include/core/processor/processor_diff_drive.h index 48d18acccc0e48f3f5f2373b0ece28e2da607f61..e3e504f36b50d95c69bf13d0a99c0107f5207b27 100644 --- a/include/core/processor/processor_diff_drive.h +++ b/include/core/processor/processor_diff_drive.h @@ -13,18 +13,18 @@ namespace wolf { -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsDiffDrive); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorDiffDrive); -struct ProcessorParamsDiffDrive : public ProcessorParamsOdom2d +struct ParamsProcessorDiffDrive : public ParamsProcessorOdom2d { - ProcessorParamsDiffDrive() = default; - ProcessorParamsDiffDrive(std::string _unique_name, const wolf::ParamsServer & _server) : - ProcessorParamsOdom2d(_unique_name, _server) + ParamsProcessorDiffDrive() = default; + ParamsProcessorDiffDrive(std::string _unique_name, const wolf::ParamsServer & _server) : + ParamsProcessorOdom2d(_unique_name, _server) { } std::string print() const { - return "\n" + ProcessorParamsOdom2d::print(); + return "\n" + ParamsProcessorOdom2d::print(); } }; @@ -33,12 +33,12 @@ WOLF_PTR_TYPEDEFS(ProcessorDiffDrive); class ProcessorDiffDrive : public ProcessorOdom2d { public: - ProcessorDiffDrive(ProcessorParamsDiffDrivePtr _params_motion); + ProcessorDiffDrive(ParamsProcessorDiffDrivePtr _params_motion); virtual ~ProcessorDiffDrive(); virtual void configure(SensorBasePtr _sensor) override; // Factory method for high level API - WOLF_PROCESSOR_CREATE(ProcessorDiffDrive, ProcessorParamsDiffDrive); + WOLF_PROCESSOR_CREATE(ProcessorDiffDrive, ParamsProcessorDiffDrive); protected: // Motion integration @@ -60,14 +60,26 @@ class ProcessorDiffDrive : public ProcessorOdom2d virtual FeatureBasePtr emplaceFeature(CaptureMotionPtr _capture_own) override; virtual FactorBasePtr emplaceFactor(FeatureBasePtr _feature_motion, CaptureBasePtr _capture_origin) override; - + virtual VectorXd getCalibration (const CaptureBasePtr _capture) const override; + virtual void setCalibration(const CaptureBasePtr _capture, const VectorXd& _calibration) override; protected: - ProcessorParamsDiffDrivePtr params_prc_diff_drv_selfcal_; + ParamsProcessorDiffDrivePtr params_prc_diff_drv_selfcal_; double radians_per_tick_; }; +inline Eigen::VectorXd ProcessorDiffDrive::getCalibration (const CaptureBasePtr _capture) const +{ + return _capture->getStateBlock("I")->getState(); +} + +inline void ProcessorDiffDrive::setCalibration (const CaptureBasePtr _capture, const VectorXd& _calibration) +{ + _capture->getStateBlock("I")->setState(_calibration); +} + + } diff --git a/include/core/processor/processor_loopclosure.h b/include/core/processor/processor_loopclosure.h index b0720f3a47afdfd7878b23929923295964340ea5..4b22ba3985cf04a1c5c1f7658419ea9ed384f390 100644 --- a/include/core/processor/processor_loopclosure.h +++ b/include/core/processor/processor_loopclosure.h @@ -6,12 +6,12 @@ namespace wolf{ -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsLoopClosure); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorLoopClosure); -struct ProcessorParamsLoopClosure : public ProcessorParamsBase +struct ParamsProcessorLoopClosure : public ParamsProcessorBase { - using ProcessorParamsBase::ProcessorParamsBase; - // virtual ~ProcessorParamsLoopClosure() = default; + using ParamsProcessorBase::ParamsProcessorBase; + // virtual ~ParamsProcessorLoopClosure() = default; // add neccesery parameters for loop closure initialisation here and initialize // them in constructor @@ -46,12 +46,11 @@ class ProcessorLoopClosure : public ProcessorBase { protected: - ProcessorParamsLoopClosurePtr params_loop_closure_; - int _dim; + ParamsProcessorLoopClosurePtr params_loop_closure_; public: - ProcessorLoopClosure(const std::string& _type, int _dim, ProcessorParamsLoopClosurePtr _params_loop_closure); + ProcessorLoopClosure(const std::string& _type, int _dim, ParamsProcessorLoopClosurePtr _params_loop_closure); virtual ~ProcessorLoopClosure() = default; virtual void configure(SensorBasePtr _sensor) override { }; diff --git a/include/core/processor/processor_motion.h b/include/core/processor/processor_motion.h index 81a9184ad4798ccbaac1ebd61a194f6e287331b4..8533e66caf5da96a06680098b44236a4fb420482 100644 --- a/include/core/processor/processor_motion.h +++ b/include/core/processor/processor_motion.h @@ -21,9 +21,9 @@ namespace wolf { -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsMotion); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorMotion); -struct ProcessorParamsMotion : public ProcessorParamsBase +struct ParamsProcessorMotion : public ParamsProcessorBase { double max_time_span = 0.5; unsigned int max_buff_length = 10; @@ -31,9 +31,9 @@ struct ProcessorParamsMotion : public ProcessorParamsBase double angle_turned = 0.5; double unmeasured_perturbation_std = 1e-4; - ProcessorParamsMotion() = default; - ProcessorParamsMotion(std::string _unique_name, const ParamsServer& _server): - ProcessorParamsBase(_unique_name, _server) + ParamsProcessorMotion() = default; + ParamsProcessorMotion(std::string _unique_name, const ParamsServer& _server): + ParamsProcessorBase(_unique_name, _server) { max_time_span = _server.getParam<double>(prefix + _unique_name + "/keyframe_vote/max_time_span"); max_buff_length = _server.getParam<unsigned int>(prefix + _unique_name + "/keyframe_vote/max_buff_length"); @@ -43,7 +43,7 @@ struct ProcessorParamsMotion : public ProcessorParamsBase } std::string print() const { - return "\n" + ProcessorParamsBase::print() + "\n" + return "\n" + ParamsProcessorBase::print() + "\n" + "max_time_span: " + std::to_string(max_time_span) + "\n" + "max_buff_length: " + std::to_string(max_buff_length) + "\n" + "dist_traveled: " + std::to_string(dist_traveled) + "\n" @@ -134,16 +134,19 @@ class ProcessorMotion : public ProcessorBase, public IsMotion { public: typedef enum { - RUNNING_WITHOUT_PACK, - RUNNING_WITH_PACK_BEFORE_ORIGIN, - RUNNING_WITH_PACK_ON_ORIGIN, - RUNNING_WITH_PACK_AFTER_ORIGIN + FIRST_TIME_WITHOUT_KF, + FIRST_TIME_WITH_KF_BEFORE_INCOMING, + FIRST_TIME_WITH_KF_ON_INCOMING, + FIRST_TIME_WITH_KF_AFTER_INCOMING, + RUNNING_WITHOUT_KF, + RUNNING_WITH_KF_BEFORE_ORIGIN, + RUNNING_WITH_KF_ON_ORIGIN, + RUNNING_WITH_KF_AFTER_ORIGIN } ProcessingStep ; protected: - ProcessorParamsMotionPtr params_motion_; + ParamsProcessorMotionPtr params_motion_; ProcessingStep processing_step_; ///< State machine controlling the processing step - virtual void setProblem(ProblemPtr) override; // This is the main public interface public: @@ -155,30 +158,16 @@ class ProcessorMotion : public ProcessorBase, public IsMotion SizeEigen _delta_cov_size, SizeEigen _data_size, SizeEigen _calib_size, - ProcessorParamsMotionPtr _params_motion); + ParamsProcessorMotionPtr _params_motion); virtual ~ProcessorMotion(); // Instructions to the processor: virtual void resetDerived(); // Queries to the processor: - - /** \brief Fill a reference to the state integrated so far - * \param _x the returned state vector - */ - virtual void getCurrentState(Eigen::VectorXd& _x) const override; - virtual void getCurrentTimeStamp(TimeStamp& _ts) const override { _ts = getBuffer().get().back().ts_; } - using IsMotion::getCurrentState; - using IsMotion::getCurrentTimeStamp; - - - /** \brief Fill the state corresponding to the provided time-stamp - * \param _ts the time stamp - * \param _x the returned state - * \return if state in the provided time-stamp could be resolved - */ - virtual bool getState(const TimeStamp& _ts, Eigen::VectorXd& _x) const override; - using IsMotion::getState; + virtual TimeStamp getTimeStamp() const override; + virtual VectorComposite getState() const override; + virtual VectorComposite getState(const TimeStamp& _ts) const override; /** \brief Gets the delta preintegrated covariance from all integrations so far * \return the delta preintegrated covariance matrix @@ -209,13 +198,12 @@ class ProcessorMotion : public ProcessorBase, public IsMotion * \param _x_origin the state at the origin * \param _ts_origin origin timestamp. */ - FrameBasePtr setOrigin(const Eigen::VectorXd& _x_origin, const TimeStamp& _ts_origin); - + FrameBasePtr setOrigin(const VectorComposite& _x_origin, const TimeStamp& _ts_origin); + // Helper functions: MotionBuffer& getBuffer(); const MotionBuffer& getBuffer() const; - // Helper functions: protected: /** \brief process an incoming capture @@ -393,10 +381,10 @@ class ProcessorMotion : public ProcessorBase, public IsMotion * * This function implements the composition (+) so that _x2 = _x1 (+) _delta. */ - virtual void statePlusDelta(const Eigen::VectorXd& _x, + virtual void statePlusDelta(const VectorComposite& _x, const Eigen::VectorXd& _delta, const double _dt, - Eigen::VectorXd& _x_plus_delta) const = 0; + VectorComposite& _x_plus_delta) const = 0; /** \brief Delta zero * \return a delta state equivalent to the null motion. @@ -409,6 +397,25 @@ class ProcessorMotion : public ProcessorBase, public IsMotion virtual Eigen::VectorXd deltaZero() const = 0; + /** \brief correct the preintegrated delta + * This produces a delta correction according to the appropriate manifold. + * @param delta_preint : the preintegrated delta to correct + * @param delta_step : an increment in the tangent space of the manifold + * + * We want to do + * + * delta_corr = delta_preint (+) d_step + * + * where the operator (+) is the right-plus operator on the delta's manifold. + * + * Note: usually in motion pre-integration we have + * + * delta_step = Jac_delta_calib * (calib - calib_pre) + * + */ + virtual Eigen::VectorXd correctDelta(const Eigen::VectorXd& delta_preint, + const Eigen::VectorXd& delta_step) const = 0; + /** \brief emplace a CaptureMotion * \param _ts time stamp * \param _sensor Sensor that produced the Capture @@ -437,6 +444,9 @@ class ProcessorMotion : public ProcessorBase, public IsMotion */ virtual FactorBasePtr emplaceFactor(FeatureBasePtr _feature_motion, CaptureBasePtr _capture_origin) = 0; + virtual VectorXd getCalibration (const CaptureBasePtr _capture) const = 0; + virtual void setCalibration(const CaptureBasePtr _capture, const VectorXd& _calibration) = 0; + Motion motionZero(const TimeStamp& _ts) const; bool hasCalibration() const {return calib_size_ > 0;} @@ -457,6 +467,13 @@ class ProcessorMotion : public ProcessorBase, public IsMotion void setDistTraveled(const double& _dist_traveled); void setAngleTurned(const double& _angle_turned); + void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const override; + protected: // Attributes SizeEigen x_size_; ///< The size of the state vector @@ -500,28 +517,14 @@ inline bool ProcessorMotion::voteForKeyFrame() const return false; } -inline void ProcessorMotion::getCurrentState(Eigen::VectorXd& _x) const -{ - // ensure integrity - assert(origin_ptr_ && "Trying to access origin_ptr_ but it is nullptr!"); - - // ensure proper size of the provided reference - Eigen::VectorXd curr_x = origin_ptr_->getFrame()->getState(state_structure_); - _x.resize( curr_x.size() ); - - // do get timestamp and state corrected by possible self-calibrations - double Dt = getCurrentTimeStamp() - origin_ptr_->getTimeStamp(); - statePlusDelta(curr_x, last_ptr_->getDeltaCorrected(origin_ptr_->getCalibration()), Dt, _x); -} - inline const Eigen::MatrixXd ProcessorMotion::getCurrentDeltaPreintCov() const { - return getBuffer().get().back().delta_integr_cov_; + return getBuffer().back().delta_integr_cov_; } inline Motion ProcessorMotion::getMotion() const { - return getBuffer().get().back(); + return getBuffer().back(); } inline Motion ProcessorMotion::getMotion(const TimeStamp& _ts) const @@ -534,7 +537,7 @@ inline Motion ProcessorMotion::getMotion(const TimeStamp& _ts) const inline double ProcessorMotion::updateDt() { - return dt_ = incoming_ptr_->getTimeStamp() - getBuffer().get().back().ts_; + return dt_ = incoming_ptr_->getTimeStamp() - getBuffer().back().ts_; } inline const MotionBuffer& ProcessorMotion::getBuffer() const diff --git a/include/core/processor/processor_odom_2d.h b/include/core/processor/processor_odom_2d.h index b03416837ec1b0a6a86a67ff0cf40fdf820b1370..0b873564bb7339e9acf63f1739076b9baa4ec29a 100644 --- a/include/core/processor/processor_odom_2d.h +++ b/include/core/processor/processor_odom_2d.h @@ -13,26 +13,27 @@ #include "core/factor/factor_odom_2d.h" #include "core/math/rotations.h" #include "core/utils/params_server.h" +#include "core/math/SE2.h" namespace wolf { WOLF_PTR_TYPEDEFS(ProcessorOdom2d); -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsOdom2d); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorOdom2d); -struct ProcessorParamsOdom2d : public ProcessorParamsMotion +struct ParamsProcessorOdom2d : public ParamsProcessorMotion { double cov_det = 1.0; - ProcessorParamsOdom2d() = default; - ProcessorParamsOdom2d(std::string _unique_name, const wolf::ParamsServer & _server) : - ProcessorParamsMotion(_unique_name, _server) + ParamsProcessorOdom2d() = default; + ParamsProcessorOdom2d(std::string _unique_name, const wolf::ParamsServer & _server) : + ParamsProcessorMotion(_unique_name, _server) { cov_det = _server.getParam<double>(prefix + _unique_name + "/keyframe_vote/cov_det"); } std::string print() const { - return "\n" + ProcessorParamsMotion::print() + "\n" + return "\n" + ParamsProcessorMotion::print() + "\n" + "cov_det: " + std::to_string(cov_det) + "\n"; } }; @@ -40,12 +41,12 @@ struct ProcessorParamsOdom2d : public ProcessorParamsMotion class ProcessorOdom2d : public ProcessorMotion { public: - ProcessorOdom2d(ProcessorParamsOdom2dPtr _params); + ProcessorOdom2d(ParamsProcessorOdom2dPtr _params); virtual ~ProcessorOdom2d(); - virtual void configure(SensorBasePtr _sensor) override; + virtual void configure(SensorBasePtr _sensor) override { }; // Factory method for high level API - WOLF_PROCESSOR_CREATE(ProcessorOdom2d, ProcessorParamsOdom2d); + WOLF_PROCESSOR_CREATE(ProcessorOdom2d, ParamsProcessorOdom2d); virtual bool voteForKeyFrame() const override; @@ -67,11 +68,13 @@ class ProcessorOdom2d : public ProcessorMotion Eigen::VectorXd& _delta1_plus_delta2, Eigen::MatrixXd& _jacobian1, Eigen::MatrixXd& _jacobian2) const override; - virtual void statePlusDelta(const Eigen::VectorXd& _x, + virtual void statePlusDelta(const VectorComposite& _x, const Eigen::VectorXd& _delta, const double _Dt, - Eigen::VectorXd& _x_plus_delta) const override; + VectorComposite& _x_plus_delta) const override; virtual Eigen::VectorXd deltaZero() const override; + Eigen::VectorXd correctDelta(const Eigen::VectorXd& delta_preint, + const Eigen::VectorXd& delta_step) const override; virtual CaptureMotionPtr emplaceCapture(const FrameBasePtr& _frame_own, const SensorBasePtr& _sensor, @@ -84,9 +87,11 @@ class ProcessorOdom2d : public ProcessorMotion virtual FeatureBasePtr emplaceFeature(CaptureMotionPtr _capture_motion) override; virtual FactorBasePtr emplaceFactor(FeatureBasePtr _feature, CaptureBasePtr _capture_origin) override; + virtual VectorXd getCalibration (const CaptureBasePtr _capture) const override; + virtual void setCalibration(const CaptureBasePtr _capture, const VectorXd& _calibration) override; protected: - ProcessorParamsOdom2dPtr params_odom_2d_; + ParamsProcessorOdom2dPtr params_odom_2d_; }; @@ -95,6 +100,23 @@ inline Eigen::VectorXd ProcessorOdom2d::deltaZero() const return Eigen::VectorXd::Zero(delta_size_); } +inline Eigen::VectorXd ProcessorOdom2d::correctDelta (const Eigen::VectorXd& delta_preint, + const Eigen::VectorXd& delta_step) const +{ + VectorXd delta_corrected(3); + SE2::plus(delta_preint, delta_step, delta_corrected); + return delta_corrected; +} + +inline VectorXd ProcessorOdom2d::getCalibration (const CaptureBasePtr _capture) const +{ + return VectorXd::Zero(0); +} + +inline void ProcessorOdom2d::setCalibration (const CaptureBasePtr _capture, const VectorXd& _calibration) +{ +} + } // namespace wolf #endif /* SRC_PROCESSOR_ODOM_2d_H_ */ diff --git a/include/core/processor/processor_odom_3d.h b/include/core/processor/processor_odom_3d.h index f8f849b896aad644f998c38b50e8ca198c0738c4..49eaf4fad2788dde0499021ec89fb58d228cb65b 100644 --- a/include/core/processor/processor_odom_3d.h +++ b/include/core/processor/processor_odom_3d.h @@ -17,19 +17,19 @@ namespace wolf { -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsOdom3d); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorOdom3d); -struct ProcessorParamsOdom3d : public ProcessorParamsMotion +struct ParamsProcessorOdom3d : public ParamsProcessorMotion { - ProcessorParamsOdom3d() = default; - ProcessorParamsOdom3d(std::string _unique_name, const ParamsServer& _server): - ProcessorParamsMotion(_unique_name, _server) + ParamsProcessorOdom3d() = default; + ParamsProcessorOdom3d(std::string _unique_name, const ParamsServer& _server): + ParamsProcessorMotion(_unique_name, _server) { // } std::string print() const { - return "\n" + ProcessorParamsMotion::print(); + return "\n" + ParamsProcessorMotion::print(); } }; @@ -60,12 +60,12 @@ WOLF_PTR_TYPEDEFS(ProcessorOdom3d); class ProcessorOdom3d : public ProcessorMotion { public: - ProcessorOdom3d(ProcessorParamsOdom3dPtr _params); + ProcessorOdom3d(ParamsProcessorOdom3dPtr _params); virtual ~ProcessorOdom3d(); virtual void configure(SensorBasePtr _sensor) override; // Factory method for high level API - WOLF_PROCESSOR_CREATE(ProcessorOdom3d, ProcessorParamsOdom3d); + WOLF_PROCESSOR_CREATE(ProcessorOdom3d, ParamsProcessorOdom3d); public: // Motion integration @@ -86,11 +86,14 @@ class ProcessorOdom3d : public ProcessorMotion Eigen::VectorXd& _delta1_plus_delta2, Eigen::MatrixXd& _jacobian1, Eigen::MatrixXd& _jacobian2) const override; - void statePlusDelta(const Eigen::VectorXd& _x, - const Eigen::VectorXd& _delta, - const double _Dt, - Eigen::VectorXd& _x_plus_delta) const override; + void statePlusDelta(const VectorComposite& _x, + const Eigen::VectorXd& _delta, + const double _Dt, + VectorComposite& _x_plus_delta) const override; Eigen::VectorXd deltaZero() const override; + Eigen::VectorXd correctDelta(const Eigen::VectorXd& delta_preint, + const Eigen::VectorXd& delta_step) const override; + bool voteForKeyFrame() const override; virtual CaptureMotionPtr emplaceCapture(const FrameBasePtr& _frame_own, const SensorBasePtr& _sensor, @@ -105,9 +108,11 @@ class ProcessorOdom3d : public ProcessorMotion virtual FactorBasePtr emplaceFactor(FeatureBasePtr _feature_motion, CaptureBasePtr _capture_origin) override; + virtual VectorXd getCalibration (const CaptureBasePtr _capture) const override; + virtual void setCalibration(const CaptureBasePtr _capture, const VectorXd& _calibration) override; protected: - ProcessorParamsOdom3dPtr params_odom_3d_; + ParamsProcessorOdom3dPtr params_odom_3d_; // noise parameters (stolen from owner SensorOdom3d) double k_disp_to_disp_; // displacement variance growth per meter of linear motion diff --git a/include/core/processor/processor_tracker.h b/include/core/processor/processor_tracker.h index d7ab951643fbc2760b8d81110a9f2338a96dad36..0b7197574ae6a05064792dbabeaea9fd019abd0b 100644 --- a/include/core/processor/processor_tracker.h +++ b/include/core/processor/processor_tracker.h @@ -13,23 +13,23 @@ namespace wolf { -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsTracker); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorTracker); -struct ProcessorParamsTracker : public ProcessorParamsBase +struct ParamsProcessorTracker : public ParamsProcessorBase { unsigned int min_features_for_keyframe; ///< minimum nbr. of features to vote for keyframe int max_new_features; ///< maximum nbr. of new features to be processed when adding a keyframe (-1: unlimited. 0: none.) - ProcessorParamsTracker() = default; - ProcessorParamsTracker(std::string _unique_name, const wolf::ParamsServer & _server): - ProcessorParamsBase(_unique_name, _server) + ParamsProcessorTracker() = default; + ParamsProcessorTracker(std::string _unique_name, const wolf::ParamsServer & _server): + ParamsProcessorBase(_unique_name, _server) { min_features_for_keyframe = _server.getParam<unsigned int>(prefix + _unique_name + "/min_features_for_keyframe"); max_new_features = _server.getParam<int>(prefix + _unique_name + "/max_new_features"); } std::string print() const { - return ProcessorParamsBase::print() + "\n" + return ParamsProcessorBase::print() + "\n" + "min_features_for_keyframe: " + std::to_string(min_features_for_keyframe) + "\n" + "max_new_features: " + std::to_string(max_new_features) + "\n"; } @@ -96,22 +96,26 @@ class ProcessorTracker : public ProcessorBase } ProcessingStep ; protected: - ProcessorParamsTrackerPtr params_tracker_; ///< parameters for the tracker + ParamsProcessorTrackerPtr params_tracker_; ///< parameters for the tracker ProcessingStep processing_step_; ///< State machine controlling the processing step CaptureBasePtr origin_ptr_; ///< Pointer to the origin of the tracker. CaptureBasePtr last_ptr_; ///< Pointer to the last tracked capture. CaptureBasePtr incoming_ptr_; ///< Pointer to the incoming capture being processed. FeatureBasePtrList new_features_last_; ///< List of new features in \b last for landmark initialization and new key-frame creation. FeatureBasePtrList new_features_incoming_; ///< list of the new features of \b last successfully tracked in \b incoming + FeatureBasePtrList known_features_last_; ///< list of the known features in previous captures successfully tracked in \b last FeatureBasePtrList known_features_incoming_; ///< list of the known features in \b last successfully tracked in \b incoming - int _dim; + StateStructure state_structure_; ///< Structure of frames created or used by this processor public: ProcessorTracker(const std::string& _type, + const StateStructure& _structure, int _dim, - ProcessorParamsTrackerPtr _params_tracker); + ParamsProcessorTrackerPtr _params_tracker); virtual ~ProcessorTracker(); + StateStructure getStateStructure() const; + bool checkTimeTolerance(const TimeStamp& _ts1, const TimeStamp& _ts2); bool checkTimeTolerance(const CaptureBasePtr _cap, const TimeStamp& _ts); bool checkTimeTolerance(const FrameBasePtr _frm, const TimeStamp& _ts); @@ -246,6 +250,13 @@ class ProcessorTracker : public ProcessorBase return this->params_tracker_->print(); } + void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const override; + protected: void computeProcessingStep(); @@ -293,6 +304,11 @@ inline bool ProcessorTracker::checkTimeTolerance(const FrameBasePtr _frm, const return checkTimeTolerance(_frm->getTimeStamp(), _cap->getTimeStamp()); } +inline StateStructure ProcessorTracker::getStateStructure ( ) const +{ + return state_structure_; +} + inline void ProcessorTracker::addNewFeatureIncoming(FeatureBasePtr _feature_ptr) { new_features_incoming_.push_back(_feature_ptr); diff --git a/include/core/processor/processor_tracker_feature.h b/include/core/processor/processor_tracker_feature.h index b86e041d25e026762ea1413429b1c6e63a594fd7..b69599ef55fce9f4624b6fe9115722aeb86aa3ca 100644 --- a/include/core/processor/processor_tracker_feature.h +++ b/include/core/processor/processor_tracker_feature.h @@ -18,11 +18,11 @@ namespace wolf { -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsTrackerFeature); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorTrackerFeature); -struct ProcessorParamsTrackerFeature : public ProcessorParamsTracker +struct ParamsProcessorTrackerFeature : public ParamsProcessorTracker { - using ProcessorParamsTracker::ProcessorParamsTracker; + using ParamsProcessorTracker::ParamsProcessorTracker; }; WOLF_PTR_TYPEDEFS(ProcessorTrackerFeature); @@ -85,12 +85,13 @@ class ProcessorTrackerFeature : public ProcessorTracker /** \brief Constructor with type */ ProcessorTrackerFeature(const std::string& _type, + const StateStructure& _structure, int _dim, - ProcessorParamsTrackerFeaturePtr _params_tracker_feature); + ParamsProcessorTrackerFeaturePtr _params_tracker_feature); virtual ~ProcessorTrackerFeature(); protected: - ProcessorParamsTrackerFeaturePtr params_tracker_feature_; + ParamsProcessorTrackerFeaturePtr params_tracker_feature_; TrackMatrix track_matrix_; FeatureMatchMap matches_last_from_incoming_; @@ -111,7 +112,7 @@ class ProcessorTrackerFeature : public ProcessorTracker * - Create the factors, of the correct type, derived from FactorBase * (through FactorAnalytic or FactorSparse). */ - virtual unsigned int processKnown(); + virtual unsigned int processKnown() override; /** \brief Track provided features in \b _capture * \param _features_in input list of features in \b last to track @@ -147,16 +148,16 @@ class ProcessorTrackerFeature : public ProcessorTracker * * WARNING! This function only votes! It does not create KeyFrames! */ - virtual bool voteForKeyFrame() const = 0; + virtual bool voteForKeyFrame() const override = 0; // We overload the advance and reset functions to update the lists of matches - void advanceDerived(); - void resetDerived(); + virtual void advanceDerived() override; + virtual void resetDerived() override; /**\brief Process new Features * */ - virtual unsigned int processNew(const int& _max_features); + virtual unsigned int processNew(const int& _max_features) override; /** \brief Detect new Features * \param _max_features maximum number of features detected (-1: unlimited. 0: none) @@ -190,7 +191,7 @@ class ProcessorTrackerFeature : public ProcessorTracker /** \brief Emplaces a new factor for each correspondence between a feature in Capture \b last and a feature in Capture \b origin */ - virtual void establishFactors(); + virtual void establishFactors() override; }; } // namespace wolf diff --git a/include/core/processor/processor_tracker_landmark.h b/include/core/processor/processor_tracker_landmark.h index 8809426f8654803fc7012068ff9d89cd1d70ea4c..6181810bde23395d70c8e28cabc2457f4b13f41b 100644 --- a/include/core/processor/processor_tracker_landmark.h +++ b/include/core/processor/processor_tracker_landmark.h @@ -16,11 +16,11 @@ namespace wolf { -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsTrackerLandmark); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorTrackerLandmark); -struct ProcessorParamsTrackerLandmark : public ProcessorParamsTracker +struct ParamsProcessorTrackerLandmark : public ParamsProcessorTracker { - using ProcessorParamsTracker::ProcessorParamsTracker; + using ParamsProcessorTracker::ParamsProcessorTracker; // }; @@ -81,12 +81,13 @@ class ProcessorTrackerLandmark : public ProcessorTracker { public: ProcessorTrackerLandmark(const std::string& _type, - ProcessorParamsTrackerLandmarkPtr _params_tracker_landmark); + const StateStructure& _structure, + ParamsProcessorTrackerLandmarkPtr _params_tracker_landmark); virtual ~ProcessorTrackerLandmark(); protected: - ProcessorParamsTrackerLandmarkPtr params_tracker_landmark_; + ParamsProcessorTrackerLandmarkPtr params_tracker_landmark_; LandmarkBasePtrList new_landmarks_; ///< List of new detected landmarks LandmarkMatchMap matches_landmark_from_incoming_; LandmarkMatchMap matches_landmark_from_last_; diff --git a/include/core/sensor/sensor_factory.h b/include/core/sensor/factory_sensor.h similarity index 78% rename from include/core/sensor/sensor_factory.h rename to include/core/sensor/factory_sensor.h index daf01499ac759d799517cdd73ab830fb6ccaf4d5..ff0574aaadc6a52015a6c9e4f076a1ec64d968c0 100644 --- a/include/core/sensor/sensor_factory.h +++ b/include/core/sensor/factory_sensor.h @@ -1,12 +1,12 @@ /** - * \file sensor_factory.h + * \file factory_sensor.h * * Created on: Apr 25, 2016 * \author: jsola */ -#ifndef SENSOR_FACTORY_H_ -#define SENSOR_FACTORY_H_ +#ifndef FACTORY_SENSOR_H_ +#define FACTORY_SENSOR_H_ namespace wolf { @@ -47,17 +47,17 @@ namespace wolf * - Write a sensor creator for SensorCamera (example). * * #### Accessing the factory - * The SensorFactory class is a <a href="http://stackoverflow.com/questions/1008019/c-singleton-design-pattern#1008289">singleton</a>: it can only exist once in your application. + * The FactorySensor class is a <a href="http://stackoverflow.com/questions/1008019/c-singleton-design-pattern#1008289">singleton</a>: it can only exist once in your application. * To obtain an instance of it, use the static method get(), * * \code - * SensorFactory::get() + * FactorySensor::get() * \endcode * * You can then call the methods you like, e.g. to create a sensor, you type: * * \code - * SensorFactory::get().create(...); // see below for creating sensors ... + * FactorySensor::get().create(...); // see below for creating sensors ... * \endcode * * #### Registering sensor creators @@ -69,7 +69,7 @@ namespace wolf * that knows how to create your specific sensor, e.g.: * * \code - * SensorFactory::get().registerCreator("CAMERA", SensorCamera::create); + * FactorySensor::get().registerCreator("CAMERA", SensorCamera::create); * \endcode * * The method SensorCamera::create() exists in the SensorCamera class as a static method. @@ -89,7 +89,7 @@ namespace wolf * For example, in sensor_camera.cpp we find the line: * * \code - * const bool registered_camera = SensorFactory::get().registerCreator("CAMERA", SensorCamera::create); + * const bool registered_camera = FactorySensor::get().registerCreator("CAMERA", SensorCamera::create); * \endcode * * which is a static invocation (i.e., it is placed at global scope outside of the SensorCamera class). @@ -99,7 +99,7 @@ namespace wolf * The method unregisterCreator() unregisters the SensorXxx::create() method. It only needs to be passed the string of the sensor type. * * \code - * SensorFactory::get().unregisterCreator("CAMERA"); + * FactorySensor::get().unregisterCreator("CAMERA"); * \endcode * * #### Creating sensors @@ -109,15 +109,15 @@ namespace wolf * To create e.g. a SensorCamera, you type: * * \code - * SensorFactory::get().create("CAMERA", "Front-left camera", extrinsics, intrinsics_ptr); + * FactorySensor::get().create("CAMERA", "Front-left camera", extrinsics, intrinsics_ptr); * \endcode * * where ABSOLUTELY ALL input parameters are important. In particular, the sensor name "Front-left camera" will be used to identify this camera * and to assign it the appropriate processors. DO NOT USE IT WITH DUMMY PARAMETERS! * * #### See also - * - ParamsSensorFactory: to create intrinsic structs deriving from ParamsSensorBase directly from YAML files. - * - ProcessorFactory: to create processors that will be bound to sensors. + * - FactoryParamsSensor: to create intrinsic structs deriving from ParamsSensorBase directly from YAML files. + * - FactoryProcessor: to create processors that will be bound to sensors. * - Problem::installSensor() : to install sensors in WOLF Problem. * * #### Example 1: writing a specific sensor creator @@ -148,14 +148,14 @@ namespace wolf * Put the code either at global scope (you must define a dummy variable for this), * \code * namespace { - * const bool registered_camera = SensorFactory::get().registerCreator("CAMERA", SensorCamera::create); + * const bool registered_camera = FactorySensor::get().registerCreator("CAMERA", SensorCamera::create); * } * main () { ... } * \endcode * or inside your main(), where a direct call is possible: * \code * main () { - * SensorFactory::get().registerCreator("CAMERA", SensorCamera::create); + * FactorySensor::get().registerCreator("CAMERA", SensorCamera::create); * ... * } * \endcode @@ -164,7 +164,7 @@ namespace wolf * Put the code at the last line of the sensor_xxx.cpp file, * \code * namespace { - * const bool registered_camera = SensorFactory::get().registerCreator("CAMERA", SensorCamera::create); + * const bool registered_camera = FactorySensor::get().registerCreator("CAMERA", SensorCamera::create); * } * \endcode * Automatic registration is recommended in wolf, and implemented in the classes shipped with it. @@ -174,7 +174,7 @@ namespace wolf * We finally provide the necessary steps to create a sensor of class SensorCamera in our application: * * \code - * #include "sensor_factory.h" + * #include "factory_sensor.h" * #include "core/sensor/sensor_camera.h" // provides SensorCamera * * // Note: SensorCamera::create() is already registered, automatically. @@ -189,10 +189,10 @@ namespace wolf * // a pointer to the intrinsics struct: * * Eigen::VectorXd extrinsics_1(7); // give it some values... - * ParamsSensorCamera intrinsics_1({...}); // see ParamsSensorFactory to fill in the derived struct + * ParamsSensorCamera intrinsics_1({...}); // see FactoryParamsSensor to fill in the derived struct * * SensorBasePtr camera_1_ptr = - * SensorFactory::get().create ( "CAMERA" , "Front-left camera" , extrinsics_1 , &intrinsics_1 ); + * FactorySensor::get().create ( "CAMERA" , "Front-left camera" , extrinsics_1 , &intrinsics_1 ); * * // A second camera... with a different name! * @@ -200,7 +200,7 @@ namespace wolf * ParamsSensorCamera intrinsics_2({...}); * * SensorBasePtr camera_2_ptr = - * SensorFactory::get().create( "CAMERA" , "Front-right camera" , extrinsics_2 , &intrinsics_2 ); + * FactorySensor::get().create( "CAMERA" , "Front-right camera" , extrinsics_2 , &intrinsics_2 ); * * return 0; * } @@ -212,42 +212,43 @@ namespace wolf // ParamsSensor factory struct ParamsSensorBase; typedef Factory<ParamsSensorBase, - const std::string&> ParamsSensorFactory; + const std::string&> FactoryParamsSensor; template<> -inline std::string ParamsSensorFactory::getClass() +inline std::string FactoryParamsSensor::getClass() const { - return "ParamsSensorFactory"; + return "FactoryParamsSensor"; } // Sensor factory typedef Factory<SensorBase, const std::string&, - const Eigen::VectorXd&, const ParamsSensorBasePtr> SensorFactory; + const Eigen::VectorXd&, + const ParamsSensorBasePtr> FactorySensor; template<> -inline std::string SensorFactory::getClass() +inline std::string FactorySensor::getClass() const { - return "SensorFactory"; + return "FactorySensor"; } -#define WOLF_REGISTER_SENSOR(SensorType, SensorName) \ - namespace{ const bool WOLF_UNUSED SensorName##Registered = \ - SensorFactory::get().registerCreator(SensorType, SensorName::create); } \ +#define WOLF_REGISTER_SENSOR(SensorType) \ + namespace{ const bool WOLF_UNUSED SensorType##Registered = \ + FactorySensor::get().registerCreator(#SensorType, SensorType::create); } \ typedef Factory<SensorBase, const std::string&, - const ParamsServer&> AutoConfSensorFactory; + const ParamsServer&> AutoConfFactorySensor; template<> -inline std::string AutoConfSensorFactory::getClass() +inline std::string AutoConfFactorySensor::getClass() const { - return "AutoConfSensorFactory"; + return "AutoConfFactorySensor"; } -#define WOLF_REGISTER_SENSOR_AUTO(SensorType, SensorName) \ - namespace{ const bool WOLF_UNUSED SensorName##AutoConfRegistered = \ - AutoConfSensorFactory::get().registerCreator(SensorType, SensorName::create); } \ +#define WOLF_REGISTER_SENSOR_AUTO(SensorType) \ + namespace{ const bool WOLF_UNUSED SensorType##AutoConfRegistered = \ + AutoConfFactorySensor::get().registerCreator(#SensorType, SensorType::create); } \ } /* namespace wolf */ diff --git a/include/core/sensor/sensor_base.h b/include/core/sensor/sensor_base.h index 1c099cb9be4827705bd43d229714ea1dabf24ed0..e1be8095b90f395477ea72ed0302520fb0ae4bbb 100644 --- a/include/core/sensor/sensor_base.h +++ b/include/core/sensor/sensor_base.h @@ -242,6 +242,22 @@ class SensorBase : public NodeBase, public HasStateBlocks, public std::enable_sh Eigen::VectorXd getNoiseStd() const; Eigen::MatrixXd getNoiseCov() const; + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const; + void print(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream = std::cout, + std::string _tabs = "") const; + + virtual CheckLog localCheck(bool _verbose, SensorBasePtr _sen_ptr, std::ostream& _stream, std::string _tabs = "") const; + bool check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs = "") const; + void link(HardwareBasePtr); template<typename classType, typename... T> static std::shared_ptr<classType> emplace(HardwareBasePtr _hwd_ptr, T&&... all); diff --git a/include/core/solver/solver_factory.h b/include/core/solver/factory_solver.h similarity index 83% rename from include/core/solver/solver_factory.h rename to include/core/solver/factory_solver.h index d80fe24f78ddaa91a44e7821f2dc0a55117b8dcf..e3cc58a4a0b6d269026312f9c946a490d1045923 100644 --- a/include/core/solver/solver_factory.h +++ b/include/core/solver/factory_solver.h @@ -1,12 +1,12 @@ /** - * \file solver_factory.h + * \file factory_solver.h * * Created on: Dec 17, 2018 * \author: jcasals */ -#ifndef SOLVER_FACTORY_H_ -#define SOLVER_FACTORY_H_ +#ifndef FACTORY_SOLVER_H_ +#define FACTORY_SOLVER_H_ namespace wolf { @@ -47,17 +47,17 @@ namespace wolf * - Write a sensor creator for SensorCamera (example). * * #### Accessing the factory - * The SensorFactory class is a <a href="http://stackoverflow.com/questions/1008019/c-singleton-design-pattern#1008289">singleton</a>: it can only exist once in your application. + * The FactorySensor class is a <a href="http://stackoverflow.com/questions/1008019/c-singleton-design-pattern#1008289">singleton</a>: it can only exist once in your application. * To obtain an instance of it, use the static method get(), * * \code - * SensorFactory::get() + * FactorySensor::get() * \endcode * * You can then call the methods you like, e.g. to create a sensor, you type: * * \code - * SensorFactory::get().create(...); // see below for creating sensors ... + * FactorySensor::get().create(...); // see below for creating sensors ... * \endcode * * #### Registering sensor creators @@ -69,7 +69,7 @@ namespace wolf * that knows how to create your specific sensor, e.g.: * * \code - * SensorFactory::get().registerCreator("CAMERA", SensorCamera::create); + * FactorySensor::get().registerCreator("CAMERA", SensorCamera::create); * \endcode * * The method SensorCamera::create() exists in the SensorCamera class as a static method. @@ -89,7 +89,7 @@ namespace wolf * For example, in sensor_camera.cpp we find the line: * * \code - * const bool registered_camera = SensorFactory::get().registerCreator("CAMERA", SensorCamera::create); + * const bool registered_camera = FactorySensor::get().registerCreator("CAMERA", SensorCamera::create); * \endcode * * which is a static invocation (i.e., it is placed at global scope outside of the SensorCamera class). @@ -99,7 +99,7 @@ namespace wolf * The method unregisterCreator() unregisters the SensorXxx::create() method. It only needs to be passed the string of the sensor type. * * \code - * SensorFactory::get().unregisterCreator("CAMERA"); + * FactorySensor::get().unregisterCreator("CAMERA"); * \endcode * * #### Creating sensors @@ -109,15 +109,15 @@ namespace wolf * To create e.g. a SensorCamera, you type: * * \code - * SensorFactory::get().create("CAMERA", "Front-left camera", extrinsics, intrinsics_ptr); + * FactorySensor::get().create("CAMERA", "Front-left camera", extrinsics, intrinsics_ptr); * \endcode * * where ABSOLUTELY ALL input parameters are important. In particular, the sensor name "Front-left camera" will be used to identify this camera * and to assign it the appropriate processors. DO NOT USE IT WITH DUMMY PARAMETERS! * * #### See also - * - ParamsSensorFactory: to create intrinsic structs deriving from ParamsSensorBase directly from YAML files. - * - ProcessorFactory: to create processors that will be bound to sensors. + * - FactoryParamsSensor: to create intrinsic structs deriving from ParamsSensorBase directly from YAML files. + * - FactoryProcessor: to create processors that will be bound to sensors. * - Problem::installSensor() : to install sensors in WOLF Problem. * * #### Example 1: writing a specific sensor creator @@ -148,14 +148,14 @@ namespace wolf * Put the code either at global scope (you must define a dummy variable for this), * \code * namespace { - * const bool registered_camera = SensorFactory::get().registerCreator("CAMERA", SensorCamera::create); + * const bool registered_camera = FactorySensor::get().registerCreator("CAMERA", SensorCamera::create); * } * main () { ... } * \endcode * or inside your main(), where a direct call is possible: * \code * main () { - * SensorFactory::get().registerCreator("CAMERA", SensorCamera::create); + * FactorySensor::get().registerCreator("CAMERA", SensorCamera::create); * ... * } * \endcode @@ -164,7 +164,7 @@ namespace wolf * Put the code at the last line of the sensor_xxx.cpp file, * \code * namespace { - * const bool registered_camera = SensorFactory::get().registerCreator("CAMERA", SensorCamera::create); + * const bool registered_camera = FactorySensor::get().registerCreator("CAMERA", SensorCamera::create); * } * \endcode * Automatic registration is recommended in wolf, and implemented in the classes shipped with it. @@ -174,7 +174,7 @@ namespace wolf * We finally provide the necessary steps to create a sensor of class SensorCamera in our application: * * \code - * #include "sensor_factory.h" + * #include "factory_sensor.h" * #include "sensor_camera.h" // provides SensorCamera * * // Note: SensorCamera::create() is already registered, automatically. @@ -189,10 +189,10 @@ namespace wolf * // a pointer to the intrinsics struct: * * Eigen::VectorXd extrinsics_1(7); // give it some values... - * ParamsSensorCamera intrinsics_1({...}); // see ParamsSensorFactory to fill in the derived struct + * ParamsSensorCamera intrinsics_1({...}); // see FactoryParamsSensor to fill in the derived struct * * SensorBasePtr camera_1_ptr = - * SensorFactory::get().create ( "CAMERA" , "Front-left camera" , extrinsics_1 , &intrinsics_1 ); + * FactorySensor::get().create ( "CAMERA" , "Front-left camera" , extrinsics_1 , &intrinsics_1 ); * * // A second camera... with a different name! * @@ -200,7 +200,7 @@ namespace wolf * ParamsSensorCamera intrinsics_2({...}); * * SensorBasePtr camera_2_ptr = - * SensorFactory::get().create( "CAMERA" , "Front-right camera" , extrinsics_2 , &intrinsics_2 ); + * FactorySensor::get().create( "CAMERA" , "Front-right camera" , extrinsics_2 , &intrinsics_2 ); * * return 0; * } @@ -211,17 +211,17 @@ namespace wolf typedef Factory<SolverManager, const ProblemPtr&, - const ParamsServer&> SolverFactory; + const ParamsServer&> FactorySolver; template<> -inline std::string SolverFactory::getClass() +inline std::string FactorySolver::getClass() const { - return "SolverFactory"; + return "FactorySolver"; } -#define WOLF_REGISTER_SOLVER(SolverType, SolverName) \ - namespace{ const bool WOLF_UNUSED SolverName##Registered = \ - wolf::SolverFactory::get().registerCreator(SolverType, SolverName::create); } \ +#define WOLF_REGISTER_SOLVER(SolverType) \ + namespace{ const bool WOLF_UNUSED SolverType##Registered = \ + wolf::FactorySolver::get().registerCreator(#SolverType, SolverType::create); } \ } /* namespace wolf */ diff --git a/include/core/solver/solver_manager.h b/include/core/solver/solver_manager.h index c2b2c161caa8c3ee8401e8d1b3426ac8f8f64db0..3a5e613276c432db263cf43a484b2550ec1cfac2 100644 --- a/include/core/solver/solver_manager.h +++ b/include/core/solver/solver_manager.h @@ -93,7 +93,7 @@ public: SolverManager(const ProblemPtr& wolf_problem); - virtual ~SolverManager() = default; + virtual ~SolverManager(); std::string solve(const ReportVerbosity report_level = ReportVerbosity::QUIET); @@ -117,30 +117,40 @@ public: virtual bool isFactorRegistered(const FactorBasePtr& fac_ptr) const; -protected: - - std::map<StateBlockPtr, Eigen::VectorXd> state_blocks_; - - virtual Eigen::VectorXd& getAssociatedMemBlock(const StateBlockPtr& state_ptr); - virtual double* getAssociatedMemBlockPtr(const StateBlockPtr& state_ptr); - - virtual std::string solveImpl(const ReportVerbosity report_level) = 0; - - virtual void addFactor(const FactorBasePtr& fac_ptr) = 0; + bool check(std::string prefix="") const; - virtual void removeFactor(const FactorBasePtr& fac_ptr) = 0; - - virtual void addStateBlock(const StateBlockPtr& state_ptr) = 0; - - virtual void removeStateBlock(const StateBlockPtr& state_ptr) = 0; +protected: - virtual void updateStateBlockStatus(const StateBlockPtr& state_ptr) = 0; + std::map<StateBlockPtr, Eigen::VectorXd> state_blocks_; + std::map<StateBlockPtr, FactorBasePtrList> state_blocks_2_factors_; + std::set<FactorBasePtr> factors_; - virtual void updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr) = 0; + virtual Eigen::VectorXd& getAssociatedMemBlock(const StateBlockPtr& state_ptr); + const double* getAssociatedMemBlockPtr(const StateBlockPtr& state_ptr) const; + virtual double* getAssociatedMemBlockPtr(const StateBlockPtr& state_ptr); - virtual bool isStateBlockRegisteredDerived(const StateBlockPtr& state_ptr) = 0; +private: + // SolverManager functions + void addFactor(const FactorBasePtr& fac_ptr); + void removeFactor(const FactorBasePtr& fac_ptr); + void addStateBlock(const StateBlockPtr& state_ptr); + void removeStateBlock(const StateBlockPtr& state_ptr); + void updateStateBlockState(const StateBlockPtr& state_ptr); + void updateStateBlockStatus(const StateBlockPtr& state_ptr); + void updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr); - virtual bool isFactorRegisteredDerived(const FactorBasePtr& fac_ptr) const = 0; +protected: + // Derived virtual functions + virtual std::string solveDerived(const ReportVerbosity report_level) = 0; + virtual void addFactorDerived(const FactorBasePtr& fac_ptr) = 0; + virtual void removeFactorDerived(const FactorBasePtr& fac_ptr) = 0; + virtual void addStateBlockDerived(const StateBlockPtr& state_ptr) = 0; + virtual void removeStateBlockDerived(const StateBlockPtr& state_ptr) = 0; + virtual void updateStateBlockStatusDerived(const StateBlockPtr& state_ptr) = 0; + virtual void updateStateBlockLocalParametrizationDerived(const StateBlockPtr& state_ptr) = 0; + virtual bool isStateBlockRegisteredDerived(const StateBlockPtr& state_ptr) = 0; + virtual bool isFactorRegisteredDerived(const FactorBasePtr& fac_ptr) const = 0; + virtual bool checkDerived(std::string prefix="") const = 0; }; } // namespace wolf diff --git a/include/core/state_block/factory_state_block.h b/include/core/state_block/factory_state_block.h new file mode 100644 index 0000000000000000000000000000000000000000..c353121b724011b993942d5a567166963a7440d0 --- /dev/null +++ b/include/core/state_block/factory_state_block.h @@ -0,0 +1,51 @@ +/* + * factory_state_block.h + * + * Created on: Apr 27, 2020 + * Author: jsola + */ + +#ifndef STATE_BLOCK_FACTORY_STATE_BLOCK_H_ +#define STATE_BLOCK_FACTORY_STATE_BLOCK_H_ + +#include "core/common/factory.h" +#include "core/state_block/state_block.h" + +namespace wolf +{ + +// State blocks factory +typedef Factory<StateBlock, const Eigen::VectorXd&, bool> FactoryStateBlock; +template<> +inline std::string FactoryStateBlock::getClass() const +{ + return "FactoryStateBlock"; +} +template<> +inline StateBlockPtr FactoryStateBlock::create(const std::string& _type, const Eigen::VectorXd& _state, bool _fixed) +{ + typename CallbackMap::const_iterator creator_callback_it = callbacks_.find(_type); + + if (creator_callback_it == callbacks_.end()) + // not found: return StateBlock base + return std::make_shared<StateBlock>(_state, _fixed); + + // Invoke the creation function + return (creator_callback_it->second)(_state, _fixed); +} + +#define WOLF_REGISTER_STATEBLOCK(StateBlockType) \ + namespace{ const bool WOLF_UNUSED StateBlockType##Registered = \ + FactoryStateBlock::get().registerCreator(#StateBlockType, StateBlockType::create); } \ + +#define WOLF_REGISTER_STATEBLOCK_WITH_KEY(Key, StateBlockType) \ + namespace{ const bool WOLF_UNUSED StateBlockType##RegisteredWith##Key = \ + FactoryStateBlock::get().registerCreator(#Key, StateBlockType::create); } \ + + + + +} + + +#endif /* STATE_BLOCK_FACTORY_STATE_BLOCK_H_ */ diff --git a/include/core/state_block/has_state_blocks.h b/include/core/state_block/has_state_blocks.h index 07c6d757bc09125c4a4e8a55aefd6d37b480c7d4..9462efe7a6dd314ff2ab94cbf923ee79f5c4e21e 100644 --- a/include/core/state_block/has_state_blocks.h +++ b/include/core/state_block/has_state_blocks.h @@ -9,6 +9,7 @@ #define STATE_BLOCK_HAS_STATE_BLOCKS_H_ #include "core/common/wolf.h" +#include "core/state_block/state_composite.h" #include <map> @@ -17,6 +18,7 @@ namespace wolf /// State of nodes containing several state blocks typedef std::unordered_map<std::string, Eigen::VectorXd> State; +//typedef std::string StateStructure; class HasStateBlocks @@ -26,7 +28,7 @@ class HasStateBlocks HasStateBlocks(const std::string& _structure) : structure_(_structure), state_block_map_() {} virtual ~HasStateBlocks(); - const std::string& getStructure() const { return structure_; } + const StateStructure& getStructure() const { return structure_; } void appendToStructure(const std::string& _frame_type){ structure_ += _frame_type; } bool isInStructure(const std::string& _sb_type) { return structure_.find(_sb_type) != std::string::npos; } @@ -62,27 +64,29 @@ class HasStateBlocks // Emplace base state blocks. template<typename ... Args> - inline StateBlockPtr emplaceStateBlock(const std::string& _sb_type, ProblemPtr _problem, Args&&... _args_of_base_state_block_constructor); + StateBlockPtr emplaceStateBlock(const std::string& _sb_type, ProblemPtr _problem, Args&&... _args_of_base_state_block_constructor); // Register/remove state blocks to/from wolf::Problem void registerNewStateBlocks(ProblemPtr _problem) const; void removeStateBlocks(ProblemPtr _problem); // States - inline void setState(const Eigen::VectorXd& _state, std::string _sub_structure="", const bool _notify = true); - void getState(Eigen::VectorXd& _state, std::string structure="") const; - Eigen::VectorXd getState(std::string structure="") const; - unsigned int getSize(std::string _sub_structure="") const; - unsigned int getLocalSize(std::string _sub_structure="") const; + VectorComposite getState(const StateStructure& structure="") const; + void setState(const VectorComposite& _state, const bool _notify = true); + void setState(const Eigen::VectorXd& _state, const StateStructure& _structure, const std::list<SizeEigen>& _sizes, const bool _notify = true); + void setState(const Eigen::VectorXd& _state, const StateStructure& _sub_structure="", const bool _notify = true); + void setState(const StateStructure& _structure, const std::list<VectorXd>& _vectors, const bool _notify = true); - State getStateComposite(); + VectorXd getStateVector(const StateStructure& structure="") const; + unsigned int getSize(const StateStructure& _sub_structure="") const; + unsigned int getLocalSize(const StateStructure& _sub_structure="") const; // Perturb state void perturb(double amplitude = 0.01); private: - std::string structure_; + StateStructure structure_; std::unordered_map<std::string, StateBlockPtr> state_block_map_; }; @@ -207,74 +211,125 @@ inline bool HasStateBlocks::isFixed() const return fixed; } -inline void HasStateBlocks::setState(const Eigen::VectorXd& _state, std::string _sub_structure, const bool _notify) +inline void HasStateBlocks::setState(const VectorComposite& _state, const bool _notify) { - if (_sub_structure == ""){ - _sub_structure = structure_; + for (const auto& pair_key_vec : _state) + { + const auto& key = pair_key_vec.first; + const auto& vec = pair_key_vec.second; + const auto& sb = getStateBlock(key); + if (!sb) + WOLF_ERROR("Stateblock key ", key, " not in the structure"); + + sb->setState(vec, _notify); } - int size = getSize(_sub_structure); +} + +inline void HasStateBlocks::setState(const Eigen::VectorXd& _state, const StateStructure& _sub_structure, const bool _notify) +{ + StateStructure structure; + if (_sub_structure == "") + structure = structure_; + else + structure = _sub_structure; + + int size = getSize(structure); assert(_state.size() == size && "In FrameBase::setState wrong state size"); unsigned int index = 0; - for (const char key : _sub_structure) + for (const char ckey : structure) { - const auto& sb = getStateBlock(key); - if (!sb){ - WOLF_ERROR("Stateblock key ", key, " not in the structure"); - } + const auto& key = string(1,ckey); + const auto& sb = getStateBlock(key); + assert (sb && "Stateblock key not in the structure"); + sb->setState(_state.segment(index, sb->getSize()), _notify); // do not notify if state block is not estimated by the solver index += sb->getSize(); } } -// _sub_structure can be either stateblock structure of the node or a subset of this structure -inline void HasStateBlocks::getState(Eigen::VectorXd& _state, std::string _sub_structure) const +inline void HasStateBlocks::setState (const Eigen::VectorXd& _state, + const StateStructure& _structure, + const std::list<SizeEigen>& _sizes, + const bool _notify) { - if (_sub_structure == ""){ - _sub_structure = structure_; + SizeEigen index = 0; + auto size_it = _sizes.begin(); + for (const auto& ckey : _structure) + { + const auto& key = string(1,ckey); + const auto& sb = getStateBlock(key); + assert (sb && "Stateblock key not in the structure"); + assert(*size_it == sb->getSize() && "State block size mismatch"); + + sb->setState(_state.segment(index, *size_it), _notify); + index += *size_it; + size_it ++; } - _state.resize(getSize(_sub_structure)); +} - unsigned int index = 0; - for (const char key : _sub_structure) + +inline void HasStateBlocks::setState(const StateStructure& _structure, const std::list<VectorXd>& _vectors, const bool _notify) +{ + auto vec_it = _vectors.begin(); + for (const auto ckey : _structure) { + const auto key = string(1,ckey); const auto& sb = getStateBlock(key); - if (!sb){ - WOLF_ERROR("Stateblock key ", key, " not in the structure"); - } - _state.segment(index,sb->getSize()) = sb->getState(); - index += sb->getSize(); - } + assert (sb && "Stateblock key not in the structure"); + assert(vec_it->size() == sb->getSize() && "State block size mismatch"); + sb->setState(*vec_it, _notify); + vec_it ++; + } } -inline Eigen::VectorXd HasStateBlocks::getState(std::string _sub_structure) const + +//// _sub_structure can be either stateblock structure of the node or a subset of this structure +inline VectorXd HasStateBlocks::getStateVector(const StateStructure& _sub_structure) const { - Eigen::VectorXd state; + StateStructure structure; + if (_sub_structure == "") + structure = structure_; + else + structure = _sub_structure; - getState(state, _sub_structure); + VectorXd state(getSize(structure)); + unsigned int index = 0; + for (const char key : structure) + { + const auto& sb = getStateBlock(key); + if (!sb){ + WOLF_ERROR("Stateblock key ", key, " not in the structure"); + } + state.segment(index,sb->getSize()) = sb->getState(); + index += sb->getSize(); + } return state; } -inline State HasStateBlocks::getStateComposite() +inline VectorComposite HasStateBlocks::getState(const StateStructure& _structure) const { - State state; - for (auto& pair_key_kf : state_block_map_) + VectorComposite state; + for (auto& pair_key_sb : state_block_map_) { - state.emplace(pair_key_kf.first, pair_key_kf.second->getState()); + state.emplace(pair_key_sb.first, pair_key_sb.second->getState()); } return state; } -inline unsigned int HasStateBlocks::getSize(std::string _sub_structure) const +inline unsigned int HasStateBlocks::getSize(const StateStructure& _sub_structure) const { - if (_sub_structure == ""){ - _sub_structure = structure_; - } + StateStructure structure; + if (_sub_structure == "") + structure = structure_; + else + structure = _sub_structure; + unsigned int size = 0; - for (const char key : _sub_structure) + for (const char key : structure) { const auto& sb = getStateBlock(key); if (!sb){ @@ -325,16 +380,16 @@ inline bool HasStateBlocks::stateBlockKey(const StateBlockPtr &_sb, std::string& } } -//inline unsigned int HasStateBlocks::getLocalSize() const -//======= -inline unsigned int HasStateBlocks::getLocalSize(std::string _sub_structure) const -//>>>>>>> devel +inline unsigned int HasStateBlocks::getLocalSize(const StateStructure& _sub_structure) const { - if (_sub_structure == ""){ - _sub_structure = structure_; - } + StateStructure structure; + if (_sub_structure == "") + structure = structure_; + else + structure = _sub_structure; + unsigned int size = 0; - for (const char key : _sub_structure) + for (const char key : structure) { const auto& sb = getStateBlock(key); if (!sb){ diff --git a/include/core/state_block/local_parametrization_base.h b/include/core/state_block/local_parametrization_base.h index 32599d9dc72a556c06f9ade7df6339f38cc7c8cf..14f2ce38f1dd55b6571884710eb7ed7b7640f985 100644 --- a/include/core/state_block/local_parametrization_base.h +++ b/include/core/state_block/local_parametrization_base.h @@ -12,8 +12,6 @@ namespace wolf { -//WOLF_PTR_TYPEDEFS(LocalParametrizationBase); - class LocalParametrizationBase{ protected: unsigned int global_size_; @@ -22,13 +20,17 @@ class LocalParametrizationBase{ LocalParametrizationBase(unsigned int _global_size, unsigned int _local_size); virtual ~LocalParametrizationBase(); + bool plus(const Eigen::VectorXd& _x, + const Eigen::VectorXd& _delta, + Eigen::VectorXd& _x_plus_delta) const; virtual bool plus(Eigen::Map<const Eigen::VectorXd>& _x, Eigen::Map<const Eigen::VectorXd>& _delta, - Eigen::Map<Eigen::VectorXd>& _x_plus_delta) const = 0; - virtual bool computeJacobian(Eigen::Map<const Eigen::VectorXd>& _x, Eigen::Map<Eigen::MatrixRowXd>& _jacobian) const = 0; + Eigen::Map<Eigen::VectorXd>& _x_plus_delta) const = 0; + virtual bool computeJacobian(Eigen::Map<const Eigen::VectorXd>& _x, + Eigen::Map<Eigen::MatrixRowXd>& _jacobian) const = 0; virtual bool minus(Eigen::Map<const Eigen::VectorXd>& _x1, Eigen::Map<const Eigen::VectorXd>& _x2, - Eigen::Map<Eigen::VectorXd>& _x2_minus_x1) = 0; + Eigen::Map<Eigen::VectorXd>& _x2_minus_x1) = 0; unsigned int getLocalSize() const; unsigned int getGlobalSize() const; diff --git a/include/core/state_block/state_angle.h b/include/core/state_block/state_angle.h index 05a87f0f25bb2af1466da5a5a5b4608b64f2a883..8b714b64c8b3bd82699fab1d845887e2bd74e10c 100644 --- a/include/core/state_block/state_angle.h +++ b/include/core/state_block/state_angle.h @@ -20,6 +20,8 @@ class StateAngle : public StateBlock StateAngle(double _angle = 0.0, bool _fixed = false); virtual ~StateAngle(); + + static StateBlockPtr create(const Eigen::VectorXd& _state, bool _fixed); }; inline StateAngle::StateAngle(double _angle, bool _fixed) : @@ -33,6 +35,12 @@ inline StateAngle::~StateAngle() // } +inline StateBlockPtr StateAngle::create (const Eigen::VectorXd& _state, bool _fixed) +{ + MatrixSizeCheck<1,1>::check(_state); + return std::make_shared<StateAngle>(_state(0), _fixed); +} + } /* namespace wolf */ #endif /* STATE_ANGLE_H_ */ diff --git a/include/core/state_block/state_block.h b/include/core/state_block/state_block.h index ab3bb7147f3c81f57a3436216412274394acc04a..c8706e2b6d081802d4a3b2590538b2e45df0584b 100644 --- a/include/core/state_block/state_block.h +++ b/include/core/state_block/state_block.h @@ -146,17 +146,21 @@ public: **/ void resetLocalParamUpdated(); + virtual void setIdentity(bool _notify = true); + void setZero (bool _notify = true); + + virtual Eigen::VectorXd identity() const; + Eigen::VectorXd zero() const; + /** \brief perturb state */ void perturb(double amplitude = 0.1); - /** \brief Add this state_block to the problem - **/ - //void addToProblem(ProblemPtr _problem_ptr); - /** \brief Remove this state_block from the problem - **/ - //void removeFromProblem(ProblemPtr _problem_ptr); + void plus(const Eigen::VectorXd& _dv); + + static StateBlockPtr create (const Eigen::VectorXd& _state, bool _fixed = false); + }; } // namespace wolf @@ -292,6 +296,30 @@ inline double* StateBlock::getStateData() return state_.data(); } +inline void StateBlock::setIdentity(bool _notify) +{ + setState( Eigen::VectorXd::Zero(state_size_), _notify ); +} + +inline void StateBlock::setZero(bool _notify) +{ + setIdentity(_notify); +} + +inline Eigen::VectorXd StateBlock::identity() const +{ + return Eigen::VectorXd::Zero(state_size_); +} +inline Eigen::VectorXd StateBlock::zero() const +{ + return identity(); +} + +inline StateBlockPtr StateBlock::create (const Eigen::VectorXd& _state, bool _fixed) +{ + return std::make_shared<StateBlock>(_state, _fixed); +} + }// namespace wolf #endif diff --git a/include/core/state_block/state_composite.h b/include/core/state_block/state_composite.h new file mode 100644 index 0000000000000000000000000000000000000000..44fdc98d588d46cbdf996ff94ec788f38bf7ce9c --- /dev/null +++ b/include/core/state_block/state_composite.h @@ -0,0 +1,370 @@ +/* + * state_composite.h + * + * Created on: Apr 6, 2020 + * Author: jsola + */ + +#ifndef STATE_BLOCK_STATE_COMPOSITE_H_ +#define STATE_BLOCK_STATE_COMPOSITE_H_ + +#include "core/common/wolf.h" + +#include <unordered_map> + +#include <iostream> + + +namespace wolf +{ + +using std::string; +using namespace Eigen; + +typedef std::string StateStructure; +typedef std::unordered_map < std::string, StateBlockPtr > StateBlockMap; +typedef StateBlockMap::const_iterator StateBlockMapCIter; + +class VectorComposite : public std::unordered_map < std::string, Eigen::VectorXd > +{ + public: + VectorComposite() {}; + VectorComposite(const StateStructure& _s); + VectorComposite(const StateStructure& _s, const std::list<int>& _sizes); + VectorComposite(const VectorComposite & v) : unordered_map<string, VectorXd>(v){}; + /** + * \brief Construct from Eigen::VectorXd and structure + * + * Usage: + * + * VectorXd vec_eigen(1,2,3,4,5); + * + * VectorComposite vec_comp( vec_eigen, "ab", {2,3} ); // vec_eigen must be at least size 5 !! + * + * result: + * + * vec_comp["a"].transpose(); // = (1,2); + * vec_comp["b"].transpose(); // = (3,4,5); + */ + VectorComposite(const VectorXd& _v, const StateStructure& _structure, const std::list<int>& _sizes); + VectorComposite(const StateStructure& _structure, const std::list<VectorXd>& _vectors); + + unsigned int size(const StateStructure& _structure) const; + + Eigen::VectorXd vector(const StateStructure& _structure) const; + + /** + * \brief set from Eigen::VectorXd and structure + * + * Usage: + * + * Eigen::VectorXd vec_eigen; + * wolf::VectorComposite vec_comp; + * + * vec_comp.set( vec_eigen, "ab", {2,3} ); // vec_eigen must be at least size 5 !! + * + * result: + * + * vec_comp["a"].transpose(); // = (1,2); + * vec_comp["b"].transpose(); // = (3,4,5); + */ + void set(const VectorXd& _v, const StateStructure& _structure, const std::list<int>& _sizes); + void setZero(); + + friend std::ostream& operator <<(std::ostream &_os, const wolf::VectorComposite &_x); + friend wolf::VectorComposite operator +(const wolf::VectorComposite &_x, const wolf::VectorComposite &_y); + friend wolf::VectorComposite operator -(const wolf::VectorComposite &_x, const wolf::VectorComposite &_y); + friend wolf::VectorComposite operator -(const wolf::VectorComposite &_x); +}; + + +class MatrixComposite : public std::unordered_map < std::string, std::unordered_map < std::string, Eigen::MatrixXd > > +{ + + private: + std::unordered_map < string, unsigned int> size_rows_, size_cols_; + unsigned int rows() const; + unsigned int cols() const; + void sizeAndIndices(const StateStructure & _struct_rows, + const StateStructure & _struct_cols, + std::unordered_map < string, unsigned int>& _indices_rows, + std::unordered_map < string, unsigned int>& _indices_cols, + unsigned int& _rows, + unsigned int& _cols) const; + + public: + MatrixComposite() {}; + MatrixComposite(const StateStructure& _row_structure, + const StateStructure& _col_structure); + MatrixComposite(const StateStructure& _row_structure, + const std::list<int>& _row_sizes, + const StateStructure& _col_structure, + const std::list<int>& _col_sizes); + MatrixComposite (const MatrixComposite& m); + /** + * \brief Construct from Eigen::VectorXd and structure + * + * Usage: + * + * VectorXd vec_eigen(1,2,3,4,5); + * + * VectorComposite vec_comp( vec_eigen, "ab", {2,3} ); // vec_eigen must be at least size 5 !! + * + * result: + * + * vec_comp["a"].transpose(); // = (1,2); + * vec_comp["b"].transpose(); // = (3,4,5); + */ + MatrixComposite(const MatrixXd& _m, + const StateStructure& _row_structure, + const std::list<int>& _row_sizes, + const StateStructure& _col_structure, + const std::list<int>& _col_sizes); + ~MatrixComposite() = default; + + bool check() const; + static MatrixComposite zero(const StateStructure& _row_structure, + const std::list<int>& _row_sizes, + const StateStructure& _col_structure, + const std::list<int>& _col_sizes); + + static MatrixComposite identity(const StateStructure& _structure, + const std::list<int>& _sizes); + + unsigned int count(const std::string &_row, + const std::string &_col) const; + + bool emplace(const std::string &_row, + const std::string &_col, + const Eigen::MatrixXd &_mat_blk); + + // throw error if queried block is not present + bool at(const std::string &_row, + const std::string &_col, + Eigen::MatrixXd &_mat_blk) const; + const MatrixXd& at(const std::string &_row, + const std::string &_col) const; + MatrixXd& at(const std::string &_row, + const std::string &_col); + + // make some shadowed API available + using std::unordered_map < std::string, std::unordered_map < std::string, Eigen::MatrixXd > >::at; + using std::unordered_map < std::string, std::unordered_map < std::string, Eigen::MatrixXd > >::count; + + + MatrixXd matrix(const StateStructure & _struct_rows, + const StateStructure & _struct_cols) const; + + MatrixComposite operator * (double scalar_right) const; + MatrixComposite operator + (const MatrixComposite & _second) const; + MatrixComposite operator - (const MatrixComposite & _second) const; + MatrixComposite operator - (void) const; + + /** + * \brief Matrix product + * + * This function computes the matrix product M * N + * + * It assumes that the second matrix's blocks are compatible with the blocks of this matrix, + * both in their structure and their individual sizes. + * + * For example: Let us call 'this' matrix with the name 'M'. + * + * The matrix 'M' maps the "PO" space into a new space "VW": + * M["V"]["P"] M["V"]["O"] + * M["W"]["P"] M["W"]["O"] + * + * The second matrix N has blocks "PO" in vertical arrangement, + * and "XY" in horizontal arrangement: + * N["P"]["X"] N["P"]["Y"] + * N["O"]["X"] N["O"]["Y"] + * + * Also, assume that the sizes of the blocks "P" and "O" are the same in M and N. + * + * Then, the result is a matrix S = M * N with block arrangements "VW" and "XY" + * S["V"]["X"] S["V"]["Y"] + * S["W"]["X"] S["W"]["Y"] + */ + MatrixComposite operator *(const MatrixComposite & _second) const; + + /** + * \brief Propagate a given covariances matrix, with 'this' being a Jacobian matrix + * + * This function computes the product J * Q * J.transpose. + * + * It considers that this is a Jacobian matrix, and that the provided matrix + * is a proper covariance (e.g. symmmetric and semi-positive). + * It also considers that the Jacobian blocks are compatible with the blocks + * of the provided covariance, both in their structure and their individual sizes. + * + * If these conditions are not satisfied, the product will fail and throw, + * or give aberrant results at best. + * + * ----- + * + * For example: Let us call 'this' a Jacobian matrix with the name 'J'. + * + * This Jacobian 'J' maps the "PO" blocks into "VW": + * + * J["V"]["P"] J["V"]["O"] + * J["W"]["P"] J["W"]["O"] + * + * The provided matrix is a covariances matrix Q. + * Q has blocks "P", "O" in both vertical and horizontal arrangements: + * + * Q["P"]["P"] Q["P"]["O"] + * Q["O"]["P"] Q["O"]["O"] + * + * Also, it is required that the sizes of the blocks "P", "O" are the same in Q and J. + * + * Now, upon a call to + * + * MatrixComposite S = J.propagate(Q); + * + * the result is a covariances matrix S with blocks "V" and "W" + * + * S["V"]["V"] S["V"]["W"] + * S["W"]["V"] S["W"]["W"] + */ + MatrixComposite propagate(const MatrixComposite & _Cov); // This performs Jac * this * Jac.tr + + /** + * \brief Matrix-vector product + * + * This function computes the matrix product M * N + * + * It assumes that the second matrix's blocks are compatible with the blocks of this matrix, + * both in their structure and their individual sizes. + * + * For example: Let us call 'this' matrix with the name 'M'. + * + * The matrix 'M' maps the "PO" space into a new space "VW": + * M["V"]["P"] M["V"]["O"] + * M["W"]["P"] M["W"]["O"] + * + * The second vector V has blocks "PO" in vertical arrangement, + * V["P"] + * V["O"] + * + * Also, assume that the sizes of the blocks "P" and "O" are the same in M and V. + * + * Then, the result is a vector S = M * V with block arrangement "VW" + * S["V"] + * S["W"] + */ + VectorComposite operator *(const VectorComposite & _second) const; + + friend std::ostream& operator << (std::ostream & _os, const MatrixComposite & _M); + + friend MatrixComposite operator * (double scalar_left, const MatrixComposite& M); +}; + + +class StateBlockComposite +{ + public: + StateBlockComposite() = default; + ~StateBlockComposite() = default; + + const StateBlockMap& getStateBlockMap() const; + + StateBlockPtr add(const std::string& _sb_type, const StateBlockPtr& _sb); + + // Emplace derived state blocks (angle, quaternion, etc). + template<typename SB, typename ... Args> + std::shared_ptr<SB> emplace(const std::string& _sb_type, Args&&... _args_of_derived_state_block_constructor); + + // Emplace base state blocks. + template<typename ... Args> + inline StateBlockPtr emplace(const std::string& _sb_type, Args&&... _args_of_base_state_block_constructor); + + unsigned int remove(const std::string& _sb_type); + bool has(const std::string& _sb_type) const { return state_block_map_.count(_sb_type) > 0; } + bool has(const StateBlockPtr& _sb) const; + StateBlockPtr at(const std::string& _sb_type) const; + void set(const std::string& _sb_type, const StateBlockPtr& _sb); + void set(const std::string& _sb_type, const VectorXd& _vec); + void setVectors(const StateStructure& _structure, const std::list<VectorXd> &_vectors); + bool key(const StateBlockPtr& _sb, std::string& _key) const; + std::string key(const StateBlockPtr& _sb) const; + StateBlockMapCIter find(const StateBlockPtr& _sb) const; + + // identity and zero (they are the same with different names) + void setIdentity(bool _notify = true); + void setZero(bool _notify = true); + VectorComposite identity() const; + VectorComposite zero() const; + + // Plus operator + void plus(const VectorComposite& _dx); + + // Perturb state with random noise + void perturb(double amplitude = 0.01); + + // These act on all state blocks. Per-block action must be done through state_block.fix() or through extended API in derived classes of this. + void fix(); + void unfix(); + bool isFixed() const; + + // Get composite of state vectors (not blocks) + VectorComposite getState() const; + bool getState(VectorComposite& _state) const; + void setState(const VectorComposite& _state); + + // Get compact Eigen vector and related things + SizeEigen stateSize() const; + SizeEigen stateSize(const StateStructure& _structure) const; + VectorXd stateVector(const StateStructure& _structure) const; + void stateVector(const StateStructure& _structure, VectorXd& _vector) const; + + private: + StateBlockMap state_block_map_; +}; + +//////////// IMPLEMENTATION //////////// + +inline unsigned int MatrixComposite::count(const std::string &_row, const std::string &_col) const +{ + const auto& rit = this->find(_row); + + if (rit == this->end()) + return 0; + + else + return rit->second.count(_col); +} + + +template<typename SB, typename ... Args> +inline std::shared_ptr<SB> wolf::StateBlockComposite::emplace(const std::string &_sb_type, + Args &&... _args_of_derived_state_block_constructor) +{ + assert(state_block_map_.count(_sb_type) == 0 && "Trying to add a state block with an existing type! Use setStateBlock instead."); + std::shared_ptr<SB> sb = std::make_shared<SB>(std::forward<Args>(_args_of_derived_state_block_constructor)...); + + add(_sb_type, sb); + + return sb; +} + +template<typename ... Args> +inline StateBlockPtr wolf::StateBlockComposite::emplace(const std::string &_sb_type, + Args &&... _args_of_base_state_block_constructor) +{ + assert(state_block_map_.count(_sb_type) == 0 && "Trying to add a state block with an existing type! Use setStateBlock instead."); + auto sb = std::make_shared<StateBlock>(std::forward<Args>(_args_of_base_state_block_constructor)...); + + add(_sb_type, sb); + + return sb; +} + +inline MatrixComposite::MatrixComposite (const MatrixComposite& m) + : unordered_map<string, unordered_map<string, MatrixXd> >(m), size_rows_(m.size_rows_), size_cols_(m.size_cols_) +{ +} + +} + + +#endif /* STATE_BLOCK_STATE_COMPOSITE_H_ */ diff --git a/include/core/state_block/state_homogeneous_3d.h b/include/core/state_block/state_homogeneous_3d.h index 4760a52b7faa2bf188b520534b8512722d209f63..ec42d19e188593b61db2a78b8f6ecbf35680216d 100644 --- a/include/core/state_block/state_homogeneous_3d.h +++ b/include/core/state_block/state_homogeneous_3d.h @@ -19,6 +19,11 @@ class StateHomogeneous3d : public StateBlock StateHomogeneous3d(bool _fixed = false); StateHomogeneous3d(const Eigen::VectorXd _state, bool _fixed = false); virtual ~StateHomogeneous3d(); + + virtual void setIdentity(bool _notify = true) override; + virtual Eigen::VectorXd identity() const override; + + static StateBlockPtr create(const Eigen::VectorXd& _state, bool _fixed); }; inline StateHomogeneous3d::StateHomogeneous3d(const Eigen::VectorXd _state, bool _fixed) : @@ -40,6 +45,23 @@ inline StateHomogeneous3d::~StateHomogeneous3d() // The local_param_ptr_ pointer is already removed by the base class } + +inline void StateHomogeneous3d::setIdentity(bool _notify) +{ + setState(Eigen::Quaterniond::Identity().coeffs(), _notify); +} + +inline Eigen::VectorXd StateHomogeneous3d::identity() const +{ + return Eigen::Quaterniond::Identity().coeffs(); +} + +inline StateBlockPtr StateHomogeneous3d::create (const Eigen::VectorXd& _state, bool _fixed) +{ + MatrixSizeCheck<4,1>::check(_state); + return std::make_shared<StateHomogeneous3d>(_state, _fixed); +} + } // namespace wolf #endif /* SRC_STATE_HOMOGENEOUS_3d_H_ */ diff --git a/include/core/state_block/state_quaternion.h b/include/core/state_block/state_quaternion.h index 3732201633ca04eeac5815b9948c8e9d7261f852..1533607134e89684674a4eec1d88d7cc83c9e6f0 100644 --- a/include/core/state_block/state_quaternion.h +++ b/include/core/state_block/state_quaternion.h @@ -20,6 +20,11 @@ class StateQuaternion : public StateBlock StateQuaternion(const Eigen::VectorXd& _state, bool _fixed = false); StateQuaternion(const Eigen::Quaterniond& _quaternion, bool _fixed = false); virtual ~StateQuaternion(); + + virtual void setIdentity(bool _notify = true) override; + virtual Eigen::VectorXd identity() const override; + + static StateBlockPtr create(const Eigen::VectorXd& _state, bool _fixed); }; inline StateQuaternion::StateQuaternion(const Eigen::Quaterniond& _quaternion, bool _fixed) : @@ -45,6 +50,23 @@ inline StateQuaternion::~StateQuaternion() // The local_param_ptr_ pointer is already removed by the base class } + +inline void StateQuaternion::setIdentity(bool _notify) +{ + setState(Eigen::Quaterniond::Identity().coeffs(), _notify); +} + +inline Eigen::VectorXd StateQuaternion::identity() const +{ + return Eigen::Quaterniond::Identity().coeffs(); +} + +inline StateBlockPtr StateQuaternion::create (const Eigen::VectorXd& _state, bool _fixed) +{ + MatrixSizeCheck<4,1>::check(_state); + return std::make_shared<StateQuaternion>(_state, _fixed); +} + } // namespace wolf #endif /* SRC_STATE_QUATERNION_H_ */ diff --git a/include/core/trajectory/trajectory_base.h b/include/core/trajectory/trajectory_base.h index 60f81c58afcb881fe8be35aae225c2ee55ac2c69..5fe9c6c9184cbdca679f5832b910be6b1bc19f99 100644 --- a/include/core/trajectory/trajectory_base.h +++ b/include/core/trajectory/trajectory_base.h @@ -26,17 +26,13 @@ class TrajectoryBase : public NodeBase, public std::enable_shared_from_this<Traj std::list<FrameBasePtr> frame_list_; protected: - std::string frame_structure_; // Defines the structure of the Frames in the Trajectory. FrameBasePtr last_key_frame_ptr_; // keeps pointer to the last key frame FrameBasePtr last_key_or_aux_frame_ptr_; // keeps pointer to the last estimated frame public: - TrajectoryBase(const std::string& _frame_sturcture); + TrajectoryBase(); virtual ~TrajectoryBase(); - // Properties - std::string getFrameStructure() const; - // Frames const FrameBasePtrList& getFrameList() const; FrameBasePtr getLastFrame() const; @@ -47,6 +43,21 @@ class TrajectoryBase : public NodeBase, public std::enable_shared_from_this<Traj void sortFrame(FrameBasePtr _frm_ptr); void updateLastFrames(); + virtual void printHeader(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream , + std::string _tabs = "") const; + void print(int depth, // + bool constr_by, // + bool metric, // + bool state_blocks, + std::ostream& stream = std::cout, + std::string _tabs = "") const; + + virtual CheckLog localCheck(bool _verbose, TrajectoryBasePtr _trj_ptr, std::ostream& _stream, std::string _tabs = "") const; + bool check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs = "") const; private: FrameBasePtr addFrame(FrameBasePtr _frame_ptr); void removeFrame(FrameBasePtr _frame_ptr); @@ -80,11 +91,6 @@ inline FrameBasePtr TrajectoryBase::getLastKeyOrAuxFrame() const return last_key_or_aux_frame_ptr_; } -inline std::string TrajectoryBase::getFrameStructure() const -{ - return frame_structure_; -} - } // namespace wolf #endif diff --git a/include/core/tree_manager/factory_tree_manager.h b/include/core/tree_manager/factory_tree_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..a56dae93e138c0f99cc51f73884a50be9f252707 --- /dev/null +++ b/include/core/tree_manager/factory_tree_manager.h @@ -0,0 +1,61 @@ +#ifndef FACTORY_TREE_MANAGER_H_ +#define FACTORY_TREE_MANAGER_H_ + +namespace wolf +{ +class TreeManagerBase; +struct ParamsTreeManagerBase; +} + +// wolf +#include "core/common/factory.h" + +// std + +namespace wolf +{ +/** \brief TreeManager factory class + * TODO + */ + +// ParamsTreeManager factory +struct ParamsTreeManagerBase; +typedef Factory<ParamsTreeManagerBase, + const std::string&> FactoryParamsTreeManager; +template<> +inline std::string FactoryParamsTreeManager::getClass() const +{ + return "FactoryParamsTreeManager"; +} + +// TreeManager factory +typedef Factory<TreeManagerBase, + const std::string&, + const ParamsTreeManagerBasePtr> FactoryTreeManager; +template<> +inline std::string FactoryTreeManager::getClass() const +{ + return "FactoryTreeManager"; +} + +#define WOLF_REGISTER_TREE_MANAGER(TreeManagerType) \ + namespace{ const bool WOLF_UNUSED TreeManagerType##Registered = \ + wolf::FactoryTreeManager::get().registerCreator(#TreeManagerType, TreeManagerType::create); } \ + +typedef Factory<TreeManagerBase, + const std::string&, + const ParamsServer&> AutoConfFactoryTreeManager; +template<> +inline std::string AutoConfFactoryTreeManager::getClass() const +{ + return "AutoConfFactoryTreeManager"; +} + + +#define WOLF_REGISTER_TREE_MANAGER_AUTO(TreeManagerType) \ + namespace{ const bool WOLF_UNUSED TreeManagerType##AutoConfRegistered = \ + wolf::AutoConfFactoryTreeManager::get().registerCreator(#TreeManagerType, TreeManagerType::create); } \ + +} /* namespace wolf */ + +#endif /* FACTORY_TREE_MANAGER_H_ */ diff --git a/include/core/tree_manager/tree_manager_base.h b/include/core/tree_manager/tree_manager_base.h new file mode 100644 index 0000000000000000000000000000000000000000..53ef9825ab029933b8c58e497e792d4f101c0406 --- /dev/null +++ b/include/core/tree_manager/tree_manager_base.h @@ -0,0 +1,82 @@ +#ifndef INCLUDE_TREE_MANAGER_BASE_H_ +#define INCLUDE_TREE_MANAGER_BASE_H_ + +// Wolf includes +#include "core/common/wolf.h" +#include "core/common/node_base.h" +#include "core/common/params_base.h" +#include "core/problem/problem.h" + +namespace wolf +{ +/* + * Macro for defining Autoconf tree manager creator for WOLF's high level API. + * + * Place a call to this macro inside your class declaration (in the tree_manager_class.h file), + * preferably just after the constructors. + * + * In order to use this macro, the derived processor class, ProcessorClass, + * must have a constructor available with the API: + * + * TreeManagerClass(const ParamsTreeManagerPtr _params); + */ +#define WOLF_TREE_MANAGER_CREATE(TreeManagerClass, ParamsTreeManagerClass) \ +static TreeManagerBasePtr create(const std::string& _unique_name, \ + const ParamsServer& _server) \ +{ \ + auto params = std::make_shared<ParamsTreeManagerClass>(_unique_name, _server); \ + \ + auto tree_manager = std::make_shared<TreeManagerClass>(params); \ + \ + tree_manager ->setName(_unique_name); \ + \ + return tree_manager; \ +} \ +static TreeManagerBasePtr create(const std::string& _unique_name, \ + const ParamsTreeManagerBasePtr _params) \ +{ \ + auto params = std::static_pointer_cast<ParamsTreeManagerClass>(_params); \ + \ + auto tree_manager = std::make_shared<TreeManagerClass>(params); \ + \ + tree_manager ->setName(_unique_name); \ + \ + return tree_manager; \ +} \ + +struct ParamsTreeManagerBase : public ParamsBase +{ + std::string prefix = "problem/tree_manager"; + ParamsTreeManagerBase() = default; + ParamsTreeManagerBase(std::string _unique_name, const ParamsServer& _server): + ParamsBase(_unique_name, _server) + { + } + + virtual ~ParamsTreeManagerBase() = default; + + std::string print() const + { + return ParamsBase::print() + "\n"; + } +}; + +class TreeManagerBase : public NodeBase +{ + public: + TreeManagerBase(const std::string& _type, ParamsTreeManagerBasePtr _params) : + NodeBase("TREE_MANAGER", _type), + params_(_params) + {} + + virtual ~TreeManagerBase(){} + + virtual void keyFrameCallback(FrameBasePtr _key_frame) = 0; + + protected: + ParamsTreeManagerBasePtr params_; +}; + +} /* namespace wolf */ + +#endif /* INCLUDE_TREE_MANAGER_BASE_H_ */ diff --git a/include/core/tree_manager/tree_manager_sliding_window.h b/include/core/tree_manager/tree_manager_sliding_window.h new file mode 100644 index 0000000000000000000000000000000000000000..8b2deec3b4fe8de046e1dd6c65c646be1a773727 --- /dev/null +++ b/include/core/tree_manager/tree_manager_sliding_window.h @@ -0,0 +1,54 @@ +#ifndef INCLUDE_TREE_MANAGER_SLIDING_WINDOW_H_ +#define INCLUDE_TREE_MANAGER_SLIDING_WINDOW_H_ + +#include "../tree_manager/tree_manager_base.h" + +namespace wolf +{ + +WOLF_STRUCT_PTR_TYPEDEFS(ParamsTreeManagerSlidingWindow) +WOLF_PTR_TYPEDEFS(TreeManagerSlidingWindow) + +struct ParamsTreeManagerSlidingWindow : public ParamsTreeManagerBase +{ + ParamsTreeManagerSlidingWindow() = default; + ParamsTreeManagerSlidingWindow(std::string _unique_name, const wolf::ParamsServer & _server) : + ParamsTreeManagerBase(_unique_name, _server) + { + n_key_frames = _server.getParam<unsigned int>(prefix + "/n_key_frames"); + fix_first_key_frame = _server.getParam<bool> (prefix + "/fix_first_key_frame"); + viral_remove_empty_parent = _server.getParam<bool> (prefix + "/viral_remove_empty_parent"); + } + std::string print() const + { + return "\n" + ParamsTreeManagerBase::print() + "\n" + + "n_key_frames: " + std::to_string(n_key_frames) + "\n" + + "fix_first_key_frame: " + std::to_string(fix_first_key_frame) + "\n" + + "viral_remove_empty_parent: " + std::to_string(viral_remove_empty_parent) + "\n"; + } + + unsigned int n_key_frames; + bool fix_first_key_frame; + bool viral_remove_empty_parent; +}; + +class TreeManagerSlidingWindow : public TreeManagerBase +{ + public: + TreeManagerSlidingWindow(ParamsTreeManagerSlidingWindowPtr _params) : + TreeManagerBase("TreeManagerSlidingWindow", _params), + params_sw_(_params) + {}; + WOLF_TREE_MANAGER_CREATE(TreeManagerSlidingWindow, ParamsTreeManagerSlidingWindow) + + virtual ~TreeManagerSlidingWindow(){} + + virtual void keyFrameCallback(FrameBasePtr _key_frame) override; + + protected: + ParamsTreeManagerSlidingWindowPtr params_sw_; +}; + +} /* namespace wolf */ + +#endif /* INCLUDE_TREE_MANAGER_SLIDING_WINDOW_H_ */ diff --git a/include/core/utils/converter.h b/include/core/utils/converter.h index a1b4a5a86ee2082b6f44bd3eb8d37e0c3a5c88d3..8c8e34935d728a505537643fa4c51bf001787bb6 100644 --- a/include/core/utils/converter.h +++ b/include/core/utils/converter.h @@ -4,6 +4,7 @@ // wolf #include "core/common/wolf.h" #include "core/utils/converter_utils.h" +#include "core/state_block/state_composite.h" // Eigen #include <eigen3/Eigen/Dense> @@ -22,6 +23,15 @@ */ namespace wolf{ +template<class A, class B> +struct Wpair : std::pair<A,B> +{ + Wpair(A first, B second): std::pair<A,B>(first, second) + { + + } +}; + //// CONVERTERS ~~~~ STRING ----> TYPE template<typename T> struct converter{ static T convert(std::string val){ @@ -120,6 +130,11 @@ struct converter<std::string>{ static std::string convert(std::pair<A,B> val){ return "{" + converter<std::string>::convert(val.first) + ":" + converter<std::string>::convert(val.second) + "}"; } + //NEW GUY + template<typename A, typename B> + static std::string convert(Wpair<A,B> val){ + return "(" + converter<std::string>::convert(val.first) + "," + converter<std::string>::convert(val.second) + ")"; + } template<typename A, typename B> static std::string convert(std::map<A,B> val){ std::string result = ""; @@ -129,6 +144,15 @@ struct converter<std::string>{ if(result.size() > 0) result = result.substr(1,result.size()); return "[" + result + "]"; } + template<typename A, typename B> + static std::string convert(std::unordered_map<A,B> val){ + std::string result = ""; + for(auto it : val){ + result += "," + converter<std::string>::convert(it); + } + if(result.size() > 0) result = result.substr(1,result.size()); + return "[" + result + "]"; + } template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> static std::string convert(Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> val){ std::string result = ""; @@ -143,7 +167,25 @@ struct converter<std::string>{ } return "[" + result + "]"; } + //// WOLF DEFINED TYPES -----> TO STRING + static std::string convert(VectorComposite val){ + //TODO + // throw std::runtime_error("TODO! We still haven't got around to implement convert for VectorComposite to String :("); + auto helper = std::unordered_map<StateStructure, Eigen::VectorXd>(); + for(const auto& pair: val) + helper.insert(std::pair<StateStructure, Eigen::VectorXd>(pair.first, pair.second)); + return converter<std::string>::convert(helper); + } + static std::string convert(MatrixComposite val){ + //TODO + // throw std::runtime_error("TODO! We still haven't got around to implement convert for MatrixComposite to String :("); + auto helper = std::unordered_map< StateStructure, std::unordered_map<StateStructure, Eigen::MatrixXd>>(); + for(const auto& pair: val) + helper.insert(std::pair<StateStructure, std::unordered_map<StateStructure, Eigen::MatrixXd>>(pair.first, pair.second)); + return converter<std::string>::convert(helper); + } }; + //// CONVERTERS ~~~~ TYPE ----> STRING template<typename A, typename B> struct converter<std::pair<A,B>>{ static std::pair<A,B> convert(std::string val){ @@ -153,6 +195,17 @@ struct converter<std::pair<A,B>>{ return std::pair<A,B>(converter<A>::convert(matches[1].str()), converter<B>::convert(matches[2].str())); } else throw std::runtime_error("Invalid string format representing a pair. Correct format is {identifier:value}. String provided: " + val); } +}; + //NEW GUY +template<typename A, typename B> +struct converter<Wpair<A,B>>{ + static Wpair<A,B> convert(std::string val){ + std::regex rgxP("\\(([^\\(,]+),([^\\)]+)\\)"); + std::smatch matches; + if(std::regex_match(val, matches, rgxP)) { + return Wpair<A,B>(converter<A>::convert(matches[1].str()), converter<B>::convert(matches[2].str())); + } else throw std::runtime_error("Invalid string format representing a Wpair. Correct format is (first,second). String provided: " + val); + } }; // TODO: WARNING!! For some reason when trying to specialize converter to std::array // it defaults to the generic T type, thus causing an error! @@ -216,5 +269,67 @@ struct converter<std::map<std::string,A>>{ return map; } }; +template<typename A, typename B> +struct converter<std::map<A,B>>{ + static std::map<A,B> convert(std::string val){ + std::regex rgxM("\\[((?:(?:\\{[^\\{:]+:[^:\\}]+\\}),?)*)\\]"); + if(not std::regex_match(val, rgxM)) + throw std::runtime_error("Invalid string representation of a Map. Correct format is [({id:value})?(,{id:value})*]. String provided: " + val); + + auto v = utils::parseList(val); + auto map = std::map<A, B>(); + for(auto it : v){ + auto p = converter<std::pair<A,B>>::convert(it); + map.insert(std::pair<A, B>(p.first, p.second)); + } + return map; + } +}; +template<typename A, typename B> +struct converter<std::unordered_map<A,B>>{ + static std::unordered_map<A,B> convert(std::string val){ + std::regex rgxM("\\[((?:(?:\\{[^\\{:]+:[^:\\}]+\\}),?)*)\\]"); + if(not std::regex_match(val, rgxM)) + throw std::runtime_error("Invalid string representation of an unordered Map. Correct format is [({id:value})?(,{id:value})*]. String provided: " + val); + + auto v = utils::parseList(val); + auto map = std::unordered_map<A, B>(); + for(auto it : v){ + auto p = converter<std::pair<A,B>>::convert(it); + map.insert(std::pair<A, B>(p.first, p.second)); + } + return map; + } +}; +//// FROM STRING -----> WOLF DEFINED TYPES +template<> +struct converter<VectorComposite>{ + static VectorComposite convert(std::string val){ + auto unordered_map = converter<std::unordered_map<StateStructure, Eigen::VectorXd>>::convert(val); + // VectorComposite result = VectorComposite(unordered_map); + // return result; + auto helper = VectorComposite(); + for(auto const& it: unordered_map) + { + helper.insert(std::pair<StateStructure, Eigen::VectorXd>(it.first, it.second)); + } + return helper; + } +}; +template<> +struct converter<MatrixComposite>{ + static MatrixComposite convert(std::string val){ + auto unordered_map = converter<std::unordered_map<StateStructure, + std::unordered_map<StateStructure, Eigen::MatrixXd>>>::convert(val); + // VectorComposite result = VectorComposite(unordered_map); + // return result; + auto helper = MatrixComposite(); + for(auto const& it: unordered_map) + { + helper.insert(std::pair<StateStructure, std::unordered_map<StateStructure, Eigen::MatrixXd>>(it.first, it.second)); + } + return helper; + } +}; } #endif diff --git a/include/core/yaml/parser_yaml.h b/include/core/yaml/parser_yaml.h index 1b6f659ebd609dffef4f3c472800cf32714f22e1..1e11cb86aeb89932815e38708f3cbf36530e2006 100644 --- a/include/core/yaml/parser_yaml.h +++ b/include/core/yaml/parser_yaml.h @@ -30,6 +30,7 @@ class ParserYAML { YAML::Node n_; }; struct PublisherManager{ + std::string package_; std::string subscriber_; std::string topic_; std::string period_; diff --git a/src/capture/capture_base.cpp b/src/capture/capture_base.cpp index d07b9b055d8197593dbdde99d05f6a4eddd46bfe..c091b5527677fb491fb2b819de8770aae7e497c2 100644 --- a/src/capture/capture_base.cpp +++ b/src/capture/capture_base.cpp @@ -17,7 +17,6 @@ CaptureBase::CaptureBase(const std::string& _type, HasStateBlocks(""), frame_ptr_(), // nullptr sensor_ptr_(_sensor_ptr), - calib_size_(0), capture_id_(++capture_id_count_), time_stamp_(_ts) { @@ -52,8 +51,6 @@ CaptureBase::CaptureBase(const std::string& _type, { WOLF_ERROR("Provided sensor parameters but no sensor pointer"); } - - updateCalibSize(); } CaptureBase::~CaptureBase() @@ -63,11 +60,26 @@ CaptureBase::~CaptureBase() void CaptureBase::remove(bool viral_remove_empty_parent) { + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) + */ if (!is_removing_) { is_removing_ = true; CaptureBasePtr this_C = shared_from_this(); // keep this alive while removing it + // remove downstream + while (!constrained_by_list_.empty()) + { + constrained_by_list_.front()->remove(viral_remove_empty_parent); // remove constrained by + } + while (!feature_list_.empty()) + { + feature_list_.front()->remove(viral_remove_empty_parent); // remove downstream + } + // Remove State Blocks removeStateBlocks(getProblem()); @@ -79,16 +91,6 @@ void CaptureBase::remove(bool viral_remove_empty_parent) if (viral_remove_empty_parent && F->getCaptureList().empty() && F->getConstrainedByList().empty()) F->remove(viral_remove_empty_parent); // remove upstream } - - // remove downstream - while (!feature_list_.empty()) - { - feature_list_.front()->remove(viral_remove_empty_parent); // remove downstream - } - while (!constrained_by_list_.empty()) - { - constrained_by_list_.front()->remove(viral_remove_empty_parent); // remove constrained by - } } } @@ -146,7 +148,7 @@ bool CaptureBase::isConstrainedBy(const FactorBasePtr &_factor) const } -const std::string& CaptureBase::getStructure() const +const StateStructure& CaptureBase::getStructure() const { if (getSensor()) return getSensor()->getStructure(); @@ -170,57 +172,11 @@ StateBlockPtr CaptureBase::getStateBlock(const std::string& _key) const void CaptureBase::fix() { HasStateBlocks::fix(); - updateCalibSize(); } void CaptureBase::unfix() { HasStateBlocks::unfix(); - updateCalibSize(); -} - -SizeEigen CaptureBase::computeCalibSize() const -{ - SizeEigen sz = 0; - for (const auto& key : getStructure()) - { - auto sb = getStateBlock(key); - if (sb && !sb->isFixed()) - sz += sb->getSize(); - } - return sz; -} - -Eigen::VectorXd CaptureBase::getCalibration() const -{ - Eigen::VectorXd calib(calib_size_); - SizeEigen index = 0; - for (const auto& key : getStructure()) - { - auto sb = getStateBlock(key); - if (sb && !sb->isFixed()) - { - calib.segment(index, sb->getSize()) = sb->getState(); - index += sb->getSize(); - } - } - return calib; -} - -void CaptureBase::setCalibration(const VectorXd& _calib) -{ - updateCalibSize(); - assert(_calib.size() == calib_size_ && "Wrong size of calibration vector"); - SizeEigen index = 0; - for (const auto& key : getStructure()) - { - auto sb = getStateBlock(key); - if (sb && !sb->isFixed()) - { - sb->setState(_calib.segment(index, sb->getSize())); - index += sb->getSize(); - } - } } void CaptureBase::move(FrameBasePtr _frm_ptr) @@ -228,15 +184,12 @@ void CaptureBase::move(FrameBasePtr _frm_ptr) WOLF_WARN_COND(this->getFrame() == nullptr, "moving a capture not linked to any frame"); WOLF_WARN_COND(_frm_ptr == nullptr, "moving a capture to a null FrameBasePtr"); + assert((this->getFrame() == nullptr || this->getFrame()->isKey()) && "Forbidden: moving a capture already linked to a KF"); + assert((_frm_ptr == nullptr || _frm_ptr->isKey()) && "Forbidden: moving a capture to a non-estimated frame"); + // Unlink if (this->getFrame()) { - if (this->getFrame()->isKey()) - { - WOLF_ERROR("moving a capture linked to a KF"); - return; - } - // unlink from previous non-key frame this->getFrame()->removeCapture(shared_from_this()); this->setFrame(nullptr); @@ -277,5 +230,161 @@ void CaptureBase::setProblem(ProblemPtr _problem) ft->setProblem(_problem); } -} // namespace wolf +void CaptureBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "Cap" << id() << " " << getType(); + if(getSensor() != nullptr) + { + _stream << " -> Sen" << getSensor()->id(); + } + else + _stream << " -> Sen-"; + + _stream << ((_depth < 3) ? " -- " + std::to_string(getFeatureList().size()) + "f" : ""); + if (_constr_by) + { + _stream << " <-- "; + for (auto cby : getConstrainedByList()) + _stream << "Fac" << cby->id() << " \t"; + } + _stream << std::endl; + + if(getStateBlockMap().size() > 0) + { + if (_metric && _state_blocks){ + for (const auto& key : getStructure()) + { + auto sb = getStateBlock(key); + _stream << _tabs << key << "[" << (sb->isFixed() ? "Fix" : "Est") << "] = ( " << sb->getState().transpose() << " )" << std::endl; + } + } + else if (_metric) + { + _stream << _tabs << (isFixed() ? "Fix" : "Est") << ", ts=" << std::setprecision(5) + << getTimeStamp(); + _stream << ",\t x= ( " << std::setprecision(2) << getStateVector() << " )"; + _stream << std::endl; + } + else if (_state_blocks) + { + _stream << " sb:"; + for (const auto& key : getStructure()) + { + const auto& sb = getStateBlock(key); + _stream << " " << key << "[" << (sb->isFixed() ? "Fix" : "Est") << "]; "; + } + _stream << std::endl; + } + } +} + +void CaptureBase::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); + if (_depth >= 3) + for (auto f : getFeatureList()) + f->print(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs + " "); +} + +CheckLog CaptureBase::localCheck(bool _verbose, CaptureBasePtr _cap_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + std::stringstream inconsistency_explanation; + + if (_verbose) + { + _stream << _tabs << "Cap" << id() << " @ " << _cap_ptr.get() << " -> Sen"; + if (getSensor()) _stream << getSensor()->id(); + else _stream << "-"; + _stream << std::endl; + _stream << _tabs << " " << "-> Prb @ " << getProblem().get() << std::endl; + _stream << _tabs << " " << "-> Frm" << getFrame()->id() << " @ " << getFrame().get() << std::endl; + } + for (auto pair: getStateBlockMap()) + { + auto sb = pair.second; + + // check for valid state block + inconsistency_explanation << "Capture " << id() << " @ " << _cap_ptr.get() << " has State block pointer " + << sb.get() << " = 0 \n"; + log.assertTrue((sb.get() != 0), inconsistency_explanation); + + if (_verbose) + { + _stream << _tabs << " " << pair.first << " sb @ " << sb.get(); + if (sb) { + auto lp = sb->getLocalParametrization(); + if (lp) + _stream << " (lp @ " << lp.get() << ")"; + } + _stream << std::endl; + } + } + + auto frm_ptr = getFrame(); + // check problem and frame pointers + inconsistency_explanation << "Capture problem pointer " << getProblem().get() + << " different from frame problem pointer " << frm_ptr->getProblem().get() << "\n"; + log.assertTrue((getProblem() == frm_ptr->getProblem()), inconsistency_explanation); + + + // check contrained_by + for (const auto& cby : getConstrainedByList()) + { + if (_verbose) + { + _stream << _tabs << " " << "<- Fac" << cby->id() << " -> "; + for (const auto& Cow : cby->getCaptureOtherList()) + _stream << " Cap" << Cow.lock()->id(); + _stream << std::endl; + } + + // check constrained_by pointer to this capture + inconsistency_explanation << "constrained by capture " << id() << " @ " << _cap_ptr.get() + << " not found among constrained-by factors\n"; + log.assertTrue((cby->hasCaptureOther(_cap_ptr)), inconsistency_explanation); + + for (auto sb : cby->getStateBlockPtrVector()) + { + if (_verbose) + { + _stream << _tabs << " " << "sb @ " << sb.get(); + if (sb) + { + auto lp = sb->getLocalParametrization(); + if (lp) + _stream << " (lp @ " << lp.get() << ")"; + } + _stream << std::endl; + } + } + } + + auto frm_cap = _cap_ptr->getFrame(); + inconsistency_explanation << "Cap" << id() << " @ " << _cap_ptr + << " ---> Frm" << frm_cap->id() << " @ " << frm_cap + << " -X-> Frm" << id(); + auto frm_cap_list = frm_cap->getCaptureList(); + auto frame_has_cap = std::find_if(frm_cap_list.begin(), frm_cap_list.end(), [&_cap_ptr](CaptureBasePtr cap){ return cap == _cap_ptr;}); + log.assertTrue(frame_has_cap != frm_cap_list.end(), inconsistency_explanation); + + for(auto f : getFeatureList()) + { + inconsistency_explanation << "Cap " << id() << " @ " << _cap_ptr + << " ---> Ftr" << f->id() << " @ " << f + << " -X-> Cap" << id(); + log.assertTrue((f->getCapture() == _cap_ptr), inconsistency_explanation); + } + return log; +} +bool CaptureBase::check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto sen_ptr = std::static_pointer_cast<CaptureBase>(_node_ptr); + auto local_log = localCheck(_verbose, sen_ptr, _stream, _tabs); + _log.compose(local_log); + + for(auto f : getFeatureList()) f->check(_log, f, _verbose, _stream, _tabs + " "); + return _log.is_consistent_; +} +} // namespace wolf diff --git a/src/capture/capture_diff_drive.cpp b/src/capture/capture_diff_drive.cpp index 05f8a5c49fb73e228b135fffc4de398e9e4ba038..7a09336470bfefeaf304cfbb817a8793c4c9a82d 100644 --- a/src/capture/capture_diff_drive.cpp +++ b/src/capture/capture_diff_drive.cpp @@ -18,8 +18,6 @@ CaptureDiffDrive::CaptureDiffDrive(const TimeStamp& _ts, _sensor_ptr, _data, _data_cov, - 3, - 3, _capture_origin_ptr, _p_ptr, _o_ptr, @@ -28,12 +26,4 @@ CaptureDiffDrive::CaptureDiffDrive(const TimeStamp& _ts, // } -Eigen::VectorXd CaptureDiffDrive::correctDelta(const VectorXd& _delta, - const VectorXd& _delta_error) const -{ - Vector3d delta_corrected = _delta + _delta_error; - delta_corrected(2) = pi2pi(delta_corrected(2)); - return delta_corrected; -} - } // namespace wolf diff --git a/src/capture/capture_motion.cpp b/src/capture/capture_motion.cpp index a736c242e7fb7047498d061d9121ce8fb56f817c..1a61a7f5c763a4508427c5fb2566c3fd53248af7 100644 --- a/src/capture/capture_motion.cpp +++ b/src/capture/capture_motion.cpp @@ -14,8 +14,6 @@ CaptureMotion::CaptureMotion(const std::string & _type, const TimeStamp& _ts, SensorBasePtr _sensor_ptr, const Eigen::VectorXd& _data, - SizeEigen _delta_size, - SizeEigen _delta_cov_size, CaptureBasePtr _capture_origin_ptr) : CaptureBase(_type, _ts, _sensor_ptr), data_(_data), @@ -31,8 +29,6 @@ CaptureMotion::CaptureMotion(const std::string & _type, SensorBasePtr _sensor_ptr, const Eigen::VectorXd& _data, const Eigen::MatrixXd& _data_cov, - SizeEigen _delta_size, - SizeEigen _delta_cov_size, CaptureBasePtr _capture_origin_ptr, StateBlockPtr _p_ptr , StateBlockPtr _o_ptr , @@ -51,24 +47,80 @@ CaptureMotion::~CaptureMotion() // } -Eigen::VectorXd CaptureMotion::getDeltaCorrected(const VectorXd& _calib_current) const +bool CaptureMotion::containsTimeStamp (const TimeStamp& _ts, double _time_tolerance) { - VectorXd calib_preint = getCalibrationPreint(); - VectorXd delta_preint = getBuffer().get().back().delta_integr_; - MatrixXd jac_calib = getBuffer().get().back().jacobian_calib_; - VectorXd delta_error = jac_calib * (_calib_current - calib_preint); - VectorXd delta_corrected = correctDelta(delta_preint, delta_error); - return delta_corrected; + // the same capture is within tolerance + if (this->time_stamp_ - _time_tolerance <= _ts && _ts <= this->time_stamp_ + _time_tolerance) + return true; + + // buffer is empty, and the capture is not within tolerance + if (this->getBuffer().empty()) + return false; + + // buffer encloses timestamp, if ts is: + // from : origin.tx + tt not included + // to : capture.ts + tt included + if (this->getOriginCapture()->getTimeStamp() +_time_tolerance < _ts and _ts <= this->getBuffer().back().ts_ + _time_tolerance) + return true; + + // not found anywhere + return false; } -Eigen::VectorXd CaptureMotion::getDeltaCorrected(const VectorXd& _calib_current, const TimeStamp& _ts) const + + + +void CaptureMotion::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const { - Motion motion = getBuffer().getMotion(_ts); - VectorXd delta_preint = motion.delta_integr_; - MatrixXd jac_calib = motion.jacobian_calib_; - VectorXd delta_error = jac_calib * (_calib_current - calib_preint_); - VectorXd delta_corrected = correctDelta(delta_preint, delta_error); - return delta_corrected; -} + _stream << _tabs << "CapM" << id() << " " << getType(); + + if(getSensor() != nullptr) + { + _stream << " -> Sen" << getSensor()->id(); + } + else + _stream << " -> Sen-"; + if (auto OC = getOriginCapture()) + { + _stream << " -> OCap" << OC->id(); + if (auto OF = OC->getFrame()) + _stream << " ; OFrm" << OF->id(); + } + + _stream << ((_depth < 3) ? " -- " + std::to_string(getFeatureList().size()) + "f" : ""); + if (_constr_by) + { + _stream << " <-- "; + for (auto cby : getConstrainedByList()) + _stream << "Fac" << cby->id() << " \t"; + } + _stream << std::endl; + if (_state_blocks) + for (const auto& sb : getStateBlockVec()) + { + if(sb != nullptr) + { + _stream << _tabs << " " << "sb: "; + _stream << (sb->isFixed() ? "Fix" : "Est"); + if (_metric) + _stream << std::setprecision(2) << " (" << sb->getState().transpose() << " )"; + _stream << std::endl; + } + } + + _stream << _tabs << " " << "buffer size : " << getBuffer().size() << std::endl; + if ( _metric && ! getBuffer().empty()) + { + _stream << _tabs << " " << "delta preint : (" << getDeltaPreint().transpose() << ")" << std::endl; +// if (hasCalibration()) +// { +// _stream << _tabs << " " << "calib preint : (" << getCalibrationPreint().transpose() << ")" << std::endl; +// _stream << _tabs << " " << "jacob preint : (" << getJacobianCalib().row(0) << ")" << std::endl; +//// _stream << _tabs << " " << "calib current: (" << getCalibration().transpose() << ")" << std::endl; +//// _stream << _tabs << " " << "delta correct: (" << getDeltaCorrected(getCalibration()).transpose() << ")" << std::endl; +// } + } + +} } diff --git a/src/capture/capture_odom_2d.cpp b/src/capture/capture_odom_2d.cpp index b024294a5df38772bc040495728958aa8cb08c4c..4755b6fe067fcbcd81c3ae66ecb4be6b562078e7 100644 --- a/src/capture/capture_odom_2d.cpp +++ b/src/capture/capture_odom_2d.cpp @@ -14,7 +14,7 @@ CaptureOdom2d::CaptureOdom2d(const TimeStamp& _init_ts, SensorBasePtr _sensor_ptr, const Eigen::VectorXd& _data, CaptureBasePtr _capture_origin_ptr): - CaptureMotion("CaptureOdom2d", _init_ts, _sensor_ptr, _data, 3, 3, _capture_origin_ptr) + CaptureMotion("CaptureOdom2d", _init_ts, _sensor_ptr, _data, _capture_origin_ptr) { // } @@ -24,7 +24,7 @@ CaptureOdom2d::CaptureOdom2d(const TimeStamp& _init_ts, const Eigen::VectorXd& _data, const Eigen::MatrixXd& _data_cov, CaptureBasePtr _capture_origin_ptr): - CaptureMotion("CaptureOdom2d", _init_ts, _sensor_ptr, _data, _data_cov, 3, 3, _capture_origin_ptr) + CaptureMotion("CaptureOdom2d", _init_ts, _sensor_ptr, _data, _data_cov, _capture_origin_ptr) { // } diff --git a/src/capture/capture_odom_3d.cpp b/src/capture/capture_odom_3d.cpp index 447e1d500f072e2754de4ed107aeb61e6e6299c0..a692011ffc2b61c0d46e9f024d39b354106feeb7 100644 --- a/src/capture/capture_odom_3d.cpp +++ b/src/capture/capture_odom_3d.cpp @@ -14,7 +14,7 @@ CaptureOdom3d::CaptureOdom3d(const TimeStamp& _init_ts, SensorBasePtr _sensor_ptr, const Eigen::VectorXd& _data, CaptureBasePtr _capture_origin_ptr): - CaptureMotion("CaptureOdom3d", _init_ts, _sensor_ptr, _data, 7, 6, _capture_origin_ptr) + CaptureMotion("CaptureOdom3d", _init_ts, _sensor_ptr, _data, _capture_origin_ptr) { // } @@ -24,7 +24,7 @@ CaptureOdom3d::CaptureOdom3d(const TimeStamp& _init_ts, const Eigen::VectorXd& _data, const Eigen::MatrixXd& _data_cov, CaptureBasePtr _capture_origin_ptr): - CaptureMotion("CaptureOdom3d", _init_ts, _sensor_ptr, _data, _data_cov, 7, 6, _capture_origin_ptr) + CaptureMotion("CaptureOdom3d", _init_ts, _sensor_ptr, _data, _data_cov, _capture_origin_ptr) { // } @@ -34,13 +34,5 @@ CaptureOdom3d::~CaptureOdom3d() // } -Eigen::VectorXd CaptureOdom3d::correctDelta(const VectorXd& _delta, const VectorXd& _delta_error) const -{ - VectorXd delta(7); - delta.head(3) = _delta.head(3) + _delta_error.head(3); - delta.tail(4) = (Quaterniond(_delta.data()+3) * exp_q(_delta_error.tail(3))).coeffs(); - return delta; -} - } /* namespace wolf */ diff --git a/src/capture/capture_velocity.cpp b/src/capture/capture_velocity.cpp deleted file mode 100644 index 538121825ba5ca528d4e850d55edb514de90a87f..0000000000000000000000000000000000000000 --- a/src/capture/capture_velocity.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "core/capture/capture_velocity.h" - -namespace wolf { - -CaptureVelocity::CaptureVelocity(const TimeStamp& _ts, - const SensorBasePtr& _sensor_ptr, - const Eigen::VectorXd& _velocity, - SizeEigen _delta_size, SizeEigen _delta_cov_size, - CaptureBasePtr _capture_origin_ptr) : - CaptureMotion("CaptureVelocity", _ts, _sensor_ptr, _velocity, - _delta_size, _delta_cov_size, _capture_origin_ptr) -{ - // -} - -CaptureVelocity::CaptureVelocity(const TimeStamp& _ts, - const SensorBasePtr& _sensor_ptr, - const Eigen::VectorXd& _velocity, - const Eigen::MatrixXd& _velocity_cov, - SizeEigen _delta_size, SizeEigen _delta_cov_size, - CaptureBasePtr _capture_origin_ptr, - StateBlockPtr _p_ptr, - StateBlockPtr _o_ptr, - StateBlockPtr _intr_ptr) : - CaptureMotion("CaptureVelocity", _ts, _sensor_ptr, _velocity, _velocity_cov, - _delta_size, _delta_cov_size, _capture_origin_ptr, - _p_ptr, _o_ptr, _intr_ptr) -{ - // -} - -const Eigen::VectorXd& CaptureVelocity::getVelocity() const -{ - return getData(); -} - -const Eigen::MatrixXd& CaptureVelocity::getVelocityCov() const -{ - return getDataCovariance(); -} - -} // namespace wolf diff --git a/src/ceres_wrapper/ceres_manager.cpp b/src/ceres_wrapper/ceres_manager.cpp index 0d8cba6f97cb7e2c2cdf067e7ebcb65d8ac79c10..b5bcfa4b7b6dc09e990adbecb93685c0294dbef5 100644 --- a/src/ceres_wrapper/ceres_manager.cpp +++ b/src/ceres_wrapper/ceres_manager.cpp @@ -37,7 +37,13 @@ CeresManager::CeresManager(const ProblemPtr& _wolf_problem, CeresManager::~CeresManager() { while (!fac_2_residual_idx_.empty()) - removeFactor(fac_2_residual_idx_.begin()->first); + removeFactorDerived(fac_2_residual_idx_.begin()->first); + + while (!state_blocks_.empty()) + { + removeStateBlockDerived(state_blocks_.begin()->first); + state_blocks_.erase(state_blocks_.begin()); + } } SolverManagerPtr CeresManager::create(const ProblemPtr &_wolf_problem, const ParamsServer& _server) @@ -48,13 +54,8 @@ CeresManager::~CeresManager() return std::make_shared<CeresManager>(_wolf_problem, opt); } -std::string CeresManager::solveImpl(const ReportVerbosity report_level) +std::string CeresManager::solveDerived(const ReportVerbosity report_level) { - // Check - #ifdef _WOLF_DEBUG - check(); - #endif - // run Ceres Solver ceres::Solve(ceres_options_, ceres_problem_.get(), &summary_); @@ -259,7 +260,7 @@ void CeresManager::computeCovariances(const std::vector<StateBlockPtr>& st_list) std::cout << "WARNING: Couldn't compute covariances!" << std::endl; } -void CeresManager::addFactor(const FactorBasePtr& fac_ptr) +void CeresManager::addFactorDerived(const FactorBasePtr& fac_ptr) { assert(fac_2_costfunction_.find(fac_ptr) == fac_2_costfunction_.end() && "adding a factor that is already in the fac_2_costfunction_ map"); @@ -287,7 +288,7 @@ void CeresManager::addFactor(const FactorBasePtr& fac_ptr) assert((unsigned int)(ceres_problem_->NumResidualBlocks()) == fac_2_residual_idx_.size() && "ceres residuals different from wrapper residuals"); } -void CeresManager::removeFactor(const FactorBasePtr& _fac_ptr) +void CeresManager::removeFactorDerived(const FactorBasePtr& _fac_ptr) { assert(fac_2_residual_idx_.find(_fac_ptr) != fac_2_residual_idx_.end() && "removing a factor that is not in the fac_2_residual map"); @@ -298,12 +299,15 @@ void CeresManager::removeFactor(const FactorBasePtr& _fac_ptr) assert((unsigned int)(ceres_problem_->NumResidualBlocks()) == fac_2_residual_idx_.size() && "ceres residuals different from wrapper residuals"); } -void CeresManager::addStateBlock(const StateBlockPtr& state_ptr) +void CeresManager::addStateBlockDerived(const StateBlockPtr& state_ptr) { + assert(state_ptr); + assert(!ceres_problem_->HasParameterBlock(getAssociatedMemBlockPtr(state_ptr)) && "adding a state block already added"); + assert(state_blocks_local_param_.count(state_ptr) == 0 && "local param stored for this state block"); + ceres::LocalParameterization* local_parametrization_ptr = nullptr; - if (state_ptr->hasLocalParametrization() && - state_blocks_local_param_.find(state_ptr)==state_blocks_local_param_.end()) + if (state_ptr->hasLocalParametrization()) { auto p = state_blocks_local_param_.emplace(state_ptr, std::make_shared<LocalParametrizationWrapper>(state_ptr->getLocalParametrization())); @@ -318,18 +322,19 @@ void CeresManager::addStateBlock(const StateBlockPtr& state_ptr) if (state_ptr->isFixed()) ceres_problem_->SetParameterBlockConstant(getAssociatedMemBlockPtr(state_ptr)); - updateStateBlockStatus(state_ptr); + updateStateBlockStatusDerived(state_ptr); } -void CeresManager::removeStateBlock(const StateBlockPtr& state_ptr) +void CeresManager::removeStateBlockDerived(const StateBlockPtr& state_ptr) { //std::cout << "CeresManager::removeStateBlock " << state_ptr.get() << " - " << getAssociatedMemBlockPtr(state_ptr) << std::endl; assert(state_ptr); + assert(ceres_problem_->HasParameterBlock(getAssociatedMemBlockPtr(state_ptr)) && "removing a state block that is not in ceres"); ceres_problem_->RemoveParameterBlock(getAssociatedMemBlockPtr(state_ptr)); state_blocks_local_param_.erase(state_ptr); } -void CeresManager::updateStateBlockStatus(const StateBlockPtr& state_ptr) +void CeresManager::updateStateBlockStatusDerived(const StateBlockPtr& state_ptr) { assert(state_ptr != nullptr); if (state_ptr->isFixed()) @@ -338,7 +343,7 @@ void CeresManager::updateStateBlockStatus(const StateBlockPtr& state_ptr) ceres_problem_->SetParameterBlockVariable(getAssociatedMemBlockPtr(state_ptr)); } -void CeresManager::updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr) +void CeresManager::updateStateBlockLocalParametrizationDerived(const StateBlockPtr& state_ptr) { assert(state_ptr != nullptr); @@ -361,17 +366,17 @@ void CeresManager::updateStateBlockLocalParametrization(const StateBlockPtr& sta // Remove all involved factors (it does not remove any parameter block) for (auto fac : involved_factors) - removeFactor(fac); + removeFactorDerived(fac); // Remove state block (it removes all involved residual blocks but they just were removed) - removeStateBlock(state_ptr); + removeStateBlockDerived(state_ptr); // Add state block - addStateBlock(state_ptr); + addStateBlockDerived(state_ptr); // Add all involved factors for (auto fac : involved_factors) - addFactor(fac); + addFactorDerived(fac); } bool CeresManager::hasConverged() @@ -410,37 +415,88 @@ ceres::CostFunctionPtr CeresManager::createCostFunction(const FactorBasePtr& _fa throw std::invalid_argument( "Wrong Jacobian Method!" ); } -void CeresManager::check() +bool CeresManager::checkDerived(std::string prefix) const { + bool ok = true; + // Check numbers - assert(ceres_problem_->NumResidualBlocks() == fac_2_costfunction_.size()); - assert(ceres_problem_->NumResidualBlocks() == fac_2_residual_idx_.size()); - assert(ceres_problem_->NumParameterBlocks() == state_blocks_.size()); + if (ceres_problem_->NumResidualBlocks() != factors_.size() or + ceres_problem_->NumResidualBlocks() != fac_2_costfunction_.size() or + ceres_problem_->NumResidualBlocks() != fac_2_residual_idx_.size()) + { + WOLF_ERROR("CeresManager::check: number of residuals mismatch - in ", prefix, ":\n\tceres_problem_->NumResidualBlocks(): ", ceres_problem_->NumResidualBlocks(), "\n\tfactors_.size(): ", factors_.size(), "\n\tfac_2_costfunction_.size(): ", fac_2_costfunction_.size(), "\n\tfac_2_residual_idx_.size(): ", fac_2_residual_idx_.size()); + ok = false; + } + if (ceres_problem_->NumParameterBlocks() != state_blocks_.size()) + { + WOLF_ERROR("CeresManager::check: number of parameters mismatch ((ceres_problem_->NumParameterBlocks(): ", ceres_problem_->NumParameterBlocks(), " != state_blocks_.size(): ", state_blocks_.size(), ") - in ", prefix); + ok = false; + } // Check parameter blocks - for (auto&& state_block_pair : state_blocks_) - assert(ceres_problem_->HasParameterBlock(state_block_pair.second.data())); + //for (auto&& state_block_pair : state_blocks_) + for (const auto& state_block_pair : state_blocks_) + { + if (!ceres_problem_->HasParameterBlock(state_block_pair.second.data())) + { + WOLF_ERROR("CeresManager::check: any state block is missing in ceres problem - in ", prefix); + ok = false; + } + } // Check residual blocks - for (auto&& fac_res_pair : fac_2_residual_idx_) + for (const auto& fac_res_pair : fac_2_residual_idx_) { + // SolverManager::factors_ + if (factors_.count(fac_res_pair.first) == 0) + { + WOLF_ERROR("CeresManager::check: factor ", fac_res_pair.first->id(), " (in fac_2_residual_idx_) not in factors_ - in ", prefix); + ok = false; + } + // costfunction - residual - assert(fac_2_costfunction_.find(fac_res_pair.first) != fac_2_costfunction_.end()); - assert(fac_2_costfunction_[fac_res_pair.first].get() == ceres_problem_->GetCostFunctionForResidualBlock(fac_res_pair.second)); + if (fac_2_costfunction_.count(fac_res_pair.first) == 0) + { + WOLF_ERROR("CeresManager::check: any factor in fac_2_residual_idx_ is not in fac_2_costfunction_ - in ", prefix); + ok = false; + } + //if (fac_2_costfunction_[fac_res_pair.first].get() != ceres_problem_->GetCostFunctionForResidualBlock(fac_res_pair.second)) + if (fac_2_costfunction_.at(fac_res_pair.first).get() != ceres_problem_->GetCostFunctionForResidualBlock(fac_res_pair.second)) + { + WOLF_ERROR("CeresManager::check: fac_2_costfunction_ and ceres mismatch - in ", prefix); + ok = false; + } // factor - residual - assert(fac_res_pair.first == static_cast<const CostFunctionWrapper*>(ceres_problem_->GetCostFunctionForResidualBlock(fac_res_pair.second))->getFactor()); + if (fac_res_pair.first != static_cast<const CostFunctionWrapper*>(ceres_problem_->GetCostFunctionForResidualBlock(fac_res_pair.second))->getFactor()) + { + WOLF_ERROR("CeresManager::check: fac_2_residual_idx_ and ceres mismatch - in ", prefix); + ok = false; + } // parameter blocks - state blocks std::vector<double*> param_blocks; ceres_problem_->GetParameterBlocksForResidualBlock(fac_res_pair.second, ¶m_blocks); - auto i = 0; - for (const StateBlockPtr& st : fac_res_pair.first->getStateBlockPtrVector()) + if (param_blocks.size() != fac_res_pair.first->getStateBlockPtrVector().size()) + { + WOLF_ERROR("CeresManager::check: number parameter blocks in ceres residual", param_blocks.size(), " different from number of state blocks in factor ", fac_res_pair.first->getStateBlockPtrVector().size(), " - in ", prefix); + ok = false; + } + else { - assert(getAssociatedMemBlockPtr(st) == param_blocks[i]); - i++; + auto i = 0; + for (const StateBlockPtr& st : fac_res_pair.first->getStateBlockPtrVector()) + { + if (getAssociatedMemBlockPtr(st) != param_blocks[i]) + { + WOLF_ERROR("CeresManager::check: parameter", i, " mismatch - in ", prefix); + ok = false; + } + i++; + } } } + return ok; } void insertSparseBlock(const Eigen::MatrixXd& ins, Eigen::SparseMatrixd& original, const unsigned int& row, const unsigned int& col) @@ -483,8 +539,8 @@ const Eigen::SparseMatrixd CeresManager::computeHessian() const StateBlockPtr sb = fac_ptr->getStateBlockPtrVector()[i]; if (!sb->isFixed()) { - assert((state_blocks_local_param_.find(sb) != state_blocks_local_param_.end()) && "factor involving a state block not added"); - assert((A.cols() >= sb->getLocalSize() + jacobians[i].cols()) - 1 && "bad A number of cols"); + assert(state_blocks_local_param_.count(sb) != 0 && "factor involving a state block not added"); + assert((A.cols() >= sb->getLocalSize() + jacobians[i].cols() - 1) && "bad A number of cols"); // insert since A_block_row has just been created so it's empty for sure if (sb->hasLocalParametrization()){ @@ -515,8 +571,8 @@ const Eigen::SparseMatrixd CeresManager::computeHessian() const } // namespace wolf -#include "core/solver/solver_factory.h" +#include "core/solver/factory_solver.h" namespace wolf { - WOLF_REGISTER_SOLVER("CERES", CeresManager) + WOLF_REGISTER_SOLVER(CeresManager) } // namespace wolf diff --git a/src/common/time_stamp.cpp b/src/common/time_stamp.cpp index 107bd0eb85917959f0b4fbdaacba3c136deacea7..528d0ad54872bc077ba74d72be0cb2cb79099d13 100644 --- a/src/common/time_stamp.cpp +++ b/src/common/time_stamp.cpp @@ -61,7 +61,7 @@ TimeStamp TimeStamp::operator -(const double& dt) const return ts; } -inline void TimeStamp::operator -=(const double& dt) +void TimeStamp::operator -=(const double& dt) { unsigned long int dt_nano = (unsigned long int)(dt*NANOSECS); time_stamp_nano_ = (dt_nano > time_stamp_nano_ ? 0 : time_stamp_nano_ - dt_nano); diff --git a/src/factor/factor_analytic.cpp b/src/factor/factor_analytic.cpp index 73bc391c2c038ec27da7e8b2fc936e054795a415..6d146706065f2ecc0d1ce51bfe1ac290a2f1d2bd 100644 --- a/src/factor/factor_analytic.cpp +++ b/src/factor/factor_analytic.cpp @@ -4,6 +4,7 @@ namespace wolf { FactorAnalytic::FactorAnalytic(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -12,7 +13,7 @@ FactorAnalytic::FactorAnalytic(const std::string& _tp, bool _apply_loss_function, FactorStatus _status, StateBlockPtr _state0Ptr, StateBlockPtr _state1Ptr, StateBlockPtr _state2Ptr, StateBlockPtr _state3Ptr, StateBlockPtr _state4Ptr, StateBlockPtr _state5Ptr, StateBlockPtr _state6Ptr, StateBlockPtr _state7Ptr, StateBlockPtr _state8Ptr, StateBlockPtr _state9Ptr ) : - FactorBase(_tp, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), + FactorBase(_tp, _feature_ptr, _frame_other_ptr, _capture_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status), state_ptr_vector_({_state0Ptr, _state1Ptr, _state2Ptr, _state3Ptr, _state4Ptr, _state5Ptr, _state6Ptr, _state7Ptr, _state8Ptr, _state9Ptr}), state_block_sizes_vector_({_state0Ptr ? (unsigned int) _state0Ptr->getSize() : 0, diff --git a/src/factor/factor_base.cpp b/src/factor/factor_base.cpp index 72b36c519a0d8d0ce2cb7ac4748e0dfc110026d0..4e18cb47d8485a7b9ee83853e863ddf20bb7e78a 100644 --- a/src/factor/factor_base.cpp +++ b/src/factor/factor_base.cpp @@ -7,6 +7,7 @@ namespace wolf { unsigned int FactorBase::factor_id_count_ = 0; FactorBase::FactorBase(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtr& _frame_other_ptr, const CaptureBasePtr& _capture_other_ptr, const FeatureBasePtr& _feature_other_ptr, @@ -15,7 +16,7 @@ FactorBase::FactorBase(const std::string& _tp, bool _apply_loss_function, FactorStatus _status) : NodeBase("FACTOR", _tp), - feature_ptr_(), + feature_ptr_(), // will be filled in link() factor_id_(++factor_id_count_), status_(_status), apply_loss_function_(_apply_loss_function), @@ -33,9 +34,14 @@ FactorBase::FactorBase(const std::string& _tp, feature_other_list_.push_back(_feature_other_ptr); if (_landmark_other_ptr) landmark_other_list_.push_back(_landmark_other_ptr); + + assert(_feature_ptr && "null feature pointer when creating a factor"); + measurement_ = _feature_ptr->getMeasurement(); + measurement_sqrt_information_upper_ = _feature_ptr->getMeasurementSquareRootInformationUpper(); } FactorBase::FactorBase(const std::string& _tp, + const FeatureBasePtr& _feature_ptr, const FrameBasePtrList& _frame_other_list, const CaptureBasePtrList& _capture_other_list, const FeatureBasePtrList& _feature_other_list, @@ -44,7 +50,7 @@ FactorBase::FactorBase(const std::string& _tp, bool _apply_loss_function, FactorStatus _status) : NodeBase("FACTOR", _tp), - feature_ptr_(), + feature_ptr_(), // will be filled in link() factor_id_(++factor_id_count_), status_(_status), apply_loss_function_(_apply_loss_function), @@ -62,25 +68,37 @@ FactorBase::FactorBase(const std::string& _tp, feature_other_list_.push_back(fo); for (auto& Lo : landmark_other_list_) landmark_other_list_.push_back(Lo); + + assert(_feature_ptr && "null feature pointer when creating a factor"); + measurement_ = _feature_ptr->getMeasurement(); + measurement_sqrt_information_upper_ = _feature_ptr->getMeasurementSquareRootInformationUpper(); } void FactorBase::remove(bool viral_remove_empty_parent) { + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) + */ if (!is_removing_) { is_removing_ = true; FactorBasePtr this_fac = shared_from_this(); // keep this alive while removing it + + // add factor to be removed from solver + if (getProblem() != nullptr and this->getStatus() == FAC_ACTIVE) + getProblem()->notifyFactor(this_fac,REMOVE); + + // remove from upstream FeatureBasePtr f = feature_ptr_.lock(); if (f) { - f->removeFactor(this_fac); // remove from upstream + f->removeFactor(this_fac); if (viral_remove_empty_parent && f->getFactorList().empty() && f->getConstrainedByList().empty()) f->remove(viral_remove_empty_parent); // remove upstream } - // add factor to be removed from solver - if (getProblem() != nullptr) - getProblem()->notifyFactor(this_fac,REMOVE); // remove other: {Frame, Capture, Feature, Landmark} for (auto& frm_ow : frame_other_list_) @@ -89,7 +107,7 @@ void FactorBase::remove(bool viral_remove_empty_parent) if (frm_o) { frm_o->removeConstrainedBy(this_fac); - if (frm_o->getConstrainedByList().empty() && frm_o->getCaptureList().empty()) + if (viral_remove_empty_parent && frm_o->getConstrainedByList().empty() && frm_o->getCaptureList().empty()) frm_o->remove(viral_remove_empty_parent); } } @@ -100,7 +118,7 @@ void FactorBase::remove(bool viral_remove_empty_parent) if (cap_o) { cap_o->removeConstrainedBy(this_fac); - if (cap_o->getConstrainedByList().empty() && cap_o->getFeatureList().empty()) + if (viral_remove_empty_parent && cap_o->getConstrainedByList().empty() && cap_o->getFeatureList().empty()) cap_o->remove(viral_remove_empty_parent); } } @@ -111,7 +129,7 @@ void FactorBase::remove(bool viral_remove_empty_parent) if (ftr_o) { ftr_o->removeConstrainedBy(this_fac); - if (ftr_o->getConstrainedByList().empty() && ftr_o->getFactorList().empty()) + if (viral_remove_empty_parent && ftr_o->getConstrainedByList().empty() && ftr_o->getFactorList().empty()) ftr_o->remove(viral_remove_empty_parent); } } @@ -122,7 +140,7 @@ void FactorBase::remove(bool viral_remove_empty_parent) if (lmk_o) { lmk_o->removeConstrainedBy(this_fac); - if (lmk_o->getConstrainedByList().empty()) + if (viral_remove_empty_parent && lmk_o->getConstrainedByList().empty()) lmk_o->remove(viral_remove_empty_parent); } } @@ -131,24 +149,6 @@ void FactorBase::remove(bool viral_remove_empty_parent) } } -const Eigen::VectorXd& FactorBase::getMeasurement() const -{ - assert(getFeature() != nullptr && "calling getMeasurement before linking with a feature"); - return getFeature()->getMeasurement(); -} - -const Eigen::MatrixXd& FactorBase::getMeasurementCovariance() const -{ - assert(getFeature() != nullptr && "calling getMeasurementCovariance before linking with a feature"); - return getFeature()->getMeasurementCovariance(); -} - -const Eigen::MatrixXd& FactorBase::getMeasurementSquareRootInformationUpper() const -{ - assert(getFeature() != nullptr && "calling getMeasurementSquareRootInformationUpper before linking with a feature"); - return getFeature()->getMeasurementSquareRootInformationUpper(); -} - CaptureBasePtr FactorBase::getCapture() const { assert(getFeature() != nullptr && "calling getCapture before linking with a feature"); @@ -241,11 +241,6 @@ bool FactorBase::hasLandmarkOther(const LandmarkBasePtr &_lmk_other) const return false; } -//void FactorBase::setApplyLossFunction(const bool _apply) -//{ -// apply_loss_function_ = _apply; -//} - void FactorBase::link(FeatureBasePtr _ftr_ptr) { assert(!is_removing_ && "linking a removed factor"); @@ -262,6 +257,10 @@ void FactorBase::link(FeatureBasePtr _ftr_ptr) _ftr_ptr->addFactor(shared_from_this()); this->setFeature(_ftr_ptr); + // if frame, should be key + if (getCapture() and getFrame()) + assert(getFrame()->isKey() && "Forbidden: linking a factor with a non-key frame."); + // set problem ( and register factor ) WOLF_WARN_COND(_ftr_ptr->getProblem() == nullptr, "ADDING FACTOR ", this->id(), " TO FEATURE ", _ftr_ptr->id(), " THAT IS NOT CONNECTED WITH PROBLEM."); this->setProblem(_ftr_ptr->getProblem()); @@ -270,7 +269,11 @@ void FactorBase::link(FeatureBasePtr _ftr_ptr) for (auto& frm_ow : frame_other_list_) { auto frame_other = frm_ow.lock(); - if(frame_other != nullptr) frame_other->addConstrainedBy(shared_from_this()); + if(frame_other != nullptr) + { + assert(frame_other->isKey() && "Forbidden: linking a factor with a non-key frame_other."); + frame_other->addConstrainedBy(shared_from_this()); + } } for (auto& cap_ow : capture_other_list_) { @@ -299,4 +302,312 @@ void FactorBase::setProblem(ProblemPtr _problem) this->getProblem()->notifyFactor(shared_from_this(),ADD); } +void FactorBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "Fac" << id() << " " << getType() << " -->"; + if ( getFrameOtherList() .empty() + && getCaptureOtherList() .empty() + && getFeatureOtherList() .empty() + && getLandmarkOtherList().empty()) + _stream << " Abs"; + + for (const auto& Fow : getFrameOtherList()) + if (!Fow.expired()) + _stream << " Frm" << Fow.lock()->id(); + for (const auto& Cow : getCaptureOtherList()) + if (!Cow.expired()) + _stream << " Cap" << Cow.lock()->id(); + for (const auto& fow : getFeatureOtherList()) + if (!fow.expired()) + _stream << " Ftr" << fow.lock()->id(); + for (const auto& Low : getLandmarkOtherList()) + if (!Low.expired()) + _stream << " Lmk" << Low.lock()->id(); + _stream << std::endl; +} + +void FactorBase::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); +} + +CheckLog FactorBase::localCheck(bool _verbose, FactorBasePtr _fac_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + std::stringstream inconsistency_explanation; + + if (_verbose) + _stream << _tabs << "Fac" << id() << " @ " << _fac_ptr.get(); + + if ( getFrameOtherList() .empty() + && getCaptureOtherList() .empty() + && getFeatureOtherList() .empty() + && getLandmarkOtherList().empty() ) // case ABSOLUTE: + { + if (_verbose) + _stream << " --> Abs."; + } + + // find constrained_by pointer in constrained frame + for (const auto& Fow : getFrameOtherList()) + { + if (!Fow.expired()) + { + const auto& Fo = Fow.lock(); + if (_verbose) + { + _stream << " ( --> Frm" << Fo->id() << " <- "; + for (auto cby : Fo->getConstrainedByList()) + _stream << " Fac" << cby->id(); + } + + // check constrained_by pointer in constrained frame + bool found = Fo->isConstrainedBy(_fac_ptr); + inconsistency_explanation << "The constrained Feature " << Fo->id() << " @ " << Fo + << " not found among constrained-by factors\n"; + log.assertTrue((found), inconsistency_explanation); + + } + } + if (_verbose && !getFrameOtherList().empty()) + _stream << ")"; + // find constrained_by pointer in constrained capture + for (const auto& Cow : getCaptureOtherList()) + { + if (!Cow.expired()) + { + const auto& Co = Cow.lock(); + + if (_verbose) + { + _stream << " ( --> Cap" << Co->id() << " <- "; + for (auto cby : Co->getConstrainedByList()) + _stream << " Fac" << cby->id(); + } + + // check constrained_by pointer in constrained frame + bool found = Co->isConstrainedBy(_fac_ptr); + inconsistency_explanation << "The constrained capture " << Co->id() << " @ " << Co + << " not found among constrained-by factors\n"; + log.assertTrue((found), inconsistency_explanation); + + } + } + if (_verbose && !getCaptureOtherList().empty()) + _stream << ")"; + // find constrained_by pointer in constrained feature + for (const auto& fow : getFeatureOtherList()) + { + if (!fow.expired()) + { + const auto& fo = fow.lock(); + if (_verbose) + { + _stream << " ( --> Ftr" << fo->id() << " <- "; + for (auto cby : fo->getConstrainedByList()) + _stream << " Fac" << cby->id(); + } + + // check constrained_by pointer in constrained feature + bool found = fo->isConstrainedBy(_fac_ptr); + inconsistency_explanation << "The constrained feature " << fo->id() << " @ " << fo + << " not found among constrained-by factors\n"; + log.assertTrue((found), inconsistency_explanation); + } + } + if (_verbose && !getFeatureOtherList().empty()) + _stream << ")"; + + // find constrained_by pointer in constrained landmark + for (const auto& Low : getLandmarkOtherList()) + { + if (Low.expired()) + { + const auto& Lo = Low.lock(); + + if (_verbose) + { + _stream << " ( --> Lmk" << Lo->id() << " <- "; + for (auto cby : Lo->getConstrainedByList()) + _stream << " Fac" << cby->id(); + } + + // check constrained_by pointer in constrained landmark + bool found = Lo->isConstrainedBy(_fac_ptr); + inconsistency_explanation << "The constrained landmark " << Lo->id() << " @ " << Lo + << " not found among constrained-by factors\n"; + log.assertTrue((found), inconsistency_explanation); + + } + } + if (_verbose && !getLandmarkOtherList().empty()) + _stream << ")"; + if (_verbose) + _stream << std::endl; + //Check Problem and feature ptrs + if (_verbose) + { + _stream << _tabs << " " << "-> Prb @ " << getProblem().get() << std::endl; + _stream << _tabs << " " << "-> Ftr" << getFeature()->id() << " @ " << getFeature().get() << std::endl; + } + auto ftr_ptr = getFeature(); + // check problem and feature pointers + inconsistency_explanation << "The factor " << id() << " @ " << _fac_ptr.get() << " problem ptr " << getProblem().get() + << " is different from Feature's problem ptr " << ftr_ptr->getProblem().get() << "\n"; + log.assertTrue((getProblem() == ftr_ptr->getProblem()), inconsistency_explanation); + + + inconsistency_explanation << "Fac" << id() << " @ " << _fac_ptr + << " ---> Ftr" << ftr_ptr->id() << " @ " << ftr_ptr + << " -X-> Fac" << id(); + auto ftr_fac_list = ftr_ptr->getFactorList(); + auto ftr_has_fac = std::find_if(ftr_fac_list.begin(), ftr_fac_list.end(), [&_fac_ptr](FactorBasePtr fac){ return fac == _fac_ptr;}); + log.assertTrue(ftr_has_fac!= ftr_fac_list.end(), inconsistency_explanation); + + // find state block pointers in all constrained nodes + SensorBasePtr S = getSensor(); // get own sensor to check sb + FrameBasePtr F = getFrame(); + CaptureBasePtr C = getCapture(); + + for (auto sb : getStateBlockPtrVector()) + { + bool found = false; + if (_verbose) + { + _stream << _tabs << " " << "sb @ " << sb.get(); + if (sb) + { + auto lp = sb->getLocalParametrization(); + if (lp) + _stream << " (lp @ " << lp.get() << ")"; + } + } + bool found_here; + + // find in own Frame + found_here = F->hasStateBlock(sb); + if (found_here && _verbose) _stream << " Frm" << F->id(); + found = found || found_here; + + // find in own Capture + found_here = C->hasStateBlock(sb); + if (found_here && _verbose) _stream << " Cap" << C->id(); + found = found || found_here; + + // Find in other Captures of the own Frame + if (!found_here) + for (auto FC : F->getCaptureList()) + { + found_here = FC->hasStateBlock(sb); + if (found_here && _verbose) _stream << " Frm" << F->id() << ".Cap" << FC->id(); + found = found || found_here; + } + + // find in own Sensor + if (S) + { + found_here = S->hasStateBlock(sb); + if (found_here && _verbose) _stream << " Sen" << S->id(); + found = found || found_here; + } + + + // find in constrained Frame + for (const auto& Fow : getFrameOtherList()) + { + if (!Fow.expired()) + { + const auto& Fo = Fow.lock(); + found_here = Fo->hasStateBlock(sb); + if (found_here && _verbose) _stream << " FrmO" << Fo->id(); + found = found || found_here; + + // find in feature other's captures + for (auto FoC : Fo->getCaptureList()) + { + found_here = FoC->hasStateBlock(sb); + if (found_here && _verbose) _stream << " FrmO" << Fo->id() << ".C" << FoC->id(); + found = found || found_here; + } + + } + } + + // find in constrained Capture + for (const auto& Cow : getCaptureOtherList()) + { + if (!Cow.expired()) + { + const auto& Co = Cow.lock(); + found_here = Co->hasStateBlock(sb); + if (found_here && _verbose) _stream << " CapO" << Co->id(); + found = found || found_here; + } + } + + // find in constrained Feature + for (const auto& fow : getFeatureOtherList()) + { + if (!fow.expired()) + { + const auto& fo = fow.lock(); + // find in constrained feature's Frame + auto foF = fo->getFrame(); + found_here = foF->hasStateBlock(sb); + if (found_here && _verbose) _stream << " FtrOF" << foF->id(); + found = found || found_here; + + // find in constrained feature's Capture + auto foC = fo->getCapture(); + found_here = foC->hasStateBlock(sb); + if (found_here && _verbose) _stream << " FtrOC" << foC->id(); + found = found || found_here; + + // find in constrained feature's Sensor + auto foS = fo->getCapture()->getSensor(); + found_here = foS->hasStateBlock(sb); + if (found_here && _verbose) _stream << " FtrOS" << foS->id(); + found = found || found_here; + } + } + + // find in constrained landmark + for (const auto& Low : getLandmarkOtherList()) + { + if (!Low.expired()) + { + const auto& Lo = Low.lock(); + found_here = Lo->hasStateBlock(sb); + if (found_here && _verbose) _stream << " LmkO" << Lo->id(); + found = found || found_here; + } + } + + if (_verbose) + { + if (found) + _stream << " found"; + else + _stream << " NOT FOUND !"; + _stream << std::endl; + } + + // check that the state block has been found somewhere + inconsistency_explanation << "The stateblock " << sb << " has not been found (is floating!)"; + log.assertTrue((found), inconsistency_explanation); + + inconsistency_explanation << "The stateblock " << sb << " of factor " << id() << " @ " << _fac_ptr << " is null\n"; + log.assertTrue((sb.get() != nullptr), inconsistency_explanation); + } + return log; +} + +bool FactorBase::check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto fac_ptr = std::static_pointer_cast<FactorBase>(_node_ptr); + auto local_log = localCheck(_verbose, fac_ptr, _stream, _tabs); + _log.compose(local_log); + + return _log.is_consistent_; +} } // namespace wolf diff --git a/src/feature/feature_base.cpp b/src/feature/feature_base.cpp index 8dc3801efa5f93e5bd0df593442e4860cb75135e..69133345e0f57c28e3135aa3b50e0d99e179be50 100644 --- a/src/feature/feature_base.cpp +++ b/src/feature/feature_base.cpp @@ -39,20 +39,16 @@ FeatureBase::~FeatureBase() void FeatureBase::remove(bool viral_remove_empty_parent) { + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) + */ if (!is_removing_) { is_removing_ = true; FeatureBasePtr this_f = shared_from_this(); // keep this alive while removing it - // remove from upstream - CaptureBasePtr C = capture_ptr_.lock(); - if (C) - { - C->removeFeature(this_f); // remove from upstream - if (viral_remove_empty_parent && C->getFeatureList().empty() && C->getConstrainedByList().empty()) - C->remove(viral_remove_empty_parent); // remove upstream - } - // remove downstream while (!factor_list_.empty()) { @@ -62,6 +58,15 @@ void FeatureBase::remove(bool viral_remove_empty_parent) { constrained_by_list_.front()->remove(viral_remove_empty_parent); // remove constrained } + + // remove from upstream + CaptureBasePtr C = capture_ptr_.lock(); + if (C) + { + C->removeFeature(this_f); // remove from upstream + if (viral_remove_empty_parent && C->getFeatureList().empty() && C->getConstrainedByList().empty()) + C->remove(viral_remove_empty_parent); // remove upstream + } } } @@ -142,6 +147,11 @@ void FeatureBase::setMeasurementInformation(const Eigen::MatrixXd & _meas_info) measurement_sqrt_information_upper_ = computeSqrtUpper(_meas_info); } +void FeatureBase::setMeasurement(const Eigen::VectorXd& _meas) +{ + measurement_ = _meas; +} + void FeatureBase::setProblem(ProblemPtr _problem) { NodeBase::setProblem(_problem); @@ -165,4 +175,93 @@ void FeatureBase::link(CaptureBasePtr _cpt_ptr) WOLF_WARN("Linking with nullptr"); } } +void FeatureBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "Ftr" << id() << " trk" << trackId() << " " << getType() << ((_depth < 4) ? " -- " + std::to_string(getFactorList().size()) + "c " : ""); + if (_constr_by) + { + _stream << " <--\t"; + for (auto cby : getConstrainedByList()) + _stream << "Fac" << cby->id() << " \t"; + } + _stream << std::endl; + if (_metric) + _stream << _tabs << " " << "m = ( " << std::setprecision(2) << getMeasurement().transpose() + << " )" << std::endl; + +} + +void FeatureBase::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); + if (_depth >= 4) + for (auto c : getFactorList()) + c->print(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs + " "); +} + +CheckLog FeatureBase::localCheck(bool _verbose, FeatureBasePtr _ftr_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + std::stringstream inconsistency_explanation; + + if (_verbose) + { + _stream << _tabs << "Ftr" << id() << " @ " << _ftr_ptr.get() << std::endl; + _stream << _tabs << " " << "-> Prb @ " << getProblem().get() << std::endl; + _stream << _tabs << " " << "-> Cap" << getCapture()->id() << " @ " << getCapture().get() + << std::endl; + } + + auto cap_ptr = getCapture(); + // check problem and capture pointers + inconsistency_explanation << "Feature frame problem pointer " << getProblem().get() + << " different from Capture problem pointer " << cap_ptr->getProblem().get() << "\n"; + log.assertTrue((getProblem() == cap_ptr->getProblem()), inconsistency_explanation); + + + // check contrained_by + for (auto cby : getConstrainedByList()) + { + if (_verbose) + { + _stream << _tabs << " " << "<- Fac" << cby->id() << " -> "; + for (const auto& fow : cby->getFeatureOtherList()) + _stream << " Ftr" << fow.lock()->id(); + _stream << std::endl; + } + + // check constrained_by pointer to this feature + inconsistency_explanation << "constrained by Feature " << id() << " @ " << _ftr_ptr.get() + << " not found among constrained-by factors\n"; + log.assertTrue((cby->hasFeatureOther(_ftr_ptr)), inconsistency_explanation); + + } + + auto cap_ftr = _ftr_ptr->getCapture(); + inconsistency_explanation << "Ftr" << id() << " @ " << _ftr_ptr + << " ---> Cap" << cap_ftr->id() << " @ " << cap_ftr + << " -X-> Ftr" << id(); + auto cap_ftr_list = cap_ftr->getFeatureList(); + auto frame_has_cap = std::find_if(cap_ftr_list.begin(), cap_ftr_list.end(), [&_ftr_ptr](FeatureBasePtr ftr){ return ftr == _ftr_ptr;}); + log.assertTrue(frame_has_cap != cap_ftr_list.end(), inconsistency_explanation); + + for(auto fac : getFactorList()) + { + inconsistency_explanation << "Ftr" << id() << " @ " << _ftr_ptr + << " ---> Fac" << fac->id() << " @ " << fac + << " -X-> Ftr" << id(); + log.assertTrue((fac->getFeature() == _ftr_ptr), inconsistency_explanation); + } + return log; +} +bool FeatureBase::check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto ftr_ptr = std::static_pointer_cast<FeatureBase>(_node_ptr); + auto local_log = localCheck(_verbose, ftr_ptr, _stream, _tabs); + _log.compose(local_log); + + for(auto f : getFactorList()) f->check(_log, f, _verbose, _stream, _tabs + " "); + + return _log.is_consistent_; +} } // namespace wolf diff --git a/src/frame/frame_base.cpp b/src/frame/frame_base.cpp index c0f4d310e1062c9a68ea94a0ee0b70f912cd9d15..de9fc606991d9f3b9cc73d52f130123c07e3d6e1 100644 --- a/src/frame/frame_base.cpp +++ b/src/frame/frame_base.cpp @@ -6,35 +6,69 @@ #include "core/state_block/state_block.h" #include "core/state_block/state_angle.h" #include "core/state_block/state_quaternion.h" +#include "core/state_block/factory_state_block.h" namespace wolf { unsigned int FrameBase::frame_id_count_ = 0; -FrameBase::FrameBase(const TimeStamp& _ts, StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, StateBlockPtr _v_ptr) : - NodeBase("FRAME", "Base"), - HasStateBlocks(""), - trajectory_ptr_(), - frame_id_(++frame_id_count_), - type_(NON_ESTIMATED), - time_stamp_(_ts) +FrameBase::FrameBase(const FrameType & _tp, + const TimeStamp& _ts, + const std::string _frame_structure, + const VectorComposite& _state) : + NodeBase("FRAME", "FrameBase"), + HasStateBlocks(_frame_structure), + trajectory_ptr_(), + frame_id_(++frame_id_count_), + type_(_tp), + time_stamp_(_ts) { - if (_p_ptr) + for (const auto& pair_key_vec : _state) { - addStateBlock("P", _p_ptr); - } - if (_o_ptr) - { - addStateBlock("O", _o_ptr); + const auto& key = pair_key_vec.first; + const auto& vec = pair_key_vec.second; + + StateBlockPtr sb = FactoryStateBlock::get().create(key, vec, false); // false = non fixed + + addStateBlock(key, sb); } - if (_v_ptr) +} + + +FrameBase::FrameBase(const FrameType & _tp, + const TimeStamp& _ts, + const std::string _frame_structure, + const std::list<VectorXd>& _vectors) : + NodeBase("FRAME", "FrameBase"), + HasStateBlocks(_frame_structure), + trajectory_ptr_(), + frame_id_(++frame_id_count_), + type_(_tp), + time_stamp_(_ts) +{ + assert(_frame_structure.size() == _vectors.size() && "Structure size does not match number of provided vectors!"); + + auto vec_it = _vectors.begin(); + for (const auto ckey : _frame_structure) { - addStateBlock("V", _v_ptr); + const auto& key = string(1,ckey); + const auto& vec = *vec_it; + + StateBlockPtr sb = FactoryStateBlock::get().create(key, vec, false); // false = non fixed + + addStateBlock(key, sb); + + vec_it++; } } -FrameBase::FrameBase(const FrameType & _tp, const TimeStamp& _ts, StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, StateBlockPtr _v_ptr) : - NodeBase("FRAME", "Base"), + +FrameBase::FrameBase(const FrameType & _tp, + const TimeStamp& _ts, + StateBlockPtr _p_ptr, + StateBlockPtr _o_ptr, + StateBlockPtr _v_ptr) : + NodeBase("FRAME", "FrameBase"), HasStateBlocks(""), trajectory_ptr_(), frame_id_(++frame_id_count_), @@ -55,8 +89,12 @@ FrameBase::FrameBase(const FrameType & _tp, const TimeStamp& _ts, StateBlockPtr } } -FrameBase::FrameBase(const std::string _frame_structure, const SizeEigen _dim, const FrameType & _tp, const TimeStamp& _ts, const Eigen::VectorXd& _x) : - NodeBase("FRAME", "Base"), +FrameBase::FrameBase(const FrameType & _tp, + const TimeStamp& _ts, + const std::string _frame_structure, + const SizeEigen _dim, + const Eigen::VectorXd& _x) : + NodeBase("FRAME", "FrameBase"), HasStateBlocks(_frame_structure), trajectory_ptr_(), frame_id_(++frame_id_count_), @@ -117,31 +155,36 @@ FrameBase::~FrameBase() void FrameBase::remove(bool viral_remove_empty_parent) { + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) + */ if (!is_removing_) { is_removing_ = true; FrameBasePtr this_F = shared_from_this(); // keep this alive while removing it - // remove from upstream - TrajectoryBasePtr T = trajectory_ptr_.lock(); - if (T) + // remove downstream + while (!constrained_by_list_.empty()) { - T->removeFrame(this_F); // remove from upstream + constrained_by_list_.front()->remove(viral_remove_empty_parent); // remove constrained } - - // remove downstream while (!capture_list_.empty()) { capture_list_.front()->remove(viral_remove_empty_parent); // remove downstream } - while (!constrained_by_list_.empty()) - { - constrained_by_list_.front()->remove(viral_remove_empty_parent); // remove constrained - } // Remove Frame State Blocks if ( isKeyOrAux() ) removeStateBlocks(getProblem()); + + // remove from upstream + TrajectoryBasePtr T = trajectory_ptr_.lock(); + if (T) + { + T->removeFrame(this_F); // remove from upstream + } } } @@ -359,4 +402,157 @@ void FrameBase::setProblem(ProblemPtr _problem) cap->setProblem(_problem); } +void FrameBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << (isKeyOrAux() ? (isKey() ? "KFrm" : "AFrm") : "Frm") << id() + << " " << getStructure() + << " ts = " << std::setprecision(3) << getTimeStamp() + << ((_depth < 2) ? " -- " + std::to_string(getCaptureList().size()) + "C " : ""); + if (_constr_by) + { + _stream << " <-- "; + for (auto cby : getConstrainedByList()) + _stream << "Fac" << cby->id() << " \t"; + } + _stream << std::endl; + + if (_metric && _state_blocks) + { + for (const auto& key : getStructure()) + { + auto sb = getStateBlock(key); + _stream << _tabs << " " << key + << "[" << (sb->isFixed() ? "Fix" : "Est") + << "] = ( " << std::setprecision(3) << sb->getState().transpose() << " )" + << std::endl; + } + } + else if (_metric) + { + _stream << _tabs << " " << (isFixed() ? "Fix" : "Est"); + _stream << ",\t x = ( " << std::setprecision(3) << getStateVector().transpose() << " )"; + _stream << std::endl; + } + else if (_state_blocks) + { + _stream << _tabs << " " << "sb:"; + for (const auto& key : getStructure()) + { + const auto& sb = getStateBlock(key); + _stream << " " << key << "[" << (sb->isFixed() ? "Fix" : "Est") << "]; "; + } + _stream << std::endl; + } +} + +void FrameBase::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); + if (_depth >= 2) + for (auto C : getCaptureList()) + C->print(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs + " "); +} + +CheckLog FrameBase::localCheck(bool _verbose, FrameBasePtr _frm_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + std::stringstream inconsistency_explanation; + + if (_verbose) { + _stream << _tabs << (isKeyOrAux() ? (isKey() ? "KFrm" : "EFrm") : "Frm") + << id() << " @ " << _frm_ptr.get() << std::endl; + _stream << _tabs << " " << "-> Prb @ " << getProblem().get() << std::endl; + _stream << _tabs << " " << "-> Trj @ " << getTrajectory().get() << std::endl; + } + for (const auto &pair: getStateBlockMap()) { + + auto sb = pair.second; + + // check for valid state block + inconsistency_explanation << "Frame " << id() << " @ "<< _frm_ptr.get() + << " has State block pointer " << sb.get() + << " = 0 \n"; + log.assertTrue((sb.get() != 0), inconsistency_explanation); + + if (_verbose) { + _stream << _tabs << " " << pair.first << " sb @ " << sb.get(); + if (sb) { + auto lp = sb->getLocalParametrization(); + if (lp) + _stream << " (lp @ " << lp.get() << ")"; + } + _stream << std::endl; + } + } + + // check problem pointer + auto trajectory_ptr = getTrajectory(); + auto trajectory_problem_ptr = trajectory_ptr->getProblem(); + inconsistency_explanation << "Frame problem pointer " << getProblem().get() + << " different from Trajectory problem pointer " << trajectory_problem_ptr.get() << "\n"; + log.assertTrue((getProblem() == trajectory_problem_ptr), inconsistency_explanation); + + // // check trajectory pointer + // inconsistency_explanation << "Frame trajectory pointer is " << getTrajectory() + // << " but trajectory pointer is" << trajectory_ptr << "\n"; + // log.assertTrue((getTrajectory() == T, inconsistency_explanation); + + // check constrained_by + for (auto cby : getConstrainedByList()) + { + if (_verbose) + { + _stream << _tabs << " " << "<- Fac" << cby->id() << " -> "; + for (const auto& Fow : cby->getFrameOtherList()) + _stream << " Frm" << Fow.lock()->id() << std::endl; + + + // check constrained_by pointer to this frame + inconsistency_explanation << "constrained-by frame " << id() << " @ " << _frm_ptr + << " not found among constrained-by factors\n"; + auto F = std::static_pointer_cast<FrameBase>(_frm_ptr); + log.assertTrue((cby->hasFrameOther(F)), inconsistency_explanation); + + for (auto sb : cby->getStateBlockPtrVector()) + { + if (_verbose) { + _stream << _tabs << " " << "sb @ " << sb.get(); + if (sb) { + auto lp = sb->getLocalParametrization(); + if (lp) + _stream << " (lp @ " << lp.get() << ")"; + } + _stream << std::endl; + } + } + } + } + + auto trj_ptr = getTrajectory(); + inconsistency_explanation << "Frm" << id() << " @ " << _frm_ptr + << " ---> Trj" << " @ " << trj_ptr + << " -X-> Frm" << id(); + auto trj_frm_list = trj_ptr->getFrameList(); + auto trj_has_frm = std::find_if(trj_frm_list.begin(), trj_frm_list.end(), [&_frm_ptr](FrameBasePtr frm){ return frm == _frm_ptr;}); + log.assertTrue(trj_has_frm != trj_frm_list.end(), inconsistency_explanation); + + for(auto C : getCaptureList()) + { + inconsistency_explanation << "Frm " << id() << " @ " << _frm_ptr + << " ---> Cap" << C->id() << " @ " << C + << " -X-> Frm" << id(); + log.assertTrue((C->getFrame() == _frm_ptr), inconsistency_explanation); + } + return log; +} + +bool FrameBase::check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto frm_ptr = std::static_pointer_cast<FrameBase>(_node_ptr); + auto local_log = localCheck(_verbose, frm_ptr, _stream, _tabs); + _log.compose(local_log); + for(auto C : getCaptureList()) C->check(_log, C, _verbose, _stream, _tabs + " "); + + return _log.is_consistent_; +} } // namespace wolf diff --git a/src/hardware/hardware_base.cpp b/src/hardware/hardware_base.cpp index adda7984748ebfb2fa6e40517f0d1bedc331efd2..72f07b8e216e6ca830ec9021dbb7ca1144d09860 100644 --- a/src/hardware/hardware_base.cpp +++ b/src/hardware/hardware_base.cpp @@ -4,7 +4,7 @@ namespace wolf { HardwareBase::HardwareBase() : - NodeBase("HARDWARE", "Base") + NodeBase("HARDWARE", "HardwareBase") { // std::cout << "constructed H" << std::endl; } @@ -20,4 +20,41 @@ SensorBasePtr HardwareBase::addSensor(SensorBasePtr _sensor_ptr) return _sensor_ptr; } +void HardwareBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "Hardware" << ((_depth < 1) ? (" -- " + std::to_string(getSensorList().size()) + "S") : "") << std::endl; + +} +void HardwareBase::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); + if (_depth >= 1) + for (auto S : getSensorList()) + S->print(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs + " "); +} + +CheckLog HardwareBase::localCheck(bool _verbose, HardwareBasePtr _hwd_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + std::stringstream inconsistency_explanation; + if (_verbose) + { + _stream << _tabs << "Hrw @ " << _hwd_ptr.get() << std::endl; + } + + // check pointer to Problem + inconsistency_explanation << "Hwd->getProblem() [" << getProblem().get() + << "] -> " << " Prb->getHardware() [" << getProblem()->getHardware().get() << "] -> Hwd [" << _hwd_ptr.get() << "] Mismatch!\n"; + log.assertTrue((_hwd_ptr->getProblem()->getHardware().get() == _hwd_ptr.get()), inconsistency_explanation); + return log; +} +bool HardwareBase::check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto hwd_ptr = std::static_pointer_cast<HardwareBase>(_node_ptr); + auto local_log = localCheck(_verbose, hwd_ptr, _stream, _tabs); + _log.compose(local_log); + for (auto S : getSensorList()) + S->check(_log, S, _verbose, _stream, _tabs + " "); + return _log.is_consistent_; +} } // namespace wolf diff --git a/src/landmark/landmark_base.cpp b/src/landmark/landmark_base.cpp index bc57f27294e6a0b05d67cbcf44725dd2b819f63b..ada2bef9648e15ca6a2809d9bf35dc88f2e454ac 100644 --- a/src/landmark/landmark_base.cpp +++ b/src/landmark/landmark_base.cpp @@ -37,16 +37,16 @@ LandmarkBase::~LandmarkBase() void LandmarkBase::remove(bool viral_remove_empty_parent) { + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) + */ if (!is_removing_) { is_removing_ = true; LandmarkBasePtr this_L = shared_from_this(); // keep this alive while removing it - // remove from upstream - auto M = map_ptr_.lock(); - if (M) - M->removeLandmark(this_L); - // remove constrained by while (!constrained_by_list_.empty()) { @@ -55,6 +55,11 @@ void LandmarkBase::remove(bool viral_remove_empty_parent) // Remove State Blocks removeStateBlocks(getProblem()); + + // remove from upstream + auto M = map_ptr_.lock(); + if (M) + M->removeLandmark(this_L); } } @@ -153,6 +158,46 @@ bool LandmarkBase::isConstrainedBy(const FactorBasePtr &_factor) const return false; } +void LandmarkBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "Lmk" << id() << " " << getType(); + if (_constr_by) + { + _stream << "\t<-- "; + for (auto cby : getConstrainedByList()) + _stream << "Fac" << cby->id() << " \t"; + } + _stream << std::endl; + + if (_metric && _state_blocks){ + for (const auto& key : getStructure()) + { + auto sb = getStateBlock(key); + _stream << " " << key << "[" << (sb->isFixed() ? "Fix" : "Est") << "] = ( " << sb->getState().transpose() << " )" << std::endl; + } + } + else if (_metric) + { + _stream << _tabs << " " << (isFixed() ? "Fix" : "Est"); + _stream << ",\t x = ( " << std::setprecision(2) << getStateVector().transpose() << " )"; + _stream << std::endl; + } + else if (_state_blocks) + { + _stream << _tabs << " " << "sb:"; + for (const auto& key : getStructure()) + { + const auto& sb = getStateBlock(key); + _stream << " " << key << "[" << (sb->isFixed() ? "Fix" : "Est") << "]; "; + } + _stream << std::endl; + } +} + +void LandmarkBase::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); +} LandmarkBasePtr LandmarkBase::create(const YAML::Node& _node) { unsigned int id = _node["id"] .as< unsigned int >(); @@ -179,10 +224,94 @@ LandmarkBasePtr LandmarkBase::create(const YAML::Node& _node) return lmk; } +CheckLog LandmarkBase::localCheck(bool _verbose, LandmarkBasePtr _lmk_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + std::stringstream inconsistency_explanation; + + if (_verbose) + { + _stream << _tabs << "Lmk" << id() << " @ " << _lmk_ptr.get() << std::endl; + _stream << _tabs << " -> Prb @ " << getProblem().get() << std::endl; + _stream << _tabs << " -> Map @ " << getMap().get() << std::endl; + for (const auto& pair : getStateBlockMap()) + { + auto sb = pair.second; + _stream << _tabs << " " << pair.first << " sb @ " << sb.get(); + if (sb) + { + auto lp = sb->getLocalParametrization(); + if (lp) + _stream << " (lp @ " << lp.get() << ")"; + } + _stream << std::endl; + } + } + + auto map_ptr = getMap(); + // check problem and map pointers + inconsistency_explanation << "Landmarks' problem ptr " + << getProblem().get() << " different from Map's problem ptr " + << map_ptr->getProblem().get() << "\n"; + + log.assertTrue((getProblem() == map_ptr->getProblem()), inconsistency_explanation); + + for (auto cby : getConstrainedByList()) + { + if (_verbose) + { + _stream << _tabs << " " << "<- Fac" << cby->id() << " ->"; + + for (const auto& Low : cby->getLandmarkOtherList()) + { + if (!Low.expired()) + { + const auto& Lo = Low.lock(); + _stream << " Lmk" << Lo->id(); + } + } + _stream << std::endl; + } + + // check constrained-by factors + inconsistency_explanation << "constrained-by landmark " << id() << " @ " << _lmk_ptr.get() + << " not found among constrained-by factors\n"; + log.assertTrue((cby->hasLandmarkOther(_lmk_ptr)), inconsistency_explanation); + + for (auto sb : cby->getStateBlockPtrVector()) { + if (_verbose) { + _stream << _tabs << " " << "sb @ " << sb.get(); + if (sb) { + auto lp = sb->getLocalParametrization(); + if (lp) + _stream << " (lp @ " << lp.get() << ")"; + } + _stream << std::endl; + } + } + } + + inconsistency_explanation << "Lmk" << id() << " @ " << _lmk_ptr + << " ---> Map" << map_ptr + << " -X-> Lmk" << id(); + auto map_lmk_list = map_ptr->getLandmarkList(); + auto map_has_lmk = std::find_if(map_lmk_list.begin(), map_lmk_list.end(), [&_lmk_ptr](LandmarkBasePtr lmk){ return lmk == _lmk_ptr;}); + log.assertTrue(map_has_lmk != map_lmk_list.end(), inconsistency_explanation); + + return log; +} +bool LandmarkBase::check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto lmk_ptr = std::static_pointer_cast<LandmarkBase>(_node_ptr); + auto local_log = localCheck(_verbose, lmk_ptr, _stream, _tabs); + _log.compose(local_log); + + return _log.is_consistent_; +} // Register landmark creator namespace { -const bool WOLF_UNUSED registered_lmk_base = LandmarkFactory::get().registerCreator("LandmarkBase", LandmarkBase::create); +const bool WOLF_UNUSED registered_lmk_base = FactoryLandmark::get().registerCreator("LandmarkBase", LandmarkBase::create); } } // namespace wolf diff --git a/src/map/map_base.cpp b/src/map/map_base.cpp index 3a3d32f8ac073ba88160995f69af8e1c150426bb..4c13360effa052b61b189042a95d2ec92bedfa4d 100644 --- a/src/map/map_base.cpp +++ b/src/map/map_base.cpp @@ -49,7 +49,7 @@ void MapBase::load(const std::string& _map_file_dot_yaml) for (unsigned int i = 0; i < nlandmarks; i++) { YAML::Node lmk_node = map["landmarks"][i]; - LandmarkBasePtr lmk_ptr = LandmarkFactory::get().create(lmk_node["type"].as<std::string>(), lmk_node); + LandmarkBasePtr lmk_ptr = FactoryLandmark::get().create(lmk_node["type"].as<std::string>(), lmk_node); lmk_ptr->link(shared_from_this()); } @@ -90,4 +90,39 @@ std::string MapBase::dateTimeNow() return date_time; } +void MapBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "Map" << ((_depth < 1) ? (" -- " + std::to_string(getLandmarkList().size()) + "L") : "") << std::endl; +} +void MapBase::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); + if (_depth >= 1) + for (auto L : getLandmarkList()) + L->print(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs + " "); +} + +CheckLog MapBase::localCheck(bool _verbose, MapBasePtr _map_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + std::stringstream inconsistency_explanation; + + if (_verbose) + _stream << _tabs << "Map @ " << _map_ptr.get() << std::endl; + + // check pointer to Problem + inconsistency_explanation << "Map->getProblem() [" << getProblem().get() + << "] -> " << " Prb->getMap() [" << getProblem()->getMap().get() << "] -> Map [" << _map_ptr.get() << "] Mismatch!\n"; + log.assertTrue((_map_ptr->getProblem()->getMap().get() == _map_ptr.get()), inconsistency_explanation); + return log; +} +bool MapBase::check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto map_ptr = std::static_pointer_cast<MapBase>(_node_ptr); + auto local_log = localCheck(_verbose, map_ptr, _stream, _tabs); + _log.compose(local_log); + for (auto L : getLandmarkList()) + L->check(_log, L, _verbose, _stream, _tabs + " "); + return _log.is_consistent_; +} } // namespace wolf diff --git a/src/problem/problem.cpp b/src/problem/problem.cpp index 53acc960ecc87a61d28d7e1567af966d0579b375..225e6f1ed184b3b51959ab4f125c1dbb9066eaec 100644 --- a/src/problem/problem.cpp +++ b/src/problem/problem.cpp @@ -7,15 +7,23 @@ #include "core/processor/processor_motion.h" #include "core/processor/processor_tracker.h" #include "core/capture/capture_pose.h" +#include "core/capture/capture_void.h" #include "core/factor/factor_base.h" -#include "core/sensor/sensor_factory.h" -#include "core/processor/processor_factory.h" +#include "core/factor/factor_block_absolute.h" +#include "core/factor/factor_quaternion_absolute.h" +#include "core/sensor/factory_sensor.h" +#include "core/processor/factory_processor.h" #include "core/state_block/state_block.h" +#include "core/state_block/state_quaternion.h" +#include "core/state_block/state_angle.h" +#include "core/tree_manager/factory_tree_manager.h" +#include "core/tree_manager/tree_manager_base.h" #include "core/utils/logging.h" #include "core/utils/params_server.h" #include "core/utils/loader.h" #include "core/utils/check_log.h" - +#include "core/math/covariance.h" +#include "core/state_block/factory_state_block.h" // IRI libs includes @@ -28,16 +36,18 @@ #include <vector> #include <unordered_set> + namespace wolf { Problem::Problem(const std::string& _frame_structure, SizeEigen _dim) : + tree_manager_(nullptr), hardware_ptr_(std::make_shared<HardwareBase>()), - trajectory_ptr_(std::make_shared<TrajectoryBase>(_frame_structure)), + trajectory_ptr_(std::make_shared<TrajectoryBase>()), map_ptr_(std::make_shared<MapBase>()), processor_is_motion_list_(std::list<IsMotionPtr>()), - prior_is_set_(false), - frame_structure_(_frame_structure) + frame_structure_(_frame_structure), + prior_options_(std::make_shared<PriorOptions>()) { dim_ = _dim; if (_frame_structure == "PO" and _dim == 2) @@ -59,7 +69,6 @@ Problem::Problem(const std::string& _frame_structure, SizeEigen _dim) : } else std::runtime_error( "Problem::Problem(): Unknown frame structure. Add appropriate frame structure to the switch statement."); - } void Problem::setup() @@ -119,13 +128,20 @@ ProblemPtr Problem::autoSetup(ParamsServer &_server) WOLF_WARN(e.what()); WOLF_WARN("Support for subscribers disabled..."); } - for (auto it : _server.getParam<std::vector<std::string>>("packages")) { + for (auto it : _server.getParam<std::vector<std::string>>("packages_subscriber")) { std::string subscriber = packages_path + "/libsubscriber_" + it + lib_extension; WOLF_TRACE("Loading subscriber " + subscriber); auto l = new LoaderRaw(subscriber); l->load(); loaders.push_back(l); } + for (auto it : _server.getParam<std::vector<std::string>>("packages_publisher")) { + std::string subscriber = packages_path + "/libpublisher_" + it + lib_extension; + WOLF_TRACE("Loading publisher " + subscriber); + auto l = new LoaderRaw(subscriber); + l->load(); + loaders.push_back(l); + } std::vector<std::string> raw_libs; try { raw_libs = _server.getParam<std::vector<std::string>>("raw_libs"); @@ -152,22 +168,40 @@ ProblemPtr Problem::autoSetup(ParamsServer &_server) procesorMap.insert(std::pair<std::string, ProcessorBasePtr>(prc["name"], problem->installProcessor(prc["type"], prc["name"], prc["sensor_name"], _server))); } + // Tree manager + std::string tree_manager_type = _server.getParam<std::string>("problem/tree_manager/type"); + WOLF_TRACE("Tree Manager Type: ", tree_manager_type); + if (tree_manager_type != "None" and tree_manager_type != "none") + problem->setTreeManager(AutoConfFactoryTreeManager::get().create(tree_manager_type, "tree manager", _server)); + // Prior - Eigen::VectorXd prior_state = _server.getParam<Eigen::VectorXd>("problem/prior/state"); - Eigen::MatrixXd prior_cov = _server.getParam<Eigen::MatrixXd>("problem/prior/cov"); - double prior_time_tolerance = _server.getParam<double>("problem/prior/time_tolerance"); - double prior_ts = _server.getParam<double>("problem/prior/timestamp"); + std::string prior_mode = _server.getParam<std::string>("problem/prior/mode"); + WOLF_TRACE("Prior mode: ", prior_mode); + if (prior_mode == "nothing") + { + problem->setPriorOptions(prior_mode); + } + else if (prior_mode == "factor") + { + problem->setPriorOptions(prior_mode, + _server.getParam<double>("problem/prior/time_tolerance"), + _server.getParam<VectorComposite>("problem/prior/state"), + _server.getParam<VectorComposite>("problem/prior/sigma")); - WOLF_TRACE("prior timestamp:\n" , prior_ts); - WOLF_TRACE("prior state:\n" , prior_state.transpose()); - WOLF_TRACE("prior covariance:\n" , prior_cov); - WOLF_TRACE("prior time tolerance:\n", prior_time_tolerance); - problem->setPrior(prior_state, prior_cov, prior_ts, prior_time_tolerance); + + } + else + { + WOLF_TRACE("Prior mode: ", prior_mode); + problem->setPriorOptions(prior_mode, + _server.getParam<double>("problem/prior/time_tolerance"), + _server.getParam<VectorComposite>("problem/prior/state")); + } // Done return problem; - } +} Problem::~Problem() { @@ -179,7 +213,7 @@ SensorBasePtr Problem::installSensor(const std::string& _sen_type, // const Eigen::VectorXd& _extrinsics, // ParamsSensorBasePtr _intrinsics) { - SensorBasePtr sen_ptr = SensorFactory::get().create(_sen_type, _unique_sensor_name, _extrinsics, _intrinsics); + SensorBasePtr sen_ptr = FactorySensor::get().create(_sen_type, _unique_sensor_name, _extrinsics, _intrinsics); sen_ptr->link(getHardware()); return sen_ptr; } @@ -194,7 +228,7 @@ SensorBasePtr Problem::installSensor(const std::string& _sen_type, // if (_intrinsics_filename != "") { assert(file_exists(_intrinsics_filename) && "Cannot install sensor: intrinsics' YAML file does not exist."); - ParamsSensorBasePtr intr_ptr = ParamsSensorFactory::get().create(_sen_type, _intrinsics_filename); + ParamsSensorBasePtr intr_ptr = FactoryParamsSensor::get().create(_sen_type, _intrinsics_filename); return installSensor(_sen_type, _unique_sensor_name, _extrinsics, intr_ptr); } else @@ -206,7 +240,7 @@ SensorBasePtr Problem::installSensor(const std::string& _sen_type, // const std::string& _unique_sensor_name, // const ParamsServer& _server) { - SensorBasePtr sen_ptr = AutoConfSensorFactory::get().create(_sen_type, _unique_sensor_name, _server); + SensorBasePtr sen_ptr = AutoConfFactorySensor::get().create(_sen_type, _unique_sensor_name, _server); sen_ptr->link(getHardware()); return sen_ptr; } @@ -214,7 +248,7 @@ SensorBasePtr Problem::installSensor(const std::string& _sen_type, // ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, // const std::string& _unique_processor_name, // SensorBasePtr _corresponding_sensor_ptr, // - ProcessorParamsBasePtr _prc_params) + ParamsProcessorBasePtr _prc_params) { if (_corresponding_sensor_ptr == nullptr) { @@ -223,7 +257,7 @@ ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, // return ProcessorBasePtr(); } - ProcessorBasePtr prc_ptr = ProcessorFactory::get().create(_prc_type, _unique_processor_name, _prc_params); + ProcessorBasePtr prc_ptr = FactoryProcessor::get().create(_prc_type, _unique_processor_name, _prc_params); //Dimension check int prc_dim = prc_ptr->getDim(); @@ -233,10 +267,6 @@ ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, // prc_ptr->configure(_corresponding_sensor_ptr); prc_ptr->link(_corresponding_sensor_ptr); - // setting the origin in all processor motion if origin already setted - if (prc_ptr->isMotion() && prior_is_set_) - (std::static_pointer_cast<ProcessorMotion>(prc_ptr))->setOrigin(getLastKeyFrame()); - return prc_ptr; } @@ -253,7 +283,7 @@ ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, // else { assert(file_exists(_params_filename) && "Cannot install processor: parameters' YAML file does not exist."); - ProcessorParamsBasePtr prc_params = ProcessorParamsFactory::get().create(_prc_type, _params_filename); + ParamsProcessorBasePtr prc_params = FactoryParamsProcessor::get().create(_prc_type, _params_filename); return installProcessor(_prc_type, _unique_processor_name, sen_ptr, prc_params); } } @@ -267,7 +297,7 @@ ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, // if (sen_ptr == nullptr) throw std::runtime_error("Cannot bind processor. Reason: Sensor \"" + _corresponding_sensor_name + "\" not found. Check sensor name, it must match in sensor and processor!"); - ProcessorBasePtr prc_ptr = AutoConfProcessorFactory::get().create(_prc_type, _unique_processor_name, _server); + ProcessorBasePtr prc_ptr = AutoConfFactoryProcessor::get().create(_prc_type, _unique_processor_name, _server); //Dimension check int prc_dim = prc_ptr->getDim(); @@ -277,11 +307,6 @@ ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, // prc_ptr->configure(sen_ptr); prc_ptr->link(sen_ptr); - - // setting the origin in all processor motion if origin already setted - if (prc_ptr->isMotion() && prior_is_set_) - (std::static_pointer_cast<ProcessorMotion>(prc_ptr))->setOrigin(getLastKeyFrame()); - return prc_ptr; } @@ -300,196 +325,231 @@ SensorBasePtr Problem::getSensor(const std::string& _sensor_name) const return (*sen_it); } -FrameBasePtr Problem::emplaceFrame(const std::string& _frame_structure, // +FrameBasePtr Problem::emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const StateStructure& _frame_structure, // const SizeEigen _dim, // - FrameType _frame_key_type, // - const Eigen::VectorXd& _frame_state, // - const TimeStamp& _time_stamp) + const Eigen::VectorXd& _frame_state) { - auto frm = FrameBase::emplace<FrameBase>(trajectory_ptr_, _frame_structure, _dim, _frame_key_type, _time_stamp, _frame_state); + auto frm = FrameBase::emplace<FrameBase>(trajectory_ptr_, + _frame_key_type, + _time_stamp, + _frame_structure, + _dim, + _frame_state); return frm; } -FrameBasePtr Problem::emplaceFrame(const std::string& _frame_structure, // - const SizeEigen _dim, // - FrameType _frame_key_type, // - const TimeStamp& _time_stamp) +FrameBasePtr Problem::emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const StateStructure& _frame_structure, // + const SizeEigen _dim) { - return emplaceFrame(_frame_structure, _dim, _frame_key_type, getState(_time_stamp), _time_stamp); + return emplaceFrame(_frame_key_type, + _time_stamp, + _frame_structure, + getState(_time_stamp)); } -FrameBasePtr Problem::emplaceFrame(FrameType _frame_key_type, // - const Eigen::VectorXd& _frame_state, // - const TimeStamp& _time_stamp) +FrameBasePtr Problem::emplaceFrame (FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const StateStructure& _frame_structure, // + const VectorComposite& _frame_state) { - return emplaceFrame(this->getFrameStructure(), this->getDim(), _frame_key_type, _frame_state, _time_stamp); + return FrameBase::emplace<FrameBase>(getTrajectory(), + _frame_key_type, + _time_stamp, + _frame_structure, + _frame_state); } -FrameBasePtr Problem::emplaceFrame(FrameType _frame_key_type, // - const TimeStamp& _time_stamp) +FrameBasePtr Problem::emplaceFrame (FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const VectorComposite& _frame_state) { - return emplaceFrame(this->getFrameStructure(), this->getDim(), _frame_key_type, _time_stamp); + return FrameBase::emplace<FrameBase>(getTrajectory(), + _frame_key_type, + _time_stamp, + getFrameStructure(), + _frame_state); } -Eigen::VectorXd Problem::getCurrentState() const +FrameBasePtr Problem::emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const Eigen::VectorXd& _frame_state) { - Eigen::VectorXd state(getFrameStructureSize()); - getCurrentState(state); - return state; + return emplaceFrame(_frame_key_type, + _time_stamp, + this->getFrameStructure(), + this->getDim(), + _frame_state); } -void Problem::getCurrentState(Eigen::VectorXd& _state) const +FrameBasePtr Problem::emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp) { - TimeStamp ts; // throwaway timestamp - getCurrentStateAndStamp(_state, ts); + return emplaceFrame(_frame_key_type, + _time_stamp, + this->getFrameStructure(), + this->getDim()); } -void Problem::getCurrentStateAndStamp(Eigen::VectorXd& _state, TimeStamp& _ts) const -{ - if (!processor_is_motion_list_.empty()) +TimeStamp Problem::getTimeStamp ( ) const +{ + if ( processor_is_motion_list_.empty() ) // Use last estimated frame's state { - // retrieve the minimum of the most recent ts in all processor is motion then call getSate(ts, state) - std::list<TimeStamp> proc_is_motion_current_ts; - for (auto proc: processor_is_motion_list_){ - proc_is_motion_current_ts.push_back(proc->getCurrentTimeStamp()); - } - auto min_it = std::min_element(proc_is_motion_current_ts.begin(), proc_is_motion_current_ts.end()); - getState(*min_it, _state); - _ts = *min_it; + auto last_kf_or_aux = trajectory_ptr_->getLastKeyOrAuxFrame(); + + assert(last_kf_or_aux != nullptr && "Problem has no Keyframe so no timestamp can be obtained!"); + + return last_kf_or_aux->getTimeStamp(); } - else if (trajectory_ptr_->getLastKeyOrAuxFrame() != nullptr) + else { - // kind of redundant with getState(_ts, _state) - trajectory_ptr_->getLastKeyOrAuxFrame()->getTimeStamp(_ts); - trajectory_ptr_->getLastKeyOrAuxFrame()->getState(_state); + TimeStamp ts(0); + for (const auto& prc : processor_is_motion_list_) + if (prc->getTimeStamp() > ts) + ts = prc->getTimeStamp(); + return ts; } - else - _state = zeroState(); } -// Problem of this implmentation: if more state -void Problem::getState(const TimeStamp& _ts, Eigen::VectorXd& _state) const +VectorComposite Problem::getState(const StateStructure& _structure) const { - // if _ts is too recent, for some of the processor is motion, they return the state corresponding to their last frame timestamp - FrameBasePtr closest_frame = trajectory_ptr_->closestKeyOrAuxFrameToTimeStamp(_ts); - if (processor_is_motion_list_.empty()){ - if (closest_frame != nullptr) - _state = closest_frame->getState(); + StateStructure structure = (_structure == "" ? getFrameStructure() : _structure); + VectorComposite state; + + if ( processor_is_motion_list_.empty() ) // Use last estimated frame's state + { + auto last_kf_or_aux = trajectory_ptr_->getLastKeyOrAuxFrame(); + if (last_kf_or_aux) + state = last_kf_or_aux->getState(structure); else - _state = zeroState(); + state = stateZero(structure); } - - // RETRIEVE FROM PROCESSOR MOTION - // TODO: current implementation messy, would be much easier with a state being an std::unordered_map - else { - // Iterate over the problem state structure and get the corresponding state - // in the first processor is motion that provides it - // finally check if the state to concatenate list has the same total size as the problem state_size - - // an map is necessary as a temporary structure because we do not know in which order we will find the state blocks in processors - std::unordered_map<char, Eigen::VectorXd> states_to_concat_map; // not necessary to be ordered - for (auto proc: processor_is_motion_list_){ - Eigen::VectorXd proc_state = proc->getState(_ts); - - int idx = 0; - for (char sb_name: proc->getStateStructure()){ - // not already there - if (states_to_concat_map.find(sb_name) == states_to_concat_map.end()){ - if (sb_name == 'O'){ - int size_sb = dim_ == 3 ? 4 : 1; // really bad: should be more transparent - states_to_concat_map[sb_name] = proc_state.segment(idx, size_sb); - idx += size_sb; - } - else{ - int size_sb = dim_ == 3 ? 3 : 2; - states_to_concat_map[sb_name] = proc_state.segment(idx, size_sb); - idx += size_sb; - } - } + else // Compose from different processor motion + { + // compose the states of all processor motions into one only state + for (const auto& prc : processor_is_motion_list_) + { + const auto& prc_state = prc->getState(); + for (const auto& pair_key_vec : prc_state) + { + if (state.count(pair_key_vec.first) == 0) // only add those keys that do not exist yet + state.insert(pair_key_vec); } } - - int concat_size = 0; - for (auto state_map_it: states_to_concat_map){ - concat_size += state_map_it.second.size(); + // check for empty blocks and fill them with zeros + for (const auto& ckey : frame_structure_) + { + const auto& key = string(1,ckey); + if (state.count(key) == 0) + state.emplace(key, stateZero(key).at(key)); } - // assert(concat_size == state_size_ && "Problem with the concatenated size: " ); - - // fill the state value from the state concatenation in the order dictated by frame_structure_ - int idx = 0; - _state.resize(state_size_); - for (char sb_name: frame_structure_){ - Eigen::VectorXd sb_state; - int size_sb; // really bad... - if (sb_name == 'O'){ - size_sb = dim_ == 3 ? 4 : 1; - } - else { - size_sb = dim_ == 3 ? 3 : 2; - } - if (states_to_concat_map.find(sb_name) != states_to_concat_map.end()){ - sb_state = states_to_concat_map[sb_name]; - } - else { - // Should be taken from the last state but too messy already - sb_state.resize(size_sb); - sb_state.setZero(); - } + } - _state.segment(idx, size_sb) = sb_state; - idx += size_sb; + return state; +} +VectorComposite Problem::getState (const TimeStamp& _ts, const StateStructure& _structure) const +{ + StateStructure structure = (_structure == "" ? getFrameStructure() : _structure); + + if ( processor_is_motion_list_.empty() ) // Use last estimated frame's state + { + const auto& last_kf_or_aux = trajectory_ptr_->closestKeyOrAuxFrameToTimeStamp(_ts); + if (last_kf_or_aux) + { + return last_kf_or_aux->getState(structure); + } + else + { + return stateZero(structure); } } -} -Eigen::VectorXd Problem::getState(const TimeStamp& _ts) const -{ - Eigen::VectorXd state(getFrameStructureSize()); - getState(_ts, state); + VectorComposite state; + for (const auto& prc : processor_is_motion_list_) + { + const auto& prc_state = prc->getState(_ts); + + // transfer processor vector blocks to problem state + for (const auto& pair_key_vec : prc_state) + { + const auto& key = pair_key_vec.first; + + if (state.count(key) == 0) // Only write once. This gives priority to processors upfront in the list + state.insert(pair_key_vec); + } + } return state; } -SizeEigen Problem::getFrameStructureSize() const +SizeEigen Problem::getDim() const { - return state_size_; + return dim_; } - -void Problem::getFrameStructureSize(SizeEigen& _x_size, SizeEigen& _cov_size) const +StateStructure Problem::getFrameStructure() const { - _x_size = state_size_; - _cov_size = state_cov_size_; + return frame_structure_; } -SizeEigen Problem::getDim() const +void Problem::appendToStructure(const StateStructure& _structure) { - return dim_; + for (const auto& ckey : _structure) + if (frame_structure_.find(ckey) == std::string::npos) // now key not found in problem structure -> append! + frame_structure_ += ckey; } -std::string Problem::getFrameStructure() const + +void Problem::setTreeManager(TreeManagerBasePtr _gm) { - return frame_structure_; + if (tree_manager_) + tree_manager_->setProblem(nullptr); + tree_manager_ = _gm; + tree_manager_->setProblem(shared_from_this()); + } void Problem::addProcessorIsMotion(IsMotionPtr _processor_motion_ptr) { processor_is_motion_list_.push_back(_processor_motion_ptr); + appendToStructure(_processor_motion_ptr->getStateStructure()); } -void Problem::clearProcessorIsMotion(IsMotionPtr proc){ +void Problem::clearProcessorIsMotion(IsMotionPtr proc) +{ auto it = std::find(processor_is_motion_list_.begin(), processor_is_motion_list_.end(), proc); if (it != processor_is_motion_list_.end()){ processor_is_motion_list_.erase(it); } + + // rebuild frame structure with remaining motion processors + frame_structure_.clear(); + for (const auto& pm : processor_is_motion_list_) + appendToStructure(pm->getStateStructure()); } -Eigen::VectorXd Problem::zeroState() const +VectorComposite Problem::stateZero ( const StateStructure& _structure ) const { - Eigen::VectorXd state = Eigen::VectorXd::Zero(getFrameStructureSize()); + StateStructure structure = (_structure == "" ? getFrameStructure() : _structure); - // Set the quaternion identity for 3d states. Set only the real part to 1: - if(this->getDim() == 3) - state(6) = 1.0; + VectorComposite state; + for (const auto& ckey : structure) + { + const auto& key = string(1,ckey); + VectorXd vec; + if (key == "O") + { + if (dim_ == 2) vec = VectorXd::Zero(1); + else if (dim_ == 3) vec = Quaterniond::Identity().coeffs(); + } + else + { + vec = VectorXd::Zero(dim_); + } + state.emplace(key, vec); + } return state; } @@ -528,6 +588,10 @@ void Problem::keyFrameCallback(FrameBasePtr _keyframe_ptr, ProcessorBasePtr _pro " microseconds: ", duration.count()); #endif } + + // notify tree manager + if (tree_manager_) + tree_manager_->keyFrameCallback(_keyframe_ptr); } bool Problem::permitAuxFrame(ProcessorBasePtr _processor_ptr) const @@ -557,7 +621,7 @@ void Problem::auxFrameCallback(FrameBasePtr _frame_ptr, ProcessorBasePtr _proces StateBlockPtr Problem::notifyStateBlock(StateBlockPtr _state_ptr, Notification _noti) { - std::lock_guard<std::mutex> lock(mut_state_block_notifications_); + std::lock_guard<std::mutex> lock(mut_notifications_); //std::cout << "Problem::addStateBlockPtr " << _state_ptr.get() << std::endl; // Check if there is already a notification for this state block @@ -584,7 +648,7 @@ StateBlockPtr Problem::notifyStateBlock(StateBlockPtr _state_ptr, Notification _ bool Problem::getStateBlockNotification(const StateBlockPtr& sb_ptr, Notification& notif) const { - std::lock_guard<std::mutex> lock(mut_state_block_notifications_); + std::lock_guard<std::mutex> lock(mut_notifications_); if (state_block_notification_map_.find(sb_ptr) == state_block_notification_map_.end()) return false; @@ -594,7 +658,7 @@ bool Problem::getStateBlockNotification(const StateBlockPtr& sb_ptr, Notificatio FactorBasePtr Problem::notifyFactor(FactorBasePtr _factor_ptr, Notification _noti) { - std::lock_guard<std::mutex> lock(mut_factor_notifications_); + std::lock_guard<std::mutex> lock(mut_notifications_); //std::cout << "Problem::addFactorPtr " << _factor_ptr->id() << std::endl; // Check if there is already the same notification for this factor @@ -609,7 +673,9 @@ FactorBasePtr Problem::notifyFactor(FactorBasePtr _factor_ptr, Notification _not } // opposite notification -> cancell out eachother else + { factor_notification_map_.erase(notification_it); + } } // Add notification @@ -621,7 +687,7 @@ FactorBasePtr Problem::notifyFactor(FactorBasePtr _factor_ptr, Notification _not bool Problem::getFactorNotification(const FactorBasePtr& fac_ptr, Notification& notif) const { - std::lock_guard<std::mutex> lock(mut_factor_notifications_); + std::lock_guard<std::mutex> lock(mut_notifications_); if (factor_notification_map_.find(fac_ptr) == factor_notification_map_.end()) return false; @@ -868,51 +934,141 @@ FrameBasePtr Problem::closestKeyOrAuxFrameToTimeStamp(const TimeStamp& _ts) cons return trajectory_ptr_->closestKeyOrAuxFrameToTimeStamp(_ts); } -FrameBasePtr Problem::setPrior(const Eigen::VectorXd& _prior_state, const Eigen::MatrixXd& _prior_cov, const TimeStamp& _ts, const double _time_tolerance) +void Problem::setPriorOptions(const std::string& _mode, + const double _time_tolerance , + const VectorComposite& _state , + const VectorComposite& _sigma ) { - if ( ! prior_is_set_ ) + assert(prior_options_ != nullptr && "prior options have already been applied"); + assert(prior_options_->mode == "" && "prior options have already been set"); + assert((_mode == "nothing" || _mode == "initial_guess" || _mode == "fix" || _mode == "factor") && "wrong _mode value, it should be: 'nothing', 'initial_guess', 'fix' or 'factor'"); + + // Store options (optionals depending on the mode) + WOLF_TRACE("prior mode: ", _mode); + prior_options_->mode = _mode; + + if (prior_options_->mode != "nothing") { - // Create origin frame - FrameBasePtr origin_keyframe = emplaceFrame(KEY, _prior_state, _ts); - - // create origin capture with the given state as data - // Capture fix only takes 3d position and Quaternion orientation - CapturePosePtr init_capture; - // if (this->getFrameStructure() == "POV" and this->getDim() == 3) - // init_capture = CaptureBase::emplace<CapturePose>(origin_keyframe, _ts, nullptr, _prior_state.head(7), _prior_cov.topLeftCorner(6,6)); - // else - // init_capture = CaptureBase::emplace<CapturePose>(origin_keyframe, _ts, nullptr, _prior_state, _prior_cov); - - if (this->getDim() == 3) - init_capture = CaptureBase::emplace<CapturePose>(origin_keyframe, _ts, nullptr, _prior_state.head(7), _prior_cov.topLeftCorner(6,6)); - else - init_capture = CaptureBase::emplace<CapturePose>(origin_keyframe, _ts, nullptr, _prior_state.head(3), _prior_cov.topLeftCorner(3,3)); + assert(_time_tolerance > 0 && "time tolerance should be bigger than 0"); + + WOLF_TRACE("prior state: ", _state); + WOLF_TRACE("prior time tolerance: ", _time_tolerance); + prior_options_->state = _state; + prior_options_->time_tolerance = _time_tolerance; + + if (prior_options_->mode == "factor") + { + bool isPositive = true; + for(const auto& it: _sigma) + isPositive = isPositive and (it.second.array() > Constants::EPS).all(); + + assert(isPositive && "sigma is not positive"); + + MatrixComposite Q; + for (const auto& pair_key_sig : _sigma) + { + const auto& key = pair_key_sig.first; + const auto& sig_blk = pair_key_sig.second; + + const auto& cov_blk = (sig_blk.array() * sig_blk.array()).matrix().asDiagonal(); + Q.emplace(key,key,cov_blk); + } + WOLF_TRACE("prior covariance:" , Q); + prior_options_->cov = Q; + } + } +} + +FrameBasePtr Problem::applyPriorOptions(const TimeStamp& _ts) +{ + assert(!isPriorSet() && "applyPriorOptions can be called once!"); + + FrameBasePtr prior_keyframe(nullptr); + + if (prior_options_->mode != "nothing" and prior_options_->mode != "") + { + prior_keyframe = emplaceFrame(KEY, + _ts, + prior_options_->state); + + if (prior_options_->mode == "fix") + prior_keyframe->fix(); + else if (prior_options_->mode == "factor") + { + // ASSUMPTION: Independent measurements (non-correlated block-diagonal covariance matrix) + + // Emplace a capture + auto prior_cap = CaptureBase::emplace<CaptureVoid>(prior_keyframe, _ts, nullptr); + // Emplace a feature and a factor for each state block + for (const auto& pair_key_sb : prior_keyframe->getStateBlockMap()) + { + const auto& key = pair_key_sb.first; + const auto& sb = pair_key_sb.second; - // emplace feature and factor - init_capture->emplaceFeatureAndFactor(); + const auto& state_blk = prior_options_->state.at(key); + const auto& covar_blk = prior_options_->cov.at(key,key); - WOLF_DEBUG("Set prior callback: KF", origin_keyframe->id(), " Callback emitted with ts = ", origin_keyframe->getTimeStamp()); + assert(sb->getSize() == state_blk.size() && "prior_options state wrong size"); + assert(sb->getLocalSize() == covar_blk.rows() && "prior_options cov. wrong size"); - // Notify all motion processors about the prior KF - for (auto sensor : hardware_ptr_->getSensorList()) - for (auto processor : sensor->getProcessorList()) - if (processor->isMotion()) - // Motion processors will set its origin at the KF - (std::static_pointer_cast<ProcessorMotion>(processor))->setOrigin(origin_keyframe); + // feature + auto prior_fea = FeatureBase::emplace<FeatureBase>(prior_cap, "Prior " + key, state_blk, covar_blk); - prior_is_set_ = true; + // factor + if (sb->hasLocalParametrization()) + { + if (std::dynamic_pointer_cast<StateQuaternion>(sb) != nullptr) + auto prior_fac = FactorBase::emplace<FactorQuaternionAbsolute>(prior_fea, prior_fea, sb, nullptr, false); + else if (std::dynamic_pointer_cast<StateAngle>(sb) != nullptr) + auto prior_fac = FactorBase::emplace<FactorBlockAbsolute>(prior_fea, prior_fea, sb, nullptr, false); + else + throw std::runtime_error("not implemented...!"); + } + else + { + auto prior_fac = FactorBase::emplace<FactorBlockAbsolute>(prior_fea, prior_fea, sb, nullptr, false); + } - // Notify all other processors about the origin KF --> they will join it or not depending on their received data - for (auto sensor : hardware_ptr_->getSensorList()) - for (auto processor : sensor->getProcessorList()) - if ( !processor->isMotion() ) - processor->keyFrameCallback(origin_keyframe, _time_tolerance); + } - return origin_keyframe; + } + else + assert(prior_options_->mode == "initial_guess" && "wrong prior_options->mode"); + + // notify all processors + keyFrameCallback(prior_keyframe, nullptr, prior_options_->time_tolerance); } - else - throw std::runtime_error("Origin already set!"); + // remove prior options + prior_options_ = nullptr; + + return prior_keyframe; +} + +FrameBasePtr Problem::setPriorFactor(const VectorComposite &_state, + const VectorComposite &_sigma, + const TimeStamp &_ts, + const double &_time_tol) +{ + setPriorOptions("factor", _time_tol, _state, _sigma); + return applyPriorOptions(_ts); +} + + +FrameBasePtr Problem::setPriorFix(const VectorComposite &_state, + const TimeStamp &_ts, + const double &_time_tol) +{ + setPriorOptions("fix", _time_tol, _state); + return applyPriorOptions(_ts); +} + +FrameBasePtr Problem::setPriorInitialGuess(const VectorComposite &_state, + const TimeStamp &_ts, + const double &_time_tol) +{ + setPriorOptions("initial_guess", _time_tol, _state); + return applyPriorOptions(_ts); } void Problem::loadMap(const std::string& _filename_dot_yaml) @@ -925,266 +1081,18 @@ void Problem::saveMap(const std::string& _filename_dot_yaml, const std::string& getMap()->save(_filename_dot_yaml, _map_name); } -void Problem::print(int _depth, std::ostream& _stream, bool _constr_by, bool _metric, bool _state_blocks) const +void Problem::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream) const { _stream << std::endl; _stream << "P: wolf tree status ---------------------" << std::endl; - _stream << "Hardware" << ((_depth < 1) ? (" -- " + std::to_string(getHardware()->getSensorList().size()) + "S") : "") << std::endl; - if (_depth >= 1) - { - // Sensors ======================================================================================= - for (auto S : getHardware()->getSensorList()) - { - _stream << " Sen" << S->id() << " " << S->getType() << " \"" << S->getName() << "\""; - if (_depth < 2) - _stream << " -- " << S->getProcessorList().size() << "p"; - _stream << std::endl; - if (_metric && _state_blocks) - { - _stream << " sb: "; - for (auto& _key : S->getStructure()) - { - auto key = std::string(1,_key); - auto sb = S->getStateBlock(key); - _stream << key << "[" << (S->isStateBlockDynamic(key) ? "Dyn" : "Sta") << "," << (sb->isFixed() ? "Fix" : "Est") << "] = ( " << sb->getState().transpose() << " ); "; - } - _stream << std::endl; - } - else if (_metric) - { - _stream << " ( "; - for (auto& _key : S->getStructure()) - { - auto key = std::string(1,_key); - auto sb = S->getStateBlock(key); - _stream << sb->getState().transpose() << " "; - } - _stream << ")" << std::endl; - } - else if (_state_blocks) - { - _stream << " sb: "; - for (auto& _key : S->getStructure()) - { - auto key = std::string(1,_key); - auto sb = S->getStateBlock(key); - _stream << key << "[" << (S->isStateBlockDynamic(key) ? "Dyn" : "Sta") << "," << (sb->isFixed() ? "Fix" : "Est") << "]; "; - } - _stream << std::endl; - } - if (_depth >= 2) - { - // Processors ======================================================================================= - for (auto p : S->getProcessorList()) - { - if (p->isMotion()) - { - _stream << " PrcM" << p->id() << " " << p->getType() << " \"" << p->getName() << "\"" << std::endl; - ProcessorMotionPtr pm = std::static_pointer_cast<ProcessorMotion>(p); - if (pm->getOrigin()) - _stream << " o: Cap" << pm->getOrigin()->id() << " - " << (pm->getOrigin()->getFrame()->isKeyOrAux() ? (pm->getOrigin()->getFrame()->isKey() ? " KFrm" : " AFrm" ) : " Frm") - << pm->getOrigin()->getFrame()->id() << std::endl; - if (pm->getLast()) - _stream << " l: Cap" << pm->getLast()->id() << " - " << (pm->getLast()->getFrame()->isKeyOrAux() ? (pm->getLast()->getFrame()->isKey() ? " KFrm" : " AFrm") : " Frm") - << pm->getLast()->getFrame()->id() << std::endl; - if (pm->getIncoming()) - _stream << " i: Cap" << pm->getIncoming()->id() << std::endl; - } - else - { - _stream << " PrcT" << p->id() << " " << p->getType() << " \"" << p->getName() << "\"" << std::endl; - ProcessorTrackerPtr pt = std::dynamic_pointer_cast<ProcessorTracker>(p); - if (pt) - { - if (pt->getOrigin()) - _stream << " o: Cap" << pt->getOrigin()->id() << " - " << (pt->getOrigin()->getFrame()->isKeyOrAux() ? (pt->getOrigin()->getFrame()->isKey() ? " KFrm" : " AFrm") : " Frm") - << pt->getOrigin()->getFrame()->id() << std::endl; - if (pt->getLast()) - _stream << " l: Cap" << pt->getLast()->id() << " - " << (pt->getLast()->getFrame()->isKeyOrAux() ? (pt->getLast()->getFrame()->isKey() ? " KFrm" : " AFrm") : " Frm") - << pt->getLast()->getFrame()->id() << std::endl; - if (pt->getIncoming()) - _stream << " i: Cap" << pt->getIncoming()->id() << std::endl; - } - } - } // for p - } - } // for S - } - _stream << "Trajectory" << ((_depth < 1) ? (" -- " + std::to_string(getTrajectory()->getFrameList().size()) + "F") : "") << std::endl; - if (_depth >= 1) - { - // Frames ======================================================================================= - for (auto F : getTrajectory()->getFrameList()) - { - _stream << (F->isKeyOrAux() ? (F->isKey() ? " KFrm" : " AFrm") : " Frm") << F->id() << ((_depth < 2) ? " -- " + std::to_string(F->getCaptureList().size()) + "C " : ""); - if (_constr_by) - { - _stream << " <-- "; - for (auto cby : F->getConstrainedByList()) - _stream << "Fac" << cby->id() << " \t"; - } - _stream << std::endl; - if (_metric) - { - _stream << (F->isFixed() ? " Fix" : " Est") << ", ts=" << std::setprecision(5) - << F->getTimeStamp(); - _stream << ",\t x = ( " << std::setprecision(2) << F->getState().transpose() << " )"; - _stream << std::endl; - } - if (_state_blocks) - { - _stream << " sb:"; - for (const auto& sb : F->getStateBlockVec()) - { - _stream << " " << (sb->isFixed() ? "Fix" : "Est"); - } - _stream << std::endl; - } - if (_depth >= 2) - { - // Captures ======================================================================================= - for (auto C : F->getCaptureList()) - { - _stream << " Cap" << (C->isMotion() ? "M" : "") << C->id() << " " << C->getType(); - if(C->getSensor() != nullptr) - { - _stream << " -> Sen" << C->getSensor()->id(); - } - else - _stream << " -> Sen-"; - if (C->isMotion()) - { - auto CM = std::static_pointer_cast<CaptureMotion>(C); - if (auto OC = CM->getOriginCapture()) - { - _stream << " -> OCap" << OC->id(); - if (auto OF = OC->getFrame()) - _stream << " ; OFrm" << OF->id(); - } - } - - _stream << ((_depth < 3) ? " -- " + std::to_string(C->getFeatureList().size()) + "f" : ""); - if (_constr_by) - { - _stream << " <-- "; - for (auto cby : C->getConstrainedByList()) - _stream << "Fac" << cby->id() << " \t"; - } - _stream << std::endl; - - if (_state_blocks) - for (const auto& sb : C->getStateBlockVec()) - { - if(sb != nullptr) - { - _stream << " sb: "; - _stream << (sb->isFixed() ? "Fix" : "Est"); - if (_metric) - _stream << std::setprecision(2) << " (" << sb->getState().transpose() << " )"; - _stream << std::endl; - } - } - - if (C->isMotion() ) - { - CaptureMotionPtr CM = std::dynamic_pointer_cast<CaptureMotion>(C); - _stream << " buffer size : " << CM->getBuffer().get().size() << std::endl; - if ( _metric && ! CM->getBuffer().get().empty()) - { - _stream << " delta preint : (" << CM->getDeltaPreint().transpose() << ")" << std::endl; - if (CM->hasCalibration()) - { - _stream << " calib preint : (" << CM->getCalibrationPreint().transpose() << ")" << std::endl; - _stream << " jacob preint : (" << CM->getJacobianCalib().row(0) << ")" << std::endl; - _stream << " calib current: (" << CM->getCalibration().transpose() << ")" << std::endl; - _stream << " delta correct: (" << CM->getDeltaCorrected(CM->getCalibration()).transpose() << ")" << std::endl; - } - } - } - - if (_depth >= 3) - { - // Features ======================================================================================= - for (auto f : C->getFeatureList()) - { - _stream << " Ftr" << f->id() << " trk" << f->trackId() << " " << f->getType() << ((_depth < 4) ? " -- " + std::to_string(f->getFactorList().size()) + "c " : ""); - if (_constr_by) - { - _stream << " <--\t"; - for (auto cby : f->getConstrainedByList()) - _stream << "Fac" << cby->id() << " \t"; - } - _stream << std::endl; - if (_metric) - _stream << " m = ( " << std::setprecision(2) << f->getMeasurement().transpose() - << " )" << std::endl; - if (_depth >= 4) - { - // Factors ======================================================================================= - for (auto c : f->getFactorList()) - { - _stream << " Fac" << c->id() << " " << c->getType() << " -->"; - if ( c->getFrameOtherList() .empty() - && c->getCaptureOtherList() .empty() - && c->getFeatureOtherList() .empty() - && c->getLandmarkOtherList().empty()) - _stream << " Abs"; - - for (const auto& Fow : c->getFrameOtherList()) - if (!Fow.expired()) - _stream << " Frm" << Fow.lock()->id(); - for (const auto& Cow : c->getCaptureOtherList()) - if (!Cow.expired()) - _stream << " Cap" << Cow.lock()->id(); - for (const auto& fow : c->getFeatureOtherList()) - if (!fow.expired()) - _stream << " Ftr" << fow.lock()->id(); - for (const auto& Low : c->getLandmarkOtherList()) - if (!Low.expired()) - _stream << " Lmk" << Low.lock()->id(); - _stream << std::endl; - } // for c - } - } // for f - } - } // for C - } - } // for F - } - _stream << "Map" << ((_depth < 1) ? (" -- " + std::to_string(getMap()->getLandmarkList().size()) + "L") : "") << std::endl; - if (_depth >= 1) - { - // Landmarks ======================================================================================= - for (auto L : getMap()->getLandmarkList()) - { - _stream << " Lmk" << L->id() << " " << L->getType(); - if (_constr_by) - { - _stream << "\t<-- "; - for (auto cby : L->getConstrainedByList()) - _stream << "Fac" << cby->id() << " \t"; - } - _stream << std::endl; - if (_metric) - { - _stream << (L->isFixed() ? " Fix" : " Est"); - _stream << ",\t x = ( " << std::setprecision(2) << L->getState().transpose() << " )"; - _stream << std::endl; - } - if (_state_blocks) - { - _stream << " sb:"; - for (const auto& sb : L->getStateBlockVec()) - { - if (sb != nullptr) - _stream << (sb->isFixed() ? " Fix" : " Est"); - } - _stream << std::endl; - } - } // for L - } + getHardware()->print(_depth, _constr_by, _metric, _state_blocks, _stream, ""); + + getTrajectory()->print(_depth, _constr_by, _metric, _state_blocks, _stream, ""); + + getMap()->print(_depth, _constr_by, _metric, _state_blocks, _stream, ""); + _stream << "-----------------------------------------" << std::endl; _stream << std::endl; } @@ -1195,6 +1103,8 @@ bool Problem::check(bool _verbose, std::ostream& _stream) const CheckLog log(true, ""); log.explanation_ = "## WOLF::problem inconsistencies list \n ---------------------------------- \n"; + std::string tabs = ""; + if (_verbose) _stream << std::endl; if (_verbose) _stream << "Wolf tree integrity ---------------------" << std::endl; auto P = shared_from_this(); @@ -1206,624 +1116,19 @@ bool Problem::check(bool _verbose, std::ostream& _stream) const // HARDWARE branch // ------------------------ auto H = hardware_ptr_; - if (_verbose) - { - _stream << "Hrw @ " << H.get() << std::endl; - } - - // check pointer to Problem - std::stringstream inconsistency_explanation; - inconsistency_explanation << "Hardware problem pointer is " << H->getProblem().get() - << " but problem pointer is " << P.get() << "\n"; - log.assertTrue((H->getProblem() == P), inconsistency_explanation); - - - // Sensors ======================================================================================= - for (auto S : H->getSensorList()) - { - if (_verbose) - { - _stream << " Sen" << S->id() << " @ " << S.get() << std::endl; - _stream << " -> Prb @ " << S->getProblem().get() << std::endl; - _stream << " -> Hrw @ " << S->getHardware().get() << std::endl; - for (auto pair: S->getStateBlockMap()) - { - auto sb = pair.second; - _stream << " " << pair.first << " sb @ " << sb.get(); - if (sb) - { - auto lp = sb->getLocalParametrization(); - if (lp) - _stream << " (lp @ " << lp.get() << ")"; - } - _stream << std::endl; - } - } - - // check problem and hardware pointers - inconsistency_explanation << "Sensor problem pointer is " << S->getProblem().get() - << " but problem pointer is " << P.get() << "\n"; - log.assertTrue((S->getProblem() == P), inconsistency_explanation); - - - inconsistency_explanation << "Sensor hardware pointer is " << S->getHardware() - << " but hardware pointer is " << H << "\n"; - log.assertTrue((S->getHardware() == H), inconsistency_explanation); - - - // Processors ======================================================================================= - for (auto p : S->getProcessorList()) - { - if (_verbose) - { - _stream << " Prc" << p->id() << " @ " << p.get() << " -> Sen" << p->getSensor()->id() << std::endl; - _stream << " -> Prb @ " << p->getProblem().get() << std::endl; - _stream << " -> Sen" << p->getSensor()->id() << " @ " << p->getSensor().get() << std::endl; - } - - // check problem and sensor pointers - inconsistency_explanation << "Processor problem pointer is " << p->getProblem().get() - << " but problem pointer is " << P.get() << "\n"; - log.assertTrue((p->getProblem() == P), inconsistency_explanation); - - - inconsistency_explanation << "Processor sensor pointer is " << p->getSensor() - << " but sensor pointer is " << P.get() << "\n"; - log.assertTrue((p->getProblem() == P), inconsistency_explanation); - - } - } + H->check(log, H, _verbose, _stream, tabs); // ------------------------ // TRAJECTORY branch // ------------------------ auto T = trajectory_ptr_; - if (_verbose) - { - _stream << "Trj @ " << T.get() << std::endl; - } - - // check pointer to Problem - inconsistency_explanation << "Trajectory problem pointer is " << T->getProblem().get() - << " but problem pointer is" << P.get() << "\n"; - log.assertTrue((T->getProblem() == P), inconsistency_explanation); - - - // Frames ======================================================================================= - for (auto F : T->getFrameList()) - { - if (_verbose) { - _stream << (F->isKeyOrAux() ? (F->isKey() ? " KFrm" : " EFrm") : " Frm") - << F->id() << " @ " << F.get() << std::endl; - _stream << " -> Prb @ " << F->getProblem().get() << std::endl; - _stream << " -> Trj @ " << F->getTrajectory().get() << std::endl; - } - for (const auto &pair: F->getStateBlockMap()) { - - auto sb = pair.second; - - // check for valid state block - inconsistency_explanation << "Frame " << F->id() << " @ "<< F.get() - << " has State block pointer " << sb.get() - << " = 0 \n"; - log.assertTrue((sb.get() != 0), inconsistency_explanation); - - if (_verbose) { - _stream << " "<< pair.first << " sb @ " << sb.get(); - if (sb) { - auto lp = sb->getLocalParametrization(); - if (lp) - _stream << " (lp @ " << lp.get() << ")"; - } - _stream << std::endl; - } - } - - // check problem pointer - inconsistency_explanation << "Frame problem pointer is " << F->getProblem().get() - << " but problem pointer is" << P.get() << "\n"; - log.assertTrue((F->getProblem() == P), inconsistency_explanation); - - // check trajectory pointer - inconsistency_explanation << "Frame trajectory pointer is " << F->getTrajectory() - << " but trajectory pointer is" << T << "\n"; - log.assertTrue((F->getTrajectory() == T), inconsistency_explanation); - + T->check(log, T, _verbose, _stream, tabs); - // check constrained_by - for (auto cby : F->getConstrainedByList()) - { - if (_verbose) - { - _stream << " <- c" << cby->id() << " -> "; - for (const auto& Fow : cby->getFrameOtherList()) - _stream << " F" << Fow.lock()->id() << std::endl; - } - - // check constrained_by pointer to this frame - inconsistency_explanation << "constrained-by frame " << F->id() << " @ " << F - << " not found among constrained-by factors\n"; - log.assertTrue((cby->hasFrameOther(F)), inconsistency_explanation); - - for (auto sb : cby->getStateBlockPtrVector()) - { - - if (_verbose) { - _stream << " sb @ " << sb.get(); - if (sb) { - auto lp = sb->getLocalParametrization(); - if (lp) - _stream << " (lp @ " << lp.get() << ")"; - } - _stream << std::endl; - } - } - } - - // Captures ======================================================================================= - for (auto C : F->getCaptureList()) - { - if (_verbose) - { - _stream << " Cap" << C->id() << " @ " << C.get() << " -> Sen"; - if (C->getSensor()) _stream << C->getSensor()->id(); - else _stream << "-"; - _stream << std::endl; - _stream << " -> Prb @ " << C->getProblem().get() << std::endl; - _stream << " -> Frm" << C->getFrame()->id() << " @ " << C->getFrame().get() << std::endl; - } - for (auto pair: C->getStateBlockMap()) - { - auto sb = pair.second; - - // check for valid state block - inconsistency_explanation << "Capture " << C->id() << " @ " << C.get() << " has State block pointer " - << sb.get() << " = 0 \n"; - log.assertTrue((sb.get() != 0), inconsistency_explanation); - - if (_verbose) - { - _stream << " " << pair.first << " sb @ " << sb.get(); - if (sb) { - auto lp = sb->getLocalParametrization(); - if (lp) - _stream << " (lp @ " << lp.get() << ")"; - } - _stream << std::endl; - } - } - - // check problem and frame pointers - inconsistency_explanation << "Capture problem pointer is " << C->getProblem().get() - << " but problem pointer is" << P.get() << "\n"; - log.assertTrue((C->getProblem() == P), inconsistency_explanation); - - - inconsistency_explanation << "Capture frame pointer is " << C->getFrame() - << " but frame pointer is" << F << "\n"; - log.assertTrue((C->getFrame() == F), inconsistency_explanation); - - - // check contrained_by - for (const auto& cby : C->getConstrainedByList()) - { - if (_verbose) - { - _stream << " <- c" << cby->id() << " -> "; - for (const auto& Cow : cby->getCaptureOtherList()) - _stream << " C" << Cow.lock()->id(); - _stream << std::endl; - } - - // check constrained_by pointer to this capture - inconsistency_explanation << "constrained by capture " << C->id() << " @ " << C - << " not found among constrained-by factors\n"; - log.assertTrue((cby->hasCaptureOther(C)), inconsistency_explanation); - - for (auto sb : cby->getStateBlockPtrVector()) - { - if (_verbose) - { - _stream << " sb @ " << sb.get(); - if (sb) - { - auto lp = sb->getLocalParametrization(); - if (lp) - _stream << " (lp @ " << lp.get() << ")"; - } - _stream << std::endl; - } - } - - } - - // Features ======================================================================================= - for (auto f : C->getFeatureList()) - { - if (_verbose) - { - _stream << " Ftr" << f->id() << " @ " << f.get() << std::endl; - _stream << " -> Prb @ " << f->getProblem().get() << std::endl; - _stream << " -> Cap" << f->getCapture()->id() << " @ " << f->getCapture().get() - << std::endl; - } - - // check problem and capture pointers - inconsistency_explanation << "Feature frame pointer is " << f->getProblem().get() - << " but problem pointer is" << P.get() << "\n"; - log.assertTrue((f->getProblem() == P), inconsistency_explanation); - - - inconsistency_explanation << "Feature capture pointer is " << f->getCapture() - << " but capture pointer is" << C << "\n"; - log.assertTrue((f->getCapture() == C), inconsistency_explanation); - - - // check contrained_by - for (auto cby : f->getConstrainedByList()) - { - if (_verbose) - { - _stream << " <- c" << cby->id() << " -> "; - for (const auto& fow : cby->getFeatureOtherList()) - _stream << " f" << fow.lock()->id(); - _stream << std::endl; - } - - // check constrained_by pointer to this feature - inconsistency_explanation << "constrained by Feature " << f->id() << " @ " << f - << " not found among constrained-by factors\n"; - log.assertTrue((cby->hasFeatureOther(f)), inconsistency_explanation); - - } - - // Factors ======================================================================================= - for (auto c : f->getFactorList()) - { - if (_verbose) - _stream << " Fac" << c->id() << " @ " << c.get(); - - if ( c->getFrameOtherList() .empty() - && c->getCaptureOtherList() .empty() - && c->getFeatureOtherList() .empty() - && c->getLandmarkOtherList().empty() ) // case ABSOLUTE: - { - if (_verbose) - _stream << " --> Abs."; - } - - // find constrained_by pointer in constrained frame - for (const auto& Fow : c->getFrameOtherList()) - { - if (!Fow.expired()) - { - const auto& Fo = Fow.lock(); - if (_verbose) - { - _stream << " ( --> F" << Fo->id() << " <- "; - for (auto cby : Fo->getConstrainedByList()) - _stream << " c" << cby->id(); - } - - // check constrained_by pointer in constrained frame - bool found = Fo->isConstrainedBy(c); - inconsistency_explanation << "The constrained Feature " << Fo->id() << " @ " << Fo - << " not found among constrained-by factors\n"; - log.assertTrue((found), inconsistency_explanation); - - } - } - if (_verbose && !c->getFrameOtherList().empty()) - _stream << ")"; - - // find constrained_by pointer in constrained capture - for (const auto& Cow : c->getCaptureOtherList()) - { - if (!Cow.expired()) - { - const auto& Co = Cow.lock(); - - if (_verbose) - { - _stream << " ( --> C" << Co->id() << " <- "; - for (auto cby : Co->getConstrainedByList()) - _stream << " c" << cby->id(); - } - - // check constrained_by pointer in constrained frame - bool found = Co->isConstrainedBy(c); - inconsistency_explanation << "The constrained capture " << Co->id() << " @ " << Co - << " not found among constrained-by factors\n"; - log.assertTrue((found), inconsistency_explanation); - - } - } - if (_verbose && !c->getCaptureOtherList().empty()) - _stream << ")"; - - // find constrained_by pointer in constrained feature - for (const auto& fow : c->getFeatureOtherList()) - { - if (!fow.expired()) - { - const auto& fo = fow.lock(); - if (_verbose) - { - _stream << " ( --> f" << fo->id() << " <- "; - for (auto cby : fo->getConstrainedByList()) - _stream << " c" << cby->id(); - } - - // check constrained_by pointer in constrained feature - bool found = fo->isConstrainedBy(c); - inconsistency_explanation << "The constrained feature " << fo->id() << " @ " << fo - << " not found among constrained-by factors\n"; - log.assertTrue((found), inconsistency_explanation); - } - } - if (_verbose && !c->getFeatureOtherList().empty()) - _stream << ")"; - - // find constrained_by pointer in constrained landmark - for (const auto& Low : c->getLandmarkOtherList()) - { - if (Low.expired()) - { - const auto& Lo = Low.lock(); - - if (_verbose) - { - _stream << " ( --> L" << Lo->id() << " <- "; - for (auto cby : Lo->getConstrainedByList()) - _stream << " c" << cby->id(); - } - - // check constrained_by pointer in constrained landmark - bool found = Lo->isConstrainedBy(c); - inconsistency_explanation << "The constrained landmark " << Lo->id() << " @ " << Lo - << " not found among constrained-by factors\n"; - log.assertTrue((found), inconsistency_explanation); - - } - } - if (_verbose && !c->getLandmarkOtherList().empty()) - _stream << ")"; - - if (_verbose) - _stream << std::endl; - - if (_verbose) - { - _stream << " -> Prb @ " << c->getProblem().get() << std::endl; - _stream << " -> Ftr" << c->getFeature()->id() << " @ " << c->getFeature().get() << std::endl; - } - - // check problem and feature pointers - inconsistency_explanation << "The factor " << c->id() << " @ " << c << " has problem ptr " << c->getProblem().get() - << " but problem ptr is " << P.get() << "\n"; - log.assertTrue((c->getProblem() == P), inconsistency_explanation); - - - inconsistency_explanation << "The factor " << c->id() << " @ " << c << " has feature ptr " << c->getFeature() - << " but it should have " << f << "\n"; - log.assertTrue((c->getProblem() == P), inconsistency_explanation); - - - // find state block pointers in all constrained nodes - SensorBasePtr S = c->getFeature()->getCapture()->getSensor(); // get own sensor to check sb - for (auto sb : c->getStateBlockPtrVector()) - { - bool found = false; - if (_verbose) - { - _stream << " sb @ " << sb.get(); - if (sb) - { - auto lp = sb->getLocalParametrization(); - if (lp) - _stream << " (lp @ " << lp.get() << ")"; - } - } - bool found_here; - - // find in own Frame - found_here = F->hasStateBlock(sb); - if (found_here && _verbose) _stream << " F" << F->id(); - found = found || found_here; - - // find in own Capture - found_here = C->hasStateBlock(sb); - if (found_here && _verbose) _stream << " C" << C->id(); - found = found || found_here; - - // Find in other Captures of the own Frame - if (!found_here) - for (auto FC : F->getCaptureList()) - { - found_here = FC->hasStateBlock(sb); - if (found_here && _verbose) _stream << " F" << F->id() << ".C" << FC->id(); - found = found || found_here; - } - - // find in own Sensor - if (S) - { - found_here = S->hasStateBlock(sb); - if (found_here && _verbose) _stream << " S" << S->id(); - found = found || found_here; - } - - - // find in constrained Frame - for (const auto& Fow : c->getFrameOtherList()) - { - if (!Fow.expired()) - { - const auto& Fo = Fow.lock(); - found_here = Fo->hasStateBlock(sb); - if (found_here && _verbose) _stream << " Fo" << Fo->id(); - found = found || found_here; - - // find in feature other's captures - for (auto FoC : Fo->getCaptureList()) - { - found_here = FoC->hasStateBlock(sb); - if (found_here && _verbose) _stream << " Fo" << Fo->id() << ".C" << FoC->id(); - found = found || found_here; - } - - } - } - - // find in constrained Capture - for (const auto& Cow : c->getCaptureOtherList()) - { - if (!Cow.expired()) - { - const auto& Co = Cow.lock(); - found_here = Co->hasStateBlock(sb); - if (found_here && _verbose) _stream << " Co" << Co->id(); - found = found || found_here; - } - } - - // find in constrained Feature - for (const auto& fow : c->getFeatureOtherList()) - { - if (!fow.expired()) - { - const auto& fo = fow.lock(); - // find in constrained feature's Frame - auto foF = fo->getFrame(); - found_here = foF->hasStateBlock(sb); - if (found_here && _verbose) _stream << " foF" << foF->id(); - found = found || found_here; - - // find in constrained feature's Capture - auto foC = fo->getCapture(); - found_here = foC->hasStateBlock(sb); - if (found_here && _verbose) _stream << " foC" << foC->id(); - found = found || found_here; - - // find in constrained feature's Sensor - auto foS = fo->getCapture()->getSensor(); - found_here = foS->hasStateBlock(sb); - if (found_here && _verbose) _stream << " foS" << foS->id(); - found = found || found_here; - } - } - - // find in constrained landmark - for (const auto& Low : c->getLandmarkOtherList()) - { - if (!Low.expired()) - { - const auto& Lo = Low.lock(); - found_here = Lo->hasStateBlock(sb); - if (found_here && _verbose) _stream << " Lo" << Lo->id(); - found = found || found_here; - } - } - - if (_verbose) - { - if (found) - _stream << " found"; - else - _stream << " NOT FOUND !"; - _stream << std::endl; - } - - // check that the state block has been found somewhere - inconsistency_explanation << "The stateblock " << sb << " has not been found (is floating!)"; - log.assertTrue((found), inconsistency_explanation); - - inconsistency_explanation << "The stateblock " << sb << " of factor " << c->id() << " @ " << c << " is null\n"; - log.assertTrue((sb.get() != nullptr), inconsistency_explanation); - } - } - } - } - } // ------------------------ // MAP branch // ------------------------ auto M = map_ptr_; - if (_verbose) - _stream << "Map @ " << M.get() << std::endl; + M->check(log, M, _verbose, _stream, tabs); - // check pointer to Problem - inconsistency_explanation << "The map problem ptr is " << M->getProblem().get() << " but problem is " << P.get() << "\n"; - log.assertTrue((M->getProblem() == P), inconsistency_explanation); - - // Landmarks ======================================================================================= - for (auto L : M->getLandmarkList()) - { - if (_verbose) - { - _stream << " Lmk" << L->id() << " @ " << L.get() << std::endl; - _stream << " -> Prb @ " << L->getProblem().get() << std::endl; - _stream << " -> Map @ " << L->getMap().get() << std::endl; - for (const auto& pair : L->getStateBlockMap()) - { - auto sb = pair.second; - _stream << " " << pair.first << " sb @ " << sb.get(); - if (sb) - { - auto lp = sb->getLocalParametrization(); - if (lp) - _stream << " (lp @ " << lp.get() << ")"; - } - _stream << std::endl; - } - } - - // check problem and map pointers - inconsistency_explanation << "Landmarks' problem ptr is " - << L->getProblem().get() << " but problem is " - << P.get() << "\n"; - - log.assertTrue((L->getProblem() == P), inconsistency_explanation); - - inconsistency_explanation << "The Landmarks' map ptr is " - << L->getMap() << " but map is " - << M << "\n"; - log.assertTrue((M->getProblem() == P), inconsistency_explanation); - - for (auto cby : L->getConstrainedByList()) - { - if (_verbose) - { - _stream << " <- Fac" << cby->id() << " ->"; - - for (const auto& Low : cby->getLandmarkOtherList()) - { - if (!Low.expired()) - { - const auto& Lo = Low.lock(); - _stream << " Lmk" << Lo->id(); - } - } - _stream << std::endl; - } - - // check constrained-by factors - inconsistency_explanation << "constrained-by landmark " << L->id() << " @ " << L - << " not found among constrained-by factors\n"; - log.assertTrue((cby->hasLandmarkOther(L)), inconsistency_explanation); - - for (auto sb : cby->getStateBlockPtrVector()) { - if (_verbose) { - _stream << " sb @ " << sb.get(); - if (sb) { - auto lp = sb->getLocalParametrization(); - if (lp) - _stream << " (lp @ " << lp.get() << ")"; - } - _stream << std::endl; - } - } - } - } if (_verbose) _stream << "--------------------------- Wolf tree " << (log.is_consistent_ ? " OK" : "Not OK !!") << std::endl; if (_verbose) _stream << std::endl; @@ -1836,25 +1141,6 @@ bool Problem::check(int _verbose_level) const { return check((_verbose_level > 0), std::cout); } -void Problem::print(int depth, bool constr_by, bool metric, bool state_blocks) const -{ - print(depth, std::cout, constr_by, metric, state_blocks); -} -void Problem::print(const std::string& depth, bool constr_by, bool metric, bool state_blocks) const -{ - if (depth.compare("T") == 0) - print(0, constr_by, metric, state_blocks); - else if (depth.compare("F") == 0) - print(1, constr_by, metric, state_blocks); - else if (depth.compare("C") == 0) - print(2, constr_by, metric, state_blocks); - else if (depth.compare("f") == 0) - print(3, constr_by, metric, state_blocks); - else if (depth.compare("c") == 0) - print(4, constr_by, metric, state_blocks); - else - print(0, constr_by, metric, state_blocks); -} void Problem::perturb(double amplitude) { diff --git a/src/processor/is_motion.cpp b/src/processor/is_motion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1bfd06a5e9669f76ef48c49a559cade0dc7845f0 --- /dev/null +++ b/src/processor/is_motion.cpp @@ -0,0 +1,9 @@ +#include "core/processor/is_motion.h" +#include "core/problem/problem.h" + +using namespace wolf; + +void IsMotion::addToProblem(ProblemPtr _prb_ptr, IsMotionPtr _motion_ptr) +{ + _prb_ptr->addProcessorIsMotion(_motion_ptr); +} diff --git a/src/processor/motion_buffer.cpp b/src/processor/motion_buffer.cpp index 5d0a595673da23a73efd69d6b1c12d0734f1172b..52383b14cbf0cb7c355f416ef96a20e726bd711b 100644 --- a/src/processor/motion_buffer.cpp +++ b/src/processor/motion_buffer.cpp @@ -64,17 +64,17 @@ void Motion::resize(SizeEigen _data_s, SizeEigen _delta_s, SizeEigen _delta_cov_ MotionBuffer::MotionBuffer() { - container_.clear(); + this->clear(); } const Motion& MotionBuffer::getMotion(const TimeStamp& _ts) const { - //assert((container_.front().ts_ <= _ts) && "Query time stamp out of buffer bounds"); - auto previous = std::find_if(container_.rbegin(), container_.rend(), [&](const Motion& m) + //assert((this->front().ts_ <= _ts) && "Query time stamp out of buffer bounds"); + auto previous = std::find_if(this->rbegin(), this->rend(), [&](const Motion& m) { return m.ts_ <= _ts; }); - if (previous == container_.rend()) + if (previous == this->rend()) // The time stamp is older than the buffer's oldest data. // We could do something here, and throw an error or something, but by now we'll return the first valid data previous--; @@ -84,12 +84,12 @@ const Motion& MotionBuffer::getMotion(const TimeStamp& _ts) const void MotionBuffer::getMotion(const TimeStamp& _ts, Motion& _motion) const { - //assert((container_.front().ts_ <= _ts) && "Query time stamp out of buffer bounds"); - auto previous = std::find_if(container_.rbegin(), container_.rend(), [&](const Motion& m) + //assert((this->front().ts_ <= _ts) && "Query time stamp out of buffer bounds"); + auto previous = std::find_if(this->rbegin(), this->rend(), [&](const Motion& m) { return m.ts_ <= _ts; }); - if (previous == container_.rend()) + if (previous == this->rend()) // The time stamp is older than the buffer's oldest data. // We could do something here, but by now we'll return the last valid data previous--; @@ -99,25 +99,25 @@ void MotionBuffer::getMotion(const TimeStamp& _ts, Motion& _motion) const void MotionBuffer::split(const TimeStamp& _ts, MotionBuffer& _buffer_part_before_ts) { - assert((container_.front().ts_ <= _ts) && "Error: Query time stamp is smaller than the buffer's first tick"); - assert((container_.back().ts_ >= _ts) && "Error: Query time stamp is greater than the buffer's last tick"); + assert((this->front().ts_ <= _ts) && "Error: Query time stamp is smaller than the buffer's first tick"); + assert((this->back().ts_ >= _ts) && "Error: Query time stamp is greater than the buffer's last tick"); - auto previous = std::find_if(container_.rbegin(), container_.rend(), [&](const Motion& m) + auto previous = std::find_if(this->rbegin(), this->rend(), [&](const Motion& m) { return m.ts_ <= _ts; }); - if (previous == container_.rend()) + if (previous == this->rend()) { // The time stamp is more recent than the buffer's most recent data: // return an empty buffer as the _oldest_buffer - _buffer_part_before_ts.get().clear(); + _buffer_part_before_ts.clear(); } else { // Transfer part of the buffer - _buffer_part_before_ts.container_.splice(_buffer_part_before_ts.container_.begin(), - container_, - container_.begin(), + _buffer_part_before_ts.splice(_buffer_part_before_ts.begin(), + *this, + this->begin(), (previous--).base()); } } @@ -130,15 +130,15 @@ void MotionBuffer::print(bool show_data, bool show_delta, bool show_delta_int, b if (!show_data && !show_delta && !show_delta_int && !show_jacs) { - cout << "Buffer state [" << container_.size() << "] : <"; - for (Motion mot : container_) + cout << "Buffer state [" << this->size() << "] : <"; + for (Motion mot : *this) cout << " " << mot.ts_; cout << " >" << endl; } else { print(0,0,0,0); - for (Motion mot : container_) + for (Motion mot : *this) { cout << "-- Motion (" << mot.ts_ << ")" << endl; if (show_data) diff --git a/src/processor/processor_base.cpp b/src/processor/processor_base.cpp index f61f861b021e51a08dd92db301aa1bd8de159272..c02228864e1db24fb0b43826736a26c1c6688451 100644 --- a/src/processor/processor_base.cpp +++ b/src/processor/processor_base.cpp @@ -7,7 +7,7 @@ namespace wolf { unsigned int ProcessorBase::processor_id_count_ = 0; -ProcessorBase::ProcessorBase(const std::string& _type, int _dim, ProcessorParamsBasePtr _params) : +ProcessorBase::ProcessorBase(const std::string& _type, int _dim, ParamsProcessorBasePtr _params) : NodeBase("PROCESSOR", _type), processor_id_(++processor_id_count_), params_(_params), @@ -53,6 +53,10 @@ void ProcessorBase::captureCallback(CaptureBasePtr _capture_ptr) assert(_capture_ptr != nullptr && "captureCallback with a nullptr capture"); WOLF_DEBUG("P", isMotion() ? "M " : "T ", getName(), ": Capture ", _capture_ptr->id(), " callback received with ts = ", _capture_ptr->getTimeStamp()); + // apply prior in problem if not done (very first capture) + if (getProblem() && !getProblem()->isPriorSet()) + getProblem()->applyPriorOptions(_capture_ptr->getTimeStamp()); + // asking if capture should be stored if (storeCapture(_capture_ptr)) buffer_capture_.add(_capture_ptr->getTimeStamp(), _capture_ptr); @@ -100,6 +104,23 @@ void ProcessorBase::link(SensorBasePtr _sen_ptr) WOLF_WARN("Linking with a nullptr"); } } + +void ProcessorBase::setProblem(ProblemPtr _problem) +{ + std::string str = "Processor works with " + std::to_string(dim_) + "D but problem is " + std::to_string(_problem->getDim()) + "D"; + assert((dim_ == 0 or dim_ == _problem->getDim()) && str.c_str()); + + if (_problem == nullptr or _problem == this->getProblem()) + return; + + NodeBase::setProblem(_problem); + + // adding processor is motion to the processor is motion vector + auto is_motion_ptr = std::dynamic_pointer_cast<IsMotion>(shared_from_this()); + if (is_motion_ptr) + getProblem()->addProcessorIsMotion(is_motion_ptr); +} + ///////////////////////////////////////////////////////////////////////////////////////// void BufferPackKeyFrame::add(const FrameBasePtr& _key_frame, const double& _time_tolerance) @@ -196,4 +217,48 @@ void BufferPackKeyFrame::print(void) const std::cout << "]" << std::endl; } +void ProcessorBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "Prc" << id() << " " << getType() << " \"" << getName() << "\"" << std::endl; + +} + +void ProcessorBase::print(int _depth, bool _metric, bool _state_blocks, bool _constr_by, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); +} +CheckLog ProcessorBase::localCheck(bool _verbose, ProcessorBasePtr _prc_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + std::stringstream inconsistency_explanation; + + auto sen_ptr = getSensor(); + if (_verbose) + { + _stream << _tabs << "Prc" << id() << " @ " << _prc_ptr.get() << " -> Sen" << sen_ptr->id() << std::endl; + _stream << _tabs << " " << "-> Prb @ " << getProblem().get() << std::endl; + _stream << _tabs << " " << "-> Sen" << sen_ptr->id() << " @ " << sen_ptr.get() << std::endl; + } + + // check problem and sensor pointers + inconsistency_explanation << "Processor problem pointer " << getProblem().get() + << " is different from Sensor problem pointer " << sen_ptr->getProblem().get() << "\n"; + log.assertTrue((getProblem() == sen_ptr->getProblem()), inconsistency_explanation); + + inconsistency_explanation << "Prc" << id() << " @ " << _prc_ptr + << " ---> Sen" << sen_ptr->id() << " @ " << sen_ptr + << " -X-> Prc" << id(); + auto sen_prc_list = sen_ptr->getProcessorList(); + auto sen_has_prc = std::find_if(sen_prc_list.begin(), sen_prc_list.end(), [&_prc_ptr](ProcessorBasePtr prc){ return prc == _prc_ptr;}); + log.assertTrue(sen_has_prc != sen_prc_list.end(), inconsistency_explanation); + + return log; +} +bool ProcessorBase::check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto prc_ptr = std::static_pointer_cast<ProcessorBase>(_node_ptr); + auto local_log = localCheck(_verbose, prc_ptr, _stream, _tabs); + _log.compose(local_log); + return _log.is_consistent_; +} } // namespace wolf diff --git a/src/processor/processor_diff_drive.cpp b/src/processor/processor_diff_drive.cpp index d80f89ccee5cddff4aab89ec3737c5b518463e7e..43f15c52d8e0eee217a4c824c67bca1e9ae5b9e3 100644 --- a/src/processor/processor_diff_drive.cpp +++ b/src/processor/processor_diff_drive.cpp @@ -16,7 +16,7 @@ namespace wolf { -ProcessorDiffDrive::ProcessorDiffDrive(const ProcessorParamsDiffDrivePtr _params) : +ProcessorDiffDrive::ProcessorDiffDrive(const ParamsProcessorDiffDrivePtr _params) : ProcessorOdom2d(_params), params_prc_diff_drv_selfcal_(_params), radians_per_tick_(0.0) // This param needs further initialization. See this->configure(sensor). @@ -36,8 +36,7 @@ void ProcessorDiffDrive::configure(SensorBasePtr _sensor) { assert(_sensor && "Provided sensor is nullptr"); - SensorDiffDriveConstPtr sensor_diff_drive = std::dynamic_pointer_cast<SensorDiffDrive>(_sensor); - assert(sensor_diff_drive != nullptr && "Sensor is not of type SensorDiffDrive"); + SensorDiffDriveConstPtr sensor_diff_drive = std::static_pointer_cast<SensorDiffDrive>(_sensor); radians_per_tick_ = sensor_diff_drive->getRadiansPerTick(); } @@ -139,7 +138,7 @@ CaptureMotionPtr ProcessorDiffDrive::emplaceCapture(const FrameBasePtr& _frame_o _data, _data_cov, _capture_origin); - cap_motion->setCalibration (_calib); + setCalibration (cap_motion, _calib); cap_motion->setCalibrationPreint(_calib_preint); return cap_motion; @@ -149,10 +148,10 @@ FeatureBasePtr ProcessorDiffDrive::emplaceFeature(CaptureMotionPtr _capture_moti { auto key_feature_ptr = FeatureBase::emplace<FeatureMotion>(_capture_motion, "ProcessorDiffDrive", - _capture_motion->getBuffer().get().back().delta_integr_, - _capture_motion->getBuffer().get().back().delta_integr_cov_, + _capture_motion->getBuffer().back().delta_integr_, + _capture_motion->getBuffer().back().delta_integr_cov_, _capture_motion->getCalibrationPreint(), - _capture_motion->getBuffer().get().back().jacobian_calib_); + _capture_motion->getBuffer().back().jacobian_calib_); return key_feature_ptr; } @@ -169,14 +168,13 @@ FactorBasePtr ProcessorDiffDrive::emplaceFactor(FeatureBasePtr _feature, return fac_odom; } - } /* namespace wolf */ -// Register in the ProcessorFactory -#include "core/processor/processor_factory.h" +// Register in the FactoryProcessor +#include "core/processor/factory_processor.h" namespace wolf { -WOLF_REGISTER_PROCESSOR("ProcessorDiffDrive", ProcessorDiffDrive); -WOLF_REGISTER_PROCESSOR_AUTO("ProcessorDiffDrive", ProcessorDiffDrive); +WOLF_REGISTER_PROCESSOR(ProcessorDiffDrive); +WOLF_REGISTER_PROCESSOR_AUTO(ProcessorDiffDrive); } // namespace wolf diff --git a/src/processor/processor_loopclosure.cpp b/src/processor/processor_loopclosure.cpp index 3517f9e20d5bb55c40ebde25636411c5be02d9cb..16e037b1c7634c4d0d7509fea51e075fbc8d0066 100644 --- a/src/processor/processor_loopclosure.cpp +++ b/src/processor/processor_loopclosure.cpp @@ -11,7 +11,9 @@ namespace wolf { -ProcessorLoopClosure::ProcessorLoopClosure(const std::string& _type, int _dim, ProcessorParamsLoopClosurePtr _params_loop_closure): +ProcessorLoopClosure::ProcessorLoopClosure(const std::string& _type, + int _dim, + ParamsProcessorLoopClosurePtr _params_loop_closure): ProcessorBase(_type, _dim, _params_loop_closure), params_loop_closure_(_params_loop_closure) { diff --git a/src/processor/processor_motion.cpp b/src/processor/processor_motion.cpp index aded1532cc17fc6a0f2e0d48edbbca857a1ab28b..ead3fc9e5d0bcbd56367ef12e1a703e658541478 100644 --- a/src/processor/processor_motion.cpp +++ b/src/processor/processor_motion.cpp @@ -1,3 +1,10 @@ +/** + * \file processor_motion.cpp + * + * Created on: 15/03/2016 + * \author: jsola + */ + #include "core/processor/processor_motion.h" @@ -14,10 +21,10 @@ ProcessorMotion::ProcessorMotion(const std::string& _type, SizeEigen _delta_cov_size, SizeEigen _data_size, SizeEigen _calib_size, - ProcessorParamsMotionPtr _params_motion) : + ParamsProcessorMotionPtr _params_motion) : ProcessorBase(_type, _dim, _params_motion), params_motion_(_params_motion), - processing_step_(RUNNING_WITHOUT_PACK), + processing_step_(RUNNING_WITHOUT_KF), x_size_(_state_size), data_size_(_data_size), delta_size_(_delta_size), @@ -56,14 +63,14 @@ void ProcessorMotion::splitBuffer(const wolf::CaptureMotionPtr& _capture_source, _capture_source->getBuffer().split(_ts_split, _capture_target->getBuffer()); // start with empty motion - TimeStamp t_zero = _capture_target->getBuffer().get().back().ts_; // last tick of previous buffer is zero tick of current buffer - _capture_source->getBuffer().get().push_front(motionZero(t_zero)); + TimeStamp t_zero = _capture_target->getBuffer().back().ts_; // last tick of previous buffer is zero tick of current buffer + _capture_source->getBuffer().push_front(motionZero(t_zero)); // Update the existing capture _capture_source->setOriginCapture(_capture_target); // Get optimized calibration params from 'origin' keyframe - VectorXd calib_preint_optim = _capture_source->getOriginCapture()->getCalibration(); + VectorXd calib_preint_optim = getCalibration(_capture_source->getOriginCapture()); // Write the calib params into the capture before re-integration _capture_source->setCalibrationPreint(calib_preint_optim); @@ -83,7 +90,8 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) return; } - incoming_ptr_ = std::static_pointer_cast<CaptureMotion>(_incoming_ptr); + incoming_ptr_ = std::dynamic_pointer_cast<CaptureMotion>(_incoming_ptr); + assert(incoming_ptr_ != nullptr && ("Capture type mismatch. Processor " + getName() + " can only process captures of type CaptureMotion").c_str()); preProcess(); // Derived class operations @@ -93,11 +101,35 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) switch(processing_step_) { - case RUNNING_WITHOUT_PACK : - case RUNNING_WITH_PACK_ON_ORIGIN : + case FIRST_TIME_WITHOUT_KF : + { + // There is no KF: create own origin + setOrigin(getProblem()->stateZero(getStateStructure()), _incoming_ptr->getTimeStamp()); + break; + } + case FIRST_TIME_WITH_KF_BEFORE_INCOMING : + { + // cannot joint to the KF: create own origin + setOrigin(getProblem()->getState(getStateStructure()), _incoming_ptr->getTimeStamp()); + break; + } + case FIRST_TIME_WITH_KF_ON_INCOMING : + { + // can joint to the KF + setOrigin(pack->key_frame); + break; + } + case FIRST_TIME_WITH_KF_AFTER_INCOMING : + { + // cannot joint to the KF: create own origin + setOrigin(getProblem()->getState(getStateStructure()), _incoming_ptr->getTimeStamp()); + break; + } + case RUNNING_WITHOUT_KF : + case RUNNING_WITH_KF_ON_ORIGIN : break; - case RUNNING_WITH_PACK_BEFORE_ORIGIN : + case RUNNING_WITH_KF_BEFORE_ORIGIN : { /* @@ -143,7 +175,7 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) auto capture_origin = capture_existing->getOriginCapture(); // Get calibration params for preintegration from origin, since it has chances to have optimized values - VectorXd calib_origin = capture_origin->getCalibration(); + VectorXd calib_origin = getCalibration(capture_origin); // emplace a new motion capture to the new keyframe TimeStamp ts_from_callback = keyframe_from_callback->getTimeStamp(); @@ -169,22 +201,29 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) // modify existing feature and factor (if they exist in the existing capture) if (!capture_existing->getFeatureList().empty()) { - auto feature_existing = capture_existing->getFeatureList().back(); // there is only one feature! - - // Modify existing feature -------- - feature_existing->setMeasurement (capture_existing->getBuffer().get().back().delta_integr_); - feature_existing->setMeasurementCovariance(capture_existing->getBuffer().get().back().delta_integr_cov_); - - // Modify existing factor -------- - // Instead of modifying, we remove one ctr, and create a new one. - auto fac_to_remove = feature_existing->getFactorList().back(); // there is only one factor! - auto new_ctr = emplaceFactor(feature_existing, capture_for_keyframe_callback); - fac_to_remove ->remove(); // remove old factor now (otherwise c->remove() gets propagated to f, C, F, etc.) + // setMeasurement is not allowed: feature (and factor) will be removed and a new feature and factor will be emplaced + capture_existing->getFeatureList().back()->remove(); // factor is removed automatically + + assert(capture_existing->getFeatureList().empty());// there was only one feature! + auto new_feature_existing = emplaceFeature(capture_existing); + emplaceFactor(new_feature_existing, capture_for_keyframe_callback); + +// auto feature_existing = capture_existing->getFeatureList().back(); // there is only one feature! +// +// // Modify existing feature -------- +// feature_existing->setMeasurement (capture_existing->getBuffer().back().delta_integr_); +// feature_existing->setMeasurementCovariance(capture_existing->getBuffer().back().delta_integr_cov_); +// +// // Modify existing factor -------- +// // Instead of modifying, we remove one ctr, and create a new one. +// auto fac_to_remove = feature_existing->getFactorList().back(); // there is only one factor! +// auto new_ctr = emplaceFactor(feature_existing, capture_for_keyframe_callback); +// fac_to_remove ->remove(); // remove old factor now (otherwise c->remove() gets propagated to f, C, F, etc.) } break; } - case RUNNING_WITH_PACK_AFTER_ORIGIN : + case RUNNING_WITH_KF_AFTER_ORIGIN : { /* * Legend: @@ -228,7 +267,7 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) auto & capture_origin = origin_ptr_; // Get calibration params for preintegration from origin, since it has chances to have optimized values - VectorXd calib_origin = capture_origin->getCalibration(); + VectorXd calib_origin = getCalibration(capture_origin); // emplace a new motion capture to the new keyframe TimeStamp ts_from_callback = keyframe_from_callback->getTimeStamp(); @@ -268,9 +307,10 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) integrateOneStep(); // Update state and time stamps - last_ptr_->setTimeStamp(getCurrentTimeStamp()); - last_ptr_->getFrame()->setTimeStamp(getCurrentTimeStamp()); - last_ptr_->getFrame()->setState(getProblem()->getState(getCurrentTimeStamp())); + const auto& ts = getTimeStamp(); + last_ptr_->setTimeStamp( ts ); + last_ptr_->getFrame()->setTimeStamp( ts ); + last_ptr_->getFrame()->setState( getProblem()->getState( ts ) ); if (permittedKeyFrame() && voteForKeyFrame()) { @@ -318,19 +358,20 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) // create a new frame auto frame_new = getProblem()->emplaceFrame(NON_ESTIMATED, - getProblem()->getCurrentState(), - getCurrentTimeStamp()); + getTimeStamp(), + getStateStructure(), + getProblem()->getState()); // create a new capture auto capture_new = emplaceCapture(frame_new, getSensor(), key_frame->getTimeStamp(), Eigen::VectorXd::Zero(data_size_), getSensor()->getNoiseCov(), - last_ptr_->getCalibration(), - last_ptr_->getCalibration(), + getCalibration(last_ptr_), + getCalibration(last_ptr_), last_ptr_); // reset the new buffer - capture_new->getBuffer().get().push_back( motionZero(key_frame->getTimeStamp()) ) ; + capture_new->getBuffer().push_back( motionZero(key_frame->getTimeStamp()) ) ; // reset derived things resetDerived(); @@ -349,51 +390,164 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) postProcess(); } -// _x needs to have the size of the processor state -bool ProcessorMotion::getState(const TimeStamp& _ts, Eigen::VectorXd& _x) const +VectorComposite ProcessorMotion::getState() const { - CaptureMotionPtr capture_motion; - if (origin_ptr_ && _ts >= origin_ptr_->getTimeStamp()) - // timestamp found in the current processor buffer - capture_motion = last_ptr_; - else - // We need to search in previous keyframes for the capture containing a motion buffer with the queried time stamp - capture_motion = findCaptureContainingTimeStamp(_ts); - if (capture_motion) // We found a CaptureMotion whose buffer contains the time stamp + if (last_ptr_ == nullptr or last_ptr_->getFrame() == nullptr) // We do not have any info of where to find a valid state + // Further checking here for origin_ptr is redundant: if last=null, then origin=null too. { - // Get origin state and calibration - CaptureBasePtr cap_orig = capture_motion->getOriginCapture(); - VectorXd state_0 = cap_orig->getFrame()->getState(state_structure_); - VectorXd calib = cap_orig->getCalibration(); + WOLF_ERROR("Processor has no state. Returning an empty VectorComposite with no blocks"); + return VectorComposite(); // return empty state + } - // Get delta and correct it with new calibration params - VectorXd calib_preint = capture_motion->getCalibrationPreint(); - Motion motion = capture_motion->getBuffer().getMotion(_ts); - VectorXd delta_step = motion.jacobian_calib_ * (calib - calib_preint); - VectorXd delta = capture_motion->correctDelta( motion.delta_integr_, delta_step); + // From here on, we do have info to compute a valid state + + // if buffer is empty --> we did not advance from origin! + // this may happen when in the very first frame where the capture has no motion info --> empty buffer + if (last_ptr_->getBuffer().empty()) + { + return last_ptr_->getFrame()->getState(state_structure_); + } + + /* Doing this: + * + * x_t = x_0 [+] ( D_0t (+) J_D_c * ( c - c_preint ) ) + * + * or, put in code form: + * + * _state = state_origin [+] (delta_preint (+) Jac_delta_calib * (calib - calib_preint) ) + * + * with + * [+] : group composition + * (+) : block-wise plus + */ + + // Get state of origin + const auto& x_origin = getOrigin()->getFrame()->getState(); + + // Get most rescent motion + const auto& motion = last_ptr_->getBuffer().back(); + + // Get delta preintegrated up to now + const auto& delta_preint = motion.delta_integr_; + + // Get calibration preint -- stored in last capture + const auto& calib_preint = last_ptr_->getCalibrationPreint(); + + VectorComposite state; + if ( hasCalibration() ) + { + // Get current calibration -- from origin capture + const auto& calib = getCalibration(origin_ptr_); - // ensure proper size of the provided reference - _x.resize( state_0.size() ); + // get Jacobian of delta wrt calibration + const auto& J_delta_calib = motion.jacobian_calib_; - // Compose on top of origin state using the buffered time stamp, not the query time stamp - double dt = motion.ts_ - capture_motion->getBuffer().get().front().ts_; - statePlusDelta(state_0, delta, dt, _x); + // compute delta change + const auto& delta_step = J_delta_calib * (calib - calib_preint); + + // correct delta // this is (+) + const auto& delta_corrected = correctDelta(delta_preint, delta_step); + + // compute current state // this is [+] + statePlusDelta(x_origin, delta_corrected, last_ptr_->getTimeStamp() - origin_ptr_->getTimeStamp(), state); } else { - // We could not find any CaptureMotion for the time stamp requested - WOLF_ERROR("Could not find any Capture for the time stamp requested. ", _ts); - WOLF_TRACE("Did you forget to call Problem::setPrior() in your application?") - return false; + statePlusDelta(x_origin, delta_preint, last_ptr_->getTimeStamp() - origin_ptr_->getTimeStamp(), state); + } + + return state; +} + + + +// _x needs to have the size of the processor state +VectorComposite ProcessorMotion::getState(const TimeStamp& _ts) const +{ + + // We need to search for the capture containing a motion buffer with the queried time stamp + CaptureMotionPtr capture_motion = findCaptureContainingTimeStamp(_ts); + + if (capture_motion == nullptr) // we do not have any info of where to find a valid state + { + WOLF_ERROR("Processor has no state. Returning an empty VectorComposite with no blocks"); + return VectorComposite(); // return empty state + } + + + else // We found a CaptureMotion whose buffer contains the time stamp + { + // if buffer is empty --> we did not advance from origin! + // this may happen when in the very first frame where the capture has no motion info --> empty buffer + if (capture_motion->getBuffer().empty()) + { + return capture_motion->getFrame()->getState(state_structure_); + } + + /* Doing this: + * + * x_t = x_0 [+] ( D_0t (+) J_D_c * ( c - c_preint ) ) + * + * or, put in code form: + * + * _state = state_origin [+] (delta_preint (+) Jac_delta_calib * (calib - calib_preint) ) + * + * with + * [+] : group composition + * (+) : block-wise plus + */ + + // Get state of origin + CaptureBasePtr cap_orig = capture_motion->getOriginCapture(); + const auto& x_origin = cap_orig->getFrame()->getState(); + + // Get motion at time stamp + const auto& motion = capture_motion->getBuffer().getMotion(_ts); + + // Get delta preintegrated up to time stamp + const auto& delta_preint = motion.delta_integr_; + + // Get calibration preint -- stored in last capture + const auto& calib_preint = capture_motion->getCalibrationPreint(); + + VectorComposite state; + + if ( hasCalibration() ) + { + // Get current calibration -- from origin capture + const auto& calib = getCalibration(cap_orig); + + // get Jacobian of delta wrt calibration + const auto& J_delta_calib = motion.jacobian_calib_; + + // compute delta change + const auto& delta_step = J_delta_calib * (calib - calib_preint); + + // correct delta // this is (+) + const auto& delta_corrected = correctDelta(delta_preint, delta_step); + + // compute current state // this is [+] + statePlusDelta(x_origin, delta_corrected, _ts - cap_orig->getTimeStamp(), state); + } + else + { + statePlusDelta(x_origin, delta_preint, _ts - cap_orig->getTimeStamp(), state); + } + + // return success + return state; + } - return true; } -FrameBasePtr ProcessorMotion::setOrigin(const Eigen::VectorXd& _x_origin, const TimeStamp& _ts_origin) +FrameBasePtr ProcessorMotion::setOrigin(const VectorComposite& _x_origin, const TimeStamp& _ts_origin) { - FrameBasePtr key_frame_ptr = getProblem()->emplaceFrame(KEY, _x_origin, _ts_origin); + FrameBasePtr key_frame_ptr = getProblem()->emplaceFrame(KEY, + _ts_origin, + getStateStructure(), + _x_origin); setOrigin(key_frame_ptr); return key_frame_ptr; @@ -406,11 +560,13 @@ void ProcessorMotion::setOrigin(FrameBasePtr _origin_frame) && "ProcessorMotion::setOrigin: origin frame must be in the trajectory."); assert(_origin_frame->isKey() && "ProcessorMotion::setOrigin: origin frame must be KEY FRAME."); + TimeStamp origin_ts = _origin_frame->getTimeStamp(); + // -------- ORIGIN --------- // emplace (empty) origin Capture origin_ptr_ = emplaceCapture(_origin_frame, getSensor(), - _origin_frame->getTimeStamp(), + origin_ts, Eigen::VectorXd::Zero(data_size_), getSensor()->getNoiseCov(), getSensor()->getCalibration(), @@ -419,15 +575,15 @@ void ProcessorMotion::setOrigin(FrameBasePtr _origin_frame) // ---------- LAST ---------- // Make non-key-frame for last Capture - TimeStamp origin_ts = _origin_frame->getTimeStamp(); auto new_frame_ptr = getProblem()->emplaceFrame(NON_ESTIMATED, - _origin_frame->getState(), - origin_ts); + origin_ts, + getStateStructure(), + _origin_frame->getState()); // emplace (emtpy) last Capture last_ptr_ = emplaceCapture(new_frame_ptr, getSensor(), - _origin_frame->getTimeStamp(), + origin_ts, Eigen::VectorXd::Zero(data_size_), getSensor()->getNoiseCov(), getSensor()->getCalibration(), @@ -435,7 +591,7 @@ void ProcessorMotion::setOrigin(FrameBasePtr _origin_frame) origin_ptr_); // clear and reset buffer - getBuffer().get().push_back(motionZero(_origin_frame->getTimeStamp())); + getBuffer().push_back(motionZero(_origin_frame->getTimeStamp())); // Reset derived things resetDerived(); @@ -460,7 +616,7 @@ void ProcessorMotion::integrateOneStep() jacobian_delta_calib_); // integrate the current delta to pre-integrated measurements, and get Jacobians - deltaPlusDelta(getBuffer().get().back().delta_integr_, + deltaPlusDelta(getBuffer().back().delta_integr_, delta_, dt_, delta_integrated_, @@ -468,29 +624,29 @@ void ProcessorMotion::integrateOneStep() jacobian_delta_); // integrate Jacobian wrt calib - if ( hasCalibration() ) + if ( hasCalibration() ) // if no calibration, matrices can have mismatching sizes, and this computation is nevertheless pointless { jacobian_calib_.noalias() - = jacobian_delta_preint_ * getBuffer().get().back().jacobian_calib_ + = jacobian_delta_preint_ * getBuffer().back().jacobian_calib_ + jacobian_delta_ * jacobian_delta_calib_; } // Integrate covariance delta_integrated_cov_.noalias() - = jacobian_delta_preint_ * getBuffer().get().back().delta_integr_cov_ * jacobian_delta_preint_.transpose() + = jacobian_delta_preint_ * getBuffer().back().delta_integr_cov_ * jacobian_delta_preint_.transpose() + jacobian_delta_ * delta_cov_ * jacobian_delta_.transpose(); // push all into buffer - getBuffer().get().emplace_back(incoming_ptr_->getTimeStamp(), - incoming_ptr_->getData(), - incoming_ptr_->getDataCovariance(), - delta_, - delta_cov_, - delta_integrated_, - delta_integrated_cov_, - jacobian_delta_, - jacobian_delta_preint_, - jacobian_calib_); + getBuffer().emplace_back(incoming_ptr_->getTimeStamp(), + incoming_ptr_->getData(), + incoming_ptr_->getDataCovariance(), + delta_, + delta_cov_, + delta_integrated_, + delta_integrated_cov_, + jacobian_delta_, + jacobian_delta_preint_, + jacobian_calib_); } void ProcessorMotion::reintegrateBuffer(CaptureMotionPtr _capture_ptr) @@ -503,15 +659,15 @@ void ProcessorMotion::reintegrateBuffer(CaptureMotionPtr _capture_ptr) jacobian_calib_ .setZero(); // check that first motion in buffer is zero! - assert(_capture_ptr->getBuffer().get().front().delta_integr_ == delta_integrated_ && "Buffer's first motion is not zero!"); - assert(_capture_ptr->getBuffer().get().front().delta_integr_cov_ == delta_integrated_cov_ && "Buffer's first motion is not zero!"); - assert(_capture_ptr->getBuffer().get().front().jacobian_calib_ == jacobian_calib_ && "Buffer's first motion is not zero!"); + assert(_capture_ptr->getBuffer().front().delta_integr_ == delta_integrated_ && "Buffer's first motion is not zero!"); + assert(_capture_ptr->getBuffer().front().delta_integr_cov_ == delta_integrated_cov_ && "Buffer's first motion is not zero!"); + assert(_capture_ptr->getBuffer().front().jacobian_calib_ == jacobian_calib_ && "Buffer's first motion is not zero!"); // Iterate all the buffer - auto motion_it = _capture_ptr->getBuffer().get().begin(); + auto motion_it = _capture_ptr->getBuffer().begin(); auto prev_motion_it = motion_it; motion_it++; - while (motion_it != _capture_ptr->getBuffer().get().end()) + while (motion_it != _capture_ptr->getBuffer().end()) { // get dt const double dt = motion_it->ts_ - prev_motion_it->ts_; @@ -574,7 +730,8 @@ CaptureMotionPtr ProcessorMotion::findCaptureContainingTimeStamp(const TimeStamp { // Rule 1 satisfied! We found a Capture belonging to this processor's Sensor ==> it is a CaptureMotion capture_motion = std::static_pointer_cast<CaptureMotion>(capture); - if (_ts < frame->getTimeStamp() and !capture_motion->getBuffer().get().empty() and _ts >= capture_motion->getBuffer().get().front().ts_) + + if (capture_motion->containsTimeStamp(_ts, params_->time_tolerance)) { // Found time stamp satisfying rule 3 above !! ==> break for loop break; @@ -588,60 +745,68 @@ CaptureMotionPtr ProcessorMotion::findCaptureContainingTimeStamp(const TimeStamp PackKeyFramePtr ProcessorMotion::computeProcessingStep() { - if (!getProblem()->priorIsSet()) + // Origin not set + if (!origin_ptr_) { - WOLF_WARN ("||*||"); - WOLF_INFO (" ... It seems you missed something!"); - WOLF_ERROR("ProcessorMotion received data before being initialized."); - WOLF_INFO ("Did you forget to issue a Problem::setPrior()?"); - throw std::runtime_error("ProcessorMotion received data before being initialized."); - } - - PackKeyFramePtr pack = buffer_pack_kf_.selectFirstPackBefore(last_ptr_, params_motion_->time_tolerance); - - // ignore "future" KF to avoid MotionBuffer::split() error - if (pack && pack->key_frame->getTimeStamp() > last_ptr_->getBuffer().get().back().ts_) - pack = nullptr; + PackKeyFramePtr pack = buffer_pack_kf_.selectFirstPackBefore(incoming_ptr_, params_motion_->time_tolerance); - if (pack) - { - if (buffer_pack_kf_.checkTimeTolerance(pack->key_frame->getTimeStamp(), pack->time_tolerance, origin_ptr_->getTimeStamp(), params_motion_->time_tolerance)) + if (pack) { - WOLF_WARN("||*||"); - WOLF_INFO(" ... It seems you missed something!"); - WOLF_ERROR("Pack's KF and origin's KF have matching time stamps (i.e. below time tolerances)"); - // throw std::runtime_error("Pack's KF and origin's KF have matching time stamps (i.e. below time tolerances)"); - processing_step_ = RUNNING_WITH_PACK_ON_ORIGIN; + if (buffer_pack_kf_.checkTimeTolerance(pack->key_frame->getTimeStamp(), pack->time_tolerance, incoming_ptr_->getTimeStamp(), params_motion_->time_tolerance)) + { + WOLF_DEBUG("First time with a KF compatible.") + processing_step_ = FIRST_TIME_WITH_KF_ON_INCOMING; + } + else if (pack->key_frame->getTimeStamp() < incoming_ptr_->getTimeStamp()) + { + WOLF_DEBUG("First time with a KF too old. It seems the prior has been set before receiving the first capture of this processor.") + processing_step_ = FIRST_TIME_WITH_KF_BEFORE_INCOMING; + } + else + { + WOLF_DEBUG("First time with a KF newer than the first capture. It only can happen if prior mode is 'nothing'") + processing_step_ = FIRST_TIME_WITH_KF_AFTER_INCOMING; + } } - else if (pack->key_frame->getTimeStamp() < origin_ptr_->getTimeStamp()) - processing_step_ = RUNNING_WITH_PACK_BEFORE_ORIGIN; - else - processing_step_ = RUNNING_WITH_PACK_AFTER_ORIGIN; + { + WOLF_DEBUG("First time with a KF newer than the first capture. It only can happen if prior mode is 'nothing'") + processing_step_ = FIRST_TIME_WITHOUT_KF; + } + return pack; } else - processing_step_ = RUNNING_WITHOUT_PACK; + { + PackKeyFramePtr pack = buffer_pack_kf_.selectFirstPackBefore(last_ptr_, params_motion_->time_tolerance); - return pack; -} + // ignore "future" KF to avoid MotionBuffer::split() error + if (pack && pack->key_frame->getTimeStamp() > last_ptr_->getBuffer().back().ts_) + pack = nullptr; -void ProcessorMotion::setProblem(ProblemPtr _problem) -{ - std::string str = "Processor works with " + std::to_string(dim_) + "D but problem is " + std::to_string(_problem->getDim()) + "D"; - assert((dim_ == 0 or dim_ == _problem->getDim()) && str.c_str()); + if (pack) + { + if (buffer_pack_kf_.checkTimeTolerance(pack->key_frame->getTimeStamp(), pack->time_tolerance, origin_ptr_->getTimeStamp(), params_motion_->time_tolerance)) - if (_problem == nullptr or _problem == this->getProblem()) - return; + processing_step_ = RUNNING_WITH_KF_ON_ORIGIN; - NodeBase::setProblem(_problem); + else if (pack->key_frame->getTimeStamp() < origin_ptr_->getTimeStamp()) - // set the origin - if (origin_ptr_ == nullptr && this->getProblem()->getLastKeyFrame() != nullptr) - this->setOrigin(this->getProblem()->getLastKeyFrame()); - - // adding processor is motion to the processor is motion vector - getProblem()->addProcessorIsMotion(std::dynamic_pointer_cast<IsMotion>(shared_from_this())); + processing_step_ = RUNNING_WITH_KF_BEFORE_ORIGIN; + + else + + processing_step_ = RUNNING_WITH_KF_AFTER_ORIGIN; + + } + else + processing_step_ = RUNNING_WITHOUT_KF; + + return pack; + } + + // not reached + return nullptr; } bool ProcessorMotion::storeKeyFrame(FrameBasePtr _frame_ptr) @@ -653,4 +818,32 @@ bool ProcessorMotion::storeCapture(CaptureBasePtr _cap_ptr) return false; } +TimeStamp ProcessorMotion::getTimeStamp ( ) const +{ + if (not last_ptr_) + { + WOLF_ERROR("Processor has no time stamp. Returning a non-valid timestamp equal to 0"); + return TimeStamp(0); + } + + if (getBuffer().empty()) + return last_ptr_->getTimeStamp(); + + return getBuffer().back().ts_; +} + +void ProcessorMotion::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "PrcM" << id() << " " << getType() << " \"" << getName() << "\"" << std::endl; + if (getOrigin()) + _stream << _tabs << " " << "o: Cap" << getOrigin()->id() << " - " << (getOrigin()->getFrame()->isKeyOrAux() ? (getOrigin()->getFrame()->isKey() ? " KFrm" : " AFrm" ) : " Frm") + << getOrigin()->getFrame()->id() << std::endl; + if (getLast()) + _stream << _tabs << " " << "l: Cap" << getLast()->id() << " - " << (getLast()->getFrame()->isKeyOrAux() ? (getLast()->getFrame()->isKey() ? " KFrm" : " AFrm") : " Frm") + << getLast()->getFrame()->id() << std::endl; + if (getIncoming()) + _stream << _tabs << " " << "i: Cap" << getIncoming()->id() << std::endl; + } + +} // namespace wolf diff --git a/src/processor/processor_odom_2d.cpp b/src/processor/processor_odom_2d.cpp index 929c1ed7ceb825fdaa265a1af592fa8125832789..284090e238f3c75327424cb76f3946e277e23bdf 100644 --- a/src/processor/processor_odom_2d.cpp +++ b/src/processor/processor_odom_2d.cpp @@ -1,11 +1,12 @@ #include "core/processor/processor_odom_2d.h" #include "core/sensor/sensor_odom_2d.h" #include "core/math/covariance.h" +#include "core/state_block/state_composite.h" namespace wolf { -ProcessorOdom2d::ProcessorOdom2d(ProcessorParamsOdom2dPtr _params) : +ProcessorOdom2d::ProcessorOdom2d(ParamsProcessorOdom2dPtr _params) : ProcessorMotion("ProcessorOdom2d", "PO", 2, 3, 3, 3, 2, 0, _params), params_odom_2d_(_params) { @@ -16,11 +17,6 @@ ProcessorOdom2d::~ProcessorOdom2d() { } -void ProcessorOdom2d::configure(SensorBasePtr _sensor) -{ - auto sensor_ = std::dynamic_pointer_cast<SensorOdom2d>(_sensor); - assert(sensor_ != nullptr && "Sensor is not of type SensorOdom2d"); -} void ProcessorOdom2d::computeCurrentDelta(const Eigen::VectorXd& _data, const Eigen::MatrixXd& _data_cov, const Eigen::VectorXd& _calib, const double _dt, Eigen::VectorXd& _delta, Eigen::MatrixXd& _delta_cov, Eigen::MatrixXd& _jacobian_calib) const @@ -89,38 +85,39 @@ void ProcessorOdom2d::deltaPlusDelta(const Eigen::VectorXd& _delta1, const Eigen _jacobian2.topLeftCorner<2, 2>() = Eigen::Rotation2Dd(_delta1(2)).matrix(); } -void ProcessorOdom2d::statePlusDelta(const Eigen::VectorXd& _x, const Eigen::VectorXd& _delta, const double _Dt, - Eigen::VectorXd& _x_plus_delta) const +void ProcessorOdom2d::statePlusDelta(const VectorComposite& _x, + const Eigen::VectorXd& _delta, + const double _Dt, + VectorComposite& _x_plus_delta) const { - assert(_x.size() == x_size_ && "Wrong _x vector size"); - assert(_x_plus_delta.size() == x_size_ && "Wrong _x_plus_delta vector size"); + assert(_delta.size() == delta_size_ && "Wrong _x_plus_delta vector size"); // This is just a frame composition in 2d - _x_plus_delta.head<2>() = _x.head<2>() + Eigen::Rotation2Dd(_x(2)).matrix() * _delta.head<2>(); - _x_plus_delta(2) = pi2pi(_x(2) + _delta(2)); + _x_plus_delta["P"] = _x.at("P") + Eigen::Rotation2Dd(_x.at("O")(0)).matrix() * _delta.head<2>(); + _x_plus_delta["O"] = Vector1d(pi2pi(_x.at("O")(0) + _delta(2))); } bool ProcessorOdom2d::voteForKeyFrame() const { // Distance criterion - if (getBuffer().get().back().delta_integr_.head<2>().norm() > params_odom_2d_->dist_traveled) + if (getBuffer().back().delta_integr_.head<2>().norm() > params_odom_2d_->dist_traveled) { WOLF_DEBUG("PM", id(), " ", getType(), " votes per distance"); return true; } - if (getBuffer().get().back().delta_integr_.tail<1>().norm() > params_odom_2d_->angle_turned) + if (getBuffer().back().delta_integr_.tail<1>().norm() > params_odom_2d_->angle_turned) { WOLF_DEBUG("PM", id(), " ", getType(), " votes per angle"); return true; } // Uncertainty criterion - if (getBuffer().get().back().delta_integr_cov_.determinant() > params_odom_2d_->cov_det) + if (getBuffer().back().delta_integr_cov_.determinant() > params_odom_2d_->cov_det) { WOLF_DEBUG("PM", id(), " ", getType(), " votes per state covariance"); return true; } // Time criterion - if (getBuffer().get().back().ts_.get() - origin_ptr_->getFrame()->getTimeStamp().get() > params_odom_2d_->max_time_span) + if (getBuffer().back().ts_.get() - origin_ptr_->getFrame()->getTimeStamp().get() > params_odom_2d_->max_time_span) { WOLF_DEBUG("PM", id(), " ", getType(), " votes per time"); return true; @@ -138,7 +135,7 @@ CaptureMotionPtr ProcessorOdom2d::emplaceCapture(const FrameBasePtr& _frame_own, const CaptureBasePtr& _capture_origin_ptr) { auto cap_motion = CaptureBase::emplace<CaptureOdom2d>(_frame_own, _ts, _sensor, _data, _data_cov, _capture_origin_ptr); - cap_motion->setCalibration(_calib); + setCalibration(cap_motion, _calib); cap_motion->setCalibrationPreint(_calib_preint); return cap_motion; @@ -156,12 +153,12 @@ FactorBasePtr ProcessorOdom2d::emplaceFactor(FeatureBasePtr _feature, CaptureBas FeatureBasePtr ProcessorOdom2d::emplaceFeature(CaptureMotionPtr _capture_motion) { - Eigen::MatrixXd covariance = _capture_motion->getBuffer().get().back().delta_integr_cov_; + Eigen::MatrixXd covariance = _capture_motion->getBuffer().back().delta_integr_cov_; makePosDef(covariance); FeatureBasePtr key_feature_ptr = FeatureBase::emplace<FeatureBase>(_capture_motion, "ProcessorOdom2d", - _capture_motion->getBuffer().get().back().delta_integr_, + _capture_motion->getBuffer().back().delta_integr_, covariance); return key_feature_ptr; } @@ -170,9 +167,9 @@ FeatureBasePtr ProcessorOdom2d::emplaceFeature(CaptureMotionPtr _capture_motion) } /* namespace wolf */ -// Register in the ProcessorFactory -#include "core/processor/processor_factory.h" +// Register in the FactoryProcessor +#include "core/processor/factory_processor.h" namespace wolf { -WOLF_REGISTER_PROCESSOR("ProcessorOdom2d", ProcessorOdom2d); -WOLF_REGISTER_PROCESSOR_AUTO("ProcessorOdom2d", ProcessorOdom2d); +WOLF_REGISTER_PROCESSOR(ProcessorOdom2d); +WOLF_REGISTER_PROCESSOR_AUTO(ProcessorOdom2d); } // namespace wolf diff --git a/src/processor/processor_odom_3d.cpp b/src/processor/processor_odom_3d.cpp index 3e1268eb1d705b3a335d9c8d9389e0c9449ebba1..5b01e98b3ad8fbbe6f31bedc4f25b1a9cfe76747 100644 --- a/src/processor/processor_odom_3d.cpp +++ b/src/processor/processor_odom_3d.cpp @@ -1,8 +1,10 @@ #include "core/processor/processor_odom_3d.h" +#include "core/math/SE3.h" + namespace wolf { -ProcessorOdom3d::ProcessorOdom3d(ProcessorParamsOdom3dPtr _params) : +ProcessorOdom3d::ProcessorOdom3d(ParamsProcessorOdom3dPtr _params) : ProcessorMotion("ProcessorOdom3d", "PO", 3, 7, 7, 6, 6, 0, _params), params_odom_3d_ (_params), k_disp_to_disp_ (0), @@ -21,8 +23,8 @@ ProcessorOdom3d::~ProcessorOdom3d() void ProcessorOdom3d::configure(SensorBasePtr _sensor) { assert (_sensor && "Trying to configure processor with a sensor but provided sensor is nullptr."); - auto sen_ptr = std::dynamic_pointer_cast<SensorOdom3d>(_sensor); - assert(sen_ptr != nullptr && "Sensor is not of type SensorOdom3d"); + + SensorOdom3dPtr sen_ptr = std::static_pointer_cast<SensorOdom3d>(_sensor); // we steal the parameters from the provided odom3d sensor. k_disp_to_disp_ = sen_ptr->getDispVarToDispNoiseFactor(); @@ -41,22 +43,17 @@ void ProcessorOdom3d::computeCurrentDelta(const Eigen::VectorXd& _data, Eigen::MatrixXd& _jacobian_calib) const { assert((_data.size() == 6 || _data.size() == 7) && "Wrong data size. Must be 6 or 7 for 3d."); - double disp, rot; // displacement and rotation of this motion step if (_data.size() == (long int)6) { // rotation in vector form _delta.head<3>() = _data.head<3>(); Eigen::Map<Eigen::Quaterniond> q(_delta.data() + 3); q = v2q(_data.tail<3>()); - disp = _data.head<3>().norm(); - rot = _data.tail<3>().norm(); } else { // rotation in quaternion form _delta = _data; - disp = _data.head<3>().norm(); - rot = 2.0 * acos(_data(6)); // '6' is the real part of the quaternion } /* Jacobians of d = data2delta(data, dt) * with: d = [Dp Dq] @@ -72,13 +69,7 @@ void ProcessorOdom3d::computeCurrentDelta(const Eigen::VectorXd& _data, * * so, J = I, and delta_cov = _data_cov */ - // We discard _data_cov and create a new one from the measured motion - double disp_var = min_disp_var_ + k_disp_to_disp_ * disp; - double rot_var = min_rot_var_ + k_disp_to_rot_ * disp + k_rot_to_rot_ * rot; - Eigen::Matrix6d data_cov(Eigen::Matrix6d::Identity()); - data_cov(0, 0) = data_cov(1, 1) = data_cov(2, 2) = disp_var; - data_cov(3, 3) = data_cov(4, 4) = data_cov(5, 5) = rot_var; - _delta_cov = data_cov; + _delta_cov = _data_cov; } void ProcessorOdom3d::deltaPlusDelta(const Eigen::VectorXd& _delta1, const Eigen::VectorXd& _delta2, const double _Dt2, @@ -149,43 +140,40 @@ void ProcessorOdom3d::deltaPlusDelta(const Eigen::VectorXd& _delta1, const Eigen dq_out = dq1 * dq2; } -void ProcessorOdom3d::statePlusDelta(const Eigen::VectorXd& _x, const Eigen::VectorXd& _delta, const double _Dt, - Eigen::VectorXd& _x_plus_delta) const -{ - assert(_x.size() >= x_size_ && "Wrong _x vector size"); //we need a state vector which size is at least x_size_ +void ProcessorOdom3d::statePlusDelta(const VectorComposite& _x, + const Eigen::VectorXd& _delta, + const double _Dt, + VectorComposite& _x_plus_delta) const +{ assert(_delta.size() == delta_size_ && "Wrong _delta vector size"); - assert(_x_plus_delta.size() >= x_size_ && "Wrong _x_plus_delta vector size"); - - Eigen::Map<const Eigen::Vector3d> p (_x.data() ); - Eigen::Map<const Eigen::Quaterniond> q (_x.data() + 3 ); - Eigen::Map<const Eigen::Vector3d> dp (_delta.data() ); - Eigen::Map<const Eigen::Quaterniond> dq (_delta.data() + 3 ); - Eigen::Map<Eigen::Vector3d> p_out (_x_plus_delta.data() ); - Eigen::Map<Eigen::Quaterniond> q_out (_x_plus_delta.data() + 3 ); + Eigen::Map<const Eigen::Vector3d> p (_x.at("P").data() ); + Eigen::Map<const Eigen::Quaterniond> q (_x.at("O").data() ); + Eigen::Map<const Eigen::Vector3d> dp (_delta.data() ); + Eigen::Map<const Eigen::Quaterniond> dq (_delta.data() + 3 ); - p_out = p + q * dp; - q_out = q * dq; + _x_plus_delta["P"] = p + q * dp; + _x_plus_delta["O"] = (q * dq).coeffs(); } bool ProcessorOdom3d::voteForKeyFrame() const { - //WOLF_DEBUG( "Time span : " , getBuffer().get().back().ts_ - getBuffer().get().front().ts_ ); - //WOLF_DEBUG( " last ts : ", getBuffer().get().back().ts_); - //WOLF_DEBUG( " first ts : ", getBuffer().get().front().ts_); - //WOLF_DEBUG( "BufferLength: " , getBuffer().get().size() ); + //WOLF_DEBUG( "Time span : " , getBuffer().back().ts_ - getBuffer().front().ts_ ); + //WOLF_DEBUG( " last ts : ", getBuffer().back().ts_); + //WOLF_DEBUG( " first ts : ", getBuffer().front().ts_); + //WOLF_DEBUG( "BufferLength: " , getBuffer().size() ); //WOLF_DEBUG( "DistTraveled: " , delta_integrated_.head(3).norm() ); //WOLF_DEBUG( "AngleTurned : " , 2.0 * acos(delta_integrated_(6)) ); // time span - if (getBuffer().get().back().ts_ - getBuffer().get().front().ts_ > params_odom_3d_->max_time_span) + if (getBuffer().back().ts_ - getBuffer().front().ts_ > params_odom_3d_->max_time_span) { WOLF_DEBUG( "PM: vote: time span" ); return true; } // buffer length - if (getBuffer().get().size() > params_odom_3d_->max_buff_length) + if (getBuffer().size() > params_odom_3d_->max_buff_length) { WOLF_DEBUG( "PM: vote: buffer size" ); return true; @@ -218,7 +206,7 @@ CaptureMotionPtr ProcessorOdom3d::emplaceCapture(const FrameBasePtr& _frame_own, const CaptureBasePtr& _capture_origin) { auto cap_motion = CaptureBase::emplace<CaptureOdom3d>(_frame_own, _ts, _sensor, _data, _data_cov, _capture_origin); - cap_motion->setCalibration(_calib); + setCalibration(cap_motion, _calib); cap_motion->setCalibrationPreint(_calib_preint); return cap_motion; @@ -228,11 +216,19 @@ FeatureBasePtr ProcessorOdom3d::emplaceFeature(CaptureMotionPtr _capture_motion) { FeatureBasePtr key_feature_ptr = FeatureBase::emplace<FeatureBase>(_capture_motion, "ProcessorOdom3d", - _capture_motion->getBuffer().get().back().delta_integr_, - _capture_motion->getBuffer().get().back().delta_integr_cov_); + _capture_motion->getBuffer().back().delta_integr_, + _capture_motion->getBuffer().back().delta_integr_cov_); return key_feature_ptr; } +Eigen::VectorXd ProcessorOdom3d::correctDelta (const Eigen::VectorXd& delta_preint, + const Eigen::VectorXd& delta_step) const +{ + VectorXd delta_corrected(7); + SE3::plus(delta_preint, delta_step, delta_corrected); + return delta_corrected; +} + FactorBasePtr ProcessorOdom3d::emplaceFactor(FeatureBasePtr _feature_motion, CaptureBasePtr _capture_origin) { auto fac_odom = FactorBase::emplace<FactorOdom3d>(_feature_motion, @@ -243,12 +239,21 @@ FactorBasePtr ProcessorOdom3d::emplaceFactor(FeatureBasePtr _feature_motion, Cap return fac_odom; } +VectorXd ProcessorOdom3d::getCalibration (const CaptureBasePtr _capture) const +{ + return VectorXd::Zero(0); +} +void ProcessorOdom3d::setCalibration (const CaptureBasePtr _capture, const VectorXd& _calibration) +{ } -// Register in the SensorFactory -#include "core/processor/processor_factory.h" +} // namespace wolf + +// Register in the FactorySensor +#include "core/processor/factory_processor.h" namespace wolf { -WOLF_REGISTER_PROCESSOR("ProcessorOdom3d", ProcessorOdom3d); -WOLF_REGISTER_PROCESSOR_AUTO("ProcessorOdom3d", ProcessorOdom3d); +WOLF_REGISTER_PROCESSOR(ProcessorOdom3d); +WOLF_REGISTER_PROCESSOR_AUTO(ProcessorOdom3d); } // namespace wolf + diff --git a/src/processor/processor_tracker.cpp b/src/processor/processor_tracker.cpp index 56d5ae4ae45ed40962274292328076087da7fb9f..7b5d5dec09eadb5aa13b84d9340c760adba3f7c4 100644 --- a/src/processor/processor_tracker.cpp +++ b/src/processor/processor_tracker.cpp @@ -15,14 +15,16 @@ namespace wolf { ProcessorTracker::ProcessorTracker(const std::string& _type, + const StateStructure& _structure, int _dim, - ProcessorParamsTrackerPtr _params_tracker) : + ParamsProcessorTrackerPtr _params_tracker) : ProcessorBase(_type, _dim, _params_tracker), params_tracker_(_params_tracker), processing_step_(FIRST_TIME_WITHOUT_PACK), origin_ptr_(nullptr), last_ptr_(nullptr), - incoming_ptr_(nullptr) + incoming_ptr_(nullptr), + state_structure_(_structure) { // } @@ -78,7 +80,10 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) { WOLF_DEBUG( "PT ", getName(), " FIRST_TIME_WITHOUT_PACK" ); - FrameBasePtr kfrm = getProblem()->emplaceFrame(KEY, incoming_ptr_->getTimeStamp()); + FrameBasePtr kfrm = getProblem()->emplaceFrame(KEY, + incoming_ptr_->getTimeStamp(), + getStateStructure(), + getProblem()->getState(getStateStructure())); incoming_ptr_->link(kfrm); // Process info @@ -102,12 +107,14 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) // No-break case only for debug. Next case will be executed too. PackKeyFramePtr pack = buffer_pack_kf_.selectPack( incoming_ptr_, params_tracker_->time_tolerance); WOLF_DEBUG( "PT ", getName(), " SECOND_TIME_WITH_PACK: KF" , pack->key_frame->id() , " callback unpacked with ts= " , pack->key_frame->getTimeStamp() ); - } // @suppress("No break at end of case") + } + // Fall through case SECOND_TIME_WITHOUT_PACK : { WOLF_DEBUG( "PT ", getName(), " SECOND_TIME_WITHOUT_PACK" ); - FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, incoming_ptr_->getTimeStamp()); + FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, + incoming_ptr_->getTimeStamp()); incoming_ptr_->link(frm); // We have a last_ Capture with no features, so we do not process known features, and we do not vote for KF. @@ -142,7 +149,8 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) last_old_frame->remove(); // Create new frame - FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, incoming_ptr_->getTimeStamp()); + FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, + incoming_ptr_->getTimeStamp()); incoming_ptr_->link(frm); // Detect new Features, initialize Landmarks, create Factors, ... @@ -170,7 +178,7 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) // process processNew(params_tracker_->max_new_features); - //TODO abort KF if last_ptr_->getFeatureList().size() < params_tracker_->min_features_for_keyframe + //TODO abort KF if known_features_last_.size() < params_tracker_->min_features_for_keyframe // We create a KF // set KF on last @@ -191,7 +199,9 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) resetDerived(); // make F; append incoming to new F - FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, last_ptr_->getFrame()->getState(), incoming_ptr_->getTimeStamp()); + FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, + incoming_ptr_->getTimeStamp(), + last_ptr_->getFrame()->getStateVector()); incoming_ptr_->link(frm); origin_ptr_ = last_ptr_; @@ -238,7 +248,9 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) advanceDerived(); // Replace last frame for a new one in incoming - FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, last_ptr_->getFrame()->getState(), incoming_ptr_->getTimeStamp()); + FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, + incoming_ptr_->getTimeStamp(), + last_ptr_->getFrame()->getStateVector()); incoming_ptr_->link(frm); last_ptr_->getFrame()->remove(); // implicitly calling last_ptr_->remove(); @@ -297,7 +309,6 @@ void ProcessorTracker::computeProcessingStep() WOLF_INFO("Pack's KF and last's KF have matching time stamps (i.e. below time tolerances)"); WOLF_INFO("Check the following for correctness:"); WOLF_INFO(" - You have all processors installed before starting receiving any data"); - WOLF_INFO(" - You issued a problem->setPrior() after all processors are installed ---> ", (getProblem()->priorIsSet() ? "OK" : "NOK")); WOLF_INFO(" - You have configured all your processors with compatible time tolerances"); WOLF_ERROR("Pack's KF and last's KF have matching time stamps (i.e. below time tolerances)."); } @@ -322,5 +333,17 @@ bool ProcessorTracker::storeCapture(CaptureBasePtr _cap_ptr) return false; } +void ProcessorTracker::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "PrcT" << id() << " " << getType() << " \"" << getName() << "\"" << std::endl; + if (getOrigin()) + _stream << _tabs << " " << "o: Cap" << getOrigin()->id() << " - " << (getOrigin()->getFrame()->isKeyOrAux() ? (getOrigin()->getFrame()->isKey() ? " KFrm" : " AFrm") : " Frm") + << getOrigin()->getFrame()->id() << std::endl; + if (getLast()) + _stream << _tabs << " " << "l: Cap" << getLast()->id() << " - " << (getLast()->getFrame()->isKeyOrAux() ? (getLast()->getFrame()->isKey() ? " KFrm" : " AFrm") : " Frm") + << getLast()->getFrame()->id() << std::endl; + if (getIncoming()) + _stream << _tabs << " " << "i: Cap" << getIncoming()->id() << std::endl; +} } // namespace wolf diff --git a/src/processor/processor_tracker_feature.cpp b/src/processor/processor_tracker_feature.cpp index 211a1aba12b12ecfb10afea00041cf82e07493be..3804962f62fcbfba13b56e7c64866be7497eeaa8 100644 --- a/src/processor/processor_tracker_feature.cpp +++ b/src/processor/processor_tracker_feature.cpp @@ -11,9 +11,10 @@ namespace wolf { ProcessorTrackerFeature::ProcessorTrackerFeature(const std::string& _type, + const StateStructure& _structure, int _dim, - ProcessorParamsTrackerFeaturePtr _params_tracker_feature) : - ProcessorTracker(_type, _dim, _params_tracker_feature), + ParamsProcessorTrackerFeaturePtr _params_tracker_feature) : + ProcessorTracker(_type, _structure, _dim, _params_tracker_feature), params_tracker_feature_(_params_tracker_feature) { } @@ -47,7 +48,10 @@ unsigned int ProcessorTrackerFeature::processNew(const int& _max_new_features) // fill the track matrix for (auto ftr : new_features_last_) + { + assert(std::find(known_features_last_.begin(), known_features_last_.end(), ftr) == known_features_last_.end() && "detectNewFeatures() provided a new feature that is already in known_features_last_`"); track_matrix_.newTrack(ftr); + } // Track new features from last to incoming. This will append new correspondences to matches_last_incoming trackFeatures(new_features_last_, @@ -72,21 +76,27 @@ unsigned int ProcessorTrackerFeature::processNew(const int& _max_new_features) unsigned int ProcessorTrackerFeature::processKnown() { - assert(incoming_ptr_->getFeatureList().size() == 0 - && "In ProcessorTrackerFeature::processKnown(): incoming_ptr_ feature list must be empty before processKnown()"); + //assert(incoming_ptr_->getFeatureList().size() == 0 + // && "In ProcessorTrackerFeature::processKnown(): incoming_ptr_ feature list must be empty before processKnown()"); // clear list of known features matches_last_from_incoming_.clear(); known_features_incoming_.clear(); - if (!last_ptr_ || last_ptr_->getFeatureList().empty()) + if (!last_ptr_) + { + WOLF_TRACE("null last, returning..."); + return 0; + } + + if (known_features_last_.empty()) { WOLF_TRACE("Empty last feature list, returning..."); return 0; } // Track features from last_ptr_ to incoming_ptr_ - trackFeatures(last_ptr_->getFeatureList(), + trackFeatures(known_features_last_, incoming_ptr_, known_features_incoming_, matches_last_from_incoming_); @@ -132,6 +142,9 @@ void ProcessorTrackerFeature::advanceDerived() { // Reset here the list of correspondences. matches_last_from_incoming_.clear(); + known_features_last_ = std::move(known_features_incoming_); + //new_features_incoming should be zero! + //known_features_last_.splice(new_features_incoming_); // // remove last from track matrix in case you want to have only KF in the track matrix // track_matrix_.remove(last_ptr_); @@ -141,6 +154,8 @@ void ProcessorTrackerFeature::resetDerived() { // Reset here the list of correspondences. matches_last_from_incoming_.clear(); + known_features_last_ = std::move(known_features_incoming_); + known_features_last_.splice(known_features_last_.end(), new_features_incoming_); // Debug //for (auto const & pair_trkid_pair : track_matrix_.matches(origin_ptr_, last_ptr_)) diff --git a/src/processor/processor_tracker_landmark.cpp b/src/processor/processor_tracker_landmark.cpp index 7035dd38de2fcfb177deef2f4ed30d28fcdd92cf..ec16f76dc095de7cf01ebf45400d0eacd7733516 100644 --- a/src/processor/processor_tracker_landmark.cpp +++ b/src/processor/processor_tracker_landmark.cpp @@ -14,8 +14,12 @@ namespace wolf { ProcessorTrackerLandmark::ProcessorTrackerLandmark(const std::string& _type, - ProcessorParamsTrackerLandmarkPtr _params_tracker_landmark) : - ProcessorTracker(_type, 0, _params_tracker_landmark), + const StateStructure& _structure, + ParamsProcessorTrackerLandmarkPtr _params_tracker_landmark) : + ProcessorTracker(_type, + _structure, + 0, + _params_tracker_landmark), params_tracker_landmark_(_params_tracker_landmark) { // @@ -30,6 +34,8 @@ void ProcessorTrackerLandmark::advanceDerived() { matches_landmark_from_last_ = std::move(matches_landmark_from_incoming_); new_features_last_ = std::move(new_features_incoming_); + known_features_last_ = std::move(known_features_incoming_); + known_features_last_.splice(known_features_last_.end(), new_features_incoming_); matches_landmark_from_incoming_.clear(); new_features_incoming_.clear(); @@ -40,6 +46,8 @@ void ProcessorTrackerLandmark::resetDerived() { matches_landmark_from_last_ = std::move(matches_landmark_from_incoming_); new_features_last_ = std::move(new_features_incoming_); + known_features_last_ = std::move(known_features_incoming_); + known_features_last_.splice(known_features_last_.end(), new_features_incoming_); matches_landmark_from_incoming_.clear(); new_features_incoming_.clear(); @@ -129,15 +137,17 @@ void ProcessorTrackerLandmark::emplaceNewLandmarks() void ProcessorTrackerLandmark::establishFactors() { - // Loop all features in last_ptr_ - for (auto last_feature : last_ptr_->getFeatureList()) - { - assert(matches_landmark_from_last_.count(last_feature) == 1); + // Loop all features tracked in last_ptr_ (two lists known_features_last_ and new_features_last_) + std::list<FeatureBasePtrList> both_lists{known_features_last_, new_features_last_}; + for (auto feature_list : both_lists) + for (auto last_feature : feature_list) + { + assert(matches_landmark_from_last_.count(last_feature) == 1); - FactorBasePtr fac_ptr = emplaceFactor(last_feature, matches_landmark_from_last_[last_feature]->landmark_ptr_); + FactorBasePtr fac_ptr = emplaceFactor(last_feature, matches_landmark_from_last_[last_feature]->landmark_ptr_); - assert(fac_ptr->getFeature() != nullptr && "not linked factor returned by emplaceFactor()"); - } + assert(fac_ptr->getFeature() != nullptr && "not linked factor returned by emplaceFactor()"); + } } } // namespace wolf diff --git a/src/sensor/sensor_base.cpp b/src/sensor/sensor_base.cpp index 09afa700e79e66b058df609ea004334bd0830e4b..f8c3c76c7e5865d241846516ce9989226d9985cd 100644 --- a/src/sensor/sensor_base.cpp +++ b/src/sensor/sensor_base.cpp @@ -184,9 +184,9 @@ void SensorBase::addPriorParameter(const std::string& _key, const Eigen::VectorX // create & add factor absolute if (is_quaternion) - FactorBase::emplace<FactorQuaternionAbsolute>(ftr_prior, _sb); + FactorBase::emplace<FactorQuaternionAbsolute>(ftr_prior, ftr_prior, _sb, nullptr, false); else - FactorBase::emplace<FactorBlockAbsolute>(ftr_prior, _sb, _start_idx, _size); + FactorBase::emplace<FactorBlockAbsolute>(ftr_prior, ftr_prior, _sb, _start_idx, _size, nullptr, false); // store feature in params_prior_map_ params_prior_map_[_key] = ftr_prior; @@ -467,4 +467,111 @@ void SensorBase::link(HardwareBasePtr _hw_ptr) } } +void SensorBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "Sen" << id() << " " << getType() << " \"" << getName() << "\""; + if (_depth < 2) + _stream << " -- " << getProcessorList().size() << "p"; + _stream << std::endl; + + if (_metric && _state_blocks) + { + _stream << _tabs << " " << "sb: "; + for (auto& _key : getStructure()) + { + auto key = std::string(1,_key); + auto sb = getStateBlock(key); + _stream << key << "[" << (isStateBlockDynamic(key) ? "Dyn" : "Sta") << "," << (sb->isFixed() ? "Fix" : "Est") << "] = ( " << sb->getState().transpose() << " ); "; + } + _stream << std::endl; + } + else if (_metric) + { + _stream << _tabs << " " << "( "; + for (auto& _key : getStructure()) + { + auto key = std::string(1,_key); + auto sb = getStateBlock(key); + _stream << sb->getState().transpose() << " "; + } + _stream << ")" << std::endl; + } + else if (_state_blocks) + { + _stream << _tabs << " " << "sb: "; + for (auto& _key : getStructure()) + { + auto key = std::string(1,_key); + auto sb = getStateBlock(key); + _stream << key << "[" << (isStateBlockDynamic(key) ? "Dyn" : "Sta") << "," << (sb->isFixed() ? "Fix" : "Est") << "]; "; + } + _stream << std::endl; + } +} + +void SensorBase::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); + + if (_depth >= 2) + for (auto p : getProcessorList()) + p->print(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs + " "); +} + +CheckLog SensorBase::localCheck(bool _verbose, SensorBasePtr _sen_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + if (_verbose) + { + _stream << _tabs << "Sen" << id() << " @ " << _sen_ptr.get() << std::endl; + _stream << _tabs << " " << "-> Prb @ " << getProblem().get() << std::endl; + _stream << _tabs << " " << "-> Hrw @ " << getHardware().get() << std::endl; + for (auto pair: getStateBlockMap()) + { + auto sb = pair.second; + _stream << _tabs << " " << pair.first << " sb @ " << sb.get(); + if (sb) + { + auto lp = sb->getLocalParametrization(); + if (lp) + _stream << " (lp @ " << lp.get() << ")"; + } + _stream << std::endl; + } + } + + std::stringstream inconsistency_explanation; + auto hwd_ptr = getHardware(); + // check problem and hardware pointers + inconsistency_explanation << "Sensor problem pointer " << getProblem().get() + << " different from Hardware problem pointer " << hwd_ptr->getProblem().get() << "\n"; + log.assertTrue((getProblem() == hwd_ptr->getProblem()), inconsistency_explanation); + + inconsistency_explanation << "Sen" << id() << " @ " << _sen_ptr + << " ---> Hwd" << " @ " << hwd_ptr + << " -X-> Sen" << id(); + auto hwd_sen_list = hwd_ptr->getSensorList(); + auto hwd_has_sen = std::find_if(hwd_sen_list.begin(), hwd_sen_list.end(), [&_sen_ptr](SensorBasePtr sen){ return sen == _sen_ptr;}); + log.assertTrue(hwd_has_sen != hwd_sen_list.end(), inconsistency_explanation); + + for(auto prc : getProcessorList()) + { + inconsistency_explanation << "Sen" << id() << " @ " << _sen_ptr + << " ---> Prc" << prc->id() << " @ " << prc + << " -X-> Sen" << id(); + log.assertTrue((prc->getSensor() == _sen_ptr), inconsistency_explanation); + } + return log; +} + +bool SensorBase::check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto sen_ptr = std::static_pointer_cast<SensorBase>(_node_ptr); + auto local_log = localCheck(_verbose, sen_ptr, _stream, _tabs); + _log.compose(local_log); + + for (auto p : getProcessorList()) p->check(_log, p, _verbose, _stream, _tabs + " "); + return _log.is_consistent_; +} + } // namespace wolf diff --git a/src/sensor/sensor_diff_drive.cpp b/src/sensor/sensor_diff_drive.cpp index ae48fcceb261da67fa2b940aa06248b3d5006e48..afdc43e02a8085feb99c4ae0ac1a9a4cdefe2162 100644 --- a/src/sensor/sensor_diff_drive.cpp +++ b/src/sensor/sensor_diff_drive.cpp @@ -22,7 +22,7 @@ SensorDiffDrive::SensorDiffDrive(const Eigen::VectorXd& _extrinsics, radians_per_tick = 2.0*M_PI / params_diff_drive_->ticks_per_wheel_revolution; getIntrinsic()->setState(Eigen::Vector3d(_intrinsics->radius_left,_intrinsics->radius_right,_intrinsics->wheel_separation)); unfixIntrinsics(); - std::cout << "Prior cov diag " << params_diff_drive_->prior_cov_diag.transpose() << std::endl; + if(params_diff_drive_->set_intrinsics_prior) addPriorIntrinsics(getIntrinsic()->getState(), params_diff_drive_->prior_cov_diag.asDiagonal()); @@ -31,26 +31,22 @@ SensorDiffDrive::SensorDiffDrive(const Eigen::VectorXd& _extrinsics, double sigma_rev = 2*radians_per_tick; Eigen::Vector2d noise_sigma; noise_sigma << sigma_rev, sigma_rev; -// // 2. unmeasured lateral wheel slippage: sigma = 1mm -// double sigma_slippage = 0.001; -// Eigen::Vector3d noise_sigma; noise_sigma << sigma_rev, sigma_rev, sigma_slippage; - setNoiseStd(noise_sigma); } SensorDiffDrive::~SensorDiffDrive() { - // TODO Auto-generated destructor stub + // Auto-generated destructor stub } } /* namespace wolf */ -// Register in the SensorFactory -#include "core/sensor/sensor_factory.h" +// Register in the FactorySensor +#include "core/sensor/factory_sensor.h" namespace wolf { -WOLF_REGISTER_SENSOR("SensorDiffDrive", SensorDiffDrive); -WOLF_REGISTER_SENSOR_AUTO("SensorDiffDrive", SensorDiffDrive); +WOLF_REGISTER_SENSOR(SensorDiffDrive); +WOLF_REGISTER_SENSOR_AUTO(SensorDiffDrive); } // namespace wolf diff --git a/src/sensor/sensor_odom_2d.cpp b/src/sensor/sensor_odom_2d.cpp index 57af930f6724980d49209aaf1ece6b6762556adc..ec7a3b54d3f8163f44276bf8120cb482a3a2fdd7 100644 --- a/src/sensor/sensor_odom_2d.cpp +++ b/src/sensor/sensor_odom_2d.cpp @@ -36,9 +36,9 @@ double SensorOdom2d::getRotVarToRotNoiseFactor() const } -// Register in the SensorFactory -#include "core/sensor/sensor_factory.h" +// Register in the FactorySensor +#include "core/sensor/factory_sensor.h" namespace wolf { -WOLF_REGISTER_SENSOR("SensorOdom2d", SensorOdom2d); -WOLF_REGISTER_SENSOR_AUTO("SensorOdom2d", SensorOdom2d); +WOLF_REGISTER_SENSOR(SensorOdom2d); +WOLF_REGISTER_SENSOR_AUTO(SensorOdom2d); } // namespace wolf diff --git a/src/sensor/sensor_odom_3d.cpp b/src/sensor/sensor_odom_3d.cpp index a79995b85e11a3c248be1f19d4c69514cd6483d8..58b9b62ee9e111ce84887ba16e728a3494e40b7a 100644 --- a/src/sensor/sensor_odom_3d.cpp +++ b/src/sensor/sensor_odom_3d.cpp @@ -39,9 +39,9 @@ SensorOdom3d::~SensorOdom3d() } // namespace wolf -// Register in the SensorFactory -#include "core/sensor/sensor_factory.h" +// Register in the FactorySensor +#include "core/sensor/factory_sensor.h" namespace wolf { -WOLF_REGISTER_SENSOR("SensorOdom3d", SensorOdom3d); -WOLF_REGISTER_SENSOR_AUTO("SensorOdom3d", SensorOdom3d); +WOLF_REGISTER_SENSOR(SensorOdom3d); +WOLF_REGISTER_SENSOR_AUTO(SensorOdom3d); } diff --git a/src/solver/solver_manager.cpp b/src/solver/solver_manager.cpp index 6532dfc6a2b95d43451e00f8fad4797e7c53edf9..24a674f5f517e7bbd5ac8448c8678a7517632b90 100644 --- a/src/solver/solver_manager.cpp +++ b/src/solver/solver_manager.cpp @@ -11,11 +11,20 @@ SolverManager::SolverManager(const ProblemPtr& _wolf_problem) : assert(_wolf_problem != nullptr && "Passed a nullptr ProblemPtr."); } +SolverManager::~SolverManager() +{ +} + void SolverManager::update() { // Consume notification maps - auto fac_notification_map = wolf_problem_->consumeFactorNotificationMap(); - auto sb_notification_map = wolf_problem_->consumeStateBlockNotificationMap(); + std::map<StateBlockPtr,Notification> sb_notification_map; + std::map<FactorBasePtr,Notification> fac_notification_map; + wolf_problem_->consumeNotifications(sb_notification_map, fac_notification_map); + + #ifdef _WOLF_DEBUG + assert(check("before update()")); + #endif // REMOVE FACTORS for (auto fac_notification_it = fac_notification_map.begin(); @@ -34,39 +43,15 @@ void SolverManager::update() // ADD/REMOVE STATE BLOCS while ( !sb_notification_map.empty() ) { - StateBlockPtr state_ptr = sb_notification_map.begin()->first; - + // add if (sb_notification_map.begin()->second == ADD) - { - // only add if not added - if (state_blocks_.find(state_ptr) == state_blocks_.end()) - { - state_blocks_.emplace(state_ptr, state_ptr->getState()); - addStateBlock(state_ptr); - // A state_block is added with its last state_ptr, status and local_param, thus, no update is needed for any of those things -> reset flags - state_ptr->resetStateUpdated(); - state_ptr->resetFixUpdated(); - state_ptr->resetLocalParamUpdated(); - } - else - { - WOLF_DEBUG("Tried to add a StateBlock that was already added !"); - } - } + addStateBlock(sb_notification_map.begin()->first); + + // remove else - { - // only remove if it exists - if (state_blocks_.find(state_ptr)!=state_blocks_.end()) - { - removeStateBlock(state_ptr); - state_blocks_.erase(state_ptr); - } - else - { - WOLF_DEBUG("Tried to remove a StateBlock that was not added !"); - } - } - // next notification + removeStateBlock(sb_notification_map.begin()->first); + + // remove notification sb_notification_map.erase(sb_notification_map.begin()); } @@ -77,6 +62,7 @@ void SolverManager::update() // add factor addFactor(fac_notification_map.begin()->first); + // remove notification fac_notification_map.erase(fac_notification_map.begin()); } @@ -88,28 +74,20 @@ void SolverManager::update() // state update if (state_ptr->stateUpdated()) - { - Eigen::VectorXd new_state = state_ptr->getState(); - // We assume the same size for the states in both WOLF and the solver. - std::copy(new_state.data(),new_state.data()+new_state.size(),getAssociatedMemBlockPtr(state_ptr)); - // reset flag - state_ptr->resetStateUpdated(); - } + updateStateBlockState(state_ptr); + // fix update if (state_ptr->fixUpdated()) - { updateStateBlockStatus(state_ptr); - // reset flag - state_ptr->resetFixUpdated(); - } + // local parameterization update if (state_ptr->localParamUpdated()) - { updateStateBlockLocalParametrization(state_ptr); - // reset flag - state_ptr->resetLocalParamUpdated(); - } } + + #ifdef _WOLF_DEBUG + assert(check("after update()")); + #endif } wolf::ProblemPtr SolverManager::getProblem() @@ -122,24 +100,179 @@ std::string SolverManager::solve(const ReportVerbosity report_level) // update problem update(); - std::string report = solveImpl(report_level); + std::string report = solveDerived(report_level); // update StateBlocks with optimized state value. /// @todo whatif someone has changed the state notification during opti ?? /// JV: I do not see a problem here, the solver provides the optimal state given the factors, if someone changed the state during optimization, it will be overwritten by the optimal one. - std::map<StateBlockPtr, Eigen::VectorXd>::iterator it = state_blocks_.begin(), - it_end = state_blocks_.end(); - for (; it != it_end; ++it) + //std::map<StateBlockPtr, Eigen::VectorXd>::iterator it = state_blocks_.begin(), + // it_end = state_blocks_.end(); + for (auto& stateblock_statevector : state_blocks_) { // Avoid usuless copies - if (!it->first->isFixed()) - it->first->setState(it->second, false); // false = do not raise the flag state_updated_ + if (!stateblock_statevector.first->isFixed()) + stateblock_statevector.first->setState(stateblock_statevector.second, false); // false = do not raise the flag state_updated_ } return report; } +void SolverManager::addFactor(const FactorBasePtr& fac_ptr) +{ + // Warning if adding an already added + if (factors_.count(fac_ptr) != 0) + { + WOLF_WARN("Tried to add a factor that was already added !"); + return; + } + + /* HANDLING 'TRUNCATED' NOTIFICATION + * This happens in multi-threading if update() is called while emplacing/removing nodes + * + * ADD factor without ADD state block constrained by the factor + * + * Notification is put back on problem notifications, it will be added next update() call. + */ + for (const auto& st : fac_ptr->getStateBlockPtrVector()) + if (state_blocks_.count(st) == 0) + { + WOLF_WARN("SolverManager::addFactor(): Factor ", fac_ptr->id(), " is notified to ADD but the involved state block ", st, " is not. Skipping, will be added later."); + // put back notification in problem (will be added next update() call) and do nothing + wolf_problem_->notifyFactor(fac_ptr, ADD); + return; + } + + // factors + factors_.insert(fac_ptr); + + // state-factor map + for (const auto& st : fac_ptr->getStateBlockPtrVector()) + { + assert(state_blocks_.count(st) != 0 && "SolverManager::addFactor before adding any involved state block"); + assert(state_blocks_2_factors_.count(st) != 0 && "SolverManager::addFactor before adding any involved state block"); + state_blocks_2_factors_.at(st).push_back(fac_ptr); + } + + // derived + addFactorDerived(fac_ptr); +} + +void SolverManager::removeFactor(const FactorBasePtr& fac_ptr) +{ + // Warning if removing a missing factor + if (factors_.count(fac_ptr) == 0) + { + WOLF_WARN("Tried to remove a factor that is missing !"); + return; + } + + // derived + removeFactorDerived(fac_ptr); + + // factors + factors_.erase(fac_ptr); + + // state-factor map + for (const auto& st : fac_ptr->getStateBlockPtrVector()) + { + assert(state_blocks_.count(st) != 0 && "SolverManager::removeFactor missing any involved state block"); + assert(state_blocks_2_factors_.count(st) != 0 && "SolverManager::removeFactor missing any involved state block"); + state_blocks_2_factors_.at(st).remove(fac_ptr); + } +} + +void SolverManager::addStateBlock(const StateBlockPtr& state_ptr) +{ + // Warning if adding an already added state block + if (state_blocks_.count(state_ptr) != 0) + { + WOLF_WARN("Tried to add a StateBlock that was already added !"); + return; + } + + assert(state_blocks_.count(state_ptr) == 0 && "SolverManager::addStateBlock state block already added"); + assert(state_blocks_2_factors_.count(state_ptr) == 0 && "SolverManager::addStateBlock state block already added"); + + // stateblock maps + state_blocks_.emplace(state_ptr, state_ptr->getState()); + state_blocks_2_factors_.emplace(state_ptr, FactorBasePtrList()); + + // derived + addStateBlockDerived(state_ptr); + + // A state_block is added with its last state_ptr, status and local_param, thus, no update is needed for any of those things -> reset flags + state_ptr->resetStateUpdated(); + state_ptr->resetFixUpdated(); + state_ptr->resetLocalParamUpdated(); +} + +void SolverManager::removeStateBlock(const StateBlockPtr& state_ptr) +{ + // Warning if removing a missing state block + if (state_blocks_.count(state_ptr) == 0) + { + WOLF_WARN("Tried to remove a StateBlock that was not added !"); + return; + } + + assert(state_blocks_.count(state_ptr) != 0 && "SolverManager::removeStateBlock missing state block"); + assert(state_blocks_2_factors_.count(state_ptr) != 0 && "SolverManager::removeStateBlock missing state block"); + + /* HANDLING 'TRUNCATED' NOTIFICATION + * This happens in multi-threading if update() is called while emplacing/removing nodes + * + * REMOVE state block without REMOVE factor that constrains it + * + * Notification is put back on problem notifications, it will be removed next update() call. + */ + if (!state_blocks_2_factors_.at(state_ptr).empty()) + { + WOLF_WARN("SolverManager::removeStateBlock(): StateBlock ", state_ptr, " is notified to REMOVE but ", state_blocks_2_factors_.at(state_ptr).size(), " involved factors still not removed. Skipping, will be removed later."); + // put back notification in problem (will be removed next update() call) and do nothing + for (auto fac : state_blocks_2_factors_.at(state_ptr)) + WOLF_INFO(fac->id()); + wolf_problem_->notifyStateBlock(state_ptr, REMOVE); + return; + } + + assert(state_blocks_2_factors_.at(state_ptr).empty() && "SolverManager::removeStateBlock removing state block before removing all factors involved"); + + // derived + removeStateBlockDerived(state_ptr); + + // stateblock maps + state_blocks_.erase(state_ptr); + state_blocks_2_factors_.erase(state_ptr); +} + +void SolverManager::updateStateBlockStatus(const StateBlockPtr& state_ptr) +{ + // derived + updateStateBlockStatusDerived(state_ptr); + + // reset flag + state_ptr->resetFixUpdated(); +} + +void SolverManager::updateStateBlockState(const StateBlockPtr& state_ptr) +{ + Eigen::VectorXd new_state = state_ptr->getState(); + // We assume the same size for the states in both WOLF and the solver. + std::copy(new_state.data(),new_state.data()+new_state.size(),getAssociatedMemBlockPtr(state_ptr)); + // reset flag + state_ptr->resetStateUpdated(); +} + +void SolverManager::updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr) +{ + // derived + updateStateBlockLocalParametrizationDerived(state_ptr); + + // reset flag + state_ptr->resetLocalParamUpdated(); +} + Eigen::VectorXd& SolverManager::getAssociatedMemBlock(const StateBlockPtr& state_ptr) { auto it = state_blocks_.find(state_ptr); @@ -150,6 +283,16 @@ Eigen::VectorXd& SolverManager::getAssociatedMemBlock(const StateBlockPtr& state return it->second; } +const double* SolverManager::getAssociatedMemBlockPtr(const StateBlockPtr& state_ptr) const +{ + auto it = state_blocks_.find(state_ptr); + + if (it == state_blocks_.end()) + throw std::runtime_error("Tried to retrieve the memory block of an unregistered StateBlock !"); + + return it->second.data(); +} + double* SolverManager::getAssociatedMemBlockPtr(const StateBlockPtr& state_ptr) { auto it = state_blocks_.find(state_ptr); @@ -162,7 +305,7 @@ double* SolverManager::getAssociatedMemBlockPtr(const StateBlockPtr& state_ptr) bool SolverManager::isStateBlockRegistered(const StateBlockPtr& state_ptr) { - return state_blocks_.find(state_ptr) != state_blocks_.end() && isStateBlockRegisteredDerived(state_ptr); + return state_blocks_.count(state_ptr) ==1 && isStateBlockRegisteredDerived(state_ptr); } bool SolverManager::isFactorRegistered(const FactorBasePtr& fac_ptr) const @@ -170,4 +313,59 @@ bool SolverManager::isFactorRegistered(const FactorBasePtr& fac_ptr) const return isFactorRegisteredDerived(fac_ptr); } + +bool SolverManager::check(std::string prefix) const +{ + bool ok = true; + + // state blocks + if (state_blocks_.size() != state_blocks_2_factors_.size()) + { + WOLF_ERROR("SolverManager::check: mismatching number of state blocks (state_blocks_, state_blocks_2_factors_) - in ", prefix); + ok = false; + } + auto sb_vec_it = state_blocks_.begin(); + auto sb_fac_it = state_blocks_2_factors_.begin(); + while (sb_vec_it != state_blocks_.end()) + { + // same state block in both maps + if (sb_vec_it->first != sb_fac_it->first) + { + WOLF_ERROR("SolverManager::check: mismatching state blocks ", sb_vec_it->first, " and ", sb_fac_it->first, " - in ", prefix); + ok = false; + } + + // factor involving state block in factors_ + for (auto fac : sb_fac_it->second) + { + if (factors_.count(fac) == 0) + { + WOLF_ERROR("SolverManager::check: factor ", fac->id(), " (involved in sb ", sb_fac_it->first, ") missing in factors_ map - in ", prefix); + ok = false; + } + } + sb_vec_it++; + sb_fac_it++; + } + + // factors + for (auto fac : factors_) + { + // involved sb stored + for (auto sb : fac->getStateBlockPtrVector()) + { + if (state_blocks_.count(sb) == 0) + { + WOLF_ERROR("SolverManager::check: state block ", sb, " inolved in factor ", fac->id(), " missing in state_blocks_ map - in ", prefix); + ok = false; + } + } + } + + // checkDerived + ok &= checkDerived(prefix); + + return ok; +} + } // namespace wolf diff --git a/src/state_block/local_parametrization_base.cpp b/src/state_block/local_parametrization_base.cpp index f46a93f9c488d0b899e94df156f3faff04a63554..aee3f704126bf4ba81e9658b3c337ded088c78a5 100644 --- a/src/state_block/local_parametrization_base.cpp +++ b/src/state_block/local_parametrization_base.cpp @@ -22,3 +22,14 @@ unsigned int LocalParametrizationBase::getGlobalSize() const } } // namespace wolf + +bool wolf::LocalParametrizationBase::plus(const Eigen::VectorXd &_x, + const Eigen::VectorXd &_delta, + Eigen::VectorXd &_x_plus_delta) const +{ + Eigen::Map<const Eigen::VectorXd> x(_x.data(), _x.size()); + Eigen::Map<const Eigen::VectorXd> delta(_delta.data(), _delta.size()); + Eigen::Map<Eigen::VectorXd> x_plus_delta(_x_plus_delta.data(), _x_plus_delta.size()); + + return plus(x, delta, x_plus_delta); +} diff --git a/src/state_block/state_block.cpp b/src/state_block/state_block.cpp index 783a56a5e8cb52fe0ae79e2ad14ca4b50976a48c..ea2c9a4cd4f32b4a1c49e1bfec6ad28efb397cbe 100644 --- a/src/state_block/state_block.cpp +++ b/src/state_block/state_block.cpp @@ -26,32 +26,52 @@ void StateBlock::setFixed(bool _fixed) fixed_.store(_fixed); } -//void StateBlock::addToProblem(ProblemPtr _problem_ptr) -//{ -// _problem_ptr->addStateBlock(shared_from_this()); -//} -// -//void StateBlock::removeFromProblem(ProblemPtr _problem_ptr) -//{ -// _problem_ptr->removeStateBlock(shared_from_this()); -//} - void StateBlock::perturb(double amplitude) { using namespace Eigen; VectorXd perturbation(VectorXd::Random(getLocalSize()) * amplitude); + this->plus(perturbation); +} + +void StateBlock::plus(const Eigen::VectorXd &_dv) +{ if (local_param_ptr_ == nullptr) - state_ += perturbation; + setState(getState() + _dv); else { - VectorXd state_perturbed(getSize()); - // Note: LocalParametrizationBase::plus() works with Eigen::Map only. Build all necessary maps: - Map<const VectorXd> state_map(state_.data(), getSize()); - Map<const VectorXd> perturbation_map(perturbation.data(), getLocalSize()); - Map<VectorXd> state_perturbed_map(state_perturbed.data(), getSize()); - local_param_ptr_->plus(state_map, perturbation_map, state_perturbed_map); - state_ = state_perturbed; + Eigen::VectorXd state(getSize()); + local_param_ptr_->plus(getState(), _dv, state); + setState(state); } } } + +#include "core/state_block/factory_state_block.h" +#include "core/state_block/state_quaternion.h" +#include "core/state_block/state_angle.h" +#include "core/state_block/state_homogeneous_3d.h" + +namespace wolf{ +WOLF_REGISTER_STATEBLOCK(StateBlock); +WOLF_REGISTER_STATEBLOCK(StateQuaternion); +WOLF_REGISTER_STATEBLOCK(StateAngle); +WOLF_REGISTER_STATEBLOCK(StateHomogeneous3d); +WOLF_REGISTER_STATEBLOCK_WITH_KEY(H, StateHomogeneous3d); + +StateBlockPtr create_orientation(const Eigen::VectorXd& _state, bool _fixed) +{ + if (_state.size() == 1) + return StateAngle::create(_state, _fixed); + if (_state.size() == 4) + return StateQuaternion::create(_state, _fixed); + + throw std::length_error("Wrong vector size for orientation. Must be 4 for a quaternion in 3D, or 1 for an angle in 2D."); + + return nullptr; +} + +//WOLF_REGISTER_STATEBLOCK_WITH_KEY(O, wolf::create_orientation); +namespace{ const bool __attribute__((used)) create_orientationRegisteredWithO = \ + FactoryStateBlock::get().registerCreator("O", wolf::create_orientation); } +} diff --git a/src/state_block/state_composite.cpp b/src/state_block/state_composite.cpp new file mode 100644 index 0000000000000000000000000000000000000000..612b8e53ec55d7e5b787a5aa0c49312d21dfe4a9 --- /dev/null +++ b/src/state_block/state_composite.cpp @@ -0,0 +1,1010 @@ + + + +#include "core/state_block/state_composite.h" +#include "core/state_block/state_block.h" + +namespace wolf{ + +////// VECTOR COMPOSITE ////////// + +VectorComposite::VectorComposite(const StateStructure& _structure, const std::list<int>& _sizes) +{ + auto size_it = _sizes.begin(); + for ( const auto& ckey : _structure) + { + const auto& key = string(1,ckey); + const auto& size = *size_it; + + this->emplace(key, VectorXd(size).setZero()); + + size_it ++; + } +} + +VectorComposite::VectorComposite(const VectorXd& _v, const StateStructure& _structure, const std::list<int>& _sizes) +{ + int index = 0; + auto size_it = _sizes.begin(); + for ( const auto& ckey : _structure) + { + const auto& key = string(1,ckey); + const auto& size = *size_it; + + (*this)[key] = _v.segment(index,size); + + index += size; + size_it ++; + } +} + +VectorComposite::VectorComposite (const StateStructure& _s) +{ + for (const auto& ckey : _s) + { + const auto& key = string(1,ckey); // ckey is char + this->emplace(key,VectorXd(0)); + } +} + +VectorComposite::VectorComposite (const StateStructure& _structure, const std::list<VectorXd>& _vectors) +{ + assert(_structure.size() == _vectors.size() && "Structure and vector list size mismatch"); + + auto vector_it = _vectors.begin(); + + for (const auto& ckey : _structure) + { + string key(1,ckey); + this->emplace(key, *vector_it); + vector_it++; + } +} + + +unsigned int VectorComposite::size(const StateStructure &_structure) const +{ + unsigned int size = 0; + for (const auto& ckey : _structure) + { + std::string key(1,ckey); // ckey is char + const VectorXd& v = this->at(key); + size += v.size(); + } + return size; +} + +Eigen::VectorXd VectorComposite::vector(const StateStructure &_structure) const +{ + // traverse once with unordered_map access + std::vector<const VectorXd*> vp; + unsigned int size = 0; + for (const auto& ckey : _structure) + { + std::string key(1,ckey); // ckey is char + vp.push_back(&(this->at(key))); + size += vp.back()->size(); + } + + Eigen::VectorXd x(size); + + // traverse once linearly + unsigned int index = 0; + for (const auto& blkp : vp) + { + x.segment(index, blkp->size()) = *blkp; + index += blkp->size(); + } + return x; +} + +std::ostream& operator <<(std::ostream &_os, const wolf::VectorComposite &_x) +{ + for (const auto &pair_key_vec : _x) + { + const auto &key = pair_key_vec.first; + const auto &vec = pair_key_vec.second; + _os << key << ": (" << vec.transpose() << "); "; + } + return _os; +} + +wolf::VectorComposite operator +(const wolf::VectorComposite &_x, const wolf::VectorComposite &_y) +{ + wolf::VectorComposite xpy; + for (const auto& pair_i_xi : _x) + { + const auto& i = pair_i_xi.first; + + xpy.emplace(i, _x.at(i) + _y.at(i)); + } + return xpy; +} + +wolf::VectorComposite operator -(const wolf::VectorComposite &_x, const wolf::VectorComposite &_y) +{ + wolf::VectorComposite xpy; + for (const auto& pair_i_xi : _x) + { + const auto& i = pair_i_xi.first; + + xpy.emplace(i, _x.at(i) - _y.at(i)); + } + return xpy; +} + +void VectorComposite::set (const VectorXd& _v, const StateStructure& _structure, const std::list<int>& _sizes) +{ + int index = 0; + auto size_it = _sizes.begin(); + for ( const auto& ckey : _structure) + { + const auto& key = string(1,ckey); // ckey is char + const auto& size = *size_it; + + (*this)[key] = _v.segment(index,size); + + index += size; + size_it ++; + } +} + +void VectorComposite::setZero() +{ + for (auto& pair_key_vec : *this) + pair_key_vec.second.setZero(); +} + +wolf::VectorComposite operator -(const wolf::VectorComposite &_x) +{ + wolf::VectorComposite m; + for (const auto& pair_i_xi : _x) + { + const auto& i = pair_i_xi.first; + m.emplace(i, - _x.at(i)); + } + return m; +} + +////// MATRIX COMPOSITE ////////// + +bool MatrixComposite::emplace(const std::string &_row, const std::string &_col, const Eigen::MatrixXd &_mat_blk) +{ + // check rows + if (size_rows_.count(_row) == 0) + size_rows_[_row] = _mat_blk.rows(); + else + assert(size_rows_.at(_row) == _mat_blk.rows() && "Provided matrix block has wrong number of rows!"); + + // check cols + if (size_cols_.count(_col) == 0) + size_cols_[_col] = _mat_blk.cols(); + else + assert(size_rows_.at(_row) == _mat_blk.rows() && "Provided matrix block has wrong number of rows!"); + + // now it's safe to use [] operator. the first one is a function-like call to [] -- just weird for this->[] + this->operator[](_row)[_col] = _mat_blk; + return true; +} + +bool MatrixComposite::at(const std::string &_row, const std::string &_col, Eigen::MatrixXd &_mat_blk) const +{ + const auto &row_it = this->find(_row); + if(row_it != this->end()) + return false; + + const auto &col_it = row_it->second.find(_col); + if(col_it != row_it->second.end()) + return false; + + _mat_blk = col_it->second; + + return true; +} + +Eigen::MatrixXd& MatrixComposite::at(const std::string &_row, const std::string &_col) +{ + const auto &row_it = this->find(_row); + assert(row_it != this->end() && "Requested matrix block does not exist in matrix composite."); + + const auto &col_it = row_it->second.find(_col); + assert(col_it != row_it->second.end() && "Requested matrix block does not exist in matrix composite."); + + return col_it->second; +} + +const Eigen::MatrixXd& MatrixComposite::at(const std::string &_row, const std::string &_col) const +{ + const auto &row_it = this->find(_row); + assert(row_it != this->end() && "Requested matrix block does not exist in matrix composite."); + + const auto &col_it = row_it->second.find(_col); + assert(col_it != row_it->second.end() && "Requested matrix block does not exist in matrix composite."); + + return col_it->second; +} + +wolf::MatrixComposite MatrixComposite::operator *(const MatrixComposite &_N) const +{ + MatrixComposite MN; + for (const auto &pair_i_Mi : (*this)) + { + const auto &i = pair_i_Mi.first; + const auto &Mi = pair_i_Mi.second; + + for (const auto &pair_k_Nk : _N) + { + const auto &k = pair_k_Nk.first; + const auto &Nk = pair_k_Nk.second; + + for (const auto &pair_j_Nkj : Nk) + { + const auto &j = pair_j_Nkj.first; + const auto &Nkj = pair_j_Nkj.second; + const auto &Mik = Mi.at(k); + + if (MN.count(i, j) == 0) + MN.emplace(i, j, Mik * Nkj); + else + MN.at(i, j) += Mik * Nkj; + } + } + } + return MN; +} + +wolf::MatrixComposite MatrixComposite::operator +(const MatrixComposite &_N) const +{ + MatrixComposite MpN; + for (const auto &pair_i_Mi : *this) + { + const auto &i = pair_i_Mi.first; + const auto &Mi = pair_i_Mi.second; + + for (const auto& pair_j_Mij : Mi) + { + const auto& j = pair_j_Mij.first; + const auto& Mij = pair_j_Mij.second; + const auto& Nij = _N.at(i,j); + + MpN.emplace(i, j, Mij + Nij); + } + } + return MpN; +} + +wolf::MatrixComposite MatrixComposite::operator -(const MatrixComposite &_N) const +{ + MatrixComposite MpN; + for (const auto &pair_i_Mi : *this) + { + const auto &i = pair_i_Mi.first; + const auto &Mi = pair_i_Mi.second; + + for (const auto& pair_j_Mij : Mi) + { + const auto& j = pair_j_Mij.first; + const auto& Mij = pair_j_Mij.second; + const auto& Nij = _N.at(i,j); + + MpN.emplace(i, j, Mij - Nij); + } + } + return MpN; +} + +MatrixComposite MatrixComposite::operator - (void) const +{ + MatrixComposite m; + + for (const auto& pair_rkey_row : *this) + { + m.unordered_map<string,unordered_map<string, MatrixXd>>::emplace(pair_rkey_row.first, unordered_map<string, MatrixXd>()); + for (const auto& pair_ckey_blk : pair_rkey_row.second) + { + m[pair_rkey_row.first].emplace(pair_ckey_blk.first, - pair_ckey_blk.second); + } + } + return m; +} + + +wolf::VectorComposite MatrixComposite::operator *(const VectorComposite &_x) const +{ + VectorComposite y; + for (const auto &pair_rkey_row : *this) + { + const auto &rkey = pair_rkey_row.first; + const auto &row = pair_rkey_row.second; + + for (const auto &pair_ckey_mat : row) + { + const auto &ckey = pair_ckey_mat.first; + const auto &J_r_c = pair_ckey_mat.second; + + const auto& it = y.find(rkey); + if (it != y.end()) + it->second += J_r_c * _x.at(ckey); + else + y.emplace(rkey, J_r_c * _x.at(ckey)); + } + } + return y; +} + +MatrixComposite MatrixComposite::propagate(const MatrixComposite& _Cov) +{ + + + // simplify names of operands + const auto& J = *this; + const auto& Q = _Cov; + + MatrixComposite S; // S = J * Q * J.tr + + + /* Covariance propagation + * + * 1. General formula for the output block S(i,j) + * + * S_ij = sum_n (J_in * sum_k(Q_nk * J_jk^T)) (A) + * + * which develops as + * + * S_ij = sum_n (J_in * QJt_nj) + * + * with: + * + * QJt_nj = sum_k (Q_nk * J_jk^T) (B) + * + * + * 2. Algorithm to accomplish the above: + * + * for i = 1 : S.rows = J.rows (1) // iterate for i and j + * { + * J_i = J[i] + * for j = i : S.cols = J.rows (2) // j starts at i: do not loop over the symmetrical blocks + * { + * S_ij = 0 (3) // start formula (A) for S_ij + * for n = 1 : Q.rows (4) + * { + * J_in = J[i][n] + * QJt_nj = 0 (5) // start formula (B) for QJt_nj + * for k = 1 : Q.cols (6) + * { + * J_jk = J[j][k] + * QJt_nj += Q_nk * J_jk^T (7) // sum on QJt_nj + * } + * S_ij += J_in * QJt_nj (8) // sum on S_ij + * } + * S[i][j] = S_ij // write block in output composite + * if (i != j) + * S[j][i] = S_ij^T (9) // write symmetrical block in output composite + * } + * } + */ + + // Iterate on the output matrix S first, row i, col j. + for (const auto& pair_i_Si : J) // (1) + { + const auto& i = pair_i_Si.first; + const auto& J_i = pair_i_Si.second; + + double i_size = J_i.begin()->second.rows(); + + for (const auto& pair_j_Sj : J) // (2) + { + const auto& j = pair_j_Sj.first; + const auto& J_j = pair_j_Sj.second; + + double j_size = J_j.begin()->second.rows(); + + MatrixXd S_ij(MatrixXd::Zero(i_size, j_size)); // (3) + + for (const auto& pair_n_Qn : Q) // (4) + { + const auto& n = pair_n_Qn.first; + const auto& Q_n = pair_n_Qn.second; + + double n_size = Q_n.begin()->second.rows(); + + const auto& J_in = J_i.at(n); + + MatrixXd QJt_nj(MatrixXd::Zero(n_size, j_size)); // (5) + + for (const auto& pair_k_Qnk : Q_n) // (6) + { + const auto& k = pair_k_Qnk.first; + const auto& Q_nk = pair_k_Qnk.second; + + const auto& J_jk = J_j.at(k); + + QJt_nj += Q_nk * J_jk.transpose(); // (7) + } + + S_ij += J_in * QJt_nj; // (8) + } + + S.emplace(i,j,S_ij); + if (j == i) + break; // avoid computing the symmetrical block! + else + S.emplace(j, i, S_ij.transpose()); // (9) + } + } + + return S; +} + +MatrixComposite MatrixComposite::operator * (double scalar_right) const +{ + MatrixComposite S(*this); + for (const auto& pair_rkey_row : *this) + { + const auto& rkey = pair_rkey_row.first; + for (const auto& pair_ckey_block : pair_rkey_row.second) + { + const auto ckey = pair_ckey_block.first; + S[rkey][ckey] *= scalar_right; + } + } + return S; +} + +MatrixComposite operator * (double scalar_left, const MatrixComposite& M) +{ + MatrixComposite S; + S = M * scalar_left; + return S; +} + +MatrixXd MatrixComposite::matrix(const StateStructure &_struct_rows, const StateStructure &_struct_cols) const +{ + + std::unordered_map < string, unsigned int> indices_rows; + std::unordered_map < string, unsigned int> indices_cols; + unsigned int rows, cols; + + sizeAndIndices(_struct_rows, _struct_cols, indices_rows, indices_cols, rows, cols); + + MatrixXd M ( MatrixXd::Zero(rows, cols) ); + + for (const auto& pair_row_rband : (*this)) + { + const auto& row = pair_row_rband.first; + const auto& rband = pair_row_rband.second; + for (const auto& pair_col_blk : rband) + { + const auto& col = pair_col_blk.first; + const auto& blk = pair_col_blk.second; + + const unsigned int & blk_rows = size_rows_.at(row); + const unsigned int & blk_cols = size_cols_.at(col); + + assert(blk.rows() == blk_rows && "MatrixComposite block size mismatch! Wrong number of rows."); + assert(blk.cols() == blk_cols && "MatrixComposite block size mismatch! Wrong number of cols."); + + M.block(indices_rows.at(row), indices_cols.at(col), blk_rows, blk_cols) = blk; + + } + } + + return M; +} + +unsigned int MatrixComposite::rows() const +{ + unsigned int rows = 0; + for (const auto& pair_row_size : this->size_rows_) + rows += pair_row_size.second; + return rows; +} + +unsigned int MatrixComposite::cols() const +{ + unsigned int cols = 0; + for (const auto& pair_col_size : this->size_rows_) + cols += pair_col_size.second; + return cols; +} + +void MatrixComposite::sizeAndIndices(const StateStructure &_struct_rows, + const StateStructure &_struct_cols, + std::unordered_map<string, unsigned int> &_indices_rows, + std::unordered_map<string, unsigned int> &_indices_cols, + unsigned int &_rows, + unsigned int &_cols) const +{ + _rows = 0; + _cols = 0; + for (const auto& crow : _struct_rows) + { + string row = string(1,crow); // crow is char + _indices_rows[row] = _rows; + _rows += size_rows_.at(row); + } + for (const auto& ccol : _struct_cols) + { + string col = string(1,ccol); // ccol is char + _indices_cols[col] = _cols; + _cols += size_cols_.at(col); + } +} + +MatrixComposite::MatrixComposite (const StateStructure& _row_structure, const StateStructure& _col_structure) +{ + for (const auto& rkey_char : _row_structure) + { + string rkey(1,rkey_char); // key was char + for (const auto& ckey_char : _col_structure) + { + string ckey(1,ckey_char); // key was char + + this->emplace(rkey, ckey, MatrixXd(0,0)); + } + } +} + +MatrixComposite::MatrixComposite (const StateStructure& _row_structure, + const std::list<int>& _row_sizes, + const StateStructure& _col_structure, + const std::list<int>& _col_sizes) +{ + assert (_row_structure.size() == _row_sizes.size() && "Row structure and sizes have different number of elements!"); + assert (_col_structure.size() == _col_sizes.size() && "Column structure and sizes have different number of elements!"); + + auto rsize_it = _row_sizes.begin(); + for (const auto& rkey_char : _row_structure) + { + string rkey(1,rkey_char); // key was char + + auto csize_it = _col_sizes.begin(); + for (const auto& ckey_char : _col_structure) + { + string ckey(1,ckey_char); // key was char + + this->emplace(rkey, ckey, MatrixXd(*rsize_it, *csize_it)); // caution: blocks non initialized. + + csize_it ++; + } + rsize_it++; + } +} + +MatrixComposite::MatrixComposite (const MatrixXd& _m, + const StateStructure& _row_structure, + const std::list<int>& _row_sizes, + const StateStructure& _col_structure, + const std::list<int>& _col_sizes) +{ + assert (_row_structure.size() == _row_sizes.size() && "Row structure and sizes have different number of elements!"); + assert (_col_structure.size() == _col_sizes.size() && "Column structure and sizes have different number of elements!"); + + SizeEigen rindex = 0, cindex; + auto rsize_it = _row_sizes.begin(); + for (const auto& rkey_char : _row_structure) + { + assert(_m.rows() >= rindex + *rsize_it && "Provided matrix has insufficient number of rows"); + + string rkey(1,rkey_char); // key was char + + cindex = 0; + auto csize_it = _col_sizes.begin(); + + for (const auto& ckey_char : _col_structure) + { + assert(_m.cols() >= cindex + *csize_it && "Provided matrix has insufficient number of columns"); + + string ckey(1,ckey_char); // key was char + + this->emplace(rkey, ckey, _m.block(rindex, cindex, *rsize_it, *csize_it)); + + cindex += *csize_it; + csize_it ++; + } + + assert(_m.cols() == cindex && "Provided matrix has too many columns"); + + rindex += *rsize_it; + rsize_it++; + } + + assert(_m.rows() == rindex && "Provided matrix has too many rows"); +} + +MatrixComposite MatrixComposite::zero (const StateStructure& _row_structure, const std::list<int>& _row_sizes, + const StateStructure& _col_structure, const std::list<int>& _col_sizes) +{ + MatrixComposite m; + + assert (_row_structure.size() == _row_sizes.size() && "Row structure and sizes have different number of elements!"); + assert (_col_structure.size() == _col_sizes.size() && "Column structure and sizes have different number of elements!"); + + auto rsize_it = _row_sizes.begin(); + for (const auto& rkey_char : _row_structure) + { + string rkey(1,rkey_char); // key was char + + auto csize_it = _col_sizes.begin(); + for (const auto& ckey_char : _col_structure) + { + string ckey(1,ckey_char); // key was char + + m.emplace(rkey, ckey, MatrixXd::Zero(*rsize_it, *csize_it)); + + csize_it ++; + } + rsize_it++; + } + return m; +} + +MatrixComposite MatrixComposite::identity (const StateStructure& _structure, const std::list<int>& _sizes) +{ + MatrixComposite m; + + assert (_structure.size() == _sizes.size() && "Structure and sizes have different number of elements!"); + + auto rsize_it = _sizes.begin(); + auto rkey_it = _structure.begin(); + + while (rkey_it != _structure.end()) + { + + const auto& rkey = string(1,*rkey_it); + const auto rsize = *rsize_it; + + m.emplace(rkey, rkey, MatrixXd::Identity(rsize,rsize)); // diagonal block + + auto csize_it = rsize_it; + auto ckey_it = rkey_it; + + csize_it ++; + ckey_it++; + + while (ckey_it != _structure.end()) + { + const auto& ckey = string(1,*ckey_it); + const auto& csize = *csize_it; + + m.emplace(rkey, ckey, MatrixXd::Zero(rsize, csize)); // above-diagonal block + m.emplace(ckey, rkey, MatrixXd::Zero(csize, rsize)); // symmetric block + + csize_it ++; + ckey_it++; + } + + rsize_it ++; + rkey_it++; + } + return m; +} + +bool MatrixComposite::check ( ) const +{ + bool size_ok = true; + + // first see matrix itself, check that sizes are OK + for (const auto& pair_rkey_row : *this) + { + const auto& rkey = pair_rkey_row.first; + const auto& row = pair_rkey_row.second; + for (const auto& pair_ckey_blk : row) + { + const auto& ckey = pair_ckey_blk.first; + const auto& blk = pair_ckey_blk.second; + + if (size_rows_.count(rkey) != 0) + { + if( size_rows_.at(rkey) != blk.rows()) + { + WOLF_ERROR("row size for row ", rkey, " has wrong size"); + size_ok = false; + } + } + else + { + WOLF_ERROR("row size for row ", rkey, " does not exist"); + size_ok = false; + } + if (size_cols_.count(ckey) != 0) + { + if( size_cols_.at(ckey) != blk.cols()) + { + WOLF_ERROR("col size for col ", rkey, " has wrong size"); + size_ok = false; + } + } + else + { + WOLF_ERROR("col size for col ", ckey, " does not exist"); + size_ok = false; + } + } + } + return size_ok; +} + +std::ostream& operator <<(std::ostream &_os, const MatrixComposite &_M) +{ + for (const auto &pair_rkey_row : _M) + { + const auto rkey = pair_rkey_row.first; + + for (const auto &pair_ckey_mat : pair_rkey_row.second) + { + const auto &ckey = pair_ckey_mat.first; + + _os << "\n[" << rkey << "," << ckey << "]: \n" << pair_ckey_mat.second; + } + } + return _os; +} + + + +////// STATE BLOCK COMPOSITE ////////// + +const StateBlockMap& StateBlockComposite::getStateBlockMap() const +{ + return state_block_map_; +} + +void StateBlockComposite::fix() +{ + for (auto pair_key_sbp : state_block_map_) + if (pair_key_sbp.second != nullptr) + pair_key_sbp.second->fix(); +} + +void StateBlockComposite::unfix() +{ + for (auto pair_key_sbp : state_block_map_) + if (pair_key_sbp.second != nullptr) + pair_key_sbp.second->unfix(); +} + +bool StateBlockComposite::isFixed() const +{ + bool fixed = true; + for (auto pair_key_sbp : state_block_map_) + { + if (pair_key_sbp.second) + fixed &= pair_key_sbp.second->isFixed(); + } + return fixed; +} + +unsigned int StateBlockComposite::remove(const std::string &_sb_type) +{ + return state_block_map_.erase(_sb_type); +} + +bool StateBlockComposite::has(const StateBlockPtr &_sb) const +{ + bool found = false; + for (const auto& pair_key_sb : state_block_map_) + { + found = found || (pair_key_sb.second == _sb); + } + return found; +} + +StateBlockPtr StateBlockComposite::at(const std::string &_sb_type) const +{ + auto it = state_block_map_.find(_sb_type); + if (it != state_block_map_.end()) + return it->second; + else + return nullptr; +} + +void StateBlockComposite::set(const std::string& _sb_type, const StateBlockPtr &_sb) +{ + auto it = state_block_map_.find(_sb_type); + assert ( it != state_block_map_.end() && "Cannot set an inexistent state block! Use addStateBlock instead."); + + it->second = _sb; +} + +void StateBlockComposite::set(const std::string& _key, const VectorXd &_vec) +{ + auto it = state_block_map_.find(_key); + assert ( it != state_block_map_.end() && "Cannot set an inexistent state block! Use addStateBlock instead."); + + assert ( it->second->getSize() == _vec.size() && "Provided vector size mismatch with associated state block"); + + it->second->setState(_vec); +} + +void StateBlockComposite::setVectors(const StateStructure& _structure, const std::list<VectorXd> &_vectors) +{ + assert(_structure.size() == _vectors.size() && "Sizes of structure and vector list do not match"); + + auto vec_it = _vectors.begin(); + for (const auto ckey : _structure) + { + string key(1,ckey); + set (key, *vec_it); + vec_it++; + } +} + +bool StateBlockComposite::key(const StateBlockPtr &_sb, std::string &_key) const +{ + const auto& it = this->find(_sb); + + bool found = (it != state_block_map_.end()); + + if (found) + { + _key = it->first; + return true; + } + else + { + _key = ""; + return false; + } +} + +std::string StateBlockComposite::key(const StateBlockPtr& _sb) const +{ + const auto& it = this->find(_sb); + + bool found = (it != state_block_map_.end()); + + if (found) + return it->first; + else + return ""; +} + + +StateBlockMapCIter StateBlockComposite::find(const StateBlockPtr &_sb) const +{ + const auto& it = std::find_if(state_block_map_.begin(), + state_block_map_.end(), + [_sb](const std::pair<std::string, StateBlockPtr>& pair) + { + return pair.second == _sb; + } + ); + + return it; +} + +StateBlockPtr StateBlockComposite::add(const std::string &_sb_type, const StateBlockPtr &_sb) +{ + assert(state_block_map_.count(_sb_type) == 0 && "Trying to add a state block with an existing type! Use setStateBlock instead."); + + state_block_map_.emplace(_sb_type, _sb); + + return _sb; +} + +void StateBlockComposite::perturb(double amplitude) +{ + for (const auto& pair_key_sb : state_block_map_) + { + auto& sb = pair_key_sb.second; + if (!sb->isFixed()) + sb->perturb(amplitude); + } +} + +void StateBlockComposite::plus(const VectorComposite &_dx) +{ + for (const auto& pair_key_sb : state_block_map_) + { + const auto& key = pair_key_sb.first; + const auto& sb = pair_key_sb.second; + const auto& dv = _dx.at(key); + + sb->plus(dv); + } +} + +VectorComposite StateBlockComposite::getState() const +{ + VectorComposite v; + getState(v); + return v; +} + +bool StateBlockComposite::getState(VectorComposite &_state) const +{ + for (auto &pair_key_sb : state_block_map_) + { + _state.emplace(pair_key_sb.first, pair_key_sb.second->getState()); + } + return true; +} + +void StateBlockComposite::setState(const VectorComposite &_state) +{ + for (const auto &pair_key_sb : _state) + { + state_block_map_[pair_key_sb.first]->setState(pair_key_sb.second); + } +} + +void StateBlockComposite::setIdentity(bool _notify) +{ + for (const auto& pair_key_sb : getStateBlockMap()) + { + pair_key_sb.second->setIdentity(_notify); + } +} + +void StateBlockComposite::setZero(bool _notify) +{ + setIdentity(_notify); +} + +VectorComposite StateBlockComposite::identity() const +{ + VectorComposite x; + for (const auto& pair_key_sb : getStateBlockMap()) + x.emplace(pair_key_sb.first, pair_key_sb.second->identity()); + return x; +} + +VectorComposite StateBlockComposite::zero() const +{ + return identity(); +} + + +SizeEigen StateBlockComposite::stateSize() const +{ + SizeEigen size = 0; + for (const auto& pair_key_sb : state_block_map_) + size += pair_key_sb.second->getSize(); + return size; +} + +SizeEigen StateBlockComposite::stateSize(const StateStructure &_structure) const +{ + SizeEigen size = 0; + for (const auto& ckey : _structure) + { + string key(1,ckey); + size += state_block_map_.at(key)->getSize(); + } + return size; +} + +VectorXd StateBlockComposite::stateVector(const StateStructure &_structure) const +{ + VectorXd x(stateSize(_structure)); + SizeEigen index = 0; + SizeEigen size; + for (const auto& ckey : _structure) + { + string key(1,ckey); + const auto& sb = state_block_map_.at(key); + size = sb->getSize(); + x.segment(index,size) = sb->getState(); + index += size; + } + return x; +} + +void StateBlockComposite::stateVector(const StateStructure &_structure, VectorXd &_vector) const +{ + _vector.resize(stateSize(_structure)); + SizeEigen index = 0; + SizeEigen size; + for (const auto& ckey : _structure) + { + string key(1,ckey); + const auto& sb = state_block_map_.at(key); + size = sb->getSize(); + _vector.segment(index,size) = sb->getState(); + index += size; + } +} + +} // namespace wolf + diff --git a/src/trajectory/trajectory_base.cpp b/src/trajectory/trajectory_base.cpp index 428faf954d89ffc8f0d7a88b182cd04a92850c4a..ad760c8c3ccf2942f734c256e7b04ed3d59aecf7 100644 --- a/src/trajectory/trajectory_base.cpp +++ b/src/trajectory/trajectory_base.cpp @@ -3,9 +3,8 @@ namespace wolf { -TrajectoryBase::TrajectoryBase(const std::string& _frame_structure) : - NodeBase("TRAJECTORY", "Base"), - frame_structure_(_frame_structure), +TrajectoryBase::TrajectoryBase() : + NodeBase("TRAJECTORY", "TrajectoryBase"), last_key_frame_ptr_(nullptr), last_key_or_aux_frame_ptr_(nullptr) { @@ -136,4 +135,42 @@ FrameBasePtr TrajectoryBase::closestKeyOrAuxFrameToTimeStamp(const TimeStamp& _t return closest_kf; } +void TrajectoryBase::printHeader(int _depth, bool _metric, bool _state_blocks, bool _constr_by, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "Trajectory" << ((_depth < 1) ? (" -- " + std::to_string(getFrameList().size()) + "F") : "") << std::endl; +} +void TrajectoryBase::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); + if (_depth >= 1) + for (auto F : getFrameList()) + F->print(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs + " "); + +} + +CheckLog TrajectoryBase::localCheck(bool _verbose, TrajectoryBasePtr _trj_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + std::stringstream inconsistency_explanation; + + if (_verbose) + { + _stream << _tabs << "Trj @ " << _trj_ptr.get() << std::endl; + } + + // check pointer to Problem + inconsistency_explanation << "Trj->getProblem() [" << getProblem().get() + << "] -> " << " Prb->getTrajectory() [" << getProblem()->getTrajectory().get() << "] -> Trj [" << _trj_ptr.get() << "] Mismatch!\n"; + log.assertTrue((_trj_ptr->getProblem()->getTrajectory().get() == _trj_ptr.get()), inconsistency_explanation); + return log; +} +bool TrajectoryBase::check(CheckLog& _log, std::shared_ptr<NodeBase> _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto trj_ptr = std::static_pointer_cast<TrajectoryBase>(_node_ptr); + auto local_log = localCheck(_verbose, trj_ptr, _stream, _tabs); + _log.compose(local_log); + for (auto F : getFrameList()) + F->check(_log, F, _verbose, _stream, _tabs + " "); + return _log.is_consistent_; +} } // namespace wolf diff --git a/src/tree_manager/tree_manager_sliding_window.cpp b/src/tree_manager/tree_manager_sliding_window.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5816567557bdd2ca5779615834a3f48a418bbabe --- /dev/null +++ b/src/tree_manager/tree_manager_sliding_window.cpp @@ -0,0 +1,43 @@ +#include "core/tree_manager/tree_manager_sliding_window.h" + +namespace wolf +{ + +void TreeManagerSlidingWindow::keyFrameCallback(FrameBasePtr _key_frame) +{ + int n_kf(0); + FrameBasePtr first_KF(nullptr), second_KF(nullptr); + for (auto frm : getProblem()->getTrajectory()->getFrameList()) + { + if (frm->isKey()) + { + n_kf++; + if (first_KF == nullptr) + first_KF = frm; + else if (second_KF == nullptr) + second_KF = frm; + } + } + + // remove first KF if too many KF + if (n_kf > params_sw_->n_key_frames) + { + WOLF_DEBUG("TreeManagerSlidingWindow removing first frame"); + first_KF->remove(params_sw_->viral_remove_empty_parent); + if (params_sw_->fix_first_key_frame) + { + WOLF_DEBUG("TreeManagerSlidingWindow fixing new first frame"); + second_KF->fix(); + } + } +} + +} /* namespace wolf */ + +// Register in the FactoryTreeManager +#include "core/tree_manager/factory_tree_manager.h" +namespace wolf { +WOLF_REGISTER_TREE_MANAGER(TreeManagerSlidingWindow); +WOLF_REGISTER_TREE_MANAGER_AUTO(TreeManagerSlidingWindow); +} // namespace wolf + diff --git a/src/yaml/parser_yaml.cpp b/src/yaml/parser_yaml.cpp index 267d0c9da2024abd59ed5b529d13de7680d14472..2d1aa8200790d5d5484b7c24c1f8dc78304a3218 100644 --- a/src/yaml/parser_yaml.cpp +++ b/src/yaml/parser_yaml.cpp @@ -430,12 +430,12 @@ void ParserYAML::parseFirstLevel(std::string _file) { for (const auto& kv : n_config["ROS publisher"]) { - WOLF_DEBUG("WHAT"); PublisherManager pPublisherManager = { - kv["type"].Scalar(), kv["topic"].Scalar(), kv["period"].Scalar(), kv + kv["package"].Scalar(), kv["type"].Scalar(), kv["topic"].Scalar(), kv["period"].Scalar(), kv }; publisher_managers_.push_back(pPublisherManager); - map_container.push_back(std::map<std::string, std::string>({ { "type", kv["type"].Scalar() }, + map_container.push_back(std::map<std::string, std::string>({ { "package", kv["package"].Scalar() }, + { "type", kv["type"].Scalar() }, { "topic", kv["topic"].Scalar() }, { "period", kv["period"].Scalar() } })); } @@ -445,7 +445,7 @@ void ParserYAML::parseFirstLevel(std::string _file) catch (YAML::InvalidNode& e) { throw std::runtime_error("Error parsing publisher @" + generatePath(_file) + - ". Please make sure that each manager has 'type', 'topic' and 'period' entries."); + ". Please make sure that each manager has 'package', 'type', 'topic' and 'period' entries."); } } std::map<std::string, std::string> ParserYAML::getParams() @@ -475,19 +475,25 @@ void ParserYAML::parse() tags.push_back("processor"); walkTreeR(it.n_, tags, "processor/" + it.name_); } - std::list<std::string> plugins, packages; + std::list<std::string> plugins; + std::list<std::string> packages_subscriber, packages_publisher; for (const auto& it : paramsSens_) plugins.push_back(it.plugin_); for (const auto& it : paramsProc_) plugins.push_back(it.plugin_); for (const auto& it : subscriber_managers_) - packages.push_back(it.package_); + packages_subscriber.push_back(it.package_); + for (const auto& it : publisher_managers_) + packages_publisher.push_back(it.package_); plugins.sort(); plugins.unique(); - packages.sort(); - packages.unique(); + packages_subscriber.sort(); + packages_subscriber.unique(); + packages_publisher.sort(); + packages_publisher.unique(); insert_register("plugins", wolf::converter<std::string>::convert(plugins)); - insert_register("packages", wolf::converter<std::string>::convert(packages)); + insert_register("packages_subscriber", wolf::converter<std::string>::convert(packages_subscriber)); + insert_register("packages_publisher", wolf::converter<std::string>::convert(packages_publisher)); YAML::Node n; n = loadYAML(generatePath(file_)); diff --git a/src/yaml/processor_odom_3d_yaml.cpp b/src/yaml/processor_odom_3d_yaml.cpp index 1047ba5fd2482ab1f89c5a7256eb54b86f6181d6..0a0884454f126a46e169c5edc25d26b3bb04ef64 100644 --- a/src/yaml/processor_odom_3d_yaml.cpp +++ b/src/yaml/processor_odom_3d_yaml.cpp @@ -20,13 +20,13 @@ namespace wolf namespace { -static ProcessorParamsBasePtr createProcessorOdom3dParams(const std::string & _filename_dot_yaml) +static ParamsProcessorBasePtr createProcessorOdom3dParams(const std::string & _filename_dot_yaml) { YAML::Node config = YAML::LoadFile(_filename_dot_yaml); if (config["type"].as<std::string>() == "ProcessorOdom3d") { - ProcessorParamsOdom3dPtr params = std::make_shared<ProcessorParamsOdom3d>(); + ParamsProcessorOdom3dPtr params = std::make_shared<ParamsProcessorOdom3d>(); params->time_tolerance = config["time_tolerance"] .as<double>(); params->unmeasured_perturbation_std = config["unmeasured_perturbation_std"] .as<double>(); @@ -47,8 +47,8 @@ static ProcessorParamsBasePtr createProcessorOdom3dParams(const std::string & _f return nullptr; } -// Register in the SensorFactory -const bool WOLF_UNUSED registered_prc_odom_3d = ProcessorParamsFactory::get().registerCreator("ProcessorOdom3d", createProcessorOdom3dParams); +// Register in the FactorySensor +const bool WOLF_UNUSED registered_prc_odom_3d = FactoryParamsProcessor::get().registerCreator("ProcessorOdom3d", createProcessorOdom3dParams); } // namespace [unnamed] diff --git a/src/yaml/sensor_odom_2d_yaml.cpp b/src/yaml/sensor_odom_2d_yaml.cpp index d59cd4decfb77338a0b3bb4ba17c607e03f847c1..b8ef1a083111a877b5b283c13d751df88a5af20d 100644 --- a/src/yaml/sensor_odom_2d_yaml.cpp +++ b/src/yaml/sensor_odom_2d_yaml.cpp @@ -39,8 +39,8 @@ static ParamsSensorBasePtr createParamsSensorOdom2d(const std::string & _filenam return nullptr; } -// Register in the SensorFactory -const bool WOLF_UNUSED registered_odom_2d_intr = ParamsSensorFactory::get().registerCreator("SensorOdom2d", createParamsSensorOdom2d); +// Register in the FactorySensor +const bool WOLF_UNUSED registered_odom_2d_intr = FactoryParamsSensor::get().registerCreator("SensorOdom2d", createParamsSensorOdom2d); } // namespace [unnamed] diff --git a/src/yaml/sensor_odom_3d_yaml.cpp b/src/yaml/sensor_odom_3d_yaml.cpp index e437bedcbf00257068bfea07830caa9f8224e7c9..5b700eb8210b337d59f1186be90b869fe123874f 100644 --- a/src/yaml/sensor_odom_3d_yaml.cpp +++ b/src/yaml/sensor_odom_3d_yaml.cpp @@ -41,8 +41,8 @@ static ParamsSensorBasePtr createParamsSensorOdom3d(const std::string & _filenam return nullptr; } -// Register in the SensorFactory -const bool WOLF_UNUSED registered_odom_3d_intr = ParamsSensorFactory::get().registerCreator("SensorOdom3d", createParamsSensorOdom3d); +// Register in the FactorySensor +const bool WOLF_UNUSED registered_odom_3d_intr = FactoryParamsSensor::get().registerCreator("SensorOdom3d", createParamsSensorOdom3d); } // namespace [unnamed] diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index db82caf1fc34b83b2509fe7d4f3ac4d6cc9e8c82..05717bad197c33e241146a8cf4d08fc337d99ea2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,7 +35,8 @@ set(SRC_DUMMY dummy/processor_tracker_feature_dummy.cpp dummy/processor_tracker_landmark_dummy.cpp ) -add_library(dummy ${SRC_DUMMY}) +add_library(dummy SHARED ${SRC_DUMMY}) +target_link_libraries(dummy ${PROJECT_NAME}) ################# ADD YOUR TESTS BELOW #################### # # # ==== IN ALPHABETICAL ORDER! ==== # @@ -47,6 +48,10 @@ add_library(dummy ${SRC_DUMMY}) wolf_add_gtest(gtest_capture_base gtest_capture_base.cpp) target_link_libraries(gtest_capture_base ${PROJECT_NAME}) +# Converter from String to various types used by the parameters server +wolf_add_gtest(gtest_converter gtest_converter.cpp) +target_link_libraries(gtest_converter ${PROJECT_NAME}) + # FactorBase class test wolf_add_gtest(gtest_factor_base gtest_factor_base.cpp) target_link_libraries(gtest_factor_base ${PROJECT_NAME}) @@ -55,9 +60,9 @@ target_link_libraries(gtest_factor_base ${PROJECT_NAME}) wolf_add_gtest(gtest_factor_autodiff gtest_factor_autodiff.cpp) target_link_libraries(gtest_factor_autodiff ${PROJECT_NAME}) -# Converter from String to various types used by the parameters server -wolf_add_gtest(gtest_converter gtest_converter.cpp) -target_link_libraries(gtest_converter ${PROJECT_NAME}) +# FactoryStateBlock factory test +wolf_add_gtest(gtest_factory_state_block gtest_factory_state_block.cpp) +target_link_libraries(gtest_factory_state_block ${PROJECT_NAME}) # FeatureBase classes test wolf_add_gtest(gtest_eigen_predicates gtest_eigen_predicates.cpp) @@ -120,6 +125,7 @@ wolf_add_gtest(gtest_rotation gtest_rotation.cpp) # SE3 test wolf_add_gtest(gtest_SE3 gtest_SE3.cpp) +target_link_libraries(gtest_SE3 ${PROJECT_NAME}) # SensorBase test wolf_add_gtest(gtest_sensor_base gtest_sensor_base.cpp) @@ -137,6 +143,10 @@ target_link_libraries(gtest_solver_manager ${PROJECT_NAME}) wolf_add_gtest(gtest_state_block gtest_state_block.cpp) target_link_libraries(gtest_state_block ${PROJECT_NAME}) +# StateBlock class test +wolf_add_gtest(gtest_state_composite gtest_state_composite.cpp) +target_link_libraries(gtest_state_composite ${PROJECT_NAME}) + # TimeStamp class test wolf_add_gtest(gtest_time_stamp gtest_time_stamp.cpp) target_link_libraries(gtest_time_stamp ${PROJECT_NAME}) @@ -149,6 +159,10 @@ target_link_libraries(gtest_track_matrix ${PROJECT_NAME}) wolf_add_gtest(gtest_trajectory gtest_trajectory.cpp) target_link_libraries(gtest_trajectory ${PROJECT_NAME}) +# TreeManager class test +wolf_add_gtest(gtest_tree_manager gtest_tree_manager.cpp) +target_link_libraries(gtest_tree_manager ${PROJECT_NAME}) + # ------- Now Derived classes ---------- IF (Ceres_FOUND) @@ -173,6 +187,10 @@ target_link_libraries(gtest_factor_block_difference ${PROJECT_NAME}) wolf_add_gtest(gtest_factor_diff_drive gtest_factor_diff_drive.cpp) target_link_libraries(gtest_factor_diff_drive ${PROJECT_NAME}) +# FactorOdom2d class test +wolf_add_gtest(gtest_factor_odom_2d gtest_factor_odom_2d.cpp) +target_link_libraries(gtest_factor_odom_2d ${PROJECT_NAME}) + # FactorOdom3d class test wolf_add_gtest(gtest_factor_odom_3d gtest_factor_odom_3d.cpp) target_link_libraries(gtest_factor_odom_3d ${PROJECT_NAME}) @@ -185,6 +203,14 @@ target_link_libraries(gtest_factor_pose_2d ${PROJECT_NAME}) wolf_add_gtest(gtest_factor_pose_3d gtest_factor_pose_3d.cpp) target_link_libraries(gtest_factor_pose_3d ${PROJECT_NAME}) +# FactorRelativePose2dWithExtrinsics class test +wolf_add_gtest(gtest_factor_relative_pose_2d_with_extrinsics gtest_factor_relative_pose_2d_with_extrinsics.cpp) +target_link_libraries(gtest_factor_relative_pose_2d_with_extrinsics ${PROJECT_NAME}) + +# FactorRelative2dAnalytic class test +wolf_add_gtest(gtest_factor_relative_2d_analytic gtest_factor_relative_2d_analytic.cpp) +target_link_libraries(gtest_factor_relative_2d_analytic ${PROJECT_NAME}) + # MakePosDef function test wolf_add_gtest(gtest_make_posdef gtest_make_posdef.cpp) target_link_libraries(gtest_make_posdef ${PROJECT_NAME}) @@ -229,6 +255,10 @@ target_link_libraries(gtest_processor_tracker_landmark_dummy ${PROJECT_NAME} dum wolf_add_gtest(gtest_sensor_diff_drive gtest_sensor_diff_drive.cpp) target_link_libraries(gtest_sensor_diff_drive ${PROJECT_NAME}) +# TreeManagerSlidingWindow class test +wolf_add_gtest(gtest_tree_manager_sliding_window gtest_tree_manager_sliding_window.cpp) +target_link_libraries(gtest_tree_manager_sliding_window ${PROJECT_NAME}) + # yaml conversions wolf_add_gtest(gtest_yaml_conversions gtest_yaml_conversions.cpp) target_link_libraries(gtest_yaml_conversions ${PROJECT_NAME}) diff --git a/test/dummy/factor_dummy_zero_1.h b/test/dummy/factor_dummy_zero_1.h new file mode 100644 index 0000000000000000000000000000000000000000..1ebe1b8fe2e4eba79fe2c9fbf236da5844327189 --- /dev/null +++ b/test/dummy/factor_dummy_zero_1.h @@ -0,0 +1,49 @@ +#ifndef FACTOR_DUMMY_ZERO_1_H_ +#define FACTOR_DUMMY_ZERO_1_H_ + +//Wolf includes +#include "core/factor/factor_autodiff.h" + +//#include "ceres/jet.h" + +namespace wolf { + +WOLF_PTR_TYPEDEFS(FactorDummyZero1); + +//class +class FactorDummyZero1 : public FactorAutodiff<FactorDummyZero1, 1, 1> +{ + using Base = FactorAutodiff<FactorDummyZero1, 1, 1>; + public: + FactorDummyZero1(const FeatureBasePtr& _ftr_ptr, + const StateBlockPtr& _sb_ptr) : + Base("FactorDummy1", + _ftr_ptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, + false, + FAC_ACTIVE, + _sb_ptr) + { + // + } + + virtual ~FactorDummyZero1() = default; + + virtual std::string getTopology() const override + { + return std::string("MOTION"); + } + + template<typename T> + bool operator ()(const T* const _st1, + T* _residuals) const + { + _residuals[0] = _st1[0]; + return true; + } +}; + +} // namespace wolf + +#endif diff --git a/test/dummy/factor_dummy_zero_12.h b/test/dummy/factor_dummy_zero_12.h new file mode 100644 index 0000000000000000000000000000000000000000..c60b9ce3232aa5c18807e80fbfb766cde275c953 --- /dev/null +++ b/test/dummy/factor_dummy_zero_12.h @@ -0,0 +1,159 @@ +#ifndef FACTOR_DUMMY_ZERO_12_H_ +#define FACTOR_DUMMY_ZERO_12_H_ + +//Wolf includes +#include "core/factor/factor_autodiff.h" + +//#include "ceres/jet.h" + +namespace wolf { + +//class +template <unsigned int ID> +class FactorDummyZero12 : public FactorAutodiff<FactorDummyZero12<ID>, ID, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12> +{ + using Base = FactorAutodiff<FactorDummyZero12<ID>, ID, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12>; + static const unsigned int id = ID; + public: + FactorDummyZero12(const FeatureBasePtr& _ftr_ptr, + const StateBlockPtr& _sb1_ptr, + const StateBlockPtr& _sb2_ptr, + const StateBlockPtr& _sb3_ptr, + const StateBlockPtr& _sb4_ptr, + const StateBlockPtr& _sb5_ptr, + const StateBlockPtr& _sb6_ptr, + const StateBlockPtr& _sb7_ptr, + const StateBlockPtr& _sb8_ptr, + const StateBlockPtr& _sb9_ptr, + const StateBlockPtr& _sb10_ptr, + const StateBlockPtr& _sb11_ptr, + const StateBlockPtr& _sb12_ptr) : + Base("FactorDummy12", + _ftr_ptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, + false, + FAC_ACTIVE, + _sb1_ptr, + _sb2_ptr, + _sb3_ptr, + _sb4_ptr, + _sb5_ptr, + _sb6_ptr, + _sb7_ptr, + _sb8_ptr, + _sb9_ptr, + _sb10_ptr, + _sb11_ptr, + _sb12_ptr) + { + assert(id > 0 && id <= 12); + } + + virtual ~FactorDummyZero12() = default; + + virtual std::string getTopology() const override + { + return std::string("MOTION"); + } + + template<typename T> + bool operator ()(const T* const _st1, + const T* const _st2, + const T* const _st3, + const T* const _st4, + const T* const _st5, + const T* const _st6, + const T* const _st7, + const T* const _st8, + const T* const _st9, + const T* const _st10, + const T* const _st11, + const T* const _st12, + T* _residuals) const + { + Eigen::Map<Eigen::Matrix<T,ID,1>> residuals(_residuals); + switch (id) + { + case 1: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st1(_st1); + residuals = st1; + break; + } + case 2: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st2(_st2); + residuals = st2; + break; + } + case 3: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st3(_st3); + residuals = st3; + break; + } + case 4: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st4(_st4); + residuals = st4; + break; + } + case 5: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st5(_st5); + residuals = st5; + break; + } + case 6: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st6(_st6); + residuals = st6; + break; + } + case 7: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st7(_st7); + residuals = st7; + break; + } + case 8: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st8(_st8); + residuals = st8; + break; + } + case 9: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st9(_st9); + residuals = st9; + break; + } + case 10: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st10(_st10); + residuals = st10; + break; + } + case 11: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st11(_st11); + residuals = st11; + break; + } + case 12: + { + Eigen::Map<const Eigen::Matrix<T,ID,1>> st12(_st12); + residuals = st12; + break; + } + default: + throw std::runtime_error("ID not found"); + } + return true; + } +}; + +} // namespace wolf + +#endif diff --git a/test/dummy/factor_feature_dummy.h b/test/dummy/factor_feature_dummy.h index 6b31ffa63a398dc166a4e51fc552352f05a28390..48c7d66ff9482ed55df9f166374948a0d07ef672 100644 --- a/test/dummy/factor_feature_dummy.h +++ b/test/dummy/factor_feature_dummy.h @@ -49,23 +49,36 @@ class FactorFeatureDummy : public FactorBase public: static FactorBasePtr create(const FeatureBasePtr& _feature_ptr, - const NodeBasePtr& _correspondant_ptr, - const ProcessorBasePtr& _processor_ptr = nullptr); + const NodeBasePtr& _correspondant_ptr, + const ProcessorBasePtr& _processor_ptr = nullptr); }; -inline FactorFeatureDummy::FactorFeatureDummy(const FeatureBasePtr& /*_feature_ptr*/, const FeatureBasePtr& _feature_other_ptr, +inline FactorFeatureDummy::FactorFeatureDummy(const FeatureBasePtr& _feature_ptr, + const FeatureBasePtr& _feature_other_ptr, const ProcessorBasePtr& _processor_ptr, - bool _apply_loss_function, FactorStatus _status) : - FactorBase("FactorFeatureDummy", nullptr, nullptr, _feature_other_ptr, nullptr, _processor_ptr, _apply_loss_function, _status) + bool _apply_loss_function, + FactorStatus _status) : + FactorBase("FactorFeatureDummy", + _feature_ptr, + nullptr, + nullptr, + _feature_other_ptr, + nullptr, + _processor_ptr, + _apply_loss_function, + _status) { // } -inline FactorBasePtr FactorFeatureDummy::create(const FeatureBasePtr& _feature_ptr, const NodeBasePtr& _correspondant_ptr, - const ProcessorBasePtr& _processor_ptr) +inline FactorBasePtr FactorFeatureDummy::create(const FeatureBasePtr& _feature_ptr, + const NodeBasePtr& _correspondant_ptr, + const ProcessorBasePtr& _processor_ptr) { - return std::make_shared<FactorFeatureDummy>(_feature_ptr, std::static_pointer_cast<FeatureBase>(_correspondant_ptr), _processor_ptr); + return std::make_shared<FactorFeatureDummy>(_feature_ptr, + std::static_pointer_cast<FeatureBase>(_correspondant_ptr), + _processor_ptr); } } // namespace wolf diff --git a/test/dummy/factor_landmark_dummy.h b/test/dummy/factor_landmark_dummy.h index b4db44b7890f73289d54cb2708c85edb8a1b8b46..8adcfff4ec7891cee87da0fe0b70fd0bb15e0065 100644 --- a/test/dummy/factor_landmark_dummy.h +++ b/test/dummy/factor_landmark_dummy.h @@ -25,11 +25,15 @@ class FactorLandmarkDummy : public FactorBase /** \brief Evaluate the factor given the input parameters and returning the residuals and jacobians **/ - virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const override {return true;}; + virtual bool evaluate(double const* const* parameters, + double* residuals, + double** jacobians) const override {return true;}; /** Returns a residual vector and a vector of Jacobian matrix corresponding to each state block evaluated in the point provided in _states_ptr **/ - virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const override {}; + virtual void evaluate(const std::vector<const double*>& _states_ptr, + Eigen::VectorXd& residual_, + std::vector<Eigen::MatrixXd>& jacobians_) const override {}; /** \brief Returns the jacobians computation method **/ @@ -37,7 +41,10 @@ class FactorLandmarkDummy : public FactorBase /** \brief Returns a vector of pointers to the states in which this factor depends **/ - virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const override {return std::vector<StateBlockPtr>(0);} + virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const override + { + return std::vector<StateBlockPtr>(0); + } /** \brief Returns the factor residual size **/ @@ -45,7 +52,10 @@ class FactorLandmarkDummy : public FactorBase /** \brief Returns the factor states sizes **/ - virtual std::vector<unsigned int> getStateSizes() const override {return std::vector<unsigned int>({1});} + virtual std::vector<unsigned int> getStateSizes() const override + { + return std::vector<unsigned int>({1}); + } public: static FactorBasePtr create(const FeatureBasePtr& _feature_ptr, @@ -54,18 +64,31 @@ class FactorLandmarkDummy : public FactorBase }; -inline FactorLandmarkDummy::FactorLandmarkDummy(const FeatureBasePtr& /*_feature_ptr*/, const LandmarkBasePtr& _landmark_other_ptr, +inline FactorLandmarkDummy::FactorLandmarkDummy(const FeatureBasePtr& _feature_ptr, + const LandmarkBasePtr& _landmark_other_ptr, const ProcessorBasePtr& _processor_ptr, - bool _apply_loss_function, FactorStatus _status) : - FactorBase("FactorFeatureDummy", nullptr, nullptr, nullptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status) + bool _apply_loss_function, + FactorStatus _status) : + FactorBase("FactorFeatureDummy", + _feature_ptr, + nullptr, + nullptr, + nullptr, + _landmark_other_ptr, + _processor_ptr, + _apply_loss_function, + _status) { // } -inline FactorBasePtr FactorLandmarkDummy::create(const FeatureBasePtr& _feature_ptr, const NodeBasePtr& _correspondant_ptr, +inline FactorBasePtr FactorLandmarkDummy::create(const FeatureBasePtr& _feature_ptr, + const NodeBasePtr& _correspondant_ptr, const ProcessorBasePtr& _processor_ptr) { - return std::make_shared<FactorLandmarkDummy>(_feature_ptr, std::static_pointer_cast<LandmarkBase>(_correspondant_ptr), _processor_ptr); + return std::make_shared<FactorLandmarkDummy>(_feature_ptr, + std::static_pointer_cast<LandmarkBase>(_correspondant_ptr), + _processor_ptr); } } // namespace wolf diff --git a/test/dummy/processor_tracker_feature_dummy.cpp b/test/dummy/processor_tracker_feature_dummy.cpp index 3a30e98af0e409fb0fc8604231d7bee16a0630e6..8485d267034febde4f08911108c0773fd67ab892 100644 --- a/test/dummy/processor_tracker_feature_dummy.cpp +++ b/test/dummy/processor_tracker_feature_dummy.cpp @@ -58,6 +58,7 @@ unsigned int ProcessorTrackerFeatureDummy::detectNewFeatures(const int& _max_new FeatureBasePtrList& _features_out) { unsigned int max_features = _max_new_features; + WOLF_INFO("Detecting " , _max_new_features , " new features..." ); if (max_features == -1) { @@ -70,7 +71,7 @@ unsigned int ProcessorTrackerFeatureDummy::detectNewFeatures(const int& _max_new for (unsigned int i = 0; i < max_features; i++) { FeatureBasePtr ftr = FeatureBase::emplace<FeatureBase>(_capture, - "DUMMY FEATURE", + "FeatureDummy", Eigen::Vector1d::Ones(), Eigen::MatrixXd::Ones(1, 1)); _features_out.push_back(ftr); @@ -92,26 +93,11 @@ FactorBasePtr ProcessorTrackerFeatureDummy::emplaceFactor(FeatureBasePtr _featur return FactorBase::emplace<FactorFeatureDummy>(_feature_ptr, _feature_ptr, _feature_other_ptr, shared_from_this()); } -ProcessorBasePtr ProcessorTrackerFeatureDummy::create(const std::string& _unique_name, - const ProcessorParamsBasePtr _params) -{ - auto params = std::static_pointer_cast<ProcessorParamsTrackerFeatureDummy>(_params); - - // if cast failed use default value - if (params == nullptr) - params = std::make_shared<ProcessorParamsTrackerFeatureDummy>(); - - auto prc_ptr = std::make_shared<ProcessorTrackerFeatureDummy>(params); - - prc_ptr->setName(_unique_name); - - return prc_ptr; -} - } // namespace wolf -// Register in the ProcessorFactory -#include "core/processor/processor_factory.h" +// Register in the FactoryProcessor +#include "core/processor/factory_processor.h" namespace wolf { -WOLF_REGISTER_PROCESSOR("ProcessorTrackerFeatureDummy", ProcessorTrackerFeatureDummy) +WOLF_REGISTER_PROCESSOR(ProcessorTrackerFeatureDummy) +WOLF_REGISTER_PROCESSOR_AUTO(ProcessorTrackerFeatureDummy) } // namespace wolf diff --git a/test/dummy/processor_tracker_feature_dummy.h b/test/dummy/processor_tracker_feature_dummy.h index 3328edf08c0234d6b587680b9b215bc91a7ae43f..d06ac67503acfda0a55d9418bac339359b3d9625 100644 --- a/test/dummy/processor_tracker_feature_dummy.h +++ b/test/dummy/processor_tracker_feature_dummy.h @@ -14,16 +14,17 @@ namespace wolf { - -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsTrackerFeatureDummy); -struct ProcessorParamsTrackerFeatureDummy : public ProcessorParamsTrackerFeature +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorTrackerFeatureDummy); + +struct ParamsProcessorTrackerFeatureDummy : public ParamsProcessorTrackerFeature { unsigned int n_tracks_lost; ///< number of tracks lost each time track is called (the first ones) - ProcessorParamsTrackerFeatureDummy() = default; - ProcessorParamsTrackerFeatureDummy(std::string _unique_name, const wolf::ParamsServer & _server): - ProcessorParamsTrackerFeature(_unique_name, _server) + ParamsProcessorTrackerFeatureDummy() = default; + ParamsProcessorTrackerFeatureDummy(std::string _unique_name, + const wolf::ParamsServer & _server): + ParamsProcessorTrackerFeature(_unique_name, _server) { n_tracks_lost = _server.getParam<unsigned int>(prefix + _unique_name + "/n_tracks_lost"); } @@ -31,19 +32,23 @@ struct ProcessorParamsTrackerFeatureDummy : public ProcessorParamsTrackerFeature WOLF_PTR_TYPEDEFS(ProcessorTrackerFeatureDummy); - + //Class class ProcessorTrackerFeatureDummy : public ProcessorTrackerFeature { public: - ProcessorTrackerFeatureDummy(ProcessorParamsTrackerFeatureDummyPtr _params_tracker_feature); + ProcessorTrackerFeatureDummy(ParamsProcessorTrackerFeatureDummyPtr _params_tracker_feature); virtual ~ProcessorTrackerFeatureDummy(); - virtual void configure(SensorBasePtr _sensor) { }; + + // Factory method for high level API + WOLF_PROCESSOR_CREATE(ProcessorTrackerFeatureDummy, ParamsProcessorTrackerFeatureDummy); + + virtual void configure(SensorBasePtr _sensor) override { }; protected: - ProcessorParamsTrackerFeatureDummyPtr params_tracker_feature_dummy_; + ParamsProcessorTrackerFeatureDummyPtr params_tracker_feature_dummy_; /** \brief Track provided features in \b _capture * \param _features_in input list of features in \b last to track @@ -59,14 +64,16 @@ class ProcessorTrackerFeatureDummy : public ProcessorTrackerFeature virtual unsigned int trackFeatures(const FeatureBasePtrList& _features_in, const CaptureBasePtr& _capture, FeatureBasePtrList& _features_out, - FeatureMatchMap& _feature_correspondences); + FeatureMatchMap& _feature_correspondences) override; /** \brief Correct the drift in incoming feature by re-comparing against the corresponding feature in origin. * \param _last_feature input feature in last capture tracked * \param _incoming_feature input/output feature in incoming capture to be corrected * \return false if the the process discards the correspondence with origin's feature */ - virtual bool correctFeatureDrift(const FeatureBasePtr _origin_feature, const FeatureBasePtr _last_feature, FeatureBasePtr _incoming_feature); + virtual bool correctFeatureDrift(const FeatureBasePtr _origin_feature, + const FeatureBasePtr _last_feature, + FeatureBasePtr _incoming_feature) override; /** \brief Vote for KeyFrame generation * @@ -75,7 +82,7 @@ class ProcessorTrackerFeatureDummy : public ProcessorTrackerFeature * * WARNING! This function only votes! It does not create KeyFrames! */ - virtual bool voteForKeyFrame() const; + virtual bool voteForKeyFrame() const override; /** \brief Detect new Features * \param _max_features maximum number of features detected (-1: unlimited. 0: none) @@ -93,24 +100,19 @@ class ProcessorTrackerFeatureDummy : public ProcessorTrackerFeature */ virtual unsigned int detectNewFeatures(const int& _max_new_features, const CaptureBasePtr& _capture, - FeatureBasePtrList& _features_out); + FeatureBasePtrList& _features_out) override; /** \brief Emplaces a new factor * \param _feature_ptr pointer to the parent Feature * \param _feature_other_ptr pointer to the other feature constrained. * * This function emplaces a factor of the appropriate type for the derived processor. */ - virtual FactorBasePtr emplaceFactor(FeatureBasePtr _feature_ptr, FeatureBasePtr _feature_other_ptr); - - public: - - static ProcessorBasePtr create(const std::string& _unique_name, - const ProcessorParamsBasePtr _params); - + virtual FactorBasePtr emplaceFactor(FeatureBasePtr _feature_ptr, + FeatureBasePtr _feature_other_ptr) override; }; -inline ProcessorTrackerFeatureDummy::ProcessorTrackerFeatureDummy(ProcessorParamsTrackerFeatureDummyPtr _params_tracker_feature_dummy) : - ProcessorTrackerFeature("ProcessorTrackerFeatureDummy", 0, _params_tracker_feature_dummy), +inline ProcessorTrackerFeatureDummy::ProcessorTrackerFeatureDummy(ParamsProcessorTrackerFeatureDummyPtr _params_tracker_feature_dummy) : + ProcessorTrackerFeature("ProcessorTrackerFeatureDummy", "PO", 0, _params_tracker_feature_dummy), params_tracker_feature_dummy_(_params_tracker_feature_dummy) { // diff --git a/test/dummy/processor_tracker_landmark_dummy.cpp b/test/dummy/processor_tracker_landmark_dummy.cpp index 72fc32f9baa1ce71216e6457d63185e057bcdc40..d36efd3f804cd71ff38fc7b835dc1b5230c59885 100644 --- a/test/dummy/processor_tracker_landmark_dummy.cpp +++ b/test/dummy/processor_tracker_landmark_dummy.cpp @@ -12,8 +12,8 @@ namespace wolf { -ProcessorTrackerLandmarkDummy::ProcessorTrackerLandmarkDummy(ProcessorParamsTrackerLandmarkDummyPtr _params_tracker_landmark_dummy) : - ProcessorTrackerLandmark("ProcessorTrackerLandmarkDummy", _params_tracker_landmark_dummy), +ProcessorTrackerLandmarkDummy::ProcessorTrackerLandmarkDummy(ParamsProcessorTrackerLandmarkDummyPtr _params_tracker_landmark_dummy) : + ProcessorTrackerLandmark("ProcessorTrackerLandmarkDummy", "PO", _params_tracker_landmark_dummy), params_tracker_landmark_dummy_(_params_tracker_landmark_dummy) { // @@ -101,10 +101,14 @@ unsigned int ProcessorTrackerLandmarkDummy::detectNewFeatures(const int& _max_fe LandmarkBasePtr ProcessorTrackerLandmarkDummy::emplaceLandmark(FeatureBasePtr _feature_ptr) { //std::cout << "ProcessorTrackerLandmarkDummy::emplaceLandmark" << std::endl; - return LandmarkBase::emplace<LandmarkBase>(getProblem()->getMap(), "LandmarkBase", std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1)); + return LandmarkBase::emplace<LandmarkBase>(getProblem()->getMap(), + "LandmarkBase", + std::make_shared<StateBlock>(2), + std::make_shared<StateBlock>(1)); } -FactorBasePtr ProcessorTrackerLandmarkDummy::emplaceFactor(FeatureBasePtr _feature_ptr, LandmarkBasePtr _landmark_ptr) +FactorBasePtr ProcessorTrackerLandmarkDummy::emplaceFactor(FeatureBasePtr _feature_ptr, + LandmarkBasePtr _landmark_ptr) { std::cout << "\tProcessorTrackerLandmarkDummy::emplaceFactor" << std::endl; std::cout << "\t\tfeature " << _feature_ptr->id() << std::endl; @@ -112,4 +116,12 @@ FactorBasePtr ProcessorTrackerLandmarkDummy::emplaceFactor(FeatureBasePtr _featu return FactorBase::emplace<FactorLandmarkDummy>(_feature_ptr, _feature_ptr, _landmark_ptr, shared_from_this()); } -} //namespace wolf +} // namespace wolf + +// Register in the FactoryProcessor +#include "core/processor/factory_processor.h" +namespace wolf { +WOLF_REGISTER_PROCESSOR(ProcessorTrackerLandmarkDummy) +WOLF_REGISTER_PROCESSOR_AUTO(ProcessorTrackerLandmarkDummy) +} // namespace wolf + diff --git a/test/dummy/processor_tracker_landmark_dummy.h b/test/dummy/processor_tracker_landmark_dummy.h index a9531c8db7a0372636c1d0cb605c21c38aec8446..5140a2b2762db740944019ac1595e7d37bf07a2c 100644 --- a/test/dummy/processor_tracker_landmark_dummy.h +++ b/test/dummy/processor_tracker_landmark_dummy.h @@ -13,15 +13,15 @@ namespace wolf { -WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsTrackerLandmarkDummy); +WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorTrackerLandmarkDummy); -struct ProcessorParamsTrackerLandmarkDummy : public ProcessorParamsTrackerLandmark +struct ParamsProcessorTrackerLandmarkDummy : public ParamsProcessorTrackerLandmark { unsigned int n_landmarks_lost; ///< number of landmarks lost each time findLandmarks is called (the last ones) - ProcessorParamsTrackerLandmarkDummy() = default; - ProcessorParamsTrackerLandmarkDummy(std::string _unique_name, const wolf::ParamsServer & _server): - ProcessorParamsTrackerLandmark(_unique_name, _server) + ParamsProcessorTrackerLandmarkDummy() = default; + ParamsProcessorTrackerLandmarkDummy(std::string _unique_name, const wolf::ParamsServer & _server): + ParamsProcessorTrackerLandmark(_unique_name, _server) { n_landmarks_lost = _server.getParam<unsigned int>(prefix + _unique_name + "/n_landmarks_lost"); } @@ -32,13 +32,17 @@ WOLF_PTR_TYPEDEFS(ProcessorTrackerLandmarkDummy); class ProcessorTrackerLandmarkDummy : public ProcessorTrackerLandmark { public: - ProcessorTrackerLandmarkDummy(ProcessorParamsTrackerLandmarkDummyPtr _params_tracker_landmark_dummy); + ProcessorTrackerLandmarkDummy(ParamsProcessorTrackerLandmarkDummyPtr _params_tracker_landmark_dummy); virtual ~ProcessorTrackerLandmarkDummy(); - virtual void configure(SensorBasePtr _sensor) { }; + + // Factory method for high level API + WOLF_PROCESSOR_CREATE(ProcessorTrackerLandmarkDummy, ParamsProcessorTrackerLandmarkDummy); + + virtual void configure(SensorBasePtr _sensor) override { }; protected: - ProcessorParamsTrackerLandmarkDummyPtr params_tracker_landmark_dummy_; + ParamsProcessorTrackerLandmarkDummyPtr params_tracker_landmark_dummy_; /** \brief Find provided landmarks as features in the provided capture * \param _landmarks_in input list of landmarks to be found @@ -54,7 +58,7 @@ class ProcessorTrackerLandmarkDummy : public ProcessorTrackerLandmark virtual unsigned int findLandmarks(const LandmarkBasePtrList& _landmarks_in, const CaptureBasePtr& _capture, FeatureBasePtrList& _features_out, - LandmarkMatchMap& _feature_landmark_correspondences); + LandmarkMatchMap& _feature_landmark_correspondences) override; /** \brief Vote for KeyFrame generation * @@ -63,7 +67,7 @@ class ProcessorTrackerLandmarkDummy : public ProcessorTrackerLandmark * * WARNING! This function only votes! It does not create KeyFrames! */ - virtual bool voteForKeyFrame() const; + virtual bool voteForKeyFrame() const override; /** \brief Detect new Features * \param _max_features maximum number of features detected (-1: unlimited. 0: none) @@ -81,13 +85,13 @@ class ProcessorTrackerLandmarkDummy : public ProcessorTrackerLandmark */ virtual unsigned int detectNewFeatures(const int& _max_new_features, const CaptureBasePtr& _capture, - FeatureBasePtrList& _features_out); + FeatureBasePtrList& _features_out) override; /** \brief Emplace one landmark * * Implement in derived classes to build the type of landmark you need for this tracker. */ - virtual LandmarkBasePtr emplaceLandmark(FeatureBasePtr _feature_ptr); + virtual LandmarkBasePtr emplaceLandmark(FeatureBasePtr _feature_ptr) override; /** \brief Emplace a new factor * \param _feature_ptr pointer to the Feature to constrain @@ -95,7 +99,8 @@ class ProcessorTrackerLandmarkDummy : public ProcessorTrackerLandmark * * Implement this method in derived classes. */ - virtual FactorBasePtr emplaceFactor(FeatureBasePtr _feature_ptr, LandmarkBasePtr _landmark_ptr); + virtual FactorBasePtr emplaceFactor(FeatureBasePtr _feature_ptr, + LandmarkBasePtr _landmark_ptr) override; }; } // namespace wolf diff --git a/test/dummy/solver_manager_dummy.h b/test/dummy/solver_manager_dummy.h new file mode 100644 index 0000000000000000000000000000000000000000..fe62d065c64fbf2f4c37f58b00ff4f51ea2a0ef1 --- /dev/null +++ b/test/dummy/solver_manager_dummy.h @@ -0,0 +1,104 @@ +/* + * solver_manager_dummy.h + * + * Created on: May 27, 2020 + * Author: joanvallve + */ + +#ifndef TEST_DUMMY_SOLVER_MANAGER_DUMMY_H_ +#define TEST_DUMMY_SOLVER_MANAGER_DUMMY_H_ + +#include "core/solver/solver_manager.h" + +namespace wolf +{ + +WOLF_PTR_TYPEDEFS(SolverManagerDummy); +class SolverManagerDummy : public SolverManager +{ + public: + std::list<FactorBasePtr> factors_; + std::map<StateBlockPtr,bool> state_block_fixed_; + std::map<StateBlockPtr,LocalParametrizationBasePtr> state_block_local_param_; + + SolverManagerDummy(const ProblemPtr& wolf_problem) : + SolverManager(wolf_problem) + { + }; + + bool isStateBlockRegistered(const StateBlockPtr& st) override + { + return state_blocks_.find(st)!=state_blocks_.end(); + }; + + bool isStateBlockFixed(const StateBlockPtr& st) const + { + return state_block_fixed_.at(st); + }; + + bool isFactorRegistered(const FactorBasePtr& fac_ptr) const override + { + return std::find(factors_.begin(), factors_.end(), fac_ptr) != factors_.end(); + }; + + bool hasThisLocalParametrization(const StateBlockPtr& st, const LocalParametrizationBasePtr& local_param) const + { + return state_block_local_param_.find(st) != state_block_local_param_.end() && state_block_local_param_.at(st) == local_param; + }; + + bool hasLocalParametrization(const StateBlockPtr& st) const + { + return state_block_local_param_.find(st) != state_block_local_param_.end(); + }; + + virtual void computeCovariances(const CovarianceBlocksToBeComputed blocks) override {}; + virtual void computeCovariances(const std::vector<StateBlockPtr>& st_list) override {}; + virtual bool isStateBlockRegisteredDerived(const StateBlockPtr& state_ptr) override {return true;}; + virtual bool isFactorRegisteredDerived(const FactorBasePtr& fac_ptr) const override {return true;}; + + // The following are dummy implementations + bool hasConverged() override { return true; } + SizeStd iterations() override { return 1; } + double initialCost() override { return double(1); } + double finalCost() override { return double(0); } + + + + protected: + + virtual bool checkDerived(std::string prefix="") const override {return true;} + virtual std::string solveDerived(const ReportVerbosity report_level) override { return std::string("");}; + virtual void addFactorDerived(const FactorBasePtr& fac_ptr) override + { + factors_.push_back(fac_ptr); + }; + virtual void removeFactorDerived(const FactorBasePtr& fac_ptr) override + { + factors_.remove(fac_ptr); + }; + virtual void addStateBlockDerived(const StateBlockPtr& state_ptr) override + { + state_block_fixed_[state_ptr] = state_ptr->isFixed(); + state_block_local_param_[state_ptr] = state_ptr->getLocalParametrization(); + }; + virtual void removeStateBlockDerived(const StateBlockPtr& state_ptr) override + { + state_block_fixed_.erase(state_ptr); + state_block_local_param_.erase(state_ptr); + }; + virtual void updateStateBlockStatusDerived(const StateBlockPtr& state_ptr) override + { + state_block_fixed_[state_ptr] = state_ptr->isFixed(); + }; + virtual void updateStateBlockLocalParametrizationDerived(const StateBlockPtr& state_ptr) override + { + if (state_ptr->getLocalParametrization() == nullptr) + state_block_local_param_.erase(state_ptr); + else + state_block_local_param_[state_ptr] = state_ptr->getLocalParametrization(); + }; +}; + +} + +#endif /* TEST_DUMMY_SOLVER_MANAGER_DUMMY_H_ */ diff --git a/test/dummy/tree_manager_dummy.h b/test/dummy/tree_manager_dummy.h new file mode 100644 index 0000000000000000000000000000000000000000..ce8e6379ece21e6a5422445b183f0576a88cc720 --- /dev/null +++ b/test/dummy/tree_manager_dummy.h @@ -0,0 +1,61 @@ +#ifndef INCLUDE_TREE_MANAGER_DUMMY_H_ +#define INCLUDE_TREE_MANAGER_DUMMY_H_ + +#include "core/tree_manager/tree_manager_base.h" + +namespace wolf +{ + +WOLF_STRUCT_PTR_TYPEDEFS(ParamsTreeManagerDummy) +struct ParamsTreeManagerDummy : public ParamsTreeManagerBase +{ + ParamsTreeManagerDummy() = default; + ParamsTreeManagerDummy(std::string _unique_name, const ParamsServer& _server): + ParamsTreeManagerBase(_unique_name, _server) + { + toy_param = _server.getParam<double>(prefix + "/toy_param"); + } + + virtual ~ParamsTreeManagerDummy() = default; + + bool toy_param; + + std::string print() const + { + return ParamsTreeManagerBase::print() + "\n" + + "toy_param: " + std::to_string(toy_param) + "\n"; + } +}; + +WOLF_PTR_TYPEDEFS(TreeManagerDummy) + +class TreeManagerDummy : public TreeManagerBase +{ + public: + TreeManagerDummy(ParamsTreeManagerBasePtr _params) : + TreeManagerBase("TreeManagerDummy", _params), + n_KF_(0) + {}; + WOLF_TREE_MANAGER_CREATE(TreeManagerDummy, ParamsTreeManagerBase) + + virtual ~TreeManagerDummy(){} + + virtual void keyFrameCallback(FrameBasePtr _KF) override + { + n_KF_++; + }; + + int n_KF_; +}; + +} /* namespace wolf */ + +// Register in the FactoryTreeManager +#include "core/tree_manager/factory_tree_manager.h" +namespace wolf { +WOLF_REGISTER_TREE_MANAGER(TreeManagerDummy) +WOLF_REGISTER_TREE_MANAGER_AUTO(TreeManagerDummy) + +} /* namespace wolf */ + +#endif /* INCLUDE_TREE_MANAGER_DUMMY_H_ */ diff --git a/test/gtest_SE3.cpp b/test/gtest_SE3.cpp index 329feed0d0aad5565204f4b746cc1781ec872c9d..27acfea3069b92076bd30e4abd4ac28d787147bf 100644 --- a/test/gtest_SE3.cpp +++ b/test/gtest_SE3.cpp @@ -20,7 +20,7 @@ TEST(SE3, exp_0) Vector6d tau = Vector6d::Zero(); Vector7d pose; pose << 0,0,0, 0,0,0,1; - ASSERT_MATRIX_APPROX(pose, exp_SE3(tau), 1e-8); + ASSERT_MATRIX_APPROX(pose, exp(tau), 1e-8); } TEST(SE3, log_I) @@ -28,16 +28,16 @@ TEST(SE3, log_I) Vector7d pose; pose << 0,0,0, 0,0,0,1; Vector6d tau = Vector6d::Zero(); - ASSERT_MATRIX_APPROX(tau, log_SE3(pose), 1e-8); + ASSERT_MATRIX_APPROX(tau, log(pose), 1e-8); } TEST(SE3, exp_log) { Vector6d tau = Vector6d::Random() / 5.0; - Vector7d pose = exp_SE3(tau); + Vector7d pose = exp(tau); - ASSERT_MATRIX_APPROX(tau, log_SE3(exp_SE3(tau)), 1e-8); - ASSERT_MATRIX_APPROX(pose, exp_SE3(log_SE3(pose)), 1e-8); + ASSERT_MATRIX_APPROX(tau, log(exp(tau)), 1e-8); + ASSERT_MATRIX_APPROX(pose, exp(log(pose)), 1e-8); } TEST(SE3, exp_of_multiple) @@ -45,20 +45,20 @@ TEST(SE3, exp_of_multiple) Vector6d tau, tau2, tau3; Vector7d pose, pose2, pose3; tau = Vector6d::Random() / 5; - pose << exp_SE3(tau); + pose << exp(tau); tau2 = 2*tau; tau3 = 3*tau; pose2 = compose(pose, pose); pose3 = compose(pose2, pose); // 1 - ASSERT_MATRIX_APPROX(exp_SE3(tau), pose, 1e-8); + ASSERT_MATRIX_APPROX(exp(tau), pose, 1e-8); // 2 - ASSERT_MATRIX_APPROX(exp_SE3(tau2), pose2, 1e-8); + ASSERT_MATRIX_APPROX(exp(tau2), pose2, 1e-8); // 3 - ASSERT_MATRIX_APPROX(exp_SE3(tau3), pose3, 1e-8); + ASSERT_MATRIX_APPROX(exp(tau3), pose3, 1e-8); } TEST(SE3, log_of_power) @@ -66,20 +66,177 @@ TEST(SE3, log_of_power) Vector6d tau, tau2, tau3; Vector7d pose, pose2, pose3; tau = Vector6d::Random() / 5; - pose << exp_SE3(tau); + pose << exp(tau); tau2 = 2*tau; tau3 = 3*tau; pose2 = compose(pose, pose); pose3 = compose(pose2, pose); // 1 - ASSERT_MATRIX_APPROX(tau, log_SE3(pose), 1e-8); + ASSERT_MATRIX_APPROX(tau, log(pose), 1e-8); // 2 - ASSERT_MATRIX_APPROX(tau2, log_SE3(pose2), 1e-8); + ASSERT_MATRIX_APPROX(tau2, log(pose2), 1e-8); // 3 - ASSERT_MATRIX_APPROX(tau3, log_SE3(pose3), 1e-8); + ASSERT_MATRIX_APPROX(tau3, log(pose3), 1e-8); +} + +TEST(SE3, composeBlocks) +{ + Vector3d p1, p2, pc; + Quaterniond q1, q2, qc; + p1.setRandom(); + q1 = exp_q(Vector3d::Random()*100); + p2.setRandom(); + q2 = exp_q(Vector3d::Random()*100); + + compose(p1, q1, p2, q2, pc, qc); + + ASSERT_MATRIX_APPROX(pc, p1 + q1*p2, 1e-8); + ASSERT_QUATERNION_APPROX(qc, q1*q2, 1e-8); +} + +TEST(SE3, composeVectorBlocks) +{ + Vector3d p1, p2, pc; + Quaterniond q1, q2, qc; + p1.setRandom(); + q1 = exp_q(Vector3d::Random()*100); + p2.setRandom(); + q2 = exp_q(Vector3d::Random()*100); + + compose(p1, q1.coeffs(), p2, q2.coeffs(), pc, qc.coeffs()); + + ASSERT_MATRIX_APPROX(pc, p1 + q1*p2, 1e-8); + ASSERT_QUATERNION_APPROX(qc, q1*q2, 1e-8); +} + +TEST(SE3, composeEigenVectors) +{ + Vector3d p1, p2, pc; + Quaterniond q1, q2, qc; + p1.setRandom(); + q1 = exp_q(Vector3d::Random()*100); + p2.setRandom(); + q2 = exp_q(Vector3d::Random()*100); + + compose(p1, q1, p2, q2, pc, qc); // tested in composeVectorBlocks + + + Vector7d x1; x1 << p1, q1.coeffs(); + Vector7d x2; x2 << p2, q2.coeffs(); + Vector7d xc, xc_true; xc_true << pc, qc.coeffs(); + + compose(x1, x2, xc); + + ASSERT_MATRIX_APPROX(xc, xc_true, 1e-8); +} + +TEST(SE3, composeVectorComposite) +{ + Vector3d p1, p2, pc; + Quaterniond q1, q2, qc; + p1.setRandom(); + q1 = exp_q(Vector3d::Random()*100); + p2.setRandom(); + q2 = exp_q(Vector3d::Random()*100); + + compose(p1, q1, p2, q2, pc, qc); // tested in composeVectorBlocks + + VectorComposite x1, x2, xc("PO", {3,4}); + + x1.emplace("P", p1); + x1.emplace("O", q1.coeffs()); + x2.emplace("P", p2); + x2.emplace("O", q2.coeffs()); + + compose(x1, x2, xc); + + ASSERT_MATRIX_APPROX(xc.at("P"), pc, 1e-8); + ASSERT_MATRIX_APPROX(xc.at("O"), qc.coeffs(), 1e-8); +} + +TEST(SE3, composeVectorComposite_Jacobians) +{ + Vector3d p1, p2, pc; + Quaterniond q1, q2, qc; + p1.setRandom(); + q1 = exp_q(Vector3d::Random()*100); + p2.setRandom(); + q2 = exp_q(Vector3d::Random()*100); + + Matrix3d R1 = q1.matrix(); + Matrix3d R2 = q2.matrix(); + + compose(p1, q1, p2, q2, pc, qc); // tested in composeVectorBlocks + + VectorComposite x1, x2, xc("PO", {3,4}); + MatrixComposite J_xc_x1, J_xc_x2; + + x1.emplace("P", p1); + x1.emplace("O", q1.coeffs()); + x2.emplace("P", p2); + x2.emplace("O", q2.coeffs()); + + // we'll do xc = x1 * x2 and obtain Jacobians + compose(x1, x2, xc, J_xc_x1, J_xc_x2); + + ASSERT_MATRIX_APPROX(xc.at("P"), pc, 1e-8); + ASSERT_MATRIX_APPROX(xc.at("O"), qc.coeffs(), 1e-8); + + ASSERT_MATRIX_APPROX(J_xc_x1.at("P", "P"), Matrix3d::Identity() , 1e-8); + ASSERT_MATRIX_APPROX(J_xc_x1.at("P", "O"), - R1 * skew(p2) , 1e-8); + ASSERT_MATRIX_APPROX(J_xc_x1.at("O", "P"), Matrix3d::Zero() , 1e-8); + ASSERT_MATRIX_APPROX(J_xc_x1.at("O", "O"), R2.transpose() , 1e-8); + + ASSERT_MATRIX_APPROX(J_xc_x2.at("P", "P"), R1 , 1e-8); + ASSERT_MATRIX_APPROX(J_xc_x2.at("P", "O"), Matrix3d::Zero() , 1e-8); + ASSERT_MATRIX_APPROX(J_xc_x2.at("O", "P"), Matrix3d::Zero() , 1e-8); + ASSERT_MATRIX_APPROX(J_xc_x2.at("O", "O"), Matrix3d::Identity() , 1e-8); +} + +TEST(SE3, exp_0_Composite) +{ + // we check that exp(zero) = identity + + Vector3d p; p.setZero(); + Vector3d theta; theta.setZero(); + + VectorComposite tau; + + tau.emplace("P", p); + tau.emplace("O", theta); + + VectorComposite x = SE3::exp(tau); + + ASSERT_MATRIX_APPROX(x.at("P"), Vector3d::Zero(), 1e-8); + ASSERT_MATRIX_APPROX(x.at("O"), Quaterniond::Identity().coeffs(), 1e-8); + +} + +TEST(SE3, plus_0_Composite) +{ + // we check that x plus zero = x + + Vector3d p; p.setRandom(); + Vector4d q; q.setRandom().normalized(); + + VectorComposite x; + x.emplace("P", p); + x.emplace("O", q); + + Vector3d dp; dp.setZero(); + Vector3d dtheta; dtheta.setZero(); + + VectorComposite tau; + tau.emplace("P", dp); + tau.emplace("O", dtheta); + + VectorComposite res = plus(x, tau); + + ASSERT_MATRIX_APPROX(res.at("P"), p, 1e-8); + ASSERT_MATRIX_APPROX(res.at("O"), q, 1e-8); } TEST(SE3, interpolate_I_xyz) @@ -183,7 +340,7 @@ TEST(SE3, interpolate_half) p1.setRandom(); p1.tail(4).normalize(); da.setRandom(); da /= 5; // small rotation - dp << exp_SE3(da); + dp << exp(da); // compose double, then interpolate 1/2 @@ -204,7 +361,7 @@ TEST(SE3, interpolate_third) p1.setRandom(); p1.tail(4).normalize(); da.setRandom(); da /= 5; // small rotation - dp << exp_SE3(da); + dp << exp(da); dp2 = compose(dp, dp); dp3 = compose(dp2, dp); diff --git a/test/gtest_capture_base.cpp b/test/gtest_capture_base.cpp index f0c1cbfcb2cee9f676700846dbb93fe0cd9e3521..4c004cd72e14e9e69bb343e288ab86e3a5b9354e 100644 --- a/test/gtest_capture_base.cpp +++ b/test/gtest_capture_base.cpp @@ -82,6 +82,15 @@ TEST(CaptureBase, addFeature) ASSERT_EQ(C->getFeatureList().front(), f); } +TEST(CaptureBase, print) +{ + CaptureBasePtr C(std::make_shared<CaptureBase>("DUMMY", 1.2)); // timestamp = 1.2 + // FeatureBasePtr f = C->addFeature(std::make_shared<FeatureBase>("DUMMY", Vector2d::Zero(), Matrix2d::Identity())); + auto f = FeatureBase::emplace<FeatureBase>(C, "DUMMY", Vector2d::Zero(), Matrix2d::Identity()); + + C->print(4, 1, 1, 1); +} + TEST(CaptureBase, process) { SensorBasePtr S(std::make_shared<SensorBase>("DUMMY", nullptr, nullptr, nullptr, 2)); diff --git a/test/gtest_ceres_manager.cpp b/test/gtest_ceres_manager.cpp index 7ead2b8f801602e664cae1e2ec4249f21ef916a5..d2b5c7e01b70fa65472f3e18bbfa7b38d8989679 100644 --- a/test/gtest_ceres_manager.cpp +++ b/test/gtest_ceres_manager.cpp @@ -88,7 +88,7 @@ TEST(CeresManager, Create) ASSERT_EQ(P, ceres_manager_ptr->getProblem()); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, AddStateBlock) @@ -111,7 +111,7 @@ TEST(CeresManager, AddStateBlock) ASSERT_TRUE(ceres_manager_ptr->isStateBlockRegisteredCeresManager(sb_ptr)); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, DoubleAddStateBlock) @@ -140,7 +140,7 @@ TEST(CeresManager, DoubleAddStateBlock) ASSERT_TRUE(ceres_manager_ptr->isStateBlockRegisteredCeresManager(sb_ptr)); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, UpdateStateBlock) @@ -171,7 +171,7 @@ TEST(CeresManager, UpdateStateBlock) ASSERT_TRUE(ceres_manager_ptr->isStateBlockFixed(sb_ptr)); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, AddUpdateStateBlock) @@ -198,7 +198,7 @@ TEST(CeresManager, AddUpdateStateBlock) ASSERT_TRUE(ceres_manager_ptr->isStateBlockFixed(sb_ptr)); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, RemoveStateBlock) @@ -230,7 +230,7 @@ TEST(CeresManager, RemoveStateBlock) ASSERT_EQ(ceres_manager_ptr->numStateBlocks(), 0); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, AddRemoveStateBlock) @@ -256,7 +256,7 @@ TEST(CeresManager, AddRemoveStateBlock) ASSERT_EQ(ceres_manager_ptr->numStateBlocks(), 0); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, RemoveUpdateStateBlock) @@ -281,7 +281,7 @@ TEST(CeresManager, RemoveUpdateStateBlock) ceres_manager_ptr->update(); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, DoubleRemoveStateBlock) @@ -309,7 +309,7 @@ TEST(CeresManager, DoubleRemoveStateBlock) ceres_manager_ptr->update(); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, AddFactor) @@ -318,7 +318,7 @@ TEST(CeresManager, AddFactor) CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, 0, P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f,f,nullptr,false); @@ -331,7 +331,7 @@ TEST(CeresManager, AddFactor) ASSERT_EQ(ceres_manager_ptr->numFactors(), 1); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, DoubleAddFactor) @@ -340,7 +340,7 @@ TEST(CeresManager, DoubleAddFactor) CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, 0, P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f,f,nullptr,false); @@ -356,7 +356,7 @@ TEST(CeresManager, DoubleAddFactor) ASSERT_EQ(ceres_manager_ptr->numFactors(), 1); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, RemoveFactor) @@ -365,7 +365,7 @@ TEST(CeresManager, RemoveFactor) CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, 0, P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f,f,nullptr,false); @@ -384,7 +384,7 @@ TEST(CeresManager, RemoveFactor) ASSERT_EQ(ceres_manager_ptr->numFactors(), 0); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, AddRemoveFactor) @@ -393,7 +393,7 @@ TEST(CeresManager, AddRemoveFactor) CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, 0, P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f,f,nullptr,false); @@ -411,7 +411,7 @@ TEST(CeresManager, AddRemoveFactor) ASSERT_EQ(ceres_manager_ptr->numFactors(), 0); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, DoubleRemoveFactor) @@ -420,7 +420,7 @@ TEST(CeresManager, DoubleRemoveFactor) CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, 0, P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f,f,nullptr,false); @@ -437,16 +437,15 @@ TEST(CeresManager, DoubleRemoveFactor) // remove factor P->notifyFactor(c,REMOVE); - ASSERT_DEATH({ // update solver - ceres_manager_ptr->update();},""); + ceres_manager_ptr->update(); // check factor ASSERT_FALSE(ceres_manager_ptr->isFactorRegistered(c)); ASSERT_EQ(ceres_manager_ptr->numFactors(), 0); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, AddStateBlockLocalParam) @@ -473,7 +472,7 @@ TEST(CeresManager, AddStateBlockLocalParam) ASSERT_TRUE(ceres_manager_ptr->hasThisLocalParametrization(sb_ptr,local_param_ptr)); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, RemoveLocalParam) @@ -505,7 +504,7 @@ TEST(CeresManager, RemoveLocalParam) ASSERT_FALSE(ceres_manager_ptr->hasLocalParametrization(sb_ptr)); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, AddLocalParam) @@ -538,7 +537,7 @@ TEST(CeresManager, AddLocalParam) ASSERT_TRUE(ceres_manager_ptr->hasThisLocalParametrization(sb_ptr,local_param_ptr)); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, FactorsRemoveLocalParam) @@ -547,11 +546,11 @@ TEST(CeresManager, FactorsRemoveLocalParam) CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P); // Create (and add) 2 factors quaternion - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, 0, P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); - FactorQuaternionAbsolutePtr c1 = FactorBase::emplace<FactorQuaternionAbsolute>(f, F->getO(),nullptr,false); - FactorQuaternionAbsolutePtr c2 = FactorBase::emplace<FactorQuaternionAbsolute>(f, F->getO(),nullptr,false); + FactorQuaternionAbsolutePtr c1 = FactorBase::emplace<FactorQuaternionAbsolute>(f, f, F->getO(),nullptr,false); + FactorQuaternionAbsolutePtr c2 = FactorBase::emplace<FactorQuaternionAbsolute>(f, f, F->getO(),nullptr,false); // update solver ceres_manager_ptr->update(); @@ -580,7 +579,7 @@ TEST(CeresManager, FactorsRemoveLocalParam) ASSERT_EQ(ceres_manager_ptr->numFactors(), 2); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } TEST(CeresManager, FactorsUpdateLocalParam) @@ -589,11 +588,11 @@ TEST(CeresManager, FactorsUpdateLocalParam) CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P); // Create (and add) 2 factors quaternion - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, 0, P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); - FactorQuaternionAbsolutePtr c1 = FactorBase::emplace<FactorQuaternionAbsolute>(f, F->getO(),nullptr,false); - FactorQuaternionAbsolutePtr c2 = FactorBase::emplace<FactorQuaternionAbsolute>(f, F->getO(),nullptr,false); + FactorQuaternionAbsolutePtr c1 = FactorBase::emplace<FactorQuaternionAbsolute>(f, f, F->getO(),nullptr,false); + FactorQuaternionAbsolutePtr c2 = FactorBase::emplace<FactorQuaternionAbsolute>(f, f, F->getO(),nullptr,false); // update solver ceres_manager_ptr->update(); @@ -624,7 +623,7 @@ TEST(CeresManager, FactorsUpdateLocalParam) ASSERT_EQ(ceres_manager_ptr->numFactors(), 2); // run ceres manager check - ceres_manager_ptr->check(); + ASSERT_TRUE(ceres_manager_ptr->check()); } int main(int argc, char **argv) diff --git a/test/gtest_emplace.cpp b/test/gtest_emplace.cpp index e60531daf9ab855e03b074384452d8e61c78d52a..457d41fe43f1adb01345065130f416f8ec785185 100644 --- a/test/gtest_emplace.cpp +++ b/test/gtest_emplace.cpp @@ -51,13 +51,13 @@ TEST(Emplace, Processor) ProblemPtr P = Problem::create("PO", 2); auto sen = SensorBase::emplace<SensorBase>(P->getHardware(), "Dummy", nullptr, nullptr, nullptr, 2, false); - auto prc = ProcessorOdom2d::emplace<ProcessorOdom2d>(sen, std::make_shared<ProcessorParamsOdom2d>()); + auto prc = ProcessorOdom2d::emplace<ProcessorOdom2d>(sen, std::make_shared<ParamsProcessorOdom2d>()); ASSERT_EQ(P, P->getHardware()->getSensorList().front()->getProcessorList().front()->getSensor()->getProblem()); ASSERT_EQ(sen, sen->getProcessorList().front()->getSensor()); ASSERT_EQ(prc, sen->getProcessorList().front()); SensorBasePtr sen2 = SensorBase::emplace<SensorBase>(P->getHardware(), "Dummy", nullptr, nullptr, nullptr, 2, false); - ProcessorOdom2dPtr prc2 = ProcessorOdom2d::emplace<ProcessorOdom2d>(sen2, std::make_shared<ProcessorParamsOdom2d>()); + ProcessorOdom2dPtr prc2 = ProcessorOdom2d::emplace<ProcessorOdom2d>(sen2, std::make_shared<ParamsProcessorOdom2d>()); ASSERT_EQ(sen2, sen2->getProcessorList().front()->getSensor()); ASSERT_EQ(prc2, sen2->getProcessorList().front()); } diff --git a/test/gtest_factor_absolute.cpp b/test/gtest_factor_absolute.cpp index c0f75e3e8753a568fafb772805910642031494d4..82b56da523c70dff134908ba3e63adf97493d914 100644 --- a/test/gtest_factor_absolute.cpp +++ b/test/gtest_factor_absolute.cpp @@ -35,10 +35,11 @@ ProblemPtr problem_ptr = Problem::create("POV", 3); CeresManager ceres_mgr(problem_ptr); // Two frames -FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, problem_ptr->zeroState(), TimeStamp(0)); +FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, 0, problem_ptr->stateZero() ); -// Capture, feature and factor -auto cap0 = CaptureBase::emplace<CaptureMotion>(frm0, "IMU ABS", 0, nullptr, pose10, 10, 9, nullptr); +// Capture +// auto cap0 = CaptureBase::emplace<CaptureMotion>(frm0, "IMU ABS", 0, nullptr, pose10, 10, 9, nullptr); +auto cap0 = CaptureBase::emplace<CaptureMotion>(frm0, "IMU ABS", 0, nullptr, pose10, nullptr); //////////////////////////////////////////////////////// /* In the tests below, we check that FactorBlockAbsolute and FactorQuaternionAbsolute are working fine @@ -49,7 +50,7 @@ auto cap0 = CaptureBase::emplace<CaptureMotion>(frm0, "IMU ABS", 0, nullptr, pos TEST(FactorBlockAbs, fac_block_abs_p) { auto fea0 = FeatureBase::emplace<FeatureBase>(cap0, "POSITION", pose10.head<3>(), data_cov.topLeftCorner<3,3>()); - FactorBase::emplace<FactorBlockAbsolute>(fea0, fea0->getFrame()->getP()); + FactorBase::emplace<FactorBlockAbsolute>(fea0, fea0, fea0->getFrame()->getP(), nullptr, false); ASSERT_TRUE(problem_ptr->check(0)); @@ -67,7 +68,7 @@ TEST(FactorBlockAbs, fac_block_abs_p) TEST(FactorBlockAbs, fac_block_abs_p_tail2) { auto fea0 = FeatureBase::emplace<FeatureBase>(cap0, "POSITION TAIL 2", pose10.segment<2>(1), data_cov.bottomRightCorner<2,2>()); - FactorBase::emplace<FactorBlockAbsolute>(fea0, fea0->getFrame()->getP(),1,2); + FactorBase::emplace<FactorBlockAbsolute>(fea0, fea0, fea0->getFrame()->getP(),1,2, nullptr, false); // Unfix frame 0, perturb frm0 frm0->unfix(); @@ -83,7 +84,7 @@ TEST(FactorBlockAbs, fac_block_abs_p_tail2) TEST(FactorBlockAbs, fac_block_abs_v) { auto fea0 = FeatureBase::emplace<FeatureBase>(cap0, "FeatureVelocity", pose10.tail<3>(), data_cov.bottomRightCorner<3,3>()); - FactorBase::emplace<FactorBlockAbsolute>(fea0, fea0->getFrame()->getV()); + FactorBase::emplace<FactorBlockAbsolute>(fea0, fea0, fea0->getFrame()->getV(), nullptr, false); ASSERT_TRUE(problem_ptr->check(0)); @@ -101,7 +102,7 @@ TEST(FactorBlockAbs, fac_block_abs_v) TEST(FactorQuatAbs, fac_block_abs_o) { auto fea0 = FeatureBase::emplace<FeatureBase>(cap0, "FeatureQuaternion", pose10.segment<4>(3), data_cov.block<3,3>(3,3)); - FactorBase::emplace<FactorQuaternionAbsolute>(fea0, fea0->getFrame()->getO()); + FactorBase::emplace<FactorQuaternionAbsolute>(fea0, fea0, fea0->getFrame()->getO(), nullptr, false); ASSERT_TRUE(problem_ptr->check(0)); diff --git a/test/gtest_factor_autodiff.cpp b/test/gtest_factor_autodiff.cpp index 993908461d6b37cae1b24d8701a3612d4dc9c432..0acd77891bf1bae60fe41575edec629e9864999b 100644 --- a/test/gtest_factor_autodiff.cpp +++ b/test/gtest_factor_autodiff.cpp @@ -13,14 +13,345 @@ #include "core/factor/factor_odom_2d.h" #include "core/factor/factor_odom_2d_analytic.h" #include "core/factor/factor_autodiff.h" +#include "dummy/factor_dummy_zero_1.h" +#include "dummy/factor_dummy_zero_12.h" using namespace wolf; using namespace Eigen; -TEST(CaptureAutodiff, ConstructorOdom2d) + +TEST(FactorAutodiff, AutodiffDummy1) { - FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1))); - FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1))); + StateBlockPtr sb = std::make_shared<StateBlock>(Eigen::Vector1d::Random()); + FeatureBasePtr ftr = std::make_shared<FeatureBase>("Feature", Vector2d(1,2), Matrix2d::Identity()); + + auto fac = std::make_shared<FactorDummyZero1>(ftr, sb); + + // COMPUTE JACOBIANS + std::vector<const double*> states_ptr({sb->getStateData()}); + + std::vector<Eigen::MatrixXd> J; + Eigen::VectorXd residuals(fac->getSize()); + fac->evaluate(states_ptr, residuals, J); + + ASSERT_MATRIX_APPROX(J[0], Eigen::Matrix1d::Ones(), wolf::Constants::EPS); +} + +TEST(FactorAutodiff, AutodiffDummy12) +{ + StateBlockPtr sb1 = std::make_shared<StateBlock>(Eigen::Vector1d::Random()); + StateBlockPtr sb2 = std::make_shared<StateBlock>(Eigen::Vector2d::Random()); + StateBlockPtr sb3 = std::make_shared<StateBlock>(Eigen::Vector3d::Random()); + StateBlockPtr sb4 = std::make_shared<StateBlock>(Eigen::Vector4d::Random()); + StateBlockPtr sb5 = std::make_shared<StateBlock>(Eigen::Vector5d::Random()); + StateBlockPtr sb6 = std::make_shared<StateBlock>(Eigen::Vector6d::Random()); + StateBlockPtr sb7 = std::make_shared<StateBlock>(Eigen::Vector7d::Random()); + StateBlockPtr sb8 = std::make_shared<StateBlock>(Eigen::Vector8d::Random()); + StateBlockPtr sb9 = std::make_shared<StateBlock>(Eigen::Vector9d::Random()); + StateBlockPtr sb10 = std::make_shared<StateBlock>(Eigen::Vector10d::Random()); + StateBlockPtr sb11 = std::make_shared<StateBlock>(Eigen::VectorXd::Random(11)); + StateBlockPtr sb12 = std::make_shared<StateBlock>(Eigen::VectorXd::Random(12)); + + std::vector<const double*> states_ptr({sb1->getStateData(),sb2->getStateData(),sb3->getStateData(),sb4->getStateData(),sb5->getStateData(),sb6->getStateData(),sb7->getStateData(),sb8->getStateData(),sb9->getStateData(),sb10->getStateData(),sb11->getStateData(),sb12->getStateData()}); + std::vector<Eigen::MatrixXd> J; + Eigen::VectorXd residuals; + unsigned int i; + FactorBasePtr fac = nullptr; + FeatureBasePtr ftr = std::make_shared<FeatureBase>("Feature", Vector2d(1,2), Matrix2d::Identity()); + + // 1 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<1>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 2 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<2>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 3 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<3>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 4 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<4>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 5 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<5>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 6 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<6>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 7 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<7>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 8 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<8>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 9 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<9>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 10 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<10>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 11 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<11>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } + + // 12 ------------------------------------------------------------------------ + fac = std::make_shared<FactorDummyZero12<12>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + i = fac->getSize(); + + // Jacobian + J.clear(); + residuals.resize(i); + fac->evaluate(states_ptr, residuals, J); + + std::cout << "i = " << i << std::endl; + for (unsigned int j = 0; j < 12; j++) + { + std::cout << "j = " << j << std::endl; + std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl; + if (j == i-1) + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS); + } + else + { + ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS); + } + } +} + +TEST(FactorAutodiff, EmplaceOdom2d) +{ + FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(KEY, TimeStamp(0), std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1))); + FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(KEY, TimeStamp(0), std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1))); // SENSOR ParamsSensorOdom2d intrinsics_odo; @@ -44,14 +375,14 @@ TEST(CaptureAutodiff, ConstructorOdom2d) ASSERT_TRUE(factor_ptr->getFrameOther()); } -TEST(CaptureAutodiff, ResidualOdom2d) +TEST(FactorAutodiff, ResidualOdom2d) { Eigen::Vector3d f1_pose, f2_pose; f1_pose << 2,1,M_PI; f2_pose << 3,5,3*M_PI/2; - FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f1_pose.head<2>()), std::make_shared<StateBlock>(f1_pose.tail<1>()))); - FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f2_pose.head<2>()), std::make_shared<StateBlock>(f2_pose.tail<1>()))); + FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(KEY, TimeStamp(0), std::make_shared<StateBlock>(f1_pose.head<2>()), std::make_shared<StateBlock>(f1_pose.tail<1>()))); + FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(KEY, TimeStamp(0), std::make_shared<StateBlock>(f2_pose.head<2>()), std::make_shared<StateBlock>(f2_pose.tail<1>()))); // SENSOR ParamsSensorOdom2d intrinsics_odo; @@ -88,14 +419,14 @@ TEST(CaptureAutodiff, ResidualOdom2d) ASSERT_TRUE(residuals.minCoeff() > -1e-9); } -TEST(CaptureAutodiff, JacobianOdom2d) +TEST(FactorAutodiff, JacobianOdom2d) { Eigen::Vector3d f1_pose, f2_pose; f1_pose << 2,1,M_PI; f2_pose << 3,5,3*M_PI/2; - FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f1_pose.head<2>()), std::make_shared<StateBlock>(f1_pose.tail<1>()))); - FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f2_pose.head<2>()), std::make_shared<StateBlock>(f2_pose.tail<1>()))); + FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(KEY, TimeStamp(0), std::make_shared<StateBlock>(f1_pose.head<2>()), std::make_shared<StateBlock>(f1_pose.tail<1>()))); + FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(KEY, TimeStamp(0), std::make_shared<StateBlock>(f2_pose.head<2>()), std::make_shared<StateBlock>(f2_pose.tail<1>()))); // SENSOR ParamsSensorOdom2d intrinsics_odo; @@ -166,14 +497,14 @@ TEST(CaptureAutodiff, JacobianOdom2d) // std::cout << "analytic J " << 3 << ":\n" << J3 << std::endl; } -TEST(CaptureAutodiff, AutodiffVsAnalytic) +TEST(FactorAutodiff, AutodiffVsAnalytic) { Eigen::Vector3d f1_pose, f2_pose; f1_pose << 2,1,M_PI; f2_pose << 3,5,3*M_PI/2; - FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f1_pose.head<2>()), std::make_shared<StateBlock>(f1_pose.tail<1>()))); - FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f2_pose.head<2>()), std::make_shared<StateBlock>(f2_pose.tail<1>()))); + FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(KEY, TimeStamp(0), std::make_shared<StateBlock>(f1_pose.head<2>()), std::make_shared<StateBlock>(f1_pose.tail<1>()))); + FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(KEY, TimeStamp(0), std::make_shared<StateBlock>(f2_pose.head<2>()), std::make_shared<StateBlock>(f2_pose.tail<1>()))); // SENSOR ParamsSensorOdom2d intrinsics_odo; @@ -194,7 +525,6 @@ TEST(CaptureAutodiff, AutodiffVsAnalytic) auto fac_analytic_ptr = FactorBase::emplace<FactorOdom2dAnalytic>(feature_ptr, feature_ptr, fr1_ptr, nullptr, false); // COMPUTE JACOBIANS - const Eigen::VectorXd fr1_pstate = fr1_ptr->getP()->getState(); const Eigen::VectorXd fr1_ostate = fr1_ptr->getO()->getState(); const Eigen::VectorXd fr2_pstate = fr2_ptr->getP()->getState(); diff --git a/test/gtest_factor_autodiff_distance_3d.cpp b/test/gtest_factor_autodiff_distance_3d.cpp index 985e25a23de5f1c6b137d1b477bb9a22b219fb2a..e25e1505a3ddaa15ecfa6152fc007bc6009696f9 100644 --- a/test/gtest_factor_autodiff_distance_3d.cpp +++ b/test/gtest_factor_autodiff_distance_3d.cpp @@ -55,13 +55,10 @@ class FactorAutodiffDistance3d_Test : public testing::Test problem = Problem::create("PO", 3); ceres_manager = std::make_shared<CeresManager>(problem); - F1 = problem->emplaceFrame (KEY, pose1, 1.0); + F1 = problem->emplaceFrame (KEY, 1.0, pose1); - F2 = problem->emplaceFrame (KEY, pose2, 2.0); + F2 = problem->emplaceFrame (KEY, 2.0, pose2); C2 = CaptureBase::emplace<CaptureBase>(F2, "Base", 1.0); - f2 = FeatureBase::emplace<FeatureBase>(C2, "Dist", dist, dist_cov); - c2 = FactorBase::emplace<FactorAutodiffDistance3d>(f2, f2, F1, nullptr, false, FAC_ACTIVE); - } }; @@ -70,6 +67,8 @@ TEST_F(FactorAutodiffDistance3d_Test, ground_truth) { double res; + f2 = FeatureBase::emplace<FeatureBase>(C2, "Dist", dist, dist_cov); + c2 = FactorBase::emplace<FactorAutodiffDistance3d>(f2, f2, F1, nullptr, false, FAC_ACTIVE); c2->operator ()(pos1.data(), pos2.data(), &res); ASSERT_NEAR(res, 0.0, 1e-5); @@ -79,7 +78,8 @@ TEST_F(FactorAutodiffDistance3d_Test, expected_residual) { double measurement = 1.400; - f2->setMeasurement(Vector1d(measurement)); + f2 = FeatureBase::emplace<FeatureBase>(C2, "Dist", Vector1d(measurement), dist_cov); + c2 = FactorBase::emplace<FactorAutodiffDistance3d>(f2, f2, F1, nullptr, false, FAC_ACTIVE); double res_expected = (measurement - (pos2-pos1).norm()) * c2->getMeasurementSquareRootInformationUpper()(0,0); @@ -92,7 +92,9 @@ TEST_F(FactorAutodiffDistance3d_Test, expected_residual) TEST_F(FactorAutodiffDistance3d_Test, solve) { double measurement = 1.400; - f2->setMeasurement(Vector1d(measurement)); + + f2 = FeatureBase::emplace<FeatureBase>(C2, "Dist", Vector1d(measurement), dist_cov); + c2 = FactorBase::emplace<FactorAutodiffDistance3d>(f2, f2, F1, nullptr, false, FAC_ACTIVE); std::string report = ceres_manager->solve(SolverManager::ReportVerbosity::QUIET); diff --git a/test/gtest_factor_base.cpp b/test/gtest_factor_base.cpp index 9e4f2ef10e8bf2fc1fb9a47d48468e254e46d0af..3237da062337d5a26c3c320e63df62c7d2798fb8 100644 --- a/test/gtest_factor_base.cpp +++ b/test/gtest_factor_base.cpp @@ -24,8 +24,8 @@ class FactorBaseTest : public testing::Test virtual void SetUp() { - F0 = std::make_shared<FrameBase>(0.0, nullptr); - F1 = std::make_shared<FrameBase>(1.0, nullptr); + F0 = std::make_shared<FrameBase>(KEY, 0.0, nullptr); + F1 = std::make_shared<FrameBase>(KEY, 1.0, nullptr); C0 = std::make_shared<CaptureBase>("Capture", 0.0, nullptr); C1 = std::make_shared<CaptureBase>("Capture", 1.0, nullptr); f0 = std::make_shared<FeatureBase>("Feature", Vector2d(1,2), Matrix2d::Identity(), FeatureBase::UncertaintyType::UNCERTAINTY_IS_COVARIANCE); @@ -39,11 +39,13 @@ class FactorBaseTest : public testing::Test class FactorDummy : public FactorBase { public: - FactorDummy(const FrameBasePtr& _frame_other, + FactorDummy(const FeatureBasePtr& _feature, + const FrameBasePtr& _frame_other, const CaptureBasePtr& _capture_other, const FeatureBasePtr& _feature_other, const LandmarkBasePtr& _landmark_other) : FactorBase("Dummy", + _feature, _frame_other, _capture_other, _feature_other, @@ -53,11 +55,13 @@ class FactorDummy : public FactorBase { // } - FactorDummy(const FrameBasePtrList& _frame_other_list, + FactorDummy(const FeatureBasePtr& _feature, + const FrameBasePtrList& _frame_other_list, const CaptureBasePtrList& _capture_other_list, const FeatureBasePtrList& _feature_other_list, const LandmarkBasePtrList& _landmark_other_list) : FactorBase("Dummy", + _feature, _frame_other_list, _capture_other_list, _feature_other_list, @@ -70,8 +74,12 @@ class FactorDummy : public FactorBase virtual ~FactorDummy() = default; virtual std::string getTopology() const override {return "DUMMY";} - virtual bool evaluate(double const* const* _parameters, double* _residuals, double** _jacobians) const override {return true;} - virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& _residual, std::vector<Eigen::MatrixXd>& _jacobians) const override {} + virtual bool evaluate(double const* const* _parameters, + double* _residuals, + double** _jacobians) const override {return true;} + virtual void evaluate(const std::vector<const double*>& _states_ptr, + Eigen::VectorXd& _residual, + std::vector<Eigen::MatrixXd>& _jacobians) const override {} virtual JacobianMethod getJacobianMethod() const override {return JacobianMethod::JAC_ANALYTIC;} virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const override {std::vector<StateBlockPtr> v; return v;} virtual std::vector<unsigned int> getStateSizes() const override {std::vector<unsigned int> v; return v;} @@ -81,7 +89,7 @@ class FactorDummy : public FactorBase TEST_F(FactorBaseTest, constructor_from_pointers) { - FactorDummy fac(nullptr,C0,f0,nullptr); + FactorDummy fac(f0,nullptr,C0,f1,nullptr); ASSERT_TRUE(fac.getFrameOtherList().empty()); @@ -90,11 +98,15 @@ TEST_F(FactorBaseTest, constructor_from_pointers) ASSERT_EQ(fac.getFeatureOtherList().size(), 1); ASSERT_TRUE(fac.getLandmarkOtherList().empty()); + + ASSERT_MATRIX_APPROX(fac.getMeasurement(), f0->getMeasurement(), 1e-12); + + ASSERT_MATRIX_APPROX(fac.getMeasurementSquareRootInformationUpper(), f0->getMeasurementSquareRootInformationUpper(), 1e-12); } TEST_F(FactorBaseTest, constructor_from_lists) { - FactorDummy fac({},{C0},{f0,f1},{}); + FactorDummy fac(f0,{},{C0},{f0,f1},{}); ASSERT_TRUE(fac.getFrameOtherList().empty()); @@ -103,6 +115,10 @@ TEST_F(FactorBaseTest, constructor_from_lists) ASSERT_EQ(fac.getFeatureOtherList().size(), 2); ASSERT_TRUE(fac.getLandmarkOtherList().empty()); + + ASSERT_MATRIX_APPROX(fac.getMeasurement(), f0->getMeasurement(), 1e-12); + + ASSERT_MATRIX_APPROX(fac.getMeasurementSquareRootInformationUpper(), f0->getMeasurementSquareRootInformationUpper(), 1e-12); } diff --git a/test/gtest_factor_block_difference.cpp b/test/gtest_factor_block_difference.cpp index 1e06c7a80377b99197a721e85473319f9bf34862..bee51d78e417f1f446a5890fa1ead4834dc366bc 100644 --- a/test/gtest_factor_block_difference.cpp +++ b/test/gtest_factor_block_difference.cpp @@ -24,7 +24,7 @@ using namespace wolf; const Vector6d zero6 = Vector6d::Zero(); const Vector3d zero3 = zero6.head<3>(); - +const Matrix3d idty02 = Matrix3d::Identity() * 0.02; class FixtureFactorBlockDifference : public testing::Test { @@ -35,6 +35,7 @@ class FixtureFactorBlockDifference : public testing::Test FrameBasePtr KF1_; CaptureBasePtr Cap_; FeatureBasePtr Feat_; + FactorBlockDifferencePtr Fac_; protected: @@ -48,31 +49,36 @@ class FixtureFactorBlockDifference : public testing::Test TimeStamp t0(0); TimeStamp t1(1); - Vector10d x_origin = problem_->zeroState(); - Eigen::Matrix9d cov_prior = 1e-3 * Eigen::Matrix9d::Identity(); - KF0_ = problem_->setPrior(x_origin, cov_prior, t0, 0.1); + // Vector10d x_origin = problem_->stateZero().vector("POV"); + VectorComposite x_origin(problem_->stateZero().vector("POV"), "POV", {3, 4, 3}); + // Eigen::Matrix9d cov_prior = 1e-3 * Eigen::Matrix9d::Identity(); + VectorComposite cov_prior("POV", {Vector3d(sqrt(0.1),sqrt(0.1),sqrt(0.1)),Vector3d(sqrt(0.1),sqrt(0.1),sqrt(0.1)),Vector3d(sqrt(0.1),sqrt(0.1),sqrt(0.1))}); + KF0_ = problem_->setPriorFactor(x_origin, cov_prior, t0, 0.1); - CaptureBasePtr capV0 = CaptureBase::emplace<CaptureBase>(KF0_, "Vel0", t0); - FeatureBasePtr featV0 = FeatureBase::emplace<FeatureBase>(capV0, "Vel0", x_origin.tail(3), cov_prior.bottomRightCorner<3,3>()); - FactorBasePtr facV0 = FactorBase::emplace<FactorBlockAbsolute>(featV0, KF0_->getV()); + //CaptureBasePtr capV0 = CaptureBase::emplace<CaptureBase>(KF0_, "Vel0", t0); + //FeatureBasePtr featV0 = FeatureBase::emplace<FeatureBase>(capV0, "Vel0", x_origin.tail(3), cov_prior.bottomRightCorner<3,3>()); + //FactorBasePtr facV0 = FactorBase::emplace<FactorBlockAbsolute>(featV0, KF0_->getV(), nullptr, false); - KF1_ = problem_->emplaceFrame(KEY, problem_->zeroState(), t1); + KF1_ = problem_->emplaceFrame(KEY, t1, problem_->stateZero()); Cap_ = CaptureBase::emplace<CaptureBase>(KF1_, "BlockDifference", t1); - Eigen::Matrix3d cov = 0.2 * Eigen::Matrix3d::Identity(); - Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "BlockDifference", zero3, cov); } virtual void TearDown() override {} }; +TEST_F(FixtureFactorBlockDifference, CheckFactorType) +{ + Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "BlockDifference", zero3, idty02); + Fac_ = FactorBase::emplace<FactorBlockDifference>(Feat_, Feat_, KF0_->getP(), KF1_->getP()); + ASSERT_EQ(Fac_->getType(), "FactorBlockDifference"); +} + TEST_F(FixtureFactorBlockDifference, EqualP) { - // Feat_->setMeasurement() - FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>( - Feat_, KF0_->getP(), KF1_->getP() - ); + Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "BlockDifference", zero3, idty02); + Fac_ = FactorBase::emplace<FactorBlockDifference>(Feat_, Feat_, KF0_->getP(), KF1_->getP()); // perturbate KF0_->getP()->setState(Vector3d::Random()); @@ -81,14 +87,12 @@ TEST_F(FixtureFactorBlockDifference, EqualP) std::string report = ceres_manager_->solve(SolverManager::ReportVerbosity::BRIEF); ASSERT_MATRIX_APPROX(KF1_->getP()->getState() - KF0_->getP()->getState(), zero3, 1e-8); - } TEST_F(FixtureFactorBlockDifference, EqualV) { - FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>( - Feat_, KF0_->getV(), KF1_->getV() - ); + Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "BlockDifference", zero3, idty02); + Fac_ = FactorBase::emplace<FactorBlockDifference>(Feat_, Feat_, KF0_->getV(), KF1_->getV()); // perturbate KF0_->getV()->setState(Vector3d::Random()); @@ -97,18 +101,14 @@ TEST_F(FixtureFactorBlockDifference, EqualV) std::string report = ceres_manager_->solve(SolverManager::ReportVerbosity::BRIEF); ASSERT_MATRIX_APPROX(KF1_->getV()->getState() - KF0_->getV()->getState(), zero3, 1e-8); - } - - TEST_F(FixtureFactorBlockDifference, DiffP) { Vector3d diff = Vector3d::Random(); - Feat_->setMeasurement(diff); - FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>( - Feat_, KF0_->getP(), KF1_->getP() - ); + + Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "BlockDifference", diff, idty02); + Fac_ = FactorBase::emplace<FactorBlockDifference>(Feat_, Feat_, KF0_->getP(), KF1_->getP()); // perturbate KF0_->getP()->setState(Vector3d::Random()); @@ -117,18 +117,14 @@ TEST_F(FixtureFactorBlockDifference, DiffP) std::string report = ceres_manager_->solve(SolverManager::ReportVerbosity::BRIEF); ASSERT_MATRIX_APPROX(KF1_->getP()->getState() - KF0_->getP()->getState(), diff, 1e-8); - } - - TEST_F(FixtureFactorBlockDifference, DiffV) { Vector3d diff = Vector3d::Random(); - Feat_->setMeasurement(diff); - FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>( - Feat_, KF0_->getV(), KF1_->getV() - ); + + Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "BlockDifference", diff, idty02); + Fac_ = FactorBase::emplace<FactorBlockDifference>(Feat_, Feat_, KF0_->getV(), KF1_->getV()); // perturbate KF0_->getV()->setState(Vector3d::Random()); @@ -145,13 +141,11 @@ TEST_F(FixtureFactorBlockDifference, DiffPx) // Vector3d diff = Vector3d::Random(); Vector1d diff; diff << 1; // measurement still of the same size as the constrained state Matrix1d cov_diff = 1e-4 * Matrix1d::Identity(); // measurement still of the same size as the constrained state - Feat_->setMeasurement(diff); - Feat_->setMeasurementCovariance(cov_diff); - FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>( - Feat_, KF0_->getP(), KF1_->getP(), - nullptr, nullptr, nullptr, nullptr, - 0, 1, 0, 1 - ); + + Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "BlockDifference", diff, cov_diff); + Fac_ = FactorBase::emplace<FactorBlockDifference>(Feat_, Feat_, KF0_->getP(), KF1_->getP(), + nullptr, nullptr, nullptr, nullptr, + 0, 1, 0, 1); // perturbate KF0_->getP()->setState(Vector3d::Random()); @@ -162,21 +156,16 @@ TEST_F(FixtureFactorBlockDifference, DiffPx) ASSERT_MATRIX_APPROX(KF1_->getP()->getState().head<1>() - KF0_->getP()->getState().head<1>(), diff.head<1>(), 1e-8); } - - - TEST_F(FixtureFactorBlockDifference, DiffPxy) { // Vector3d diff = Vector3d::Random(); Vector2d diff; diff << 1, 2; // measurement still of the same size as the constrained state Matrix2d cov_diff = 1e-4 * Matrix2d::Identity(); // measurement still of the same size as the constrained state - Feat_->setMeasurement(diff); - Feat_->setMeasurementCovariance(cov_diff); - FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>( - Feat_, KF0_->getP(), KF1_->getP(), - nullptr, nullptr, nullptr, nullptr, - 0, 2, 0, 2 - ); + + Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "BlockDifference", diff, cov_diff); + Fac_ = FactorBase::emplace<FactorBlockDifference>(Feat_, Feat_, KF0_->getP(), KF1_->getP(), + nullptr, nullptr, nullptr, nullptr, + 0, 2, 0, 2); // perturbate KF0_->getP()->setState(Vector3d::Random()); @@ -192,13 +181,11 @@ TEST_F(FixtureFactorBlockDifference, DiffPyz) // Vector3d diff = Vector3d::Random(); Vector2d diff; diff << 1, 2; // measurement still of the same size as the constrained state Matrix2d cov_diff = 1e-4 * Matrix2d::Identity(); // measurement still of the same size as the constrained state - Feat_->setMeasurement(diff); - Feat_->setMeasurementCovariance(cov_diff); - FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>( - Feat_, KF0_->getP(), KF1_->getP(), - nullptr, nullptr, nullptr, nullptr, - 1, 2, 1, 2 - ); + + Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "BlockDifference", diff, cov_diff); + Fac_ = FactorBase::emplace<FactorBlockDifference>(Feat_, Feat_, KF0_->getP(), KF1_->getP(), + nullptr, nullptr, nullptr, nullptr, + 1, 2, 1, 2); // perturbate KF0_->getP()->setState(Vector3d::Random()); diff --git a/test/gtest_factor_diff_drive.cpp b/test/gtest_factor_diff_drive.cpp index 67ef0974061dfa88339bbf3be362794ec6af060d..0413c21cb2c30bb91b1a03dabac0b595d1843349 100644 --- a/test/gtest_factor_diff_drive.cpp +++ b/test/gtest_factor_diff_drive.cpp @@ -25,7 +25,7 @@ class ProcessorDiffDrivePublic : public ProcessorDiffDrive { using Base = ProcessorDiffDrive; public: - ProcessorDiffDrivePublic(ProcessorParamsDiffDrivePtr _params_motion) : + ProcessorDiffDrivePublic(ParamsProcessorDiffDrivePtr _params_motion) : ProcessorDiffDrive(_params_motion) { // @@ -63,12 +63,9 @@ class ProcessorDiffDrivePublic : public ProcessorDiffDrive Base::deltaPlusDelta(_delta1, _delta2, _dt2, _delta1_plus_delta2, _jacobian1, _jacobian2); } - virtual void statePlusDelta(const Eigen::VectorXd& _x, - const Eigen::VectorXd& _delta, - const double _dt, - Eigen::VectorXd& _x_plus_delta) const + virtual VectorXd getCalibration (const CaptureBasePtr _capture) const { - Base::statePlusDelta(_x, _delta, _dt, _x_plus_delta); + return Base::getCalibration(_capture); } virtual Eigen::VectorXd deltaZero() const @@ -99,7 +96,7 @@ class ProcessorDiffDrivePublic : public ProcessorDiffDrive return Base::emplaceFactor(_feature_motion, _capture_origin); } - ProcessorParamsDiffDrivePtr getParams() + ParamsProcessorDiffDrivePtr getParams() { return params_prc_diff_drv_selfcal_; } @@ -121,7 +118,7 @@ class FactorDiffDriveTest : public testing::Test TrajectoryBasePtr trajectory; ParamsSensorDiffDrivePtr intr; SensorDiffDrivePtr sensor; - ProcessorParamsDiffDrivePtr params; + ParamsProcessorDiffDrivePtr params; ProcessorDiffDrivePublicPtr processor; FrameBasePtr F0, F1; CaptureMotionPtr C0, C1; @@ -154,7 +151,7 @@ class FactorDiffDriveTest : public testing::Test calib = sensor->getIntrinsic()->getState(); // params and processor - params = std::make_shared<ProcessorParamsDiffDrive>(); + params = std::make_shared<ParamsProcessorDiffDrive>(); params->angle_turned = 1; params->dist_traveled = 2; params->max_buff_length = 3; @@ -163,16 +160,16 @@ class FactorDiffDriveTest : public testing::Test // frames F0 = FrameBase::emplace<FrameBase>(trajectory, - "PO", - 2, KEY, 0.0, - Vector3d(0,0,0)); - F1 = FrameBase::emplace<FrameBase>(trajectory, "PO", 2, + Vector3d(0,0,0)); + F1 = FrameBase::emplace<FrameBase>(trajectory, KEY, 1.0, + "PO", + 2, Vector3d(1,0,0)); // captures @@ -201,7 +198,7 @@ class FactorDiffDriveTest : public testing::Test "FeatureDiffDrive", delta1, delta1_cov, - C0->getCalibration(), + processor->getCalibration(C0), Matrix3d::Identity()); // TODO Jacobian? @@ -290,7 +287,15 @@ TEST_F(FactorDiffDriveTest, residual_right_turn_90_deg) ASSERT_MATRIX_APPROX(delta2, Vector3d(1.5, -1.5, -M_PI_2), 1e-6); - f1->setMeasurement(delta2); + // modify f1 measurement (remove and emplace - FeatureBase::setMeasurement is private) + f1 ->remove(); + f1 = FeatureBase::emplace<FeatureMotion>(C1, + "FeatureDiffDrive", + delta2, + delta1_cov, + processor->getCalibration(C0), + Matrix3d::Identity()); // TODO Jacobian? + F1->setState(Vector3d(1.5, -1.5, -M_PI_2)); // wolf: emplace @@ -317,7 +322,15 @@ TEST_F(FactorDiffDriveTest, solve_F1) delta1 .setZero(); processor->deltaPlusDelta(delta1, delta, dt, delta2); // 90deg - f1->setMeasurement(delta2); + // modify f1 measurement (remove and emplace - FeatureBase::setMeasurement is private) + f1 ->remove(); + f1 = FeatureBase::emplace<FeatureMotion>(C1, + "FeatureDiffDrive", + delta2, + delta1_cov, + processor->getCalibration(C0), + Matrix3d::Identity()); // TODO Jacobian? + F1->setState(Vector3d(1.5, -1.5, -M_PI_2)); // wolf: emplace @@ -328,14 +341,14 @@ TEST_F(FactorDiffDriveTest, solve_F1) // Fix all but F1 ; perturb F1 ; solve ; print and assert values of F1 F0->fix(); sensor->fixIntrinsics(); - F1->setState(F1->getState() + Vector3d::Random() * 0.1); + F1->perturb(0.1); std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); // WOLF_TRACE("\n", report); problem->print(1,0,1,1); - ASSERT_MATRIX_APPROX(F1->getState(), delta, 1e-6); + ASSERT_MATRIX_APPROX(F1->getStateVector(), delta, 1e-6); } @@ -355,7 +368,15 @@ TEST_F(FactorDiffDriveTest, solve_sensor_intrinsics) delta1 .setZero(); processor->deltaPlusDelta(delta1, delta, dt, delta2); // 90deg - f1->setMeasurement(delta2); + // modify f1 measurement (remove and emplace - FeatureBase::setMeasurement is private) + f1 ->remove(); + f1 = FeatureBase::emplace<FeatureMotion>(C1, + "FeatureDiffDrive", + delta2, + delta1_cov, + processor->getCalibration(C0), + Matrix3d::Identity()); // TODO Jacobian? + F1->setState(Vector3d(1.5, -1.5, -M_PI_2)); // wolf: emplace @@ -367,7 +388,7 @@ TEST_F(FactorDiffDriveTest, solve_sensor_intrinsics) F0->fix(); F1->fix(); sensor->unfixIntrinsics(); - sensor->getIntrinsic()->setState(calib + Vector3d::Random() * 0.1); + sensor->perturb(0.1); std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); @@ -432,7 +453,7 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics_gt) Vector3d calib_gt(1,1,1); // params and processor - ProcessorParamsDiffDrivePtr params = std::make_shared<ProcessorParamsDiffDrive>(); + ParamsProcessorDiffDrivePtr params = std::make_shared<ParamsProcessorDiffDrive>(); params->angle_turned = 99; params->dist_traveled = 99; params->max_buff_length = 99; @@ -441,15 +462,17 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics_gt) auto prc = problem->installProcessor("ProcessorDiffDrive", "diff drive", sensor, params); auto processor = std::static_pointer_cast<ProcessorDiffDrivePublic>(prc); - TimeStamp t(0.0); double dt = 1.0; - Vector3d x0(0,0,0); + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); Vector3d x1(1.5, -1.5, -M_PI/2.0); Vector3d x2(3.0, -3.0, 0.0); - Matrix3d P0; P0.setIdentity(); + // Matrix3d P0; P0.setIdentity(); + VectorComposite s0(Vector3d(0.1,0.1,0.1), "PO", {2,1}); - auto F0 = problem->setPrior(x0, P0, t, 0.1); + // set prior at t=0 and processor origin + auto F0 = problem->setPriorFactor(x0, s0, t, 0.1); + processor->setOrigin(F0); // right turn 90 deg in N steps --> ends up in (1.5, -1.5, -pi/2) int N = 6; @@ -459,7 +482,7 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics_gt) data(0) = 0.50*intr->ticks_per_wheel_revolution / N; data(1) = 0.25*intr->ticks_per_wheel_revolution / N; - auto C = std::make_shared<CaptureDiffDrive>(t, sensor, data, data_cov, F0->getCaptureList().front()); + auto C = std::make_shared<CaptureDiffDrive>(t, sensor, data, data_cov, nullptr); for (int n = 0; n < N; n++) { @@ -481,29 +504,28 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics_gt) auto F2 = problem->getLastKeyFrame(); - // Fix boundaries F0->fix(); F2->fix(); // Perturb S - Vector3d calib_pert = calib_gt + Vector3d::Random()*0.2; - sensor->getIntrinsic()->setState(calib_pert); + sensor->getIntrinsic()->perturb(0.2); + Vector3d calib_pert = sensor->getIntrinsic()->getState(); WOLF_TRACE("\n ========== SOLVE ========="); std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); WOLF_TRACE("\n", report); - WOLF_TRACE("x1 : ", problem->getState(N*dt).transpose()); - WOLF_TRACE("x2 : ", F2->getState().transpose()); + WOLF_TRACE("x1 : ", problem->getState(N*dt).vector("PO").transpose()); + WOLF_TRACE("x2 : ", F2->getStateVector().transpose()); WOLF_TRACE("calib_preint : ", calib_preint.transpose()); WOLF_TRACE("calib_pert : ", calib_pert.transpose()); WOLF_TRACE("calib_est : ", sensor->getIntrinsic()->getState().transpose()); WOLF_TRACE("calib_gt : ", calib_gt.transpose()); - ASSERT_MATRIX_APPROX(sensor->getIntrinsic()->getState(), calib_gt, 1e-6); - ASSERT_MATRIX_APPROX(problem->getState( N*dt), x1, 1e-6); - ASSERT_MATRIX_APPROX(problem->getState(2*N*dt), x2, 1e-6); + ASSERT_MATRIX_APPROX(sensor->getIntrinsic()->getState() , calib_gt , 1e-6 ); + ASSERT_MATRIX_APPROX(problem->getState( N*dt).vector("PO") , x1 , 1e-6 ); + ASSERT_MATRIX_APPROX(problem->getState(2*N*dt).vector("PO") , x2 , 1e-6 ); std::cout << "\n\n" << std::endl; @@ -564,7 +586,7 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics) Vector3d calib_gt(1.0, 1.0, 1.0); // ground truth calib // params and processor - ProcessorParamsDiffDrivePtr params = std::make_shared<ProcessorParamsDiffDrive>(); + ParamsProcessorDiffDrivePtr params = std::make_shared<ParamsProcessorDiffDrive>(); params->angle_turned = 99; params->dist_traveled = 99; params->max_buff_length = 99; @@ -573,15 +595,18 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics) auto prc = problem->installProcessor("ProcessorDiffDrive", "diff drive", sensor, params); auto processor = std::static_pointer_cast<ProcessorDiffDrivePublic>(prc); - TimeStamp t(0.0); double dt = 1.0; - Vector3d x0(0,0,0); + // Vector3d x0(0,0,0); + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); Vector3d x1(1.5, -1.5, -M_PI/2.0); Vector3d x2(3.0, -3.0, 0.0); - Matrix3d P0; P0.setIdentity(); + // Matrix3d P0; P0.setIdentity(); + VectorComposite s0(Vector3d(1,1,1), "PO", {2,1}); - auto F0 = problem->setPrior(x0, P0, t, 0.1); + // set prior at t=0 and processor origin + auto F0 = problem->setPriorFactor(x0, s0, t, 0.1); + processor->setOrigin(F0); // right turn 90 deg in N steps --> ends up in (1.5, -1.5, -pi/2) int N = 6; @@ -591,7 +616,7 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics) data(0) = 0.50*intr->ticks_per_wheel_revolution / N; data(1) = 0.25*intr->ticks_per_wheel_revolution / N; - auto C = std::make_shared<CaptureDiffDrive>(t, sensor, data, data_cov, F0->getCaptureList().front()); + auto C = std::make_shared<CaptureDiffDrive>(t, sensor, data, data_cov, nullptr); for (int n = 0; n < N; n++) { @@ -615,27 +640,27 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics) auto F2 = problem->getLastKeyFrame(); - F2->setState(x2); // Impose known final state regardless of integrated value. +// VectorComposite x2c(x2, "PO", {2,1}); + F2->setState(x2, "PO"); // Impose known final state regardless of integrated value. // Fix boundaries F0->fix(); F2->fix(); - WOLF_TRACE("\n ========== SOLVE ========="); std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); WOLF_TRACE("\n", report); - WOLF_TRACE("x1 : ", problem->getState(N*dt).transpose()); - WOLF_TRACE("x2 : ", F2->getState().transpose()); + WOLF_TRACE("x1 : ", problem->getState(N*dt).vector("PO").transpose()); + WOLF_TRACE("x2 : ", F2->getStateVector().transpose()); WOLF_TRACE("calib_preint : ", calib_preint.transpose()); WOLF_TRACE("calib_est : ", sensor->getIntrinsic()->getState().transpose()); WOLF_TRACE("calib_GT : ", calib_gt.transpose()); ASSERT_MATRIX_APPROX(sensor->getIntrinsic()->getState(), calib_gt, 1e-2); - ASSERT_MATRIX_APPROX(problem->getState( N*dt), x1, 1e-2); - ASSERT_MATRIX_APPROX(problem->getState(2*N*dt), x2, 1e-6); + ASSERT_MATRIX_APPROX(problem->getState( N*dt).vector("PO"), x1, 1e-2); + ASSERT_MATRIX_APPROX(problem->getState(2*N*dt).vector("PO"), x2, 1e-6); } diff --git a/test/gtest_factor_odom_2d.cpp b/test/gtest_factor_odom_2d.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c0b11e3b428cfbfa99c91c29bffe53ceeeb1d92 --- /dev/null +++ b/test/gtest_factor_odom_2d.cpp @@ -0,0 +1,119 @@ +#include "core/utils/utils_gtest.h" + +#include "core/factor/factor_odom_2d.h" +#include "core/capture/capture_odom_2d.h" +#include "core/math/rotations.h" + +#include "core/ceres_wrapper/ceres_manager.h" + +using namespace Eigen; +using namespace wolf; +using std::cout; +using std::endl; + +// Input odometry data and covariance +Matrix3d data_cov = 0.1*Matrix3d::Identity(); + +// Problem and solver +ProblemPtr problem_ptr = Problem::create("PO", 2); +CeresManager ceres_mgr(problem_ptr); + +// Two frames +FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, TimeStamp(0), Vector3d::Zero()); +FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, TimeStamp(1), Vector3d::Zero()); + +// Capture from frm1 to frm0 +auto cap1 = CaptureBase::emplace<CaptureOdom2d>(frm1, 1, nullptr, Vector3d::Zero(), data_cov); + +TEST(FactorOdom2d, check_tree) +{ + ASSERT_TRUE(problem_ptr->check(0)); +} + +TEST(FactorOdom2d, fix_0_solve) +{ + for (int i = 0; i < 1e3; i++) + { + // Random delta + Vector3d delta = Vector3d::Random() * 10; + pi2pi(delta(2)); + + // Random initial pose + Vector3d x0 = Vector3d::Random() * 10; + pi2pi(x0(2)); + + // x1 groundtruth + Vector3d x1; + x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>(); + x1(2) = pi2pi(x0(2) + delta(2)); + + // Set states + frm0->setState(x0); + frm1->setState(x1); + cap1->setData(delta); + + // feature & factor with delta measurement + auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", delta, data_cov); + FactorBase::emplace<FactorOdom2d>(fea1, fea1, frm0, nullptr, false); + + // Fix frm0, perturb frm1 + frm0->fix(); + frm1->unfix(); + frm1->perturb(5); + + // solve for frm1 + std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); + + ASSERT_POSE2d_APPROX(frm1->getStateVector(), x1, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); + } +} + +TEST(FactorOdom2d, fix_1_solve) +{ + for (int i = 0; i < 1e3; i++) + { + // Random delta + Vector3d delta = Vector3d::Random() * 10; + pi2pi(delta(2)); + + // Random initial pose + Vector3d x0 = Vector3d::Random() * 10; + pi2pi(x0(2)); + + // x1 groundtruth + Vector3d x1; + x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>(); + x1(2) = pi2pi(x0(2) + delta(2)); + + // Set states + frm0->setState(x0); + frm1->setState(x1); + cap1->setData(delta); + + // feature & factor with delta measurement + auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", delta, data_cov); + FactorBase::emplace<FactorOdom2d>(fea1, fea1, frm0, nullptr, false); + + // Fix frm1, perturb frm0 + frm1->fix(); + frm0->unfix(); + frm0->perturb(5); + + // solve for frm0 + std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); + + ASSERT_POSE2d_APPROX(frm0->getStateVector(), x0, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); + } +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/gtest_factor_odom_3d.cpp b/test/gtest_factor_odom_3d.cpp index 1315118016ebe3319a04e07b37d0d8438b714ebe..8001bbe70f25f774a55cf0c834950529934bdb36 100644 --- a/test/gtest_factor_odom_3d.cpp +++ b/test/gtest_factor_odom_3d.cpp @@ -37,11 +37,11 @@ ProblemPtr problem_ptr = Problem::create("PO", 3); CeresManager ceres_mgr(problem_ptr); // Two frames -FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, problem_ptr->zeroState(), TimeStamp(0)); -FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, delta, TimeStamp(1)); +FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, TimeStamp(0), problem_ptr->stateZero()); +FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, TimeStamp(1), delta); // Capture, feature and factor from frm1 to frm0 -auto cap1 = CaptureBase::emplace<CaptureMotion>(frm1, "CaptureOdom3d", 1, nullptr, delta, 7, 6, nullptr); +auto cap1 = CaptureBase::emplace<CaptureMotion>(frm1, "CaptureOdom3d", 1, nullptr, delta, nullptr); auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom3d", delta, data_cov); FactorOdom3dPtr ctr1 = FactorBase::emplace<FactorOdom3d>(fea1, fea1, frm0, nullptr, false); // create and add @@ -68,7 +68,7 @@ TEST(FactorOdom3d, fix_0_solve) // solve for frm1 std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); - ASSERT_MATRIX_APPROX(frm1->getState(), delta, 1e-6); + ASSERT_MATRIX_APPROX(frm1->getStateVector(), delta, 1e-6); } @@ -82,7 +82,7 @@ TEST(FactorOdom3d, fix_1_solve) // solve for frm0 std::string brief_report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); - ASSERT_MATRIX_APPROX(frm0->getState(), problem_ptr->zeroState(), 1e-6); + ASSERT_MATRIX_APPROX(frm0->getStateVector(), problem_ptr->stateZero().vector("PO"), 1e-6); } int main(int argc, char **argv) diff --git a/test/gtest_factor_pose_2d.cpp b/test/gtest_factor_pose_2d.cpp index 5d9cb7f406beef3b95ce1da4add8f2041a20c685..e3107b7a5f976f5626f22016f64f60695e1fc982 100644 --- a/test/gtest_factor_pose_2d.cpp +++ b/test/gtest_factor_pose_2d.cpp @@ -30,10 +30,10 @@ ProblemPtr problem = Problem::create("PO", 2); CeresManager ceres_mgr(problem); // Two frames -FrameBasePtr frm0 = problem->emplaceFrame(KEY, problem->zeroState(), TimeStamp(0)); +FrameBasePtr frm0 = problem->emplaceFrame(KEY, TimeStamp(0), problem->stateZero()); // Capture, feature and factor from frm1 to frm0 -auto cap0 = CaptureBase::emplace<CaptureMotion>(frm0, "CaptureOdom2d", 0, nullptr, pose, 3, 3, nullptr); +auto cap0 = CaptureBase::emplace<CaptureMotion>(frm0, "CaptureOdom2d", 0, nullptr, pose, nullptr); auto fea0 = FeatureBase::emplace<FeatureBase>(cap0, "FeatureOdom2d", pose, data_cov); auto ctr0 = FactorBase::emplace<FactorPose2d>(fea0, fea0, nullptr, false); @@ -59,7 +59,7 @@ TEST(FactorPose2d, solve) // solve for frm0 std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::QUIET); // 0: nothing, 1: BriefReport, 2: FullReport - ASSERT_MATRIX_APPROX(frm0->getState(), pose, 1e-6); + ASSERT_MATRIX_APPROX(frm0->getStateVector(), pose, 1e-6); } diff --git a/test/gtest_factor_pose_3d.cpp b/test/gtest_factor_pose_3d.cpp index 9eeb5dfc14bbc6b185c598a8a17489a44794206e..d57aee85c27b47e41f9610040c3b8bcceb57ad35 100644 --- a/test/gtest_factor_pose_3d.cpp +++ b/test/gtest_factor_pose_3d.cpp @@ -36,10 +36,10 @@ ProblemPtr problem = Problem::create("PO", 3); CeresManager ceres_mgr(problem); // Two frames -FrameBasePtr frm0 = problem->emplaceFrame(KEY, problem->zeroState(), TimeStamp(0)); +FrameBasePtr frm0 = problem->emplaceFrame(KEY, 0, problem->stateZero() ); // Capture, feature and factor -auto cap0 = CaptureBase::emplace<CaptureMotion>(frm0, "CaptureOdom3d", 0, nullptr, pose7, 7, 6, nullptr); +auto cap0 = CaptureBase::emplace<CaptureMotion>(frm0, "CaptureOdom3d", 0, nullptr, pose7, nullptr); auto fea0 = FeatureBase::emplace<FeatureBase>(cap0, "FeatureOdom3d", pose7, data_cov); FactorPose3dPtr ctr0 = FactorBase::emplace<FactorPose3d>(fea0, fea0, nullptr, false); @@ -65,7 +65,7 @@ TEST(FactorPose3d, solve) // solve for frm0 std::string brief_report = ceres_mgr.solve(SolverManager::ReportVerbosity::FULL); - ASSERT_MATRIX_APPROX(frm0->getState(), pose7, 1e-6); + ASSERT_MATRIX_APPROX(frm0->getStateVector(), pose7, 1e-6); } diff --git a/test/gtest_factor_relative_2d_analytic.cpp b/test/gtest_factor_relative_2d_analytic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c461bbb94743c9ee8b3665650fb00686d979fc20 --- /dev/null +++ b/test/gtest_factor_relative_2d_analytic.cpp @@ -0,0 +1,119 @@ +#include "core/utils/utils_gtest.h" + +#include "core/factor/factor_relative_2d_analytic.h" +#include "core/capture/capture_odom_2d.h" +#include "core/math/rotations.h" + +#include "core/ceres_wrapper/ceres_manager.h" + +using namespace Eigen; +using namespace wolf; +using std::cout; +using std::endl; + +// Input odometry data and covariance +Matrix3d data_cov = 0.1*Matrix3d::Identity(); + +// Problem and solver +ProblemPtr problem_ptr = Problem::create("PO", 2); +CeresManager ceres_mgr(problem_ptr); + +// Two frames +FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, 0.0, Vector3d::Zero()); +FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, 1.0, Vector3d::Zero()); + +// Capture from frm1 to frm0 +auto cap1 = CaptureBase::emplace<CaptureOdom2d>(frm1, 1, nullptr, Vector3d::Zero(), data_cov); + +TEST(FactorRelative2dAnalytic, check_tree) +{ + ASSERT_TRUE(problem_ptr->check(0)); +} + +TEST(FactorRelative2dAnalytic, fix_0_solve) +{ + for (int i = 0; i < 1e3; i++) + { + // Random delta + Vector3d delta = Vector3d::Random() * 10; + pi2pi(delta(2)); + + // Random initial pose + Vector3d x0 = Vector3d::Random() * 10; + pi2pi(x0(2)); + + // x1 groundtruth + Vector3d x1; + x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>(); + x1(2) = pi2pi(x0(2) + delta(2)); + + // Set states and measurement + frm0->setState(x0); + frm1->setState(x1); + cap1->setData(delta); + + // feature & factor with delta measurement + auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", delta, data_cov); + FactorBase::emplace<FactorRelative2dAnalytic>(fea1, "odom2d", fea1, frm0, nullptr, false); + + // Fix frm0, perturb frm1 + frm0->fix(); + frm1->unfix(); + frm1->perturb(5); + + // solve for frm1 + std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); + + ASSERT_POSE2d_APPROX(frm1->getStateVector(), x1, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); + } +} + +TEST(FactorRelative2dAnalytic, fix_1_solve) +{ + for (int i = 0; i < 1e3; i++) + { + // Random delta + Vector3d delta = Vector3d::Random() * 10; + pi2pi(delta(2)); + + // Random initial pose + Vector3d x0 = Vector3d::Random() * 10; + pi2pi(x0(2)); + + // x1 groundtruth + Vector3d x1; + x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>(); + x1(2) = pi2pi(x0(2) + delta(2)); + + // Set states and measurement + frm0->setState(x0); + frm1->setState(x1); + cap1->setData(delta); + + // feature & factor with delta measurement + auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", delta, data_cov); + FactorBase::emplace<FactorRelative2dAnalytic>(fea1, "odom2d", fea1, frm0, nullptr, false); + + // Fix frm1, perturb frm0 + frm1->fix(); + frm0->unfix(); + frm0->perturb(5); + + // solve for frm0 + std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); + + ASSERT_POSE2d_APPROX(frm0->getStateVector(), x0, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); + } +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/gtest_factor_relative_pose_2d_with_extrinsics.cpp b/test/gtest_factor_relative_pose_2d_with_extrinsics.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9ad5bbe208d981a4ca69aa3eab8eac806f62e14 --- /dev/null +++ b/test/gtest_factor_relative_pose_2d_with_extrinsics.cpp @@ -0,0 +1,239 @@ +#include "core/utils/utils_gtest.h" + +#include "core/factor/factor_relative_pose_2d_with_extrinsics.h" +#include "core/capture/capture_odom_2d.h" +#include "core/sensor/sensor_odom_2d.h" +#include "core/processor/processor_odom_2d.h" +#include "core/math/rotations.h" + +#include "core/ceres_wrapper/ceres_manager.h" + +using namespace Eigen; +using namespace wolf; +using std::cout; +using std::endl; + +std::string wolf_root = _WOLF_ROOT_DIR; + +// Input odometry data and covariance +Matrix3d data_cov = 0.1*Matrix3d::Identity(); + +// Problem and solver +ProblemPtr problem_ptr = Problem::create("PO", 2); +CeresManager ceres_mgr(problem_ptr); + +// Sensor +auto sensor_odom2d = problem_ptr->installSensor("SensorOdom2d", "odom", Vector3d(0,0,0), wolf_root + "/test/yaml/sensor_odom_2d.yaml"); +auto processor_odom2d = problem_ptr->installProcessor("ProcessorOdom2d", "odom", sensor_odom2d, std::make_shared<ParamsProcessorOdom2d>()); + +// Two frames +FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, 0, Vector3d::Zero() ); +FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, 1, Vector3d::Zero() ); + +// Capture from frm1 to frm0 +auto cap1 = CaptureBase::emplace<CaptureOdom2d>(frm1, 1, sensor_odom2d, Vector3d::Zero(), data_cov); + +TEST(FactorRelativePose2dWithExtrinsics, check_tree) +{ + ASSERT_TRUE(problem_ptr->check(0)); +} + +TEST(FactorRelativePose2dWithExtrinsics, fix_0_solve) +{ + for (int i = 0; i < 1e3; i++) + { + // Random delta + Vector3d delta = Vector3d::Random() * 10; + pi2pi(delta(2)); + + // Random initial pose + Vector3d x0 = Vector3d::Random() * 10; + pi2pi(x0(2)); + + // Random extrinsics + Vector3d xs = Vector3d::Random(); + pi2pi(xs(2)); + + // x1 groundtruth + Vector3d x1; + x1(2) = pi2pi(x0(2) + delta(2)); + x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * (xs.head<2>() + Rotation2Dd(xs(2)) * delta.head<2>()) - Rotation2Dd(x1(2)) * xs.head<2>(); + + // Set states + frm0->setState(x0); + frm1->setState(x1); + cap1->setData(delta); + sensor_odom2d->setState(xs); + + // feature & factor with delta measurement + auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", delta, data_cov); + FactorBase::emplace<FactorRelativePose2dWithExtrinsics>(fea1, fea1, frm0, processor_odom2d, false); // create and add + + // Perturb frm1, fix the rest + frm0->fix(); + frm1->unfix(); + sensor_odom2d->getP()->fix(); + sensor_odom2d->getO()->fix(); + frm1->perturb(5); + + // solve for frm1 + std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); + + ASSERT_POSE2d_APPROX(frm1->getStateVector(), x1, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); + } +} + +TEST(FactorRelativePose2dWithExtrinsics, fix_1_solve) +{ + for (int i = 0; i < 1e3; i++) + { + // Random delta + Vector3d delta = Vector3d::Random() * 10; + pi2pi(delta(2)); + + // Random initial pose + Vector3d x0 = Vector3d::Random() * 10; + pi2pi(x0(2)); + + // Random extrinsics + Vector3d xs = Vector3d::Random(); + pi2pi(xs(2)); + + // x1 groundtruth + Vector3d x1; + x1(2) = pi2pi(x0(2) + delta(2)); + x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * (xs.head<2>() + Rotation2Dd(xs(2)) * delta.head<2>()) - Rotation2Dd(x1(2)) * xs.head<2>(); + + // Set states + frm0->setState(x0); + frm1->setState(x1); + cap1->setData(delta); + sensor_odom2d->setState(xs); + + // feature & factor with delta measurement + auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", delta, data_cov); + FactorBase::emplace<FactorRelativePose2dWithExtrinsics>(fea1, fea1, frm0, processor_odom2d, false); // create and add + + // Perturb frm0, fix the rest + frm1->fix(); + frm0->unfix(); + sensor_odom2d->getP()->fix(); + sensor_odom2d->getO()->fix(); + frm0->perturb(5); + + // solve for frm0 + std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); + + ASSERT_POSE2d_APPROX(frm0->getStateVector(), x0, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); + } +} + +TEST(FactorRelativePose2dWithExtrinsics, extrinsics_p_solve) +{ + for (int i = 0; i < 1e3; i++) + { + // Random delta + Vector3d delta = Vector3d::Random() * 10; + pi2pi(delta(2)); + + // Random initial pose + Vector3d x0 = Vector3d::Random() * 10; + pi2pi(x0(2)); + + // Random extrinsics + Vector3d xs = Vector3d::Random(); + pi2pi(xs(2)); + + // x1 groundtruth + Vector3d x1; + x1(2) = pi2pi(x0(2) + delta(2)); + x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * (xs.head<2>() + Rotation2Dd(xs(2)) * delta.head<2>()) - Rotation2Dd(x1(2)) * xs.head<2>(); + + // Set states + frm0->setState(x0); + frm1->setState(x1); + cap1->setData(delta); + sensor_odom2d->setState(xs); + + // feature & factor with delta measurement + auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", delta, data_cov); + FactorBase::emplace<FactorRelativePose2dWithExtrinsics>(fea1, fea1, frm0, processor_odom2d, false); // create and add + + // Perturb sensor P, fix the rest + frm1->fix(); + frm0->fix(); + sensor_odom2d->getP()->unfix(); + sensor_odom2d->getO()->fix(); + sensor_odom2d->getP()->perturb(1); + + // solve for frm0 + std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); + + ASSERT_POSE2d_APPROX(sensor_odom2d->getStateVector(), xs, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); + } +} + +TEST(FactorRelativePose2dWithExtrinsics, extrinsics_o_solve) +{ + for (int i = 0; i < 1e3; i++) + { + // Random delta + Vector3d delta = Vector3d::Random() * 10; + pi2pi(delta(2)); + + // Random initial pose + Vector3d x0 = Vector3d::Random() * 10; + pi2pi(x0(2)); + + // Random extrinsics + Vector3d xs = Vector3d::Random(); + pi2pi(xs(2)); + + // x1 groundtruth + Vector3d x1; + x1(2) = pi2pi(x0(2) + delta(2)); + x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * (xs.head<2>() + Rotation2Dd(xs(2)) * delta.head<2>()) - Rotation2Dd(x1(2)) * xs.head<2>(); + + // Set states + frm0->setState(x0); + frm1->setState(x1); + cap1->setData(delta); + sensor_odom2d->setState(xs); + + // feature & factor with delta measurement + auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", delta, data_cov); + FactorBase::emplace<FactorRelativePose2dWithExtrinsics>(fea1, fea1, frm0, processor_odom2d, false); // create and add + + // Perturb sensor O, fix the rest + frm1->fix(); + frm0->fix(); + sensor_odom2d->getP()->fix(); + sensor_odom2d->getO()->unfix(); + sensor_odom2d->getO()->perturb(.2); + + //std::cout << "Sensor O (perturbed): " << sensor_odom2d->getO()->getState().transpose() << std::endl; + + // solve for frm0 + std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); + + ASSERT_POSE2d_APPROX(sensor_odom2d->getStateVector(), xs, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); + } +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/gtest_factory_state_block.cpp b/test/gtest_factory_state_block.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fbded073c2e9a226c0f66b1feb34388bd5c06dfc --- /dev/null +++ b/test/gtest_factory_state_block.cpp @@ -0,0 +1,157 @@ +/* + * gtest_factory_state_block.cpp + * + * Created on: Apr 28, 2020 + * Author: jsola + */ + +#include "core/common/wolf.h" +#include "core/state_block/factory_state_block.h" +#include "core/sensor/factory_sensor.h" + +#include "core/utils/utils_gtest.h" +#include "core/utils/logging.h" + +using namespace wolf; + +/* +// You may use this to make some methods of Foo public +WOLF_PTR_TYPEDEFS(FooPublic); +class FooPublic : public Foo +{ + // You may use this to make some methods of Foo public +} + +class TestInit : public testing::Test +{ + public: + // You may use this to initialize stuff + // Combine it with TEST_F(FooTest, testName) { } + void SetUp() override + { + // Init all you want here + // e.g. FooPublic foo; + } + void TearDown() override {} // you can delete this if unused +}; + +TEST_F(TestInit, testName) +{ + // Use class TestInit +} +*/ + +TEST(FactoryStateBlock, get_getClass) +{ + const auto& f = FactoryStateBlock::get(); + + const std::string& s = f.getClass(); + + ASSERT_EQ(s, "FactoryStateBlock"); +} + +TEST(FactoryStateBlock, creator_default) +{ + auto sbp = FactoryStateBlock::get().create("P", Eigen::Vector3d(1,2,3), false); + auto sbv = FactoryStateBlock::get().create("V", Eigen::Vector2d(4,5), false); + auto sbw = FactoryStateBlock::get().create("W", Eigen::Vector1d(6), false); + + ASSERT_MATRIX_APPROX(Eigen::Vector3d(1,2,3) , sbp->getState(), 1e-20); + ASSERT_MATRIX_APPROX(Eigen::Vector2d(4,5) , sbv->getState(), 1e-20); + ASSERT_MATRIX_APPROX(Eigen::Vector1d(6) , sbw->getState(), 1e-20); + + ASSERT_FALSE(sbp->hasLocalParametrization()); + ASSERT_FALSE(sbv->hasLocalParametrization()); + ASSERT_FALSE(sbw->hasLocalParametrization()); +} + +TEST(FactoryStateBlock, creator_StateBlock) +{ + auto sbp = FactoryStateBlock::get().create("StateBlock", Eigen::Vector3d(1,2,3), false); + auto sbv = FactoryStateBlock::get().create("StateBlock", Eigen::Vector2d(4,5), true); + auto sbw = FactoryStateBlock::get().create("StateBlock", Eigen::Vector1d(6), false); + + ASSERT_MATRIX_APPROX(Eigen::Vector3d(1,2,3) , sbp->getState(), 1e-20); + ASSERT_MATRIX_APPROX(Eigen::Vector2d(4,5) , sbv->getState(), 1e-20); + ASSERT_MATRIX_APPROX(Eigen::Vector1d(6) , sbw->getState(), 1e-20); + + ASSERT_FALSE(sbp->isFixed()); + ASSERT_TRUE (sbv->isFixed()); + ASSERT_FALSE(sbw->isFixed()); + + ASSERT_FALSE(sbp->hasLocalParametrization()); + ASSERT_FALSE(sbv->hasLocalParametrization()); + ASSERT_FALSE(sbw->hasLocalParametrization()); +} + +TEST(FactoryStateBlock, creator_Quaternion) +{ + auto sbq = FactoryStateBlock::get().create("StateQuaternion", Eigen::Vector4d(1,2,3,4), false); + + ASSERT_EQ(sbq->getSize() , 4); + ASSERT_EQ(sbq->getLocalSize(), 3); + ASSERT_TRUE(sbq->hasLocalParametrization()); +} + +TEST(FactoryStateBlock, creator_Angle) +{ + auto sba = FactoryStateBlock::get().create("StateAngle", Eigen::Vector1d(1), false); + + ASSERT_EQ(sba->getSize() , 1); + ASSERT_EQ(sba->getLocalSize(), 1); + ASSERT_TRUE(sba->hasLocalParametrization()); +} + +TEST(FactoryStateBlock, creator_Homogeneous3d) +{ + auto sbh = FactoryStateBlock::get().create("StateHomogeneous3d", Eigen::Vector4d(1,2,3,4), false); + + ASSERT_EQ(sbh->getSize() , 4); + ASSERT_EQ(sbh->getLocalSize(), 3); + ASSERT_TRUE(sbh->hasLocalParametrization()); +} + +TEST(FactoryStateBlock, creator_H) +{ + auto sbh = FactoryStateBlock::get().create("H", Eigen::Vector4d(1,2,3,4), false); + + ASSERT_EQ(sbh->getSize() , 4); + ASSERT_EQ(sbh->getLocalSize(), 3); + ASSERT_TRUE(sbh->hasLocalParametrization()); +} + +TEST(FactoryStateBlock, creator_O_is_quaternion) +{ + auto sbq = FactoryStateBlock::get().create("O", Eigen::Vector4d(1,2,3,4), false); + + ASSERT_EQ(sbq->getSize() , 4); + ASSERT_EQ(sbq->getLocalSize(), 3); + ASSERT_TRUE(sbq->hasLocalParametrization()); +} + +TEST(FactoryStateBlock, creator_O_is_angle) +{ + auto sba = FactoryStateBlock::get().create("O", Eigen::Vector1d(1), false); + + ASSERT_EQ(sba->getSize() , 1); + ASSERT_EQ(sba->getLocalSize(), 1); + ASSERT_TRUE(sba->hasLocalParametrization()); +} + +TEST(FactoryStateBlock, creator_O_is_wrong_size) +{ + ASSERT_THROW(auto sba = FactoryStateBlock::get().create("O", Eigen::Vector2d(1,2), false) , std::length_error); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + // restrict to a group of tests only + //::testing::GTEST_FLAG(filter) = "TestInit.*"; + + // restrict to this test only + //::testing::GTEST_FLAG(filter) = "TestInit.testName"; + + return RUN_ALL_TESTS(); +} diff --git a/test/gtest_feature_base.cpp b/test/gtest_feature_base.cpp index 2824fe179096eaca65136b5fadb31b4053bd99cc..bbb978af9c69260bb409ee28e0c9da88214609f5 100644 --- a/test/gtest_feature_base.cpp +++ b/test/gtest_feature_base.cpp @@ -12,7 +12,7 @@ using namespace wolf; using namespace Eigen; -TEST(FeatureBase, Constructor) +TEST(FeatureBase, ConstructorCov) { Vector3d m; m << 1,2,3; Matrix3d M; M.setRandom(); M = M*M.transpose(); @@ -29,7 +29,7 @@ TEST(FeatureBase, Constructor) ASSERT_MATRIX_APPROX(f->getMeasurementSquareRootInformationUpper(), U, 1e-6); } -TEST(FeatureBase, SetMeasurement) +TEST(FeatureBase, ConstructorInfo) { Vector3d m; m << 1,2,3; Matrix3d M; M.setRandom(); M = M*M.transpose(); @@ -38,26 +38,9 @@ TEST(FeatureBase, SetMeasurement) Eigen::MatrixXd U = llt_of_info.matrixU(); Eigen::MatrixXd L = llt_of_info.matrixL(); - FeatureBasePtr f(std::make_shared<FeatureBase>("DUMMY", Vector3d::Zero(), Matrix3d::Identity())); - - f->setMeasurement(m); + FeatureBasePtr f(std::make_shared<FeatureBase>("DUMMY", m, I, FeatureBase::UncertaintyType::UNCERTAINTY_IS_INFO)); ASSERT_MATRIX_APPROX(f->getMeasurement(), m, 1e-6); -} - -TEST(FeatureBase, SetMeasurementCovariance) -{ - Vector3d m; m << 1,2,3; - Matrix3d M; M.setRandom(); M = M*M.transpose(); - Matrix3d I = M.inverse(); - Eigen::LLT<Eigen::MatrixXd> llt_of_info(I); // compute the Cholesky decomposition of A - Eigen::MatrixXd U = llt_of_info.matrixU(); - Eigen::MatrixXd L = llt_of_info.matrixL(); - - FeatureBasePtr f(std::make_shared<FeatureBase>("DUMMY", Vector3d::Zero(), Matrix3d::Identity())); - - f->setMeasurementCovariance(M); - ASSERT_MATRIX_APPROX(f->getMeasurementCovariance(), M, 1e-6); ASSERT_MATRIX_APPROX(f->getMeasurementSquareRootInformationUpper().transpose() * f->getMeasurementSquareRootInformationUpper(), U.transpose()*U, 1e-6); ASSERT_MATRIX_APPROX(f->getMeasurementSquareRootInformationUpper(), U, 1e-6); diff --git a/test/gtest_frame_base.cpp b/test/gtest_frame_base.cpp index 77fa1ace2c4bf876b0c318fe79dc476688e92af0..9d1368d3b673bb1d00baf11c8100273cbc813d1d 100644 --- a/test/gtest_frame_base.cpp +++ b/test/gtest_frame_base.cpp @@ -22,7 +22,7 @@ using namespace wolf; TEST(FrameBase, GettersAndSetters) { - FrameBasePtr F = make_shared<FrameBase>(1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); + FrameBasePtr F = make_shared<FrameBase>(NON_ESTIMATED, 1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); // getters ASSERT_EQ(F->id(), (unsigned int) 1); @@ -37,7 +37,7 @@ TEST(FrameBase, GettersAndSetters) TEST(FrameBase, StateBlocks) { - FrameBasePtr F = make_shared<FrameBase>(1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); + FrameBasePtr F = make_shared<FrameBase>(NON_ESTIMATED, 1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); ASSERT_EQ(F->getStateBlockMap().size(),(unsigned int) 2); ASSERT_EQ(F->getP()->getState().size(),(unsigned int) 2); @@ -47,7 +47,7 @@ TEST(FrameBase, StateBlocks) TEST(FrameBase, LinksBasic) { - FrameBasePtr F = make_shared<FrameBase>(1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); + FrameBasePtr F = make_shared<FrameBase>(NON_ESTIMATED, 1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); ASSERT_FALSE(F->getTrajectory()); ASSERT_FALSE(F->getProblem()); @@ -69,10 +69,15 @@ TEST(FrameBase, LinksToTree) intrinsics_odo.k_disp_to_disp = 1; intrinsics_odo.k_rot_to_rot = 1; auto S = SensorBase::emplace<SensorOdom2d>(P->getHardware(), Vector3d::Zero(), intrinsics_odo); - auto F1 = FrameBase::emplace<FrameBase>(T, 1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); - auto F2 = FrameBase::emplace<FrameBase>(T, 1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); - auto C = CaptureBase::emplace<CaptureMotion>(F1, "CaptureMotion", 1, S, Vector3d::Zero(), 3, 3, nullptr); - auto p = ProcessorBase::emplace<ProcessorOdom2d>(S, std::make_shared<ProcessorParamsOdom2d>()); + auto F1 = FrameBase::emplace<FrameBase>(T, KEY, 1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); + auto F2 = FrameBase::emplace<FrameBase>(T, KEY, 1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); + auto C = CaptureBase::emplace<CaptureMotion>(F1, "CaptureMotion", 1, S, Vector3d::Zero(), nullptr); + WOLF_INFO("F2->getCaptureList().size() ", F2->getCaptureList().size()); + auto p = std::make_shared<ProcessorOdom2d>(std::make_shared<ParamsProcessorOdom2d>()); + WOLF_INFO("F2->getCaptureList().size() ", F2->getCaptureList().size()); + p->link(S); + //auto p = ProcessorBase::emplace<ProcessorOdom2d>(S, std::make_shared<ParamsProcessorOdom2d>()); + WOLF_INFO("F2->getCaptureList().size() ", F2->getCaptureList().size()); auto f = FeatureBase::emplace<FeatureBase>(C, "f", Vector1d(1), Matrix<double,1,1>::Identity()*.01); auto c = FactorBase::emplace<FactorOdom2d>(f, f, F2, p, false); @@ -126,7 +131,7 @@ TEST(FrameBase, GetSetState) StateQuaternionPtr sbq = make_shared<StateQuaternion>(); // Create frame - FrameBase F(1, sbp, sbq, sbv); + FrameBase F(NON_ESTIMATED, 1, sbp, sbq, sbv); // Give values to vectors and vector blocks VectorXd x(10), x1(10), x2(10); @@ -143,15 +148,39 @@ TEST(FrameBase, GetSetState) ASSERT_MATRIX_APPROX(q, F.getO()->getState(), Constants::EPS_SMALL); ASSERT_MATRIX_APPROX(v, F.getV()->getState(), Constants::EPS_SMALL); - // Get the state, form 1 by reference - F.getState(x1); - ASSERT_MATRIX_APPROX(x1 , x, Constants::EPS_SMALL); - // get the state, form 2 by return value - x2 = F.getState(); + x2 = F.getStateVector(); ASSERT_MATRIX_APPROX(x2, x, Constants::EPS_SMALL); } +TEST(FrameBase, Constructor_composite) +{ + FrameBase F = FrameBase(KEY, + 0.0, + "POV", + VectorComposite("POV", {Vector3d(1,2,3), Vector4d(1,2,3,4).normalized(), Vector3d(1,2,3)})); + + ASSERT_TRUE (F.isKey()); + ASSERT_MATRIX_APPROX(F.getP()->getState(), Vector3d(1,2,3), 1e-15); + ASSERT_TRUE (F.getO()->hasLocalParametrization()); + ASSERT_EQ (F.getStateBlock("V")->getSize(), 3); +} + +TEST(FrameBase, Constructor_vectors) +{ + FrameBase F = FrameBase(KEY, + 0.0, + "POV", + {Vector3d(1,2,3), Vector4d(1,2,3,4).normalized(), Vector3d(1,2,3)}); + + ASSERT_TRUE (F.isKey()); + ASSERT_MATRIX_APPROX(F.getP()->getState(), Vector3d(1,2,3), 1e-15); + ASSERT_TRUE (F.getO()->hasLocalParametrization()); + ASSERT_EQ (F.getStateBlock("V")->getSize(), 3); +} + + + int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); diff --git a/test/gtest_has_state_blocks.cpp b/test/gtest_has_state_blocks.cpp index df90859ba57d46382d97e7fa29fa66b23b137580..111ccd08d5653eab1bb73a71a9711dc426a2ab08 100644 --- a/test/gtest_has_state_blocks.cpp +++ b/test/gtest_has_state_blocks.cpp @@ -41,8 +41,8 @@ class HasStateBlocksTest : public testing::Test sbo1 = std::make_shared<StateQuaternion>(); sbv1 = std::make_shared<StateBlock>(3); // size 3 - F0 = std::make_shared<FrameBase>(0.0, sbp0, sbo0); // non KF - F1 = std::make_shared<FrameBase>(1.0, nullptr); // non KF + F0 = std::make_shared<FrameBase>(NON_ESTIMATED, 0.0, sbp0, sbo0); // non KF + F1 = std::make_shared<FrameBase>(NON_ESTIMATED, 1.0, nullptr); // non KF } virtual void TearDown(){} diff --git a/test/gtest_motion_buffer.cpp b/test/gtest_motion_buffer.cpp index 987c713a245df58dba2c32e9edde9505bcd15d56..3c74ede52ce7ec57a153cdcf416b9c84597cadd9 100644 --- a/test/gtest_motion_buffer.cpp +++ b/test/gtest_motion_buffer.cpp @@ -42,8 +42,8 @@ TEST(MotionBuffer, QueryTimeStamps) { MotionBuffer MB; - MB.get().push_back(m0); - MB.get().push_back(m1); + MB.push_back(m0); + MB.push_back(m1); TimeStamp t; t.set(-1); // t is older than m0.ts_ -> return m0 @@ -66,10 +66,10 @@ TEST(MotionBuffer, getMotion) { MotionBuffer MB; - MB.get().push_back(m0); + MB.push_back(m0); ASSERT_EQ(MB.getMotion(t0).delta_, m0.delta_); - MB.get().push_back(m1); + MB.push_back(m1); ASSERT_EQ(MB.getMotion(t0).delta_, m0.delta_); ASSERT_EQ(MB.getMotion(t1).delta_, m1.delta_); ASSERT_EQ(MB.getMotion(t0).delta_integr_, m0.delta_integr_); @@ -80,11 +80,11 @@ TEST(MotionBuffer, getDelta) { MotionBuffer MB; - MB.get().push_back(m0); + MB.push_back(m0); ASSERT_EQ(MB.getMotion(t0).delta_integr_, m0.delta_integr_); - MB.get().push_back(m1); + MB.push_back(m1); ASSERT_EQ(MB.getMotion(t0).delta_integr_, m0.delta_integr_); ASSERT_EQ(MB.getMotion(t1).delta_integr_, m1.delta_integr_); @@ -94,19 +94,19 @@ TEST(MotionBuffer, Split) { MotionBuffer MB; - MB.get().push_back(m0); - MB.get().push_back(m1); - MB.get().push_back(m2); - MB.get().push_back(m3); - MB.get().push_back(m4); // put 5 motions + MB.push_back(m0); + MB.push_back(m1); + MB.push_back(m2); + MB.push_back(m3); + MB.push_back(m4); // put 5 motions MotionBuffer MB_old; TimeStamp t = 1.5; // between m1 and m2 MB.split(t, MB_old); - ASSERT_EQ(MB_old.get().size(), (unsigned int) 2); - ASSERT_EQ(MB .get().size(), (unsigned int) 3); + ASSERT_EQ(MB_old.size(), (unsigned int) 2); + ASSERT_EQ(MB .size(), (unsigned int) 3); ASSERT_EQ(MB_old.getMotion(t1).ts_, t1); ASSERT_EQ(MB_old.getMotion(t2).ts_, t1); // last ts is t1 @@ -118,11 +118,11 @@ TEST(MotionBuffer, Split) // { // MotionBuffer MB; // -// MB.get().push_back(m0); -// MB.get().push_back(m1); -// MB.get().push_back(m2); -// MB.get().push_back(m3); -// MB.get().push_back(m4); // put 5 motions +// MB.push_back(m0); +// MB.push_back(m1); +// MB.push_back(m2); +// MB.push_back(m3); +// MB.push_back(m4); // put 5 motions // // Eigen::MatrixXd cov = MB.integrateCovariance(); // ASSERT_NEAR(cov(0), 0.04, 1e-8); @@ -133,11 +133,11 @@ TEST(MotionBuffer, Split) // { // MotionBuffer MB; // -// MB.get().push_back(m0); -// MB.get().push_back(m1); -// MB.get().push_back(m2); -// MB.get().push_back(m3); -// MB.get().push_back(m4); // put 5 motions +// MB.push_back(m0); +// MB.push_back(m1); +// MB.push_back(m2); +// MB.push_back(m3); +// MB.push_back(m4); // put 5 motions // // Eigen::MatrixXd cov = MB.integrateCovariance(t2); // ASSERT_NEAR(cov(0), 0.02, 1e-8); @@ -147,11 +147,11 @@ TEST(MotionBuffer, Split) // { // MotionBuffer MB; // -// MB.get().push_back(m0); -// MB.get().push_back(m1); -// MB.get().push_back(m2); -// MB.get().push_back(m3); -// MB.get().push_back(m4); // put 5 motions +// MB.push_back(m0); +// MB.push_back(m1); +// MB.push_back(m2); +// MB.push_back(m3); +// MB.push_back(m4); // put 5 motions // // Eigen::MatrixXd cov = MB.integrateCovariance(t1, t3); // ASSERT_NEAR(cov(0), 0.03, 1e-8); @@ -164,9 +164,9 @@ TEST(MotionBuffer, print) { MotionBuffer MB; - MB.get().push_back(m0); - MB.get().push_back(m1); - MB.get().push_back(m2); + MB.push_back(m0); + MB.push_back(m1); + MB.push_back(m2); MB.print(); MB.print(0,0,0,0); diff --git a/test/gtest_odom_2d.cpp b/test/gtest_odom_2d.cpp index 1176783c855954afba8bf5e0a7566fb37ecbc8b5..8d97fc8d063ed1a08c36b25f259353cc74852f76 100644 --- a/test/gtest_odom_2d.cpp +++ b/test/gtest_odom_2d.cpp @@ -92,7 +92,7 @@ void show(const ProblemPtr& problem) << F->getCaptureList().front()->getFeatureList().front()->getMeasurementCovariance() << endl; } } - cout << " state: \n" << F->getState().transpose() << endl; + cout << " state: \n" << F->getStateVector().transpose() << endl; Eigen::MatrixXd cov; problem->getFrameCovariance(F,cov); cout << " covariance: \n" << cov << endl; @@ -119,8 +119,8 @@ TEST(Odom2d, FactorFix_and_FactorOdom2d) TimeStamp t0(0.0), t = t0; double dt = .01; - Vector3d x0 (0,0,0); - Eigen::Matrix3d P0 = Eigen::Matrix3d::Identity() * 0.1; + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); + VectorComposite s0(Vector3d(sqrt(0.1),sqrt(0.1),sqrt(0.1)), "PO", {2,1}); Vector3d delta (2,0,0); Matrix3d delta_cov; delta_cov << .02, 0, 0, 0, .025, .02, 0, .02, .02; @@ -128,18 +128,18 @@ TEST(Odom2d, FactorFix_and_FactorOdom2d) CeresManager ceres_manager(Pr); // KF0 and absolute prior - FrameBasePtr F0 = Pr->setPrior(x0, P0,t0, dt/2); + FrameBasePtr F0 = Pr->setPriorFactor(x0, s0,t0, dt/2); // KF1 and motion from KF0 t += dt; - FrameBasePtr F1 = Pr->emplaceFrame(KEY, Vector3d::Zero(), t); + FrameBasePtr F1 = Pr->emplaceFrame(KEY, t, Vector3d::Zero()); auto C1 = CaptureBase::emplace<CaptureBase>(F1, "CaptureOdom2d", t); auto f1 = FeatureBase::emplace<FeatureBase>(C1, "FeatureOdom2d", delta, delta_cov); auto c1 = FactorBase::emplace<FactorOdom2d>(f1, f1, F0, nullptr, false); // KF2 and motion from KF1 t += dt; - FrameBasePtr F2 = Pr->emplaceFrame(KEY, Vector3d::Zero(), t); + FrameBasePtr F2 = Pr->emplaceFrame(KEY, t, Vector3d::Zero()); auto C2 = CaptureBase::emplace<CaptureBase>(F2, "CaptureOdom2d", t); auto f2 = FeatureBase::emplace<FeatureBase>(C2, "FeatureOdom2d", delta, delta_cov); auto c2 = FactorBase::emplace<FactorOdom2d>(f2, f2, F1, nullptr, false); @@ -170,11 +170,12 @@ TEST(Odom2d, FactorFix_and_FactorOdom2d) ASSERT_TRUE(Pr->getFrameCovariance(F1, P1_solver)); ASSERT_TRUE(Pr->getFrameCovariance(F2, P2_solver)); - ASSERT_POSE2d_APPROX(F0->getState(), Vector3d(0,0,0), 1e-6); - ASSERT_MATRIX_APPROX(P0_solver, P0, 1e-6); - ASSERT_POSE2d_APPROX(F1->getState(), Vector3d(2,0,0), 1e-6); + ASSERT_POSE2d_APPROX(F0->getStateVector(), Vector3d(0,0,0), 1e-6); + auto s0_vector = s0.vector("PO"); + ASSERT_MATRIX_APPROX(P0_solver, MatrixXd((s0_vector.array() * s0_vector.array()).matrix().asDiagonal()), 1e-6); + ASSERT_POSE2d_APPROX(F1->getStateVector(), Vector3d(2,0,0), 1e-6); ASSERT_MATRIX_APPROX(P1_solver, P1, 1e-6); - ASSERT_POSE2d_APPROX(F2->getState(), Vector3d(4,0,0), 1e-6); + ASSERT_POSE2d_APPROX(F2->getStateVector(), Vector3d(4,0,0), 1e-6); ASSERT_MATRIX_APPROX(P2_solver, P2, 1e-6); } @@ -187,8 +188,10 @@ TEST(Odom2d, VoteForKfAndSolve) TimeStamp t0(0.0), t = t0; double dt = .01; // Origin frame: - Vector3d x0(0,0,0); - Eigen::Matrix3d P0 = Eigen::Matrix3d::Identity() * 0.1; + // Vector3d x0(0,0,0); + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); + // Eigen::Matrix3d P0 = Eigen::Matrix3d::Identity() * 0.1; + VectorComposite s0(Vector3d(sqrt(0.1),sqrt(0.1),sqrt(0.1)), "PO", {2,1}); // motion data VectorXd data(Vector2d(1, M_PI_4) ); // advance 1m turn pi/4 rad (45 deg). Need 8 steps for a complete turn Eigen::MatrixXd data_cov = Eigen::MatrixXd::Identity(2, 2) * 0.01; @@ -197,12 +200,13 @@ TEST(Odom2d, VoteForKfAndSolve) // Create Wolf tree nodes ProblemPtr problem = Problem::create("PO", 2); SensorBasePtr sensor_odom2d = problem->installSensor("SensorOdom2d", "odom", Vector3d(0,0,0), wolf_root + "/test/yaml/sensor_odom_2d.yaml"); - ProcessorParamsOdom2dPtr params(std::make_shared<ProcessorParamsOdom2d>()); + ParamsProcessorOdom2dPtr params(std::make_shared<ParamsProcessorOdom2d>()); params->voting_active = true; params->dist_traveled = 100; - params->angle_turned = 6.28; - params->max_time_span = 2.5*dt; // force KF at every third process() + params->angle_turned = data(1)*2.5; // force KF at every third process() + params->max_time_span = 100; params->cov_det = 100; + params->time_tolerance = dt/2; params->unmeasured_perturbation_std = 0.00; Matrix3d unmeasured_cov = params->unmeasured_perturbation_std*params->unmeasured_perturbation_std*Matrix3d::Identity(); ProcessorBasePtr prc_base = problem->installProcessor("ProcessorOdom2d", "odom", sensor_odom2d, params); @@ -211,13 +215,15 @@ TEST(Odom2d, VoteForKfAndSolve) // NOTE: We integrate and create KFs as follows: // i= 0 1 2 3 4 5 6 - // KF -- * -- * -- KF - * -- * -- KF - * + // KF - * -- * -- KF - * -- * -- KF - * // Ceres wrapper CeresManager ceres_manager(problem); // Origin Key Frame - FrameBasePtr origin_frame = problem->setPrior(x0, P0, t0, dt/2); + auto KF = problem->setPriorFactor(x0, s0, t, dt/2); + processor_odom2d->setOrigin(KF); + ceres_manager.solve(SolverManager::ReportVerbosity::BRIEF); ceres_manager.computeCovariances(SolverManager::CovarianceBlocksToBeComputed::ALL_MARGINALS); @@ -226,8 +232,8 @@ TEST(Odom2d, VoteForKfAndSolve) // std::cout << "Motion data : " << data.transpose() << std::endl; // Check covariance values - Eigen::Vector3d integrated_pose = x0; - Eigen::Matrix3d integrated_cov = P0; + Eigen::Vector3d integrated_pose = Vector3d(0,0,0); + Eigen::Matrix3d integrated_cov = Eigen::Matrix3d::Identity() * 0.1; Eigen::Vector3d integrated_delta = Eigen::Vector3d::Zero(); Eigen::Matrix3d integrated_delta_cov = Eigen::Matrix3d::Zero(); Eigen::MatrixXd Ju(3, 2); @@ -246,7 +252,7 @@ TEST(Odom2d, VoteForKfAndSolve) for (int n=1; n<=N; n++) { - // std::cout << "-------------------\nStep " << i << " at time " << t << std::endl; + std::cout << "-------------------\nStep " << n << " at time " << t << std::endl; // re-use capture with updated timestamp capture->setTimeStamp(t); @@ -269,9 +275,9 @@ TEST(Odom2d, VoteForKfAndSolve) integrated_delta_cov = Jx * integrated_delta_cov * Jx.transpose() + Ju * data_cov * Ju.transpose() + unmeasured_cov; } - WOLF_DEBUG("n: ", n, " t:", t); - WOLF_DEBUG("wolf delta: ", processor_odom2d->getMotion().delta_integr_.transpose()); - WOLF_DEBUG("test delta: ", integrated_delta .transpose()); + WOLF_INFO("n: ", n, " t:", t); + WOLF_INFO("wolf delta: ", processor_odom2d->getMotion().delta_integr_.transpose()); + WOLF_INFO("test delta: ", integrated_delta .transpose()); ASSERT_POSE2d_APPROX(processor_odom2d->getMotion().delta_integr_, integrated_delta, 1e-6); ASSERT_MATRIX_APPROX(odom2d_delta_cov, integrated_delta_cov, 1e-6); @@ -282,7 +288,7 @@ TEST(Odom2d, VoteForKfAndSolve) integrated_pose = plus(integrated_pose, data); integrated_cov = Jx * integrated_cov * Jx.transpose() + Ju * data_cov * Ju.transpose() + unmeasured_cov; - ASSERT_POSE2d_APPROX(processor_odom2d->getCurrentState(), integrated_pose, 1e-6); + ASSERT_POSE2d_APPROX(processor_odom2d->getState().vector("PO"), integrated_pose, 1e-6); integrated_pose_vector.push_back(integrated_pose); integrated_cov_vector.push_back(integrated_cov); @@ -295,6 +301,8 @@ TEST(Odom2d, VoteForKfAndSolve) ceres_manager.computeCovariances(SolverManager::CovarianceBlocksToBeComputed::ALL_MARGINALS); + problem->print(4,1,1,1); + // Check the 3 KFs' states and covariances MatrixXd computed_cov; int n = 0; @@ -302,7 +310,7 @@ TEST(Odom2d, VoteForKfAndSolve) { if (!F->isKey()) break; - ASSERT_POSE2d_APPROX(F->getState(), integrated_pose_vector[n] , 1e-6); + ASSERT_POSE2d_APPROX(F->getStateVector("PO"), integrated_pose_vector[n] , 1e-6); ASSERT_TRUE (F->getCovariance(computed_cov)); ASSERT_MATRIX_APPROX(computed_cov , integrated_cov_vector[n] , 1e-6); n += 3; @@ -320,8 +328,8 @@ TEST(Odom2d, KF_callback) // time TimeStamp t0(0.0), t = t0; double dt = .01; - Vector3d x0(0,0,0); - Eigen::Matrix3d x0_cov = Eigen::Matrix3d::Identity() * 0.1; + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); + VectorComposite x0_cov(Vector3d(sqrt(0.1),sqrt(0.1),sqrt(0.1)), "PO", {2,1}); VectorXd data(Vector2d(1, M_PI/4) ); // advance 1m Eigen::MatrixXd data_cov = Eigen::MatrixXd::Identity(2, 2) * 0.01; int N = 8; // number of process() steps @@ -337,11 +345,12 @@ TEST(Odom2d, KF_callback) // Create Wolf tree nodes ProblemPtr problem = Problem::create("PO", 2); SensorBasePtr sensor_odom2d = problem->installSensor("SensorOdom2d", "odom", Vector3d(0,0,0), wolf_root + "/test/yaml/sensor_odom_2d.yaml"); - ProcessorParamsOdom2dPtr params(std::make_shared<ProcessorParamsOdom2d>()); + ParamsProcessorOdom2dPtr params(std::make_shared<ParamsProcessorOdom2d>()); params->dist_traveled = 100; - params->angle_turned = 6.28; + params->angle_turned = data(1)*2.5; // force KF at every third process() params->max_time_span = 100; params->cov_det = 100; + params->time_tolerance = dt/2; params->unmeasured_perturbation_std = 0.000001; Matrix3d unmeasured_cov = params->unmeasured_perturbation_std*params->unmeasured_perturbation_std*Matrix3d::Identity(); ProcessorBasePtr prc_base = problem->installProcessor("ProcessorOdom2d", "odom", sensor_odom2d, params); @@ -352,11 +361,12 @@ TEST(Odom2d, KF_callback) CeresManager ceres_manager(problem); // Origin Key Frame - FrameBasePtr keyframe_0 = problem->setPrior(x0, x0_cov, t0, dt/2); + FrameBasePtr keyframe_0 = problem->setPriorFactor(x0, x0_cov, t0, dt/2); + processor_odom2d->setOrigin(keyframe_0); // Check covariance values - Eigen::Vector3d integrated_pose = x0; - Eigen::Matrix3d integrated_cov = x0_cov; + Eigen::Vector3d integrated_pose = Vector3d(0,0,0); + Eigen::Matrix3d integrated_cov = Eigen::Matrix3d::Identity() * 0.1; Eigen::Vector3d integrated_delta = Eigen::Vector3d::Zero(); Eigen::Matrix3d integrated_delta_cov = Eigen::Matrix3d::Zero(); Eigen::MatrixXd Ju(3, 2); @@ -412,8 +422,8 @@ TEST(Odom2d, KF_callback) std::cout << "-----------------------------\nSplit after last KF; time: " << t_split << std::endl; - Vector3d x_split = processor_odom2d->getState(t_split); - FrameBasePtr keyframe_2 = problem->emplaceFrame(KEY, x_split, t_split); + Vector3d x_split = processor_odom2d->getState(t_split).vector("PO"); + FrameBasePtr keyframe_2 = problem->emplaceFrame(KEY, t_split, x_split); // there must be 2KF and one F ASSERT_EQ(problem->getTrajectory()->getFrameList().size(), 3); @@ -436,7 +446,7 @@ TEST(Odom2d, KF_callback) // std::cout << report << std::endl; ceres_manager.computeCovariances(SolverManager::CovarianceBlocksToBeComputed::ALL_MARGINALS); - ASSERT_POSE2d_APPROX(problem->getLastKeyFrame()->getState() , integrated_pose_vector[n_split], 1e-6); + ASSERT_POSE2d_APPROX(problem->getLastKeyFrame()->getStateVector() , integrated_pose_vector[n_split], 1e-6); MatrixXd computed_cov; ASSERT_TRUE(problem->getLastKeyFrameCovariance(computed_cov)); ASSERT_MATRIX_APPROX(computed_cov, integrated_cov_vector [n_split], 1e-6); @@ -449,8 +459,8 @@ TEST(Odom2d, KF_callback) problem->print(4,1,1,1); - x_split = processor_odom2d->getState(t_split); - FrameBasePtr keyframe_1 = problem->emplaceFrame(KEY, x_split, t_split); + x_split = processor_odom2d->getState(t_split).vector("PO"); + FrameBasePtr keyframe_1 = problem->emplaceFrame(KEY, t_split, x_split); ASSERT_TRUE(problem->check(0)); processor_odom2d->keyFrameCallback(keyframe_1, dt/2); @@ -477,13 +487,13 @@ TEST(Odom2d, KF_callback) // check the split KF MatrixXd KF1_cov; ASSERT_TRUE(problem->getFrameCovariance(keyframe_1, KF1_cov)); - ASSERT_POSE2d_APPROX(keyframe_1->getState(), integrated_pose_vector[m_split], 1e-6); - ASSERT_MATRIX_APPROX(KF1_cov, integrated_cov_vector [m_split], 1e-6); + ASSERT_POSE2d_APPROX(keyframe_1->getStateVector(), integrated_pose_vector[m_split], 1e-6); + ASSERT_MATRIX_APPROX(KF1_cov, integrated_cov_vector [m_split], 1e-6); // check other KF in the future of the split KF MatrixXd KF2_cov; ASSERT_TRUE(problem->getFrameCovariance(keyframe_2, KF2_cov)); - ASSERT_POSE2d_APPROX(problem->getLastKeyFrame()->getState(), integrated_pose_vector[n_split], 1e-6); + ASSERT_POSE2d_APPROX(problem->getLastKeyFrame()->getStateVector(), integrated_pose_vector[n_split], 1e-6); ASSERT_MATRIX_APPROX(KF2_cov, integrated_cov_vector [n_split], 1e-6); // Check full trajectory @@ -491,9 +501,9 @@ TEST(Odom2d, KF_callback) for (int n=1; n<=N; n++) { t += dt; - WOLF_DEBUG(" estimated(", t, ") = ", problem->getState(t).transpose()); + WOLF_DEBUG(" estimated(", t, ") = ", problem->getState(t).vector("PO").transpose()); WOLF_DEBUG("ground truth(", t, ") = ", integrated_pose_vector[n].transpose()); - ASSERT_POSE2d_APPROX(problem->getState(t), integrated_pose_vector[n], 1e-6); + ASSERT_POSE2d_APPROX(problem->getState(t).vector("PO"), integrated_pose_vector[n], 1e-6); } } diff --git a/test/gtest_pack_KF_buffer.cpp b/test/gtest_pack_KF_buffer.cpp index 3862e263cb747b443e77ef113e9d85efa529f3a5..32bcd10d01a3604d16548cfd738d555af6b7e019 100644 --- a/test/gtest_pack_KF_buffer.cpp +++ b/test/gtest_pack_KF_buffer.cpp @@ -34,10 +34,10 @@ class BufferPackKeyFrameTest : public testing::Test void SetUp(void) { - f10 = std::make_shared<FrameBase>(TimeStamp(10),nullptr,nullptr,nullptr); - f20 = std::make_shared<FrameBase>(TimeStamp(20),nullptr,nullptr,nullptr); - f21 = std::make_shared<FrameBase>(TimeStamp(21),nullptr,nullptr,nullptr); - f28 = std::make_shared<FrameBase>(TimeStamp(28),nullptr,nullptr,nullptr); + f10 = std::make_shared<FrameBase>(NON_ESTIMATED, TimeStamp(10),nullptr,nullptr,nullptr); + f20 = std::make_shared<FrameBase>(NON_ESTIMATED, TimeStamp(20),nullptr,nullptr,nullptr); + f21 = std::make_shared<FrameBase>(NON_ESTIMATED, TimeStamp(21),nullptr,nullptr,nullptr); + f28 = std::make_shared<FrameBase>(NON_ESTIMATED, TimeStamp(28),nullptr,nullptr,nullptr); tt10 = 1.0; tt20 = 1.0; @@ -137,7 +137,9 @@ TEST_F(BufferPackKeyFrameTest, selectPack) { PackKeyFramePtr packQ = pack_kf_buffer.selectPack(16, q[iq]); if (packQ!=nullptr) + { ASSERT_EQ(packQ->key_frame->getTimeStamp(),res(ip1*6+ip2*3+iq)); + } } pack_kf_buffer.clear(); } @@ -228,7 +230,7 @@ TEST_F(BufferPackKeyFrameTest, removeUpTo) // Specifically, only f28 should remain pack_kf_buffer.add(f28, tt28); ASSERT_EQ(pack_kf_buffer.size(), (unsigned int) 2); - FrameBasePtr f22 = std::make_shared<FrameBase>(TimeStamp(22),nullptr,nullptr,nullptr); + FrameBasePtr f22 = std::make_shared<FrameBase>(NON_ESTIMATED, TimeStamp(22),nullptr,nullptr,nullptr); PackKeyFramePtr pack22 = std::make_shared<PackKeyFrame>(f22,5); pack_kf_buffer.removeUpTo( pack22->key_frame->getTimeStamp() ); ASSERT_EQ(pack_kf_buffer.size(), (unsigned int) 1); diff --git a/test/gtest_problem.cpp b/test/gtest_problem.cpp index 6d262ba06b81438499b29ab3d45fd4bb101c89db..8ec6ebcae42990451909902ee8f245c35fbf16c4 100644 --- a/test/gtest_problem.cpp +++ b/test/gtest_problem.cpp @@ -6,7 +6,7 @@ */ #include "core/utils/utils_gtest.h" -#include "core/utils/logging.h" +//#include "core/utils/logging.h" #include "core/problem/problem.h" #include "core/sensor/sensor_base.h" @@ -15,6 +15,7 @@ #include "core/processor/processor_odom_3d.h" #include "dummy/processor_tracker_feature_dummy.h" #include "core/solver/solver_manager.h" +#include "dummy/solver_manager_dummy.h" #include "core/sensor/sensor_diff_drive.h" #include "core/processor/processor_diff_drive.h" @@ -31,41 +32,8 @@ using namespace wolf; using namespace Eigen; -// Register in the ProcessorFactory -#include "core/processor/processor_factory.h" -namespace wolf { -WOLF_REGISTER_PROCESSOR("TRACKER FEATURE DUMMY", ProcessorTrackerFeatureDummy) -} // namespace wolf - - -WOLF_PTR_TYPEDEFS(DummySolverManager); - -class DummySolverManager : public SolverManager -{ -public: - DummySolverManager(const ProblemPtr& _problem) - : SolverManager(_problem) - { - // - } - virtual void computeCovariances(const CovarianceBlocksToBeComputed blocks){}; - virtual void computeCovariances(const std::vector<StateBlockPtr>& st_list){}; - virtual bool hasConverged(){return true;}; - virtual SizeStd iterations(){return 0;}; - virtual double initialCost(){return 0;}; - virtual double finalCost(){return 0;}; - virtual std::string solveImpl(const ReportVerbosity report_level){return std::string("");}; - virtual void addFactor(const FactorBasePtr& fac_ptr){}; - virtual void removeFactor(const FactorBasePtr& fac_ptr){}; - virtual void addStateBlock(const StateBlockPtr& state_ptr){}; - virtual void removeStateBlock(const StateBlockPtr& state_ptr){}; - virtual void updateStateBlockStatus(const StateBlockPtr& state_ptr){}; - virtual void updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr){}; - virtual bool isStateBlockRegistered(const StateBlockPtr& state_ptr){return true;}; - virtual bool isFactorRegistered(const FactorBasePtr& fac_ptr) const {return true;}; - virtual bool isStateBlockRegisteredDerived(const StateBlockPtr& state_ptr){return true;}; - virtual bool isFactorRegisteredDerived(const FactorBasePtr& fac_ptr) const {return true;}; -}; +// Register in the FactoryProcessor +#include "core/processor/factory_processor.h" TEST(Problem, create) { @@ -77,7 +45,7 @@ TEST(Problem, create) ASSERT_EQ(P, P->getMap()->getProblem()); // check frame structure through the state size - ASSERT_EQ(P->getFrameStructureSize(), 10); + ASSERT_EQ(P->getFrameStructure(), "POV"); } TEST(Problem, Sensors) @@ -104,7 +72,7 @@ TEST(Problem, Processor) auto Sm = SensorBase::emplace<SensorOdom3d>(P->getHardware(), (Eigen::Vector7d()<<0,0,0, 0,0,0,1).finished(), ParamsSensorOdom3d()); // add motion processor - auto Pm = ProcessorBase::emplace<ProcessorOdom3d>(Sm, std::make_shared<ProcessorParamsOdom3d>()); + auto Pm = ProcessorBase::emplace<ProcessorOdom3d>(Sm, std::make_shared<ParamsProcessorOdom3d>()); // check motion processor IS NOT by emplace ASSERT_EQ(P->getProcessorIsMotion(), Pm); @@ -138,35 +106,56 @@ TEST(Problem, SetOrigin_PO_2d) { ProblemPtr P = Problem::create("PO", 2); TimeStamp t0(0); - Eigen::VectorXd x0(3); x0 << 1,2,3; - Eigen::MatrixXd P0(3,3); P0.setIdentity(); P0 *= 0.1; // P0 is 0.1*Id + // Eigen::VectorXd x0(3); x0 << 1,2,3; + VectorComposite x0(Vector3d(1,2,3), "PO", {2,1}); + // Eigen::MatrixXd P0(Eigen::MatrixXd::Identity(3,3) * 0.1); // P0 is 0.1*Id + VectorComposite s0(Vector3d(sqrt(0.1),sqrt(0.1),sqrt(0.1)), "PO", {2,1}); + + P->setPriorFactor(x0, s0, t0, 1.0); - P->setPrior(x0, P0, t0, 1.0); + P->print(4,1,1,1); // check that no sensor has been added ASSERT_EQ(P->getHardware()->getSensorList().size(), (SizeStd) 0); // check that the state is correct - ASSERT_MATRIX_APPROX(x0, P->getCurrentState(), Constants::EPS_SMALL ); + ASSERT_MATRIX_APPROX(x0.vector("PO"), P->getState().vector("PO"), Constants::EPS_SMALL ); // check that we have one frame, one capture, one feature, one factor TrajectoryBasePtr T = P->getTrajectory(); - ASSERT_EQ(T->getFrameList().size(), (SizeStd) 1); FrameBasePtr F = P->getLastFrame(); - ASSERT_EQ(F->getCaptureList().size(), (SizeStd) 1); CaptureBasePtr C = F->getCaptureList().front(); - ASSERT_EQ(C->getFeatureList().size(), (SizeStd) 1); - FeatureBasePtr f = C->getFeatureList().front(); - ASSERT_EQ(f->getFactorList().size(), (SizeStd) 1); + FeatureBasePtr fo = (*std::find_if(C->getFeatureList().begin(), C->getFeatureList().end(), [](FeatureBasePtr ftr){ return ftr->getType() == "Prior O";})); + FeatureBasePtr fp = (*std::find_if(C->getFeatureList().begin(), C->getFeatureList().end(), [](FeatureBasePtr ftr){ return ftr->getType() == "Prior P";})); + FactorBasePtrList fac_list; + F->getFactorList(fac_list); + + // check that we have one frame (prior) + ASSERT_EQ(T->getFrameList().size(), (SizeStd) 1); + // check that we have one capture (prior) + ASSERT_EQ(F->getCaptureList().size(), (SizeStd) 1); + // check that we have two features (prior: one per state block) + ASSERT_EQ(C->getFeatureList().size(), (SizeStd) 2); + // check that we have two factors (prior: one per state block) + ASSERT_EQ(fac_list.size(), (SizeStd) 2); - // check that the factor is absolute (no pointers to other F, f, or L) - FactorBasePtr c = f->getFactorList().front(); - ASSERT_FALSE(c->getFrameOther()); - ASSERT_FALSE(c->getLandmarkOther()); + // check that the factors are absolute (no pointers to other F, f, or L) + for (auto fac : fac_list) + { + ASSERT_FALSE(fac->getFrameOther()); + ASSERT_FALSE(fac->getLandmarkOther()); + ASSERT_FALSE(fac->getCaptureOther()); + ASSERT_FALSE(fac->getFeatureOther()); + } + auto x0_vector = x0.vector("PO"); + auto s0_vector = s0.vector("PO"); + MatrixXd P0_matrix = (s0_vector.array() * s0_vector.array()).matrix().asDiagonal(); // check that the Feature measurement and covariance are the ones provided - ASSERT_MATRIX_APPROX(x0, f->getMeasurement(), Constants::EPS_SMALL ); - ASSERT_MATRIX_APPROX(P0, f->getMeasurementCovariance(), Constants::EPS_SMALL ); + ASSERT_MATRIX_APPROX(x0_vector.head<2>(), fp->getMeasurement(), Constants::EPS_SMALL ); + ASSERT_MATRIX_APPROX(x0_vector.tail<1>(), fo->getMeasurement(), Constants::EPS_SMALL ); + ASSERT_MATRIX_APPROX(P0_matrix.topLeftCorner(2,2), fp->getMeasurementCovariance(), Constants::EPS_SMALL ); + ASSERT_MATRIX_APPROX(P0_matrix.bottomRightCorner(1,1), fo->getMeasurementCovariance(), Constants::EPS_SMALL ); // P->print(4,1,1,1); } @@ -175,35 +164,57 @@ TEST(Problem, SetOrigin_PO_3d) { ProblemPtr P = Problem::create("PO", 3); TimeStamp t0(0); - Eigen::VectorXd x0(7); x0 << 1,2,3,4,5,6,7; - Eigen::MatrixXd P0(6,6); P0.setIdentity(); P0 *= 0.1; // P0 is 0.1*Id + Eigen::VectorXd vec7(7); vec7 << 1,2,3,4,5,6,7; // not normalized quaternion, this is not what's tested + VectorComposite x0(vec7, "PO", {3,4}); + // Eigen::MatrixXd P0(6,6); P0.setIdentity(); P0 *= 0.1; // P0 is 0.1*Id + Eigen::VectorXd vec6(6); vec6 << sqrt(0.1), sqrt(0.1), sqrt(0.1), sqrt(0.1), sqrt(0.1), sqrt(0.1); + VectorComposite s0(vec6, "PO", {3,3}); - P->setPrior(x0, P0, t0, 1.0); + P->setPriorFactor(x0, s0, t0, 1.0); // check that no sensor has been added ASSERT_EQ(P->getHardware()->getSensorList().size(), (SizeStd) 0); // check that the state is correct - ASSERT_TRUE((x0 - P->getCurrentState()).isMuchSmallerThan(1, Constants::EPS_SMALL)); + ASSERT_TRUE((x0.vector("PO") - P->getState().vector("PO")).isMuchSmallerThan(1, Constants::EPS_SMALL)); // check that we have one frame, one capture, one feature, one factor TrajectoryBasePtr T = P->getTrajectory(); - ASSERT_EQ(T->getFrameList().size(), (SizeStd) 1); FrameBasePtr F = P->getLastFrame(); - ASSERT_EQ(F->getCaptureList().size(), (SizeStd) 1); CaptureBasePtr C = F->getCaptureList().front(); - ASSERT_EQ(C->getFeatureList().size(), (SizeStd) 1); - FeatureBasePtr f = C->getFeatureList().front(); - ASSERT_EQ(f->getFactorList().size(), (SizeStd) 1); + // FeatureBasePtr fo = C->getFeatureList().front(); + // FeatureBasePtr fp = C->getFeatureList().back(); + FeatureBasePtr fo = (*std::find_if(C->getFeatureList().begin(), C->getFeatureList().end(), [](FeatureBasePtr ftr){ return ftr->getType() == "Prior O";})); + FeatureBasePtr fp = (*std::find_if(C->getFeatureList().begin(), C->getFeatureList().end(), [](FeatureBasePtr ftr){ return ftr->getType() == "Prior P";})); + FactorBasePtrList fac_list; + F->getFactorList(fac_list); + + // check that we have one frame (prior) + ASSERT_EQ(T->getFrameList().size(), (SizeStd) 1); + // check that we have one capture (prior) + ASSERT_EQ(F->getCaptureList().size(), (SizeStd) 1); + // check that we have two features (prior: one per state block) + ASSERT_EQ(C->getFeatureList().size(), (SizeStd) 2); + // check that we have two factors (prior: one per state block) + ASSERT_EQ(fac_list.size(), (SizeStd) 2); - // check that the factor is absolute (no pointers to other F, f, or L) - FactorBasePtr c = f->getFactorList().front(); - ASSERT_FALSE(c->getFrameOther()); - ASSERT_FALSE(c->getLandmarkOther()); + // check that the factors are absolute (no pointers to other F, f, or L) + for (auto fac : fac_list) + { + ASSERT_FALSE(fac->getFrameOther()); + ASSERT_FALSE(fac->getLandmarkOther()); + ASSERT_FALSE(fac->getCaptureOther()); + ASSERT_FALSE(fac->getFeatureOther()); + } + auto x0_vector = x0.vector("PO"); + auto s0_vector = s0.vector("PO"); + MatrixXd P0_matrix = (s0_vector.array() * s0_vector.array()).matrix().asDiagonal(); // check that the Feature measurement and covariance are the ones provided - ASSERT_TRUE((x0 - f->getMeasurement()).isMuchSmallerThan(1, Constants::EPS_SMALL)); - ASSERT_TRUE((P0 - f->getMeasurementCovariance()).isMuchSmallerThan(1, Constants::EPS_SMALL)); + ASSERT_MATRIX_APPROX(x0_vector.head<3>(), fp->getMeasurement(), Constants::EPS_SMALL ); + ASSERT_MATRIX_APPROX(x0_vector.tail<4>(), fo->getMeasurement(), Constants::EPS_SMALL ); + ASSERT_MATRIX_APPROX(P0_matrix.topLeftCorner(3,3), fp->getMeasurementCovariance(), Constants::EPS_SMALL ); + ASSERT_MATRIX_APPROX(P0_matrix.bottomRightCorner(3,3), fo->getMeasurementCovariance(), Constants::EPS_SMALL ); // P->print(4,1,1,1); } @@ -212,9 +223,9 @@ TEST(Problem, emplaceFrame_factory) { ProblemPtr P = Problem::create("PO", 2); - FrameBasePtr f0 = P->emplaceFrame("PO", 2, KEY, VectorXd(3), TimeStamp(0.0)); - FrameBasePtr f1 = P->emplaceFrame("PO", 3, KEY, VectorXd(7), TimeStamp(1.0)); - FrameBasePtr f2 = P->emplaceFrame("POV", 3, KEY, VectorXd(10), TimeStamp(2.0)); + FrameBasePtr f0 = P->emplaceFrame(KEY, 0, "PO" , 2, VectorXd(3) ); + FrameBasePtr f1 = P->emplaceFrame(KEY, 1, "PO" , 3, VectorXd(7) ); + FrameBasePtr f2 = P->emplaceFrame(KEY, 2, "POV", 3, VectorXd(10) ); // std::cout << "f0: type PO 2d? " << f0->getType() << std::endl; // std::cout << "f1: type PO 3d? " << f1->getType() << std::endl; @@ -253,7 +264,7 @@ TEST(Problem, StateBlocks) auto pm = P->installProcessor("ProcessorOdom3d", "odom integrator", "odometer", wolf_root + "/test/yaml/processor_odom_3d.yaml"); // 2 state blocks, estimated - auto KF = P->emplaceFrame("PO", 3, KEY, xs3d, 0); + auto KF = P->emplaceFrame(KEY, 0, "PO", 3, xs3d ); ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd)(2 + 2)); // Notifications @@ -268,24 +279,26 @@ TEST(Problem, StateBlocks) Sm->unfixExtrinsics(); ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd)(2 + 2)); // changes in state_blocks status (fix/state/localparam) does not raise a notification in problem, only ADD/REMOVE - // P->print(4,1,1,1); + P->print(4,1,1,1); // consume notifications - DummySolverManagerPtr SM = std::make_shared<DummySolverManager>(P); + SolverManagerDummyPtr SM = std::make_shared<SolverManagerDummy>(P); ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd)(2 + 2)); - SM->update(); // calls P->consumeStateBlockNotificationMap(); - ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd) (0)); // consume empties the notification map + SM->update(); // calls P->consumeNotifications(); + ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd) (0)); // consumeNotifications empties the notification map // remove frame auto SB_P = KF->getP(); auto SB_O = KF->getO(); + WOLF_INFO("removing frame..."); KF->remove(); + WOLF_INFO("removed"); ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd)(2)); ASSERT_TRUE(P->getStateBlockNotification(SB_P, notif)); ASSERT_EQ(notif, REMOVE); ASSERT_TRUE(P->getStateBlockNotification(SB_O, notif)); ASSERT_EQ(notif, REMOVE); - + WOLF_INFO("test end"); } TEST(Problem, Covariances) @@ -300,7 +313,7 @@ TEST(Problem, Covariances) // SensorBasePtr St = P->installSensor ("SensorOdom2d", "other odometer", xs2d, wolf_root + "/test/yaml/sensor_odom_2d.yaml"); SensorBasePtr St = P->installSensor ("SensorOdom3d", "other odometer", xs3d, wolf_root + "/test/yaml/sensor_odom_3d.yaml"); - ProcessorParamsTrackerFeaturePtr params = std::make_shared<ProcessorParamsTrackerFeature>(); + ParamsProcessorTrackerFeaturePtr params = std::make_shared<ParamsProcessorTrackerFeature>(); params->time_tolerance = 0.1; params->max_new_features = 5; params->min_features_for_keyframe = 10; @@ -310,7 +323,7 @@ TEST(Problem, Covariances) // 4 state blocks, estimated St->unfixExtrinsics(); - FrameBasePtr F = P->emplaceFrame("PO", 3, KEY, xs3d, 0); + FrameBasePtr F = P->emplaceFrame(KEY, 0, "PO", 3, xs3d ); // set covariance (they are not computed without a solver) P->addCovarianceBlock(F->getP(), Eigen::Matrix3d::Identity()); @@ -346,7 +359,7 @@ TEST(Problem, perturb) int i = 0; for (TimeStamp t = 0.0; t < 2.0; t += 1.0) { - auto F = problem->emplaceFrame(KEY, pose, t); + auto F = problem->emplaceFrame(KEY, t, pose ); if (i==0) F->fix(); for (int j = 0; j< 2 ; j++) @@ -436,7 +449,7 @@ TEST(Problem, check) int i = 0; for (TimeStamp t = 0.0; t < 2.0; t += 1.0) { - auto F = problem->emplaceFrame(KEY, pose, t); + auto F = problem->emplaceFrame(KEY, t, pose); if (i==0) F->fix(); for (int j = 0; j< 2 ; j++) diff --git a/test/gtest_processor_base.cpp b/test/gtest_processor_base.cpp index c4a1c4b0470c92bf09df1a950a1c19e57d35642d..ed01245b29c903a7584e932196fb93a2c01c5c20 100644 --- a/test/gtest_processor_base.cpp +++ b/test/gtest_processor_base.cpp @@ -23,14 +23,6 @@ using namespace wolf; using namespace Eigen; - -// Register in the ProcessorFactory -#include "core/processor/processor_factory.h" -namespace wolf { -WOLF_REGISTER_PROCESSOR("TRACKER FEATURE DUMMY", ProcessorTrackerFeatureDummy) -} // namespace wolf - - TEST(ProcessorBase, IsMotion) { using namespace wolf; @@ -57,7 +49,7 @@ TEST(ProcessorBase, IsMotion) // Install odometer (sensor and processor) SensorBasePtr sens_odo = problem->installSensor("SensorOdom2d", "odometer", Vector3d(0,0,0), wolf_root + "/test/yaml/sensor_odom_2d.yaml"); - ProcessorParamsOdom2dPtr proc_odo_params = make_shared<ProcessorParamsOdom2d>(); + ParamsProcessorOdom2dPtr proc_odo_params = make_shared<ParamsProcessorOdom2d>(); proc_odo_params->time_tolerance = dt/2; ProcessorBasePtr proc_odo = problem->installProcessor("ProcessorOdom2d", "odom processor", sens_odo, proc_odo_params); @@ -84,15 +76,17 @@ TEST(ProcessorBase, KeyFrameCallback) // Install tracker (sensor and processor) auto sens_trk = SensorBase::emplace<SensorBase>(problem->getHardware(), - "SensorOdom2d", + "SensorTrackerDummy", std::make_shared<StateBlock>(Eigen::VectorXd::Zero(2)), std::make_shared<StateBlock>(Eigen::VectorXd::Zero(1)), std::make_shared<StateBlock>(Eigen::VectorXd::Zero(2)), 2); - auto proc_trk = problem->installProcessor("ProcessorTrackerFeatureDummy", "dummy", sens_trk); + auto proc_trk_params = make_shared<ParamsProcessorTrackerFeatureDummy>(); + proc_trk_params->time_tolerance = dt/2; + auto proc_trk = problem->installProcessor("ProcessorTrackerFeatureDummy", "dummy", sens_trk, proc_trk_params); // Install odometer (sensor and processor) SensorBasePtr sens_odo = problem->installSensor("SensorOdom2d", "odometer", Vector3d(0,0,0), wolf_root + "/test/yaml/sensor_odom_2d.yaml"); - ProcessorParamsOdom2dPtr proc_odo_params = make_shared<ProcessorParamsOdom2d>(); + ParamsProcessorOdom2dPtr proc_odo_params = make_shared<ParamsProcessorOdom2d>(); proc_odo_params->time_tolerance = dt/2; ProcessorBasePtr proc_odo = problem->installProcessor("ProcessorOdom2d", "odom processor", sens_odo, proc_odo_params); @@ -102,9 +96,11 @@ TEST(ProcessorBase, KeyFrameCallback) // initialize TimeStamp t(0.0); - Vector3d x(0,0,0); - Matrix3d P = Matrix3d::Identity() * 0.1; - problem->setPrior(x, P, t, dt/2); // KF1 + // Vector3d x(0,0,0); + VectorComposite x(Vector3d(0,0,0), "PO", {2,1}); + // Matrix3d P = Matrix3d::Identity() * 0.1; + VectorComposite P(Vector3d(sqrt(0.1),sqrt(0.1),sqrt(0.1)), "PO", {2,1}); + problem->setPriorFactor(x, P, t, dt/2); // KF1 CaptureOdom2dPtr capt_odo = make_shared<CaptureOdom2d>(t, sens_odo, Vector2d(0.5,0)); @@ -117,18 +113,24 @@ TEST(ProcessorBase, KeyFrameCallback) // Move t = t+dt; WOLF_INFO("----------------------- ts: ", t , " --------------------------"); + std::cout << "1\n"; capt_odo->setTimeStamp(t); + std::cout << "2\n"; proc_odo->captureCallback(capt_odo); + std::cout << "3\n"; // Track capt_trk = make_shared<CaptureVoid>(t, sens_trk); + std::cout << "4\n"; proc_trk->captureCallback(capt_trk); + std::cout << "5\n"; - problem->print(4,1,1,0); + problem->print(4,1,1,0); + std::cout << "6\n"; // Only odom creating KFs - ASSERT_TRUE( problem->getLastKeyFrame()->getType().compare("PO 2d")==0 ); + ASSERT_TRUE( problem->getLastKeyFrame()->getStructure().compare("PO")==0 ); } } @@ -137,4 +139,3 @@ int main(int argc, char **argv) testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } - diff --git a/test/gtest_processor_diff_drive.cpp b/test/gtest_processor_diff_drive.cpp index 612f66019cd62b892a300df15da4a809b0d51e9a..ee908013b9eadd216363d528d7f60757ea331f29 100644 --- a/test/gtest_processor_diff_drive.cpp +++ b/test/gtest_processor_diff_drive.cpp @@ -20,7 +20,7 @@ class ProcessorDiffDrivePublic : public ProcessorDiffDrive { using Base = ProcessorDiffDrive; public: - ProcessorDiffDrivePublic(ProcessorParamsDiffDrivePtr _params_motion) : + ProcessorDiffDrivePublic(ParamsProcessorDiffDrivePtr _params_motion) : ProcessorDiffDrive(_params_motion) { // @@ -58,10 +58,10 @@ class ProcessorDiffDrivePublic : public ProcessorDiffDrive Base::deltaPlusDelta(_delta1, _delta2, _dt2, _delta1_plus_delta2, _jacobian1, _jacobian2); } - virtual void statePlusDelta(const Eigen::VectorXd& _x, + virtual void statePlusDelta(const VectorComposite& _x, const Eigen::VectorXd& _delta, const double _dt, - Eigen::VectorXd& _x_plus_delta) const + VectorComposite& _x_plus_delta) const { Base::statePlusDelta(_x, _delta, _dt, _x_plus_delta); } @@ -94,7 +94,7 @@ class ProcessorDiffDrivePublic : public ProcessorDiffDrive return Base::emplaceFactor(_feature_motion, _capture_origin); } - ProcessorParamsDiffDrivePtr getParams() + ParamsProcessorDiffDrivePtr getParams() { return params_prc_diff_drv_selfcal_; } @@ -111,7 +111,7 @@ class ProcessorDiffDriveTest : public testing::Test public: ParamsSensorDiffDrivePtr intr; SensorDiffDrivePtr sensor; - ProcessorParamsDiffDrivePtr params; + ParamsProcessorDiffDrivePtr params; ProcessorDiffDrivePublicPtr processor; ProblemPtr problem; @@ -129,7 +129,7 @@ class ProcessorDiffDriveTest : public testing::Test sensor = std::static_pointer_cast<SensorDiffDrive>(problem->installSensor("SensorDiffDrive", "sensor diff drive", extr, intr)); // params and processor - params = std::make_shared<ProcessorParamsDiffDrive>(); + params = std::make_shared<ParamsProcessorDiffDrive>(); params->voting_active = true; params->angle_turned = 1; params->dist_traveled = 2; @@ -145,7 +145,7 @@ class ProcessorDiffDriveTest : public testing::Test TEST(ProcessorDiffDrive, constructor) { - auto params = std::make_shared<ProcessorParamsDiffDrive>(); + auto params = std::make_shared<ParamsProcessorDiffDrive>(); ASSERT_NE(params, nullptr); @@ -164,7 +164,7 @@ TEST(ProcessorDiffDrive, create) auto sen = std::make_shared<SensorDiffDrive>(extr, intr); // params - auto params = std::make_shared<ProcessorParamsDiffDrive>(); + auto params = std::make_shared<ParamsProcessorDiffDrive>(); // processor auto prc_base = ProcessorDiffDrive::create("prc", params); @@ -268,7 +268,8 @@ TEST_F(ProcessorDiffDriveTest, statePlusDelta) Matrix2d data_cov; data_cov . setIdentity(); Vector3d calib(1,1,1); double dt = 1.0; - VectorXd delta(3), x1(3), x2(3); + VectorXd delta(3); + VectorComposite x1("PO", {2,1}), x2("PO", {2,1}); MatrixXd delta_cov(3,3), J_delta_calib(3,3); // 1. left turn 90 deg in 3 steps of 30 deg --> ends up in (1.5, 1.5, pi/2) @@ -283,7 +284,7 @@ TEST_F(ProcessorDiffDriveTest, statePlusDelta) x1 = x2; processor->statePlusDelta(x1, delta, dt, x2); // 90 - ASSERT_MATRIX_APPROX(x2, Vector3d(1.5, 1.5, M_PI_2), 1e-6); + ASSERT_MATRIX_APPROX(x2.vector("PO"), Vector3d(1.5, 1.5, M_PI_2), 1e-6); // 2. right turn 90 deg in 4 steps of 22.5 deg --> ends up in (1.5, -1.5, -pi/2) data(0) = 0.50*intr->ticks_per_wheel_revolution / 4; @@ -299,7 +300,7 @@ TEST_F(ProcessorDiffDriveTest, statePlusDelta) x1 = x2; processor->statePlusDelta(x1, delta, dt, x2); // 90 - ASSERT_MATRIX_APPROX(x2, Vector3d(1.5, -1.5, -M_PI_2), 1e-6); + ASSERT_MATRIX_APPROX(x2.vector("PO"), Vector3d(1.5, -1.5, -M_PI_2), 1e-6); } TEST_F(ProcessorDiffDriveTest, process) @@ -308,10 +309,13 @@ TEST_F(ProcessorDiffDriveTest, process) Matrix2d data_cov; data_cov . setIdentity(); TimeStamp t = 0.0; double dt = 1.0; - Vector3d x(0,0,0); - Matrix3d P; P.setIdentity(); + // Vector3d x(0,0,0); + VectorComposite x(Vector3d(0,0,0), "PO", {2,1}); + // Matrix3d P; P.setIdentity(); + VectorComposite P(Vector3d(1,1,1), "PO", {2,1}); - auto F0 = problem->setPrior(x, P, t, 0.1); + auto F0 = problem->setPriorFactor(x, P, t, 0.1); + processor->setOrigin(F0); // 1. left turn 90 deg in N steps of 90/N deg --> ends up in (1.5, 1.5, pi/2) int N = 9; @@ -320,14 +324,12 @@ TEST_F(ProcessorDiffDriveTest, process) auto C = std::make_shared<CaptureDiffDrive>(t, sensor, data, data_cov, F0->getCaptureList().front()); - WOLF_TRACE("t = ", t, "; x = ", processor->getCurrentState().transpose()); for (int n = 1; n <= N; n++) { - C->process(); - WOLF_TRACE("t = ", t, "; x = ", processor->getCurrentState().transpose()); - t += dt; C->setTimeStamp(t); + C->process(); + WOLF_TRACE("t = ", t, "; x = ", processor->getState().vector("PO").transpose()); } problem->print(4,1,1,1); @@ -338,10 +340,13 @@ TEST_F(ProcessorDiffDriveTest, linear) Vector2d data; Matrix2d data_cov; data_cov . setIdentity(); TimeStamp t = 0.0; - Vector3d x(0,0,0); - Matrix3d P; P.setIdentity(); + // Vector3d x(0,0,0); + VectorComposite x(Vector3d(0,0,0), "PO", {2,1}); + // Matrix3d P; P.setIdentity(); + VectorComposite P(Vector3d(1,1,1), "PO", {2,1}); - auto F0 = problem->setPrior(x, P, t, 0.1); + auto F0 = problem->setPriorFactor(x, P, t, 0.1); + processor->setOrigin(F0); // Straight one turn of the wheels, in one go data(0) = 100.0 ; // one turn of the wheels @@ -350,12 +355,12 @@ TEST_F(ProcessorDiffDriveTest, linear) auto C = std::make_shared<CaptureDiffDrive>(t, sensor, data, data_cov, F0->getCaptureList().front()); C->process(); - WOLF_TRACE("t = ", t, "; x = ", processor->getCurrentState().transpose()); + WOLF_TRACE("t = ", t, "; x = ", processor->getState().vector("PO").transpose()); // radius is 1.0m, 100 ticks per revolution, so advanced distance is double distance = 2 * M_PI * 1.0; - ASSERT_MATRIX_APPROX(processor->getCurrentState(), Vector3d(distance,0,0), 1e-6) + ASSERT_MATRIX_APPROX(processor->getState().vector("PO"), Vector3d(distance,0,0), 1e-6) } TEST_F(ProcessorDiffDriveTest, angular) @@ -363,10 +368,13 @@ TEST_F(ProcessorDiffDriveTest, angular) Vector2d data; Matrix2d data_cov; data_cov . setIdentity(); TimeStamp t = 0.0; - Vector3d x(0,0,0); - Matrix3d P; P.setIdentity(); + // Vector3d x(0,0,0); + VectorComposite x(Vector3d(0,0,0), "PO", {2,1}); + // Matrix3d P; P.setIdentity(); + VectorComposite P(Vector3d(1,1,1), "PO", {2,1}); - auto F0 = problem->setPrior(x, P, t, 0.1); + auto F0 = problem->setPriorFactor(x, P, t, 0.1); + processor->setOrigin(F0); // Straight one turn of the wheels, in one go data(0) = -20.0 ; // one fifth of a turn of the left wheel, in reverse @@ -375,7 +383,7 @@ TEST_F(ProcessorDiffDriveTest, angular) auto C = std::make_shared<CaptureDiffDrive>(t, sensor, data, data_cov, F0->getCaptureList().front()); C->process(); - WOLF_TRACE("t = ", t, "; x = ", processor->getCurrentState().transpose()); + WOLF_TRACE("t = ", t, "; x = ", processor->getState().vector("PO").transpose()); // this is a turn in place, so distance = 0; double distance = 0.0; @@ -383,7 +391,7 @@ TEST_F(ProcessorDiffDriveTest, angular) // radius is 1.0m, 100 ticks per revolution, and wheel separation is 1m, so turn angle is double angle = pi2pi(2 * M_PI * 1.0 / 0.5 / 5); - ASSERT_MATRIX_APPROX(processor->getCurrentState(), Vector3d(distance,0,angle), 1e-6) + ASSERT_MATRIX_APPROX(processor->getState().vector("PO"), Vector3d(distance,0,angle), 1e-6) } diff --git a/test/gtest_processor_loopclosure.cpp b/test/gtest_processor_loopclosure.cpp index d00fb93407ab75bb150a576bc434640f1c75fe12..9b8683f8b74ee566370d4630a248d039257ebb17 100644 --- a/test/gtest_processor_loopclosure.cpp +++ b/test/gtest_processor_loopclosure.cpp @@ -23,16 +23,16 @@ private: bool* factor_created; public: - ProcessorLoopClosureDummy(ProcessorParamsLoopClosurePtr _params_loop_closure, bool& factor_created): + ProcessorLoopClosureDummy(ParamsProcessorLoopClosurePtr _params_loop_closure, bool& factor_created): ProcessorLoopClosure("LOOP CLOSURE DUMMY", 0, _params_loop_closure), factor_created(&factor_created){}; std::pair<FrameBasePtr,CaptureBasePtr> public_selectPairKC(){ return selectPairKC();}; protected: - virtual bool voteComputeFeatures() { return true;}; - virtual bool voteSearchLoopClosure() { return true;}; - virtual bool detectFeatures(CaptureBasePtr cap) { return true;}; - virtual CaptureBasePtr findLoopCandidate(CaptureBasePtr _capture) + virtual bool voteComputeFeatures() override { return true;}; + virtual bool voteSearchLoopClosure() override { return true;}; + virtual bool detectFeatures(CaptureBasePtr cap) override { return true;}; + virtual CaptureBasePtr findLoopCandidate(CaptureBasePtr _capture) override { for (FrameBasePtr kf : getProblem()->getTrajectory()->getFrameList()) if (kf->isKey()) @@ -41,7 +41,8 @@ protected: return cap; return nullptr; }; - virtual void emplaceFactors(CaptureBasePtr _capture_1, CaptureBasePtr _capture_2) { + virtual void emplaceFactors(CaptureBasePtr _capture_1, CaptureBasePtr _capture_2) override + { std::cout << "factor created\n"; *factor_created = true; }; @@ -71,20 +72,22 @@ TEST(ProcessorLoopClosure, installProcessor) std::make_shared<StateBlock>(Eigen::VectorXd::Zero(2)), std::make_shared<StateBlock>(Eigen::VectorXd::Zero(1)), std::make_shared<StateBlock>(Eigen::VectorXd::Zero(2)), 2); - ProcessorParamsLoopClosurePtr params = std::make_shared<ProcessorParamsLoopClosure>(); + ParamsProcessorLoopClosurePtr params = std::make_shared<ParamsProcessorLoopClosure>(); auto proc_lc = ProcessorBase::emplace<ProcessorLoopClosureDummy>(sens_lc, params, factor_created); std::cout << "sensor & processor created and added to wolf problem" << std::endl; // initialize TimeStamp t(0.0); - Vector3d x(0,0,0); - Matrix3d P = Matrix3d::Identity() * 0.1; - problem->setPrior(x, P, t, dt/2); // KF1 + // Vector3d x(0,0,0); + VectorComposite x(Vector3d(0,0,0), "PO", {2,1}); + // Matrix3d P = Matrix3d::Identity() * 0.1; + VectorComposite P(Vector3d(sqrt(0.1),sqrt(0.1),sqrt(0.1)), "PO", {2,1}); + problem->setPriorFactor(x, P, t, dt/2); // KF1 // new KF t += dt; - auto kf = problem->emplaceFrame(KEY, x, t); //KF2 + auto kf = problem->emplaceFrame(KEY, t, x); //KF2 // emplace a capture in KF auto capt_lc = CaptureBase::emplace<CaptureVoid>(kf, t, sens_lc); proc_lc->captureCallback(capt_lc); diff --git a/test/gtest_processor_motion.cpp b/test/gtest_processor_motion.cpp index 076118ba3d7836dbf61cdb2ed1d38d81d46b9084..509f495c1bd4c56be08f2d70279e6fba9a5b6ccc 100644 --- a/test/gtest_processor_motion.cpp +++ b/test/gtest_processor_motion.cpp @@ -21,7 +21,7 @@ using std::static_pointer_cast; class ProcessorOdom2dPublic : public ProcessorOdom2d { public: - ProcessorOdom2dPublic(ProcessorParamsOdom2dPtr params) : ProcessorOdom2d(params) + ProcessorOdom2dPublic(ParamsProcessorOdom2dPtr params) : ProcessorOdom2d(params) { // } @@ -63,7 +63,7 @@ class ProcessorMotion_test : public testing::Test{ dt = 1.0; problem = Problem::create("PO", 2); sensor = static_pointer_cast<SensorOdom2d>(problem->installSensor("SensorOdom2d", "odom", Vector3d(0,0,0), wolf_root + "/test/yaml/sensor_odom_2d.yaml")); - ProcessorParamsOdom2dPtr params(std::make_shared<ProcessorParamsOdom2d>()); + ParamsProcessorOdom2dPtr params(std::make_shared<ParamsProcessorOdom2d>()); params->time_tolerance = 0.25; params->dist_traveled = 100; params->angle_turned = 6.28; @@ -71,19 +71,19 @@ class ProcessorMotion_test : public testing::Test{ params->cov_det = 100; params->unmeasured_perturbation_std = 0.001; processor = ProcessorBase::emplace<ProcessorOdom2dPublic>(sensor, params); - capture = std::make_shared<CaptureMotion>("CaptureOdom2d", 0.0, sensor, data, data_cov, 3, 3, nullptr); - - Vector3d x0; x0 << 0, 0, 0; - Matrix3d P0; P0.setIdentity(); - problem->setPrior(x0, P0, 0.0, 0.01); + capture = std::make_shared<CaptureMotion>("CaptureOdom2d", 0.0, sensor, data, data_cov, nullptr); } virtual void TearDown(){} }; -TEST_F(ProcessorMotion_test, IntegrateStraight) +TEST_F(ProcessorMotion_test, IntegrateStraightAutoPrior) { + // Prior + Vector3d x0; x0 << 0, 0, 0; + Matrix3d P0; P0.setIdentity(); + data << 1, 0; // advance straight data_cov.setIdentity(); TimeStamp t(0.0); @@ -95,17 +95,130 @@ TEST_F(ProcessorMotion_test, IntegrateStraight) capture->setData(data); capture->setDataCovariance(data_cov); processor->captureCallback(capture); - WOLF_DEBUG("t: ", t, " x: ", problem->getCurrentState().transpose()); + WOLF_DEBUG("t: ", t, " x: ", problem->getState().vector("PO").transpose()); + } + + ASSERT_MATRIX_APPROX(problem->getState().vector("PO"), (Vector3d()<<9,0,0).finished(), 1e-8); +} + + +TEST_F(ProcessorMotion_test, IntegrateStraightFactorPrior) +{ + // Prior + TimeStamp t(0.0); + // Vector3d x0; x0 << 0, 0, 0; + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); + // Matrix3d P0; P0.setIdentity(); + VectorComposite s0(Vector3d(1,1,1), "PO", {2,1}); + auto KF_0 = problem->setPriorFactor(x0, s0, t, 0.01); + processor->setOrigin(KF_0); + + data << 1, 0; // advance straight + data_cov.setIdentity(); + + for (int i = 0; i<9; i++) + { + t += dt; + capture->setTimeStamp(t); + capture->setData(data); + capture->setDataCovariance(data_cov); + processor->captureCallback(capture); + WOLF_DEBUG("t: ", t, " x: ", problem->getState().vector("PO").transpose()); + } + + ASSERT_MATRIX_APPROX(problem->getState().vector("PO"), (Vector3d()<<9,0,0).finished(), 1e-8); +} + +TEST_F(ProcessorMotion_test, IntegrateStraightFixPrior) +{ + // Prior + TimeStamp t(0.0); + // Vector3d x0; x0 << 0, 0, 0; + // Matrix3d P0; P0.setIdentity(); + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); + VectorComposite s0(Vector3d(1,1,1), "PO", {2,1}); + auto KF_0 = problem->setPriorFix(x0, t, 0.01); + processor->setOrigin(KF_0); + + data << 1, 0; // advance straight + data_cov.setIdentity(); + + for (int i = 0; i<9; i++) + { + t += dt; + capture->setTimeStamp(t); + capture->setData(data); + capture->setDataCovariance(data_cov); + processor->captureCallback(capture); + WOLF_DEBUG("t: ", t, " x: ", problem->getState().vector("PO").transpose()); } - ASSERT_MATRIX_APPROX(problem->getCurrentState(), (Vector3d()<<9,0,0).finished(), 1e-8); + ASSERT_MATRIX_APPROX(problem->getState().vector("PO"), (Vector3d()<<9,0,0).finished(), 1e-8); } -TEST_F(ProcessorMotion_test, IntegrateCircle) +TEST_F(ProcessorMotion_test, IntegrateCircleAutoPrior) { + // Prior + Vector3d x0; x0 << 0, 0, 0; + Matrix3d P0; P0.setIdentity(); + + data << 1, 2*M_PI/10; // advance in circle + data_cov.setIdentity(); + TimeStamp t(0.0); + + for (int i = 0; i<10; i++) // one full turn exactly + { + t += dt; + capture->setTimeStamp(t); + capture->setData(data); + capture->setDataCovariance(data_cov); + processor->captureCallback(capture); + WOLF_DEBUG("t: ", t, " x: ", problem->getState().vector("PO").transpose()); + } + + ASSERT_MATRIX_APPROX(problem->getState().vector("PO"), (Vector3d()<<0,0,0).finished(), 1e-8); +} + +TEST_F(ProcessorMotion_test, IntegrateCircleFactorPrior) +{ + // Prior + TimeStamp t(0.0); + // Vector3d x0; x0 << 0, 0, 0; + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); + // Matrix3d P0; P0.setIdentity(); + VectorComposite s0(Vector3d(1,1,1), "PO", {2,1}); + auto KF_0 = problem->setPriorFactor(x0, s0, t, 0.01); + processor->setOrigin(KF_0); + data << 1, 2*M_PI/10; // advance in circle data_cov.setIdentity(); + + for (int i = 0; i<10; i++) // one full turn exactly + { + t += dt; + capture->setTimeStamp(t); + capture->setData(data); + capture->setDataCovariance(data_cov); + processor->captureCallback(capture); + WOLF_DEBUG("t: ", t, " x: ", problem->getState().vector("PO").transpose()); + } + + ASSERT_MATRIX_APPROX(problem->getState().vector("PO"), (Vector3d()<<0,0,0).finished(), 1e-8); +} + +TEST_F(ProcessorMotion_test, IntegrateCircleFixPrior) +{ + // Prior TimeStamp t(0.0); + // Vector3d x0; x0 << 0, 0, 0; + // Matrix3d P0; P0.setIdentity(); + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); + VectorComposite s0(Vector3d(1,1,1), "PO", {2,1}); + auto KF_0 = problem->setPriorFix(x0, t, 0.01); + processor->setOrigin(KF_0); + + data << 1, 2*M_PI/10; // advance in circle + data_cov.setIdentity(); for (int i = 0; i<10; i++) // one full turn exactly { @@ -114,14 +227,18 @@ TEST_F(ProcessorMotion_test, IntegrateCircle) capture->setData(data); capture->setDataCovariance(data_cov); processor->captureCallback(capture); - WOLF_DEBUG("t: ", t, " x: ", problem->getCurrentState().transpose()); + WOLF_DEBUG("t: ", t, " x: ", problem->getState().vector("PO").transpose()); } - ASSERT_MATRIX_APPROX(problem->getCurrentState(), (Vector3d()<<0,0,0).finished(), 1e-8); + ASSERT_MATRIX_APPROX(problem->getState().vector("PO"), (Vector3d()<<0,0,0).finished(), 1e-8); } -TEST_F(ProcessorMotion_test, splitBuffer) +TEST_F(ProcessorMotion_test, splitBufferAutoPrior) { + // Prior + Vector3d x0; x0 << 0, 0, 0; + Matrix3d P0; P0.setIdentity(); + data << 1, 2*M_PI/10; // advance in circle data_cov.setIdentity(); TimeStamp t(0.0); @@ -133,7 +250,97 @@ TEST_F(ProcessorMotion_test, splitBuffer) capture->setData(data); capture->setDataCovariance(data_cov); processor->captureCallback(capture); - WOLF_DEBUG("t: ", t, " x: ", problem->getCurrentState().transpose()); + WOLF_DEBUG("t: ", t, " x: ", problem->getState().vector("PO").transpose()); + } + + SensorBasePtr S = processor->getSensor(); + + TimeStamp t_target = 8.5; + FrameBasePtr F_target = problem->emplaceFrame(KEY, t_target); + CaptureMotionPtr C_source = std::dynamic_pointer_cast<CaptureMotion>(processor->getLast()); + CaptureMotionPtr C_target = CaptureBase::emplace<CaptureMotion>(F_target, + "ODOM 2d", + t_target, + sensor, + data, + nullptr); + + processor->splitBuffer(C_source, + t_target, + F_target, + C_target); + + C_target->getBuffer().print(1,1,1,0); + C_source->getBuffer().print(1,1,1,0); +} + +TEST_F(ProcessorMotion_test, splitBufferFactorPrior) +{ + // Prior + TimeStamp t(0.0); + // Vector3d x0; x0 << 0, 0, 0; + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); + // Matrix3d P0; P0.setIdentity(); + VectorComposite s0(Vector3d(1,1,1), "PO", {2,1}); + auto KF_0 = problem->setPriorFactor(x0, s0, t, 0.01); + processor->setOrigin(KF_0); + + data << 1, 2*M_PI/10; // advance in circle + data_cov.setIdentity(); + + for (int i = 0; i<10; i++) // one full turn exactly + { + t += dt; + capture->setTimeStamp(t); + capture->setData(data); + capture->setDataCovariance(data_cov); + processor->captureCallback(capture); + WOLF_DEBUG("t: ", t, " x: ", problem->getState().vector("PO").transpose()); + } + + SensorBasePtr S = processor->getSensor(); + + TimeStamp t_target = 8.5; + FrameBasePtr F_target = problem->emplaceFrame(KEY, t_target); + CaptureMotionPtr C_source = std::dynamic_pointer_cast<CaptureMotion>(processor->getLast()); + CaptureMotionPtr C_target = CaptureBase::emplace<CaptureMotion>(F_target, + "ODOM 2d", + t_target, + sensor, + data, + nullptr); + + processor->splitBuffer(C_source, + t_target, + F_target, + C_target); + + C_target->getBuffer().print(1,1,1,0); + C_source->getBuffer().print(1,1,1,0); +} + +TEST_F(ProcessorMotion_test, splitBufferFixPrior) +{ + // Prior + TimeStamp t(0.0); + // Vector3d x0; x0 << 0, 0, 0; + // Matrix3d P0; P0.setIdentity(); + VectorComposite x0(Vector3d(0,0,0), "PO", {2,1}); + VectorComposite s0(Vector3d(1,1,1), "PO", {2,1}); + auto KF_0 = problem->setPriorFix(x0, t, 0.01); + processor->setOrigin(KF_0); + + data << 1, 2*M_PI/10; // advance in circle + data_cov.setIdentity(); + + for (int i = 0; i<10; i++) // one full turn exactly + { + t += dt; + capture->setTimeStamp(t); + capture->setData(data); + capture->setDataCovariance(data_cov); + processor->captureCallback(capture); + WOLF_DEBUG("t: ", t, " x: ", problem->getState().vector("PO").transpose()); } SensorBasePtr S = processor->getSensor(); @@ -146,8 +353,6 @@ TEST_F(ProcessorMotion_test, splitBuffer) t_target, sensor, data, - 3, - 3, nullptr); processor->splitBuffer(C_source, diff --git a/test/gtest_processor_odom_3d.cpp b/test/gtest_processor_odom_3d.cpp index 24e5e875ea0b5775747c7325239884a586f0a0c4..4a94d3e1b88d1afc89ef80a39b9fad1baa67a1f7 100644 --- a/test/gtest_processor_odom_3d.cpp +++ b/test/gtest_processor_odom_3d.cpp @@ -52,7 +52,7 @@ class ProcessorOdom3dTest : public ProcessorOdom3d double& dvar_min() {return min_disp_var_;} double& rvar_min() {return min_rot_var_;} }; -ProcessorOdom3dTest::ProcessorOdom3dTest() : ProcessorOdom3d(std::make_shared<ProcessorParamsOdom3d>()) +ProcessorOdom3dTest::ProcessorOdom3dTest() : ProcessorOdom3d(std::make_shared<ParamsProcessorOdom3d>()) { dvar_min() = 0.5; rvar_min() = 0.25; diff --git a/test/gtest_processor_tracker_feature_dummy.cpp b/test/gtest_processor_tracker_feature_dummy.cpp index c8bf458bbcdc5058862accd76beedcb13b1d011f..604cd09b4f20ed68e1c44273f85a93c8c1a88c1a 100644 --- a/test/gtest_processor_tracker_feature_dummy.cpp +++ b/test/gtest_processor_tracker_feature_dummy.cpp @@ -1,7 +1,7 @@ // wolf includes #include "core/utils/utils_gtest.h" -#include "core/sensor/sensor_factory.h" +#include "core/sensor/factory_sensor.h" #include "dummy/processor_tracker_feature_dummy.h" #include "core/capture/capture_void.h" @@ -15,7 +15,7 @@ class ProcessorTrackerFeatureDummyDummy : public ProcessorTrackerFeatureDummy { public: - ProcessorTrackerFeatureDummyDummy(ProcessorParamsTrackerFeatureDummyPtr& _params) : + ProcessorTrackerFeatureDummyDummy(ParamsProcessorTrackerFeatureDummyPtr& _params) : ProcessorTrackerFeatureDummy(_params){} void setLast(CaptureBasePtr _last_ptr){ last_ptr_ = _last_ptr; } @@ -71,7 +71,7 @@ class ProcessorTrackerFeatureDummyTest : public testing::Test public: ProblemPtr problem; SensorBasePtr sensor; - ProcessorParamsTrackerFeatureDummyPtr params; + ParamsProcessorTrackerFeatureDummyPtr params; ProcessorTrackerFeatureDummyDummyPtr processor; virtual ~ProcessorTrackerFeatureDummyTest(){} @@ -85,7 +85,7 @@ class ProcessorTrackerFeatureDummyTest : public testing::Test sensor = problem->installSensor("SensorOdom2d", "auxiliar sensor", (Eigen::Vector3d() << 0,0,0).finished(), std::make_shared<ParamsSensorBase>()); // Install processor - params = std::make_shared<ProcessorParamsTrackerFeatureDummy>(); + params = std::make_shared<ParamsProcessorTrackerFeatureDummy>(); params->max_new_features = 10; params->min_features_for_keyframe = 7; params->time_tolerance = 0.25; @@ -283,7 +283,7 @@ TEST_F(ProcessorTrackerFeatureDummyTest, process) { //1ST TIME -> KF (origin) - WOLF_DEBUG("First time..."); + WOLF_INFO("First time..."); CaptureBasePtr cap1 = std::make_shared<CaptureVoid>(0, sensor); cap1->process(); @@ -292,7 +292,7 @@ TEST_F(ProcessorTrackerFeatureDummyTest, process) ASSERT_TRUE(problem->check(0)); //2ND TIME - WOLF_DEBUG("Second time..."); + WOLF_INFO("Second time..."); CaptureBasePtr cap2 = std::make_shared<CaptureVoid>(1, sensor); cap2->process(); @@ -301,7 +301,7 @@ TEST_F(ProcessorTrackerFeatureDummyTest, process) ASSERT_TRUE(problem->check(0)); //3RD TIME - WOLF_DEBUG("Third time..."); + WOLF_INFO("Third time..."); CaptureBasePtr cap3 = std::make_shared<CaptureVoid>(2, sensor); cap3->process(); @@ -309,7 +309,7 @@ TEST_F(ProcessorTrackerFeatureDummyTest, process) ASSERT_TRUE(problem->check(0)); //4TH TIME - WOLF_DEBUG("Forth time..."); + WOLF_INFO("Forth time..."); CaptureBasePtr cap4 = std::make_shared<CaptureVoid>(3, sensor); cap4->process(); @@ -317,7 +317,7 @@ TEST_F(ProcessorTrackerFeatureDummyTest, process) ASSERT_TRUE(problem->check(0)); //5TH TIME -> KF in cap4 (tracked features < 7 (params->min_features_for_keyframe)) - WOLF_DEBUG("Fifth time..."); + WOLF_INFO("Fifth time..."); CaptureBasePtr cap5 = std::make_shared<CaptureVoid>(4, sensor); cap5->process(); @@ -326,7 +326,7 @@ TEST_F(ProcessorTrackerFeatureDummyTest, process) ASSERT_TRUE(problem->check(0)); // check factors - WOLF_DEBUG("checking factors..."); + WOLF_INFO("checking factors..."); TrackMatrix track_matrix = processor->getTrackMatrix(); ASSERT_EQ(cap4->getFeatureList().size(), params->min_features_for_keyframe + params->max_new_features); ASSERT_TRUE(problem->check(0)); diff --git a/test/gtest_processor_tracker_landmark_dummy.cpp b/test/gtest_processor_tracker_landmark_dummy.cpp index a75ba7ffb962509468343f66e894a1b527610c04..8963211c45c292341d3754e83579f8bf9738a752 100644 --- a/test/gtest_processor_tracker_landmark_dummy.cpp +++ b/test/gtest_processor_tracker_landmark_dummy.cpp @@ -1,7 +1,7 @@ // wolf includes #include "core/utils/utils_gtest.h" -#include "core/sensor/sensor_factory.h" +#include "core/sensor/factory_sensor.h" #include "dummy/processor_tracker_landmark_dummy.h" #include "core/capture/capture_void.h" @@ -15,7 +15,7 @@ class ProcessorTrackerLandmarkDummyDummy : public ProcessorTrackerLandmarkDummy { public: - ProcessorTrackerLandmarkDummyDummy(ProcessorParamsTrackerLandmarkDummyPtr& _params) : + ProcessorTrackerLandmarkDummyDummy(ParamsProcessorTrackerLandmarkDummyPtr& _params) : ProcessorTrackerLandmarkDummy(_params){} void setLast(CaptureBasePtr _last_ptr){ last_ptr_ = _last_ptr; } @@ -89,7 +89,7 @@ class ProcessorTrackerLandmarkDummyTest : public testing::Test public: ProblemPtr problem; SensorBasePtr sensor; - ProcessorParamsTrackerLandmarkDummyPtr params; + ParamsProcessorTrackerLandmarkDummyPtr params; ProcessorTrackerLandmarkDummyDummyPtr processor; virtual ~ProcessorTrackerLandmarkDummyTest(){} @@ -103,7 +103,7 @@ class ProcessorTrackerLandmarkDummyTest : public testing::Test sensor = problem->installSensor("SensorOdom2d", "auxiliar sensor", (Eigen::Vector3d() << 0,0,0).finished(), std::make_shared<ParamsSensorBase>()); // Install processor - params = std::make_shared<ProcessorParamsTrackerLandmarkDummy>(); + params = std::make_shared<ParamsProcessorTrackerLandmarkDummy>(); params->max_new_features = 10; params->min_features_for_keyframe = 7; params->time_tolerance = 0.25; diff --git a/test/gtest_solver_manager.cpp b/test/gtest_solver_manager.cpp index 640dc71faefcdfcaa937bdc928c904ef618f05d9..e8afad2af2283b3a0aaa2fdb7f9290fc9e633981 100644 --- a/test/gtest_solver_manager.cpp +++ b/test/gtest_solver_manager.cpp @@ -13,104 +13,20 @@ #include "core/state_block/state_block.h" #include "core/capture/capture_void.h" #include "core/factor/factor_pose_2d.h" -#include "core/solver/solver_manager.h" #include "core/state_block/local_parametrization_base.h" #include "core/state_block/local_parametrization_angle.h" +#include "dummy/solver_manager_dummy.h" #include <iostream> +#include <thread> using namespace wolf; using namespace Eigen; -WOLF_PTR_TYPEDEFS(SolverManagerWrapper); -class SolverManagerWrapper : public SolverManager -{ - public: - std::list<FactorBasePtr> factors_; - std::map<StateBlockPtr,bool> state_block_fixed_; - std::map<StateBlockPtr,LocalParametrizationBasePtr> state_block_local_param_; - - SolverManagerWrapper(const ProblemPtr& wolf_problem) : - SolverManager(wolf_problem) - { - }; - - bool isStateBlockRegistered(const StateBlockPtr& st) - { - return state_blocks_.find(st)!=state_blocks_.end(); - }; - - bool isStateBlockFixed(const StateBlockPtr& st) const - { - return state_block_fixed_.at(st); - }; - - bool isFactorRegistered(const FactorBasePtr& fac_ptr) const - { - return std::find(factors_.begin(), factors_.end(), fac_ptr) != factors_.end(); - }; - - bool hasThisLocalParametrization(const StateBlockPtr& st, const LocalParametrizationBasePtr& local_param) const - { - return state_block_local_param_.find(st) != state_block_local_param_.end() && state_block_local_param_.at(st) == local_param; - }; - - bool hasLocalParametrization(const StateBlockPtr& st) const - { - return state_block_local_param_.find(st) != state_block_local_param_.end(); - }; - - virtual void computeCovariances(const CovarianceBlocksToBeComputed blocks){}; - virtual void computeCovariances(const std::vector<StateBlockPtr>& st_list){}; - virtual bool isStateBlockRegisteredDerived(const StateBlockPtr& state_ptr){return true;}; - virtual bool isFactorRegisteredDerived(const FactorBasePtr& fac_ptr) const {return true;}; - - // The following are dummy implementations - bool hasConverged() { return true; } - SizeStd iterations() { return 1; } - double initialCost() { return double(1); } - double finalCost() { return double(0); } - - - - protected: - - virtual std::string solveImpl(const ReportVerbosity report_level){ return std::string("");}; - virtual void addFactor(const FactorBasePtr& fac_ptr) - { - factors_.push_back(fac_ptr); - }; - virtual void removeFactor(const FactorBasePtr& fac_ptr) - { - factors_.remove(fac_ptr); - }; - virtual void addStateBlock(const StateBlockPtr& state_ptr) - { - state_block_fixed_[state_ptr] = state_ptr->isFixed(); - state_block_local_param_[state_ptr] = state_ptr->getLocalParametrization(); - }; - virtual void removeStateBlock(const StateBlockPtr& state_ptr) - { - state_block_fixed_.erase(state_ptr); - state_block_local_param_.erase(state_ptr); - }; - virtual void updateStateBlockStatus(const StateBlockPtr& state_ptr) - { - state_block_fixed_[state_ptr] = state_ptr->isFixed(); - }; - virtual void updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr) - { - if (state_ptr->getLocalParametrization() == nullptr) - state_block_local_param_.erase(state_ptr); - else - state_block_local_param_[state_ptr] = state_ptr->getLocalParametrization(); - }; -}; - TEST(SolverManager, Create) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // check double pointers to branches ASSERT_EQ(P, solver_manager_ptr->getProblem()); @@ -119,7 +35,7 @@ TEST(SolverManager, Create) TEST(SolverManager, AddStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -138,7 +54,7 @@ TEST(SolverManager, AddStateBlock) TEST(SolverManager, DoubleAddStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -163,7 +79,7 @@ TEST(SolverManager, DoubleAddStateBlock) TEST(SolverManager, UpdateStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -211,7 +127,7 @@ TEST(SolverManager, UpdateStateBlock) TEST(SolverManager, AddUpdateStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -249,7 +165,7 @@ TEST(SolverManager, AddUpdateStateBlock) TEST(SolverManager, AddUpdateLocalParamStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -292,7 +208,7 @@ TEST(SolverManager, AddUpdateLocalParamStateBlock) TEST(SolverManager, AddLocalParamRemoveLocalParamStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -339,7 +255,7 @@ TEST(SolverManager, AddLocalParamRemoveLocalParamStateBlock) TEST(SolverManager, RemoveStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -364,7 +280,7 @@ TEST(SolverManager, RemoveStateBlock) TEST(SolverManager, AddRemoveStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -386,7 +302,7 @@ TEST(SolverManager, AddRemoveStateBlock) TEST(SolverManager, RemoveUpdateStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -405,7 +321,7 @@ TEST(SolverManager, RemoveUpdateStateBlock) TEST(SolverManager, DoubleRemoveStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -430,7 +346,7 @@ TEST(SolverManager, DoubleRemoveStateBlock) TEST(SolverManager, AddUpdatedStateBlock) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; @@ -508,17 +424,17 @@ TEST(SolverManager, AddUpdatedStateBlock) TEST(SolverManager, AddFactor) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, 0, P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); - FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); + auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); // notification Notification notif; @@ -535,17 +451,17 @@ TEST(SolverManager, AddFactor) TEST(SolverManager, RemoveFactor) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, 0, P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); - FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); + auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); // update solver solver_manager_ptr->update(); @@ -568,18 +484,18 @@ TEST(SolverManager, RemoveFactor) TEST(SolverManager, AddRemoveFactor) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, 0, P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); - FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); + auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); // notification Notification notif; @@ -603,18 +519,18 @@ TEST(SolverManager, AddRemoveFactor) TEST(SolverManager, DoubleRemoveFactor) { ProblemPtr P = Problem::create("PO", 2); - SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); // Create State block Vector2d state; state << 1, 2; StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceFrame(KEY, P->zeroState(), TimeStamp(0)); + FrameBasePtr F = P->emplaceFrame(KEY, TimeStamp(0), P->stateZero() ); auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); auto f = FeatureBase::emplace<FeatureBase>(C, "FeatureOdom2d", Vector3d::Zero(), Matrix3d::Identity()); - FactorPose2dPtr c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); + auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); // update solver solver_manager_ptr->update(); @@ -635,9 +551,44 @@ TEST(SolverManager, DoubleRemoveFactor) ASSERT_FALSE(solver_manager_ptr->isFactorRegistered(c)); } +TEST(SolverManager, MultiThreadingTruncatedNotifications) +{ + double Dt = 5.0; + ProblemPtr P = Problem::create("PO", 2); + SolverManagerDummyPtr solver_manager_ptr = std::make_shared<SolverManagerDummy>(P); + + // loop updating (without sleep) + std::thread t([&](){ + auto start_t = std::chrono::high_resolution_clock::now(); + while (true) + { + solver_manager_ptr->update(); + if (std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - start_t).count() > Dt) + break; + }}); + + // loop emplacing and removing frames (window of 10 KF) + auto start = std::chrono::high_resolution_clock::now(); + while (true) + { + // Emplace Frame, Capture, feature and factor pose 2d + FrameBasePtr F = P->emplaceFrame(KEY, TimeStamp(0), P->stateZero()); + auto C = CaptureBase::emplace<CaptureVoid>(F, 0, nullptr); + auto f = FeatureBase::emplace<FeatureBase>(C, "FeaturePose2d", Vector3d::Zero(), Matrix3d::Identity()); + auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); + + if (P->getTrajectory()->getFrameList().size() > 10) + P->getTrajectory()->getFrameList().front()->remove(); + + if (std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - start).count() > Dt) + break; + } + + t.join(); +} + int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } - diff --git a/test/gtest_state_composite.cpp b/test/gtest_state_composite.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d5a420119526c2fc1984aecfc22e01b40d0084b --- /dev/null +++ b/test/gtest_state_composite.cpp @@ -0,0 +1,886 @@ +/* + * gtest_state_composite.cpp + * + * Created on: Apr 6, 2020 + * Author: jsola + */ + +#include "core/state_block/state_composite.h" +#include "core/state_block/state_quaternion.h" + +#include "core/utils/utils_gtest.h" + +using namespace wolf; +using namespace std; + + +class StateBlockCompositeInit : public testing::Test +{ + public: + + StateBlockPtr sbp, sbv, sbx; + StateQuaternionPtr sbq; + + StateBlockComposite states; + + void SetUp() override + { + sbp = states.emplace("P", Vector3d(1,2,3)); + sbv = states.emplace("V", Vector3d(4,5,6)); + sbq = states.emplace<StateQuaternion>("Q", Vector4d(.5,.5,.5,.5)); + + sbx = std::make_shared<StateBlock>(Vector3d(7,8,9)); + } +}; + +TEST_F(StateBlockCompositeInit, stateSize) +{ + ASSERT_EQ( states.stateSize() , 10 ); + ASSERT_EQ( states.stateSize("PQ"), 7 ); + ASSERT_EQ( states.stateSize("PV"), 6 ); +} + +TEST_F(StateBlockCompositeInit, stateVector) +{ + ASSERT_EQ( states.stateVector("PQ") , (VectorXd( 7) << 1,2,3,.5,.5,.5,.5) .finished() ); + ASSERT_EQ( states.stateVector("PVQ"), (VectorXd(10) << 1,2,3,4,5,6,.5,.5,.5,.5).finished() ); + ASSERT_EQ( states.stateVector("PQV"), (VectorXd(10) << 1,2,3,.5,.5,.5,.5,4,5,6).finished() ); +} + +TEST_F(StateBlockCompositeInit, emplace) +{ + // Emplaces called in SetUp() + + // check 3 elements + ASSERT_EQ(states.getStateBlockMap().size(), 3); +} + +TEST_F(StateBlockCompositeInit, has_key) +{ + ASSERT_TRUE(states.has("P")); + ASSERT_FALSE(states.has("X")); +} + +TEST_F(StateBlockCompositeInit, has_sb) +{ + ASSERT_TRUE(states.has(sbp)); + ASSERT_FALSE(states.has(sbx)); +} + +TEST_F(StateBlockCompositeInit, at) +{ + ASSERT_EQ(states.at("P"), sbp); + + ASSERT_EQ(states.at("X"), nullptr); +} + +TEST_F(StateBlockCompositeInit, set_sb) +{ + states.set("P", sbx); + + ASSERT_EQ(states.at("P"), sbx); + + states.set("P", sbp); + + ASSERT_DEATH(states.set("X", sbx), ""); + + ASSERT_EQ(states.at("X"), nullptr); +} + +TEST_F(StateBlockCompositeInit, set_vec) +{ + Vector3d p(11,22,33); + Vector3d x(55,66,77); + + states.set("P", p); + + ASSERT_MATRIX_APPROX(states.at("P")->getState(), p, 1e-20); + + ASSERT_DEATH(states.set("X", x), ""); + + ASSERT_EQ(states.at("X"), nullptr); +} + +TEST_F(StateBlockCompositeInit, set_vectors) +{ + Vector3d p(11,22,33); + Vector4d q(11,22,33,44); q.normalize(); + Vector3d x(55,66,77); + + states.setVectors("PQ", {p, q}); + + ASSERT_MATRIX_APPROX(states.at("P")->getState(), p, 1e-20); + ASSERT_MATRIX_APPROX(states.at("Q")->getState(), q, 1e-20); + + ASSERT_DEATH(states.setVectors("PX", {p,x}), ""); + + ASSERT_EQ(states.at("X"), nullptr); +} + +TEST_F(StateBlockCompositeInit, key_ref) +{ + std::string key; + ASSERT_TRUE(states.key(sbp, key)); + ASSERT_EQ(key, "P"); + + ASSERT_FALSE(states.key(sbx, key)); + ASSERT_EQ(key, ""); +} + +TEST_F(StateBlockCompositeInit, key_return) +{ + // existing key + ASSERT_EQ(states.key(sbp), "P"); + + // non existing key returns empty string + ASSERT_EQ(states.key(sbx), ""); +} + +TEST_F(StateBlockCompositeInit, find) +{ + auto it = states.find(sbp); + ASSERT_NE(it, states.getStateBlockMap().end()); + + it = states.find(sbx); + ASSERT_EQ(it, states.getStateBlockMap().end()); +} + +TEST_F(StateBlockCompositeInit, add) +{ + states.add("X", sbx); + + ASSERT_EQ(states.at("X"), sbx); +} + +TEST_F(StateBlockCompositeInit, remove) +{ + // remove existing block + states.remove("V"); + ASSERT_EQ(states.getStateBlockMap().size(), 2); + + // remove non existing block -- no effect + states.remove("X"); + ASSERT_EQ(states.getStateBlockMap().size(), 2); +} + +TEST_F(StateBlockCompositeInit, perturb) +{ + ASSERT_TRUE(states.at("P")->getState().isApprox(sbp->getState(), 1e-3)); + ASSERT_TRUE(states.at("V")->getState().isApprox(sbv->getState(), 1e-3)); + ASSERT_TRUE(states.at("Q")->getState().isApprox(sbq->getState(), 1e-3)); + + states.perturb(0.1); + + // values have moved wrt original + ASSERT_FALSE(states.at("P")->getState().isApprox(Vector3d(1,2,3), 1e-3)); + ASSERT_FALSE(states.at("V")->getState().isApprox(Vector3d(4,5,6), 1e-3)); + ASSERT_FALSE(states.at("Q")->getState().isApprox(Vector4d(.5,.5,.5,.5), 1e-3)); +} + +TEST_F(StateBlockCompositeInit, setIdentity) +{ + ASSERT_TRUE(states.at("P")->getState().isApprox(sbp->getState(), 1e-3)); + ASSERT_TRUE(states.at("V")->getState().isApprox(sbv->getState(), 1e-3)); + ASSERT_TRUE(states.at("Q")->getState().isApprox(sbq->getState(), 1e-3)); + + states.setIdentity(); + + // values have moved wrt original + ASSERT_TRUE(states.at("P")->getState().isApprox(Vector3d(0,0,0), 1e-10)); + ASSERT_TRUE(states.at("V")->getState().isApprox(Vector3d(0,0,0), 1e-10)); + ASSERT_TRUE(states.at("Q")->getState().isApprox(Vector4d(0,0,0,1), 1e-10)); +} + +TEST_F(StateBlockCompositeInit, identity) +{ + VectorComposite v = states.identity(); + + ASSERT_TRUE(v.at("P").isApprox(Vector3d(0,0,0), 1e-10)); + ASSERT_TRUE(v.at("V").isApprox(Vector3d(0,0,0), 1e-10)); + ASSERT_TRUE(v.at("Q").isApprox(Vector4d(0,0,0,1), 1e-10)); +} + +TEST_F(StateBlockCompositeInit, fix) +{ + states.fix(); + + ASSERT_TRUE(states.at("P")->isFixed()); + ASSERT_TRUE(states.at("V")->isFixed()); + ASSERT_TRUE(states.at("Q")->isFixed()); +} + +TEST_F(StateBlockCompositeInit, unfix) +{ + states.fix(); + + ASSERT_TRUE(states.at("P")->isFixed()); + ASSERT_TRUE(states.at("V")->isFixed()); + ASSERT_TRUE(states.at("Q")->isFixed()); + + states.unfix(); + + ASSERT_FALSE(states.at("P")->isFixed()); + ASSERT_FALSE(states.at("V")->isFixed()); + ASSERT_FALSE(states.at("Q")->isFixed()); +} + +TEST_F(StateBlockCompositeInit, isFixed) +{ + states.fix(); + + ASSERT_TRUE(states.isFixed()); + + states.at("P")->unfix(); + + ASSERT_FALSE(states.isFixed()); +} + + +TEST(VectorComposite, constructor_empty) +{ + VectorComposite v; + ASSERT_TRUE(v.empty()); +} + +TEST(VectorComposite, constructor_copy) +{ + VectorComposite u; + u.emplace("a", Vector2d(1,2)); + u.emplace("b", Vector3d(3,4,5)); + + VectorComposite v(u); + + ASSERT_FALSE(v.empty()); + + ASSERT_MATRIX_APPROX(u["a"], v["a"], 1e-20); + ASSERT_MATRIX_APPROX(u["b"], v["b"], 1e-20); +} + +TEST(VectorComposite, constructor_from_list) +{ + VectorComposite v(Vector4d(1,2,3,4), "ab", {3,1}); + + ASSERT_MATRIX_APPROX(v.at("a"), Vector3d(1,2,3), 1e-20); + ASSERT_MATRIX_APPROX(v.at("b"), Vector1d(4), 1e-20); +} + +TEST(VectorComposite, set) +{ + VectorComposite v; + + v.set(Vector4d(1,2,3,4), "ab", {3,1}); + + ASSERT_MATRIX_APPROX(v.at("a"), Vector3d(1,2,3), 1e-20); + ASSERT_MATRIX_APPROX(v.at("b"), Vector1d(4), 1e-20); +} + +TEST(VectorComposite, operatorStream) +{ + using namespace Eigen; + + VectorComposite x; + + x.emplace("P", Vector2d(1,1)); + x.emplace("O", Vector3d(2,2,2)); + + WOLF_DEBUG("X = ", x); +} + +TEST(VectorComposite, operatorPlus) +{ + VectorComposite x, y; + + x.emplace("P", Vector2d(1,1)); + x.emplace("O", Vector3d(2,2,2)); + y.emplace("P", Vector2d(1,1)); + y.emplace("O", Vector3d(2,2,2)); + + WOLF_DEBUG("x + y = ", x + y); + + ASSERT_MATRIX_APPROX((x+y).at("P"), Vector2d(2,2), 1e-20); + ASSERT_MATRIX_APPROX((x+y).at("O"), Vector3d(4,4,4), 1e-20); +} + +TEST(VectorComposite, operatorMinus) +{ + VectorComposite x, y; + + x.emplace("P", Vector2d(3,3)); + x.emplace("O", Vector3d(6,6,6)); + y.emplace("P", Vector2d(1,1)); + y.emplace("O", Vector3d(2,2,2)); + + WOLF_DEBUG("x = ", x); + WOLF_DEBUG("y = ", y); + WOLF_DEBUG("x - y = ", x - y); + + ASSERT_MATRIX_APPROX((x-y).at("P"), Vector2d(2,2), 1e-20); + ASSERT_MATRIX_APPROX((x-y).at("O"), Vector3d(4,4,4), 1e-20); +} + +TEST(VectorComposite, unary_Minus) +{ + VectorComposite x, y; + + x.emplace("P", Vector2d(1,1)); + x.emplace("O", Vector3d(2,2,2)); + + WOLF_DEBUG("-x = ", -x); + + ASSERT_MATRIX_APPROX((-x).at("P"), Vector2d(-1,-1), 1e-20); + ASSERT_MATRIX_APPROX((-x).at("O"), Vector3d(-2,-2,-2), 1e-20); +} + +TEST(VectorComposite, size) +{ + VectorComposite x; + + x.emplace("P", Vector2d(1,1)); + x.emplace("O", Vector3d(2,2,2)); + x.emplace("V", Vector4d(3,3,3,3)); + + ASSERT_EQ(x.size("PO"), 5); + ASSERT_EQ(x.size("VO"), 7); + ASSERT_EQ(x.size("PVO"), 9); + ASSERT_EQ(x.size("OPV"), 9); +} + +TEST(VectorComposite, stateVector) +{ + VectorComposite x; + + x.emplace("P", Vector2d(1,1)); + x.emplace("O", Vector3d(2,2,2)); + x.emplace("V", Vector4d(3,3,3,3)); + + VectorXd y(5); y<<1,1,2,2,2; + ASSERT_MATRIX_APPROX(x.vector("PO"), y, 1e-20); + + y.resize(7); + y << 3,3,3,3,2,2,2; + ASSERT_MATRIX_APPROX(x.vector("VO"), y, 1e-20); + + y.resize(9); + y << 1,1,3,3,3,3,2,2,2; + ASSERT_MATRIX_APPROX(x.vector("PVO"), y, 1e-20); +} + +TEST(MatrixComposite, Constructor_empty) +{ + MatrixComposite M; + + ASSERT_EQ(M.size() , 0); + + ASSERT_TRUE(M.check()); +} + +TEST(MatrixComposite, Constructor_structure) +{ + MatrixComposite M("PO", "POV"); + + ASSERT_EQ(M.size() , 2); + ASSERT_EQ(M.at("P").size() , 3); + + ASSERT_TRUE(M.check()); +} + +TEST(MatrixComposite, Constructor_structure_sizes) +{ + MatrixComposite M("PO", {3,4}, "POV", {3,4,3}); + + ASSERT_EQ(M.size() , 2); + ASSERT_EQ(M.at("P").size() , 3); + + ASSERT_EQ(M.at("P","O").rows() , 3); + ASSERT_EQ(M.at("P","O").cols() , 4); + + ASSERT_EQ(M.matrix("PO","POV").rows() , 7); + ASSERT_EQ(M.matrix("PO","POV").cols() , 10); + + ASSERT_TRUE(M.check()); +} + +TEST(MatrixComposite, Constructor_eigenMatrix_structure_sizes) +{ + MatrixXd m ( MatrixXd::Random(7,10) ); + + MatrixComposite M(m, "PO", {3,4}, "POV", {3,4,3}); + + ASSERT_EQ(M.size() , 2); + ASSERT_EQ(M.at("P").size() , 3); + + ASSERT_EQ(M.at("P","O").rows() , 3); + ASSERT_EQ(M.at("P","O").cols() , 4); + + ASSERT_EQ(M.matrix("PO","POV").rows() , 7); + ASSERT_EQ(M.matrix("PO","POV").cols() , 10); + + ASSERT_MATRIX_APPROX(M.at("P","O"), m.block(0,3,3,4), 1e-20); + ASSERT_MATRIX_APPROX(M.at("O","V"), m.block(3,7,4,3), 1e-20); + + ASSERT_TRUE(M.check()); +} + +TEST(MatrixComposite, Constructor_eigenMatrix_structure_sizes_mismatches) +{ + MatrixXd m; + +// // input m has too few rows +// m.setRandom(6,10); +// MatrixComposite M1(m, "PO", {3,4}, "POV", {3,4,3}); + +// // input m has too many rows +// m.setRandom(8,10); +// MatrixComposite M2(m, "PO", {3,4}, "POV", {3,4,3}); + +// // input m has too few cols +// m.setRandom(7,9) ; +// MatrixComposite M3(m, "PO", {3,4}, "POV", {3,4,3}); + +// // input m has too many cols +// m.setRandom(7,11) ; +// MatrixComposite M4(m, "PO", {3,4}, "POV", {3,4,3}); + +} + +TEST(MatrixComposite, Zero) +{ + MatrixComposite M = MatrixComposite::zero("PO", {3,4}, "POV", {3,4,3}); + + ASSERT_MATRIX_APPROX(M.matrix("PO", "POV"), MatrixXd::Zero(7,10), 1e-20); + + ASSERT_TRUE(M.check()); +} + +TEST(MatrixComposite, Identity) +{ + MatrixComposite M = MatrixComposite::identity("POV", {3,4,3}); + + ASSERT_MATRIX_APPROX(M.matrix("POV", "POV"), MatrixXd::Identity(10,10), 1e-20); + + ASSERT_TRUE(M.check()); +} + +TEST(MatrixComposite, emplace_operatorStream) +{ + MatrixComposite M; + + unsigned int psize, osize; + psize = 2; + osize = 3; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + ASSERT_TRUE(M.emplace("P", "P", Mpp)); + ASSERT_TRUE(M.emplace("P", "O", Mpo)); + ASSERT_TRUE(M.emplace("O", "P", Mop)); + ASSERT_TRUE(M.emplace("O", "O", Moo)); + + cout << "M = " << M << endl; +} + +//TEST(MatrixComposite, operatorBrackets) +//{ +// MatrixComposite M; +// +// unsigned int psize, osize; +// psize = 2; +// osize = 3; +// +// MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); +// +// Mpp.setOnes(); +// Mpo.setOnes(); Mpo *= 2; +// Mop.setOnes(); Mop *= 3; +// Moo.setOnes(); Moo *= 4; +// +// M.emplace("P", "P", Mpp); +// ASSERT_MATRIX_APPROX( M["P"]["P"], Mpp, 1e-20); +// +// M.emplace("P", "O", Mpo); +// ASSERT_MATRIX_APPROX( M["P"]["O"], Mpo, 1e-20); +// +// // return default empty matrix if block not present +// MatrixXd N = M["O"]["O"]; +// ASSERT_EQ(N.rows(), 0); +// ASSERT_EQ(N.cols(), 0); +//} + +//TEST(MatrixComposite, operatorParenthesis) +//{ +// MatrixComposite M; +// +// unsigned int psize, osize; +// psize = 2; +// osize = 3; +// +// MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); +// +// Mpp.setOnes(); +// Mpo.setOnes(); Mpo *= 2; +// Mop.setOnes(); Mop *= 3; +// Moo.setOnes(); Moo *= 4; +// +// M.emplace("P", "P", Mpp); +// ASSERT_MATRIX_APPROX( M("P", "P"), Mpp, 1e-20); +// +// M.emplace("P", "O", Mpo); +// ASSERT_MATRIX_APPROX( M("P", "O"), Mpo, 1e-20); +// +// // return default empty matrix if block not present +// MatrixXd N = M("O", "O"); +// ASSERT_EQ(N.rows(), 0); +// ASSERT_EQ(N.cols(), 0); +//} + +TEST(MatrixComposite, operatorAt) +{ + MatrixComposite M; + + unsigned int psize, osize; + psize = 2; + osize = 3; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + M.emplace("P", "P", Mpp); + ASSERT_MATRIX_APPROX( M.at("P", "P"), Mpp, 1e-20); + + M.emplace("P", "O", Mpo); + ASSERT_MATRIX_APPROX( M.at("P", "O"), Mpo, 1e-20); + + // error if block not present + ASSERT_DEATH(MatrixXd N = M.at("O", "O"), ""); +} + +TEST(MatrixComposite, productScalar) +{ + unsigned int psize, osize; + psize = 2; + osize = 3; + + MatrixComposite M; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + M.emplace("P", "P", Mpp); + M.emplace("P", "O", Mpo); + M.emplace("O", "P", Mop); + M.emplace("O", "O", Moo); + WOLF_DEBUG("M = " , M); + + + // right-multiply by scalar + MatrixComposite R = M * 1.2; + ASSERT_MATRIX_APPROX(R.matrix("PO","PO"), 1.2 * M.matrix("PO","PO"), 1e-20); + + + // left-multiply by scalar + MatrixComposite L = 1.2 * M; + ASSERT_MATRIX_APPROX(L.matrix("PO","PO"), 1.2 * M.matrix("PO","PO"), 1e-20); + + +} + +TEST(MatrixComposite, productVector) +{ + unsigned int psize, osize; + psize = 2; + osize = 3; + + VectorComposite x; + x.emplace("P", Vector2d(1,1)); + x.emplace("O", Vector3d(2,2,2)); + + cout << "x= " << x << endl; + +// WOLF_DEBUG("x = " , x); + + MatrixComposite M; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + M.emplace("P", "P", Mpp); + M.emplace("P", "O", Mpo); + M.emplace("O", "P", Mop); + M.emplace("O", "O", Moo); + WOLF_DEBUG("M = " , M); + + VectorComposite y; + + y = M * x; + +// WOLF_DEBUG("y = M * x = " , y); + + /* M * x = y + * p o + * p [1 1 2 2 2] p [1] p [14] + * [1 1 2 2 2] [1] [14] + * [3 3 4 4 4] * [2] = [30] + * o [3 3 4 4 4] o [2] o [30] + * [3 3 4 4 4] [2] [30] + */ + + Vector2d yp(14,14); + Vector3d yo(30,30,30); + + ASSERT_MATRIX_APPROX(y.at("P"), yp, 1e-20); + ASSERT_MATRIX_APPROX(y.at("O"), yo, 1e-20); + + // throw if x has extra blocks + // x.emplace("V", Vector2d(3,3)); + // ASSERT_DEATH(y = M * x , ""); // M * x --> does not die if x has extra blocks wrt M + + // throw if x has missing blocks + // x.erase("O"); + // cout << "x = " << x << endl; + // ASSERT_DEATH(y = M * x , ""); // M * x --> exception if x has missing blocks wrt M, not caught by ASSERT_DEATH + +} + +TEST(MatrixComposite, product) +{ + unsigned int psize, osize, vsize; + psize = 2; + osize = 1; + vsize = 2; + + MatrixComposite M, N; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + M.emplace("P", "P", Mpp); + M.emplace("P", "O", Mpo); + M.emplace("O", "P", Mop); + M.emplace("O", "O", Moo); + WOLF_DEBUG("M = " , M); + + MatrixXd Noo(osize,osize), Nov(osize, vsize), Npo(psize,osize), Npv(psize,vsize); + Noo.setOnes(); + Nov.setOnes(); Nov *= 2; + Npo.setOnes(); Npo *= 3; + Npv.setOnes(); Npv *= 4; + + N.emplace("O", "O", Noo); + N.emplace("O", "V", Nov); + N.emplace("P", "O", Npo); + N.emplace("P", "V", Npv); + WOLF_DEBUG("N = " , N); + + MatrixComposite MN; + + MN = M * N; + + WOLF_DEBUG("MN = M * N = " , MN); + + /* M * N = MN + * p o o v o v + * p [1 1 2] p [3 4 4] p [ 8 12 12] + * [1 1 2] * [3 4 4] = [ 8 12 12] + * o [3 3 4] o [1 2 2] o [22 32 32] + */ + + MatrixXd MNpo(MatrixXd::Ones(psize,osize) * 8); + MatrixXd MNpv(MatrixXd::Ones(psize,vsize) * 12); + MatrixXd MNoo(MatrixXd::Ones(osize,osize) * 22); + MatrixXd MNov(MatrixXd::Ones(osize,vsize) * 32); + + ASSERT_MATRIX_APPROX(MN.at("P","O"), MNpo, 1e-20); + ASSERT_MATRIX_APPROX(MN.at("P","V"), MNpv, 1e-20); + ASSERT_MATRIX_APPROX(MN.at("O","O"), MNoo, 1e-20); + ASSERT_MATRIX_APPROX(MN.at("O","V"), MNov, 1e-20); + + ASSERT_TRUE(MN.check()); +} + +TEST(MatrixComposite, propagate) +{ + unsigned int psize, osize, vsize, wsize; + psize = 2; + osize = 3; + vsize = 4; + wsize = 1; + + MatrixComposite Q, J; + + MatrixXd Qpp(psize,psize), Qpo(psize, osize), Qop(osize,psize), Qoo(osize,osize); + Qpp.setOnes(); + Qpo.setOnes(); Qpo *= 2; + Qop.setOnes(); Qop *= 2; + Qoo.setOnes(); Qoo *= 3; + + Q.emplace("P", "P", Qpp); + Q.emplace("P", "O", Qpo); + Q.emplace("O", "P", Qop); + Q.emplace("O", "O", Qoo); + WOLF_DEBUG("Q = " , Q); + + MatrixXd Jvp(vsize,psize), Jvo(vsize, osize), Jwp(wsize,psize), Jwo(wsize,osize); + Jvp.setOnes(); + Jvo.setOnes(); Jvo *= 2; + Jwp.setOnes(); Jwp *= 3; + Jwo.setOnes(); Jwo *= 4; + + J.emplace("V", "P", Jvp); + J.emplace("V", "O", Jvo); + J.emplace("W", "P", Jwp); + J.emplace("W", "O", Jwo); + WOLF_DEBUG("J = " , J); + + MatrixComposite JQJt; + + JQJt = J.propagate(Q); + + WOLF_DEBUG("JQJt = J * Q * J.tr = " , JQJt); + + WOLF_DEBUG("JQJt = J * Q * J.tr = \n" , JQJt.matrix("VW", "VW")); + + ASSERT_MATRIX_APPROX(JQJt.matrix("VW", "VW"), J.matrix("VW","PO") * Q.matrix("PO","PO") * J.matrix("VW","PO").transpose(), 1e-8); + + ASSERT_TRUE(JQJt.check()); + +} + +TEST(MatrixComposite, sum) +{ + unsigned int psize, osize; + psize = 2; + osize = 1; + + MatrixComposite M, N; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + M.emplace("P", "P", Mpp); + M.emplace("P", "O", Mpo); + M.emplace("O", "P", Mop); + M.emplace("O", "O", Moo); + WOLF_DEBUG("M = " , M); + N.emplace("P", "P", Mpp); + N.emplace("P", "O", Mpo); + N.emplace("O", "P", Mop); + N.emplace("O", "O", Moo); + WOLF_DEBUG("N = " , N); + + MatrixComposite MpN; + + MpN = M + N; + + WOLF_DEBUG("MpN = M + N = " , MpN); + + ASSERT_MATRIX_APPROX(MpN.at("P","P"), 2 * Mpp, 1e-10); + ASSERT_MATRIX_APPROX(MpN.at("P","O"), 2 * Mpo, 1e-10); + ASSERT_MATRIX_APPROX(MpN.at("O","P"), 2 * Mop, 1e-10); + ASSERT_MATRIX_APPROX(MpN.at("O","O"), 2 * Moo, 1e-10); + +} + +TEST(MatrixComposite, difference) +{ + unsigned int psize, osize; + psize = 2; + osize = 1; + + MatrixComposite M, N; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + M.emplace("P", "P", Mpp); + M.emplace("P", "O", Mpo); + M.emplace("O", "P", Mop); + M.emplace("O", "O", Moo); + WOLF_DEBUG("M = " , M); + N.emplace("P", "P", Mpp); + N.emplace("P", "O", Mpo); + N.emplace("O", "P", Mop); + N.emplace("O", "O", Moo); + WOLF_DEBUG("N = " , N); + + MatrixComposite MmN; + + MmN = M - N; + + WOLF_DEBUG("MmN = M - N = " , MmN); + + ASSERT_MATRIX_APPROX(MmN.at("P","P"), Mpp * 0, 1e-10); + ASSERT_MATRIX_APPROX(MmN.at("P","O"), Mpo * 0, 1e-10); + ASSERT_MATRIX_APPROX(MmN.at("O","P"), Mop * 0, 1e-10); + ASSERT_MATRIX_APPROX(MmN.at("O","O"), Moo * 0, 1e-10); + +} + +TEST(MatrixComposite, unary_minus) +{ + unsigned int psize, osize; + psize = 2; + osize = 1; + + MatrixComposite M, N; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + M.emplace("P", "P", Mpp); + M.emplace("P", "O", Mpo); + M.emplace("O", "P", Mop); + M.emplace("O", "O", Moo); + WOLF_DEBUG("M = " , M); + + MatrixComposite m; + + m = - M; + + WOLF_DEBUG("m = - M = " , m); + + ASSERT_MATRIX_APPROX(m.at("P","P"), - M.at("P","P"), 1e-10); + ASSERT_MATRIX_APPROX(m.at("P","O"), - M.at("P","O"), 1e-10); + ASSERT_MATRIX_APPROX(m.at("O","P"), - M.at("O","P"), 1e-10); + ASSERT_MATRIX_APPROX(m.at("O","O"), - M.at("O","O"), 1e-10); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + // restrict to a group of tests only + // ::testing::GTEST_FLAG(filter) = "VectorComposite.*"; + + // restrict to this test only + // ::testing::GTEST_FLAG(filter) = "MatrixComposite.propagate"; +// ::testing::GTEST_FLAG(filter) = "MatrixComposite.*"; + + return RUN_ALL_TESTS(); +} diff --git a/test/gtest_track_matrix.cpp b/test/gtest_track_matrix.cpp index 1f641dcf0da9765ddd155b5d35eaf87041879828..5b333f26c6cb097957a6963e0602314ba3eef481 100644 --- a/test/gtest_track_matrix.cpp +++ b/test/gtest_track_matrix.cpp @@ -35,11 +35,11 @@ class TrackMatrixTest : public testing::Test // unlinked frames // Some warnings will be thrown "linking with nullptr" for emplacing without providing frame pointer - F0 = FrameBase::emplace<FrameBase>(nullptr, 0.0, nullptr); - F1 = FrameBase::emplace<FrameBase>(nullptr, 1.0, nullptr); - F2 = FrameBase::emplace<FrameBase>(nullptr, 2.0, nullptr); - F3 = FrameBase::emplace<FrameBase>(nullptr, 3.0, nullptr); - F4 = FrameBase::emplace<FrameBase>(nullptr, 4.0, nullptr); + F0 = FrameBase::emplace<FrameBase>(nullptr, NON_ESTIMATED, 0.0, nullptr); + F1 = FrameBase::emplace<FrameBase>(nullptr, NON_ESTIMATED, 1.0, nullptr); + F2 = FrameBase::emplace<FrameBase>(nullptr, NON_ESTIMATED, 2.0, nullptr); + F3 = FrameBase::emplace<FrameBase>(nullptr, NON_ESTIMATED, 3.0, nullptr); + F4 = FrameBase::emplace<FrameBase>(nullptr, NON_ESTIMATED, 4.0, nullptr); // unlinked features // Some warnings will be thrown "linking with nullptr" for emplacing without providing capture pointer diff --git a/test/gtest_trajectory.cpp b/test/gtest_trajectory.cpp index 82c65c284c5f06b518943679ac70ae3f2803bc42..9be1e82fafac833ca90d000e487072d5488ff240 100644 --- a/test/gtest_trajectory.cpp +++ b/test/gtest_trajectory.cpp @@ -12,37 +12,12 @@ #include "core/trajectory/trajectory_base.h" #include "core/frame/frame_base.h" #include "core/solver/solver_manager.h" +#include "dummy/solver_manager_dummy.h" #include <iostream> using namespace wolf; -struct DummySolverManager : public SolverManager -{ - DummySolverManager(const ProblemPtr& _problem) - : SolverManager(_problem) - { - // - } - virtual void computeCovariances(const CovarianceBlocksToBeComputed blocks){}; - virtual void computeCovariances(const std::vector<StateBlockPtr>& st_list){}; - virtual bool hasConverged(){return true;}; - virtual SizeStd iterations(){return 0;}; - virtual double initialCost(){return 0;}; - virtual double finalCost(){return 0;}; - virtual std::string solveImpl(const ReportVerbosity report_level){return std::string("");}; - virtual void addFactor(const FactorBasePtr& fac_ptr){}; - virtual void removeFactor(const FactorBasePtr& fac_ptr){}; - virtual void addStateBlock(const StateBlockPtr& state_ptr){}; - virtual void removeStateBlock(const StateBlockPtr& state_ptr){}; - virtual void updateStateBlockStatus(const StateBlockPtr& state_ptr){}; - virtual void updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr){}; - virtual bool isStateBlockRegistered(const StateBlockPtr& state_ptr){return true;}; - virtual bool isFactorRegistered(const FactorBasePtr& fac_ptr) const {return true;}; - virtual bool isStateBlockRegisteredDerived(const StateBlockPtr& state_ptr){return true;}; - virtual bool isFactorRegisteredDerived(const FactorBasePtr& fac_ptr) const {return true;}; -}; - /// Set to true if you want debug info bool debug = false; @@ -57,10 +32,10 @@ TEST(TrajectoryBase, ClosestKeyFrame) // 1 2 3 4 time stamps // --+-----+-----+-----+---> time - FrameBasePtr F1 = P->emplaceFrame(KEY, Eigen::Vector3d::Zero(), 1); - FrameBasePtr F2 = P->emplaceFrame(KEY, Eigen::Vector3d::Zero(), 2); - FrameBasePtr F3 = P->emplaceFrame(AUXILIARY, Eigen::Vector3d::Zero(), 3); - FrameBasePtr F4 = P->emplaceFrame(NON_ESTIMATED, Eigen::Vector3d::Zero(), 4); + FrameBasePtr F1 = P->emplaceFrame(KEY, 1, Eigen::Vector3d::Zero() ); + FrameBasePtr F2 = P->emplaceFrame(KEY, 2, Eigen::Vector3d::Zero() ); + FrameBasePtr F3 = P->emplaceFrame(AUXILIARY, 3, Eigen::Vector3d::Zero() ); + FrameBasePtr F4 = P->emplaceFrame(NON_ESTIMATED, 4, Eigen::Vector3d::Zero() ); FrameBasePtr KF; // closest key-frame queried @@ -94,9 +69,9 @@ TEST(TrajectoryBase, ClosestKeyOrAuxFrame) // 1 2 3 time stamps // --+-----+-----+---> time - FrameBasePtr F1 = P->emplaceFrame(KEY, Eigen::Vector3d::Zero(), 1); - FrameBasePtr F2 = P->emplaceFrame(AUXILIARY, Eigen::Vector3d::Zero(), 2); - FrameBasePtr F3 = P->emplaceFrame(NON_ESTIMATED, Eigen::Vector3d::Zero(), 3); + FrameBasePtr F1 = P->emplaceFrame(KEY, 1, Eigen::Vector3d::Zero() ); + FrameBasePtr F2 = P->emplaceFrame(AUXILIARY, 2, Eigen::Vector3d::Zero() ); + FrameBasePtr F3 = P->emplaceFrame(NON_ESTIMATED, 3, Eigen::Vector3d::Zero() ); FrameBasePtr KF; // closest key-frame queried @@ -123,7 +98,7 @@ TEST(TrajectoryBase, Add_Remove_Frame) ProblemPtr P = Problem::create("PO", 2); TrajectoryBasePtr T = P->getTrajectory(); - DummySolverManager N(P); + SolverManagerDummy N(P); // Trajectory status: // KF1 KF2 F3 frames @@ -133,21 +108,21 @@ TEST(TrajectoryBase, Add_Remove_Frame) std::cout << __LINE__ << std::endl; // add F1 - FrameBasePtr F1 = P->emplaceFrame(KEY, Eigen::Vector3d::Zero(), 1); // 2 non-fixed + FrameBasePtr F1 = P->emplaceFrame(KEY, 1, Eigen::Vector3d::Zero()); // 2 non-fixed if (debug) P->print(2,0,0,0); ASSERT_EQ(T->getFrameList(). size(), (SizeStd) 1); ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd) 2); std::cout << __LINE__ << std::endl; // add F2 - FrameBasePtr F2 = P->emplaceFrame(KEY, Eigen::Vector3d::Zero(), 2); // 1 fixed, 1 not + FrameBasePtr F2 = P->emplaceFrame(KEY, 2, Eigen::Vector3d::Zero()); // 1 fixed, 1 not if (debug) P->print(2,0,0,0); ASSERT_EQ(T->getFrameList(). size(), (SizeStd) 2); ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd) 4); std::cout << __LINE__ << std::endl; // add F3 - FrameBasePtr F3 = P->emplaceFrame(NON_ESTIMATED, Eigen::Vector3d::Zero(), 3); + FrameBasePtr F3 = P->emplaceFrame(NON_ESTIMATED, 3, Eigen::Vector3d::Zero()); if (debug) P->print(2,0,0,0); ASSERT_EQ(T->getFrameList(). size(), (SizeStd) 3); ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd) 4); @@ -203,19 +178,19 @@ TEST(TrajectoryBase, KeyFramesAreSorted) // --+-----+-----+---> time // add frames and keyframes in random order --> keyframes must be sorted after that - FrameBasePtr F2 = P->emplaceFrame(KEY, Eigen::Vector3d::Zero(), 2); + FrameBasePtr F2 = P->emplaceFrame(KEY, 2, Eigen::Vector3d::Zero()); if (debug) P->print(2,0,0,0); ASSERT_EQ(T->getLastFrame() ->id(), F2->id()); ASSERT_EQ(T->getLastKeyOrAuxFrame()->id(), F2->id()); ASSERT_EQ(T->getLastKeyFrame() ->id(), F2->id()); - FrameBasePtr F3 = P->emplaceFrame(NON_ESTIMATED, Eigen::Vector3d::Zero(), 3); // non-key-frame + FrameBasePtr F3 = P->emplaceFrame(NON_ESTIMATED, 3, Eigen::Vector3d::Zero()); // non-key-frame if (debug) P->print(2,0,0,0); ASSERT_EQ(T->getLastFrame() ->id(), F3->id()); ASSERT_EQ(T->getLastKeyOrAuxFrame()->id(), F2->id()); ASSERT_EQ(T->getLastKeyFrame() ->id(), F2->id()); - FrameBasePtr F1 = P->emplaceFrame(KEY, Eigen::Vector3d::Zero(), 1); + FrameBasePtr F1 = P->emplaceFrame(KEY, 1, Eigen::Vector3d::Zero()); if (debug) P->print(2,0,0,0); ASSERT_EQ(T->getLastFrame() ->id(), F3->id()); ASSERT_EQ(T->getLastKeyOrAuxFrame()->id(), F2->id()); @@ -227,7 +202,7 @@ TEST(TrajectoryBase, KeyFramesAreSorted) ASSERT_EQ(T->getLastKeyOrAuxFrame()->id(), F3->id()); ASSERT_EQ(T->getLastKeyFrame() ->id(), F3->id()); - auto F4 = P->emplaceFrame(NON_ESTIMATED, Eigen::Vector3d::Zero(), 1.5); + auto F4 = P->emplaceFrame(NON_ESTIMATED, 1.5, Eigen::Vector3d::Zero()); // Trajectory status: // KF1 KF2 KF3 F4 frames // 1 2 3 1.5 time stamps @@ -265,7 +240,7 @@ TEST(TrajectoryBase, KeyFramesAreSorted) if (debug) P->print(2,0,1,0); ASSERT_EQ(T->getFrameList().front()->id(), F4->id()); - auto F5 = P->emplaceFrame(AUXILIARY, Eigen::Vector3d::Zero(), 1.5); + auto F5 = P->emplaceFrame(AUXILIARY, 1.5, Eigen::Vector3d::Zero()); // Trajectory status: // KF4 KF2 AuxF5 KF3 KF2 frames // 0.5 1 1.5 3 4 time stamps @@ -285,7 +260,7 @@ TEST(TrajectoryBase, KeyFramesAreSorted) ASSERT_EQ(T->getLastKeyOrAuxFrame()->id(), F5->id()); ASSERT_EQ(T->getLastKeyFrame() ->id(), F2->id()); - auto F6 = P->emplaceFrame(NON_ESTIMATED, Eigen::Vector3d::Zero(), 6); + auto F6 = P->emplaceFrame(NON_ESTIMATED, 6, Eigen::Vector3d::Zero()); // Trajectory status: // KF4 KF2 KF3 KF2 AuxF5 F6 frames // 0.5 1 3 4 5 6 time stamps @@ -295,7 +270,7 @@ TEST(TrajectoryBase, KeyFramesAreSorted) ASSERT_EQ(T->getLastKeyOrAuxFrame()->id(), F5->id()); ASSERT_EQ(T->getLastKeyFrame() ->id(), F2->id()); - auto F7 = P->emplaceFrame(NON_ESTIMATED, Eigen::Vector3d::Zero(), 5.5); + auto F7 = P->emplaceFrame(NON_ESTIMATED, 5.5, Eigen::Vector3d::Zero()); // Trajectory status: // KF4 KF2 KF3 KF2 AuxF5 F7 F6 frames // 0.5 1 3 4 5 5.5 6 time stamps diff --git a/test/gtest_tree_manager.cpp b/test/gtest_tree_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..507d2104e14bf43f57d563dc4873481322f57090 --- /dev/null +++ b/test/gtest_tree_manager.cpp @@ -0,0 +1,107 @@ +#include "core/utils/utils_gtest.h" +#include "core/utils/logging.h" + +#include "core/problem/problem.h" +#include "dummy/tree_manager_dummy.h" +#include "core/yaml/parser_yaml.h" + +using namespace wolf; +using namespace Eigen; + +std::string wolf_root = _WOLF_ROOT_DIR; + +TEST(TreeManager, make_shared) +{ + ProblemPtr P = Problem::create("PO", 2); + + auto ParamsGM = std::make_shared<ParamsTreeManagerBase>(); + + auto GM = std::make_shared<TreeManagerDummy>(ParamsGM); + + P->setTreeManager(GM); + + ASSERT_EQ(std::static_pointer_cast<TreeManagerDummy>(P->getTreeManager())->n_KF_, 0); + ASSERT_EQ(P->getTreeManager(), GM); +} + +TEST(TreeManager, createParams) +{ + ProblemPtr P = Problem::create("PO", 2); + + auto ParamsGM = std::make_shared<ParamsTreeManagerBase>(); + + auto GM = TreeManagerDummy::create("tree_manager", ParamsGM); + + ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerDummy>(GM) != nullptr); + + P->setTreeManager(GM); + + ASSERT_EQ(std::static_pointer_cast<TreeManagerDummy>(P->getTreeManager())->n_KF_, 0); + ASSERT_EQ(P->getTreeManager(), GM); +} + +TEST(TreeManager, createParamServer) +{ + ProblemPtr P = Problem::create("PO", 2); + + ParserYAML parser = ParserYAML("test/yaml/params_tree_manager1.yaml", wolf_root); + ParamsServer server = ParamsServer(parser.getParams()); + + auto GM = TreeManagerDummy::create("tree_manager", server); + + ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerDummy>(GM) != nullptr); + + P->setTreeManager(GM); + + ASSERT_EQ(std::static_pointer_cast<TreeManagerDummy>(P->getTreeManager())->n_KF_, 0); + ASSERT_EQ(P->getTreeManager(), GM); +} + +TEST(TreeManager, autoConf) +{ + + ParserYAML parser = ParserYAML("test/yaml/params_tree_manager1.yaml", wolf_root); + ParamsServer server = ParamsServer(parser.getParams()); + + ProblemPtr P = Problem::autoSetup(server); + P->applyPriorOptions(0); + + ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerDummy>(P->getTreeManager()) != nullptr); + ASSERT_EQ(std::static_pointer_cast<TreeManagerDummy>(P->getTreeManager())->n_KF_, 1); // prior KF +} + +TEST(TreeManager, autoConfNone) +{ + + ParserYAML parser = ParserYAML("test/yaml/params_tree_manager2.yaml", wolf_root); + ParamsServer server = ParamsServer(parser.getParams()); + + ProblemPtr P = Problem::autoSetup(server); + P->applyPriorOptions(0); + + ASSERT_TRUE(P->getTreeManager() == nullptr); // params_tree_manager2.yaml problem/tree_manager/type: None +} + +TEST(TreeManager, keyFrameCallback) +{ + ProblemPtr P = Problem::create("PO", 3); + + auto ParamsGM = std::make_shared<ParamsTreeManagerBase>(); + + auto GM = std::make_shared<TreeManagerDummy>(ParamsGM); + + P->setTreeManager(GM); + + ASSERT_EQ(GM->n_KF_, 0); + + auto F0 = P->emplaceFrame(KEY, 0, "PO", 3, VectorXd(7) ); + P->keyFrameCallback(F0, nullptr, 0); + + ASSERT_EQ(GM->n_KF_, 1); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/gtest_tree_manager_sliding_window.cpp b/test/gtest_tree_manager_sliding_window.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8909987f091831fddc686c585e827035ce629ebd --- /dev/null +++ b/test/gtest_tree_manager_sliding_window.cpp @@ -0,0 +1,269 @@ +#include "core/utils/utils_gtest.h" +#include "core/utils/logging.h" + +#include "core/problem/problem.h" +#include "core/tree_manager/tree_manager_sliding_window.h" +#include "core/yaml/parser_yaml.h" +#include "core/capture/capture_void.h" +#include "core/feature/feature_base.h" +#include "core/factor/factor_odom_3d.h" +#include "core/factor/factor_pose_3d.h" + +using namespace wolf; +using namespace Eigen; + +std::string wolf_root = _WOLF_ROOT_DIR; + +TEST(TreeManagerSlidingWindow, make_shared) +{ + ProblemPtr P = Problem::create("PO", 2); + + auto ParamsGM = std::make_shared<ParamsTreeManagerSlidingWindow>(); + + auto GM = std::make_shared<TreeManagerSlidingWindow>(ParamsGM); + + P->setTreeManager(GM); + + ASSERT_EQ(P->getTreeManager(), GM); +} + +TEST(TreeManagerSlidingWindow, createParams) +{ + ProblemPtr P = Problem::create("PO", 2); + + auto ParamsGM = std::make_shared<ParamsTreeManagerSlidingWindow>(); + + auto GM = TreeManagerSlidingWindow::create("tree_manager", ParamsGM); + + ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerSlidingWindow>(GM) != nullptr); + + P->setTreeManager(GM); + + ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerSlidingWindow>(P->getTreeManager()) != nullptr); + ASSERT_EQ(P->getTreeManager(), GM); +} + +TEST(TreeManagerSlidingWindow, createParamServer) +{ + ProblemPtr P = Problem::create("PO", 2); + + ParserYAML parser = ParserYAML("test/yaml/params_tree_manager_sliding_window1.yaml", wolf_root); + ParamsServer server = ParamsServer(parser.getParams()); + + auto GM = TreeManagerSlidingWindow::create("tree_manager", server); + + ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerSlidingWindow>(GM) != nullptr); + + P->setTreeManager(GM); + + ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerSlidingWindow>(P->getTreeManager()) != nullptr); + ASSERT_EQ(P->getTreeManager(), GM); +} + +TEST(TreeManagerSlidingWindow, autoConf) +{ + ParserYAML parser = ParserYAML("test/yaml/params_tree_manager_sliding_window1.yaml", wolf_root); + ParamsServer server = ParamsServer(parser.getParams()); + + ProblemPtr P = Problem::autoSetup(server); + + ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerSlidingWindow>(P->getTreeManager()) != nullptr); +} + +TEST(TreeManagerSlidingWindow, slidingWindowFixViral) +{ + ParserYAML parser = ParserYAML("test/yaml/params_tree_manager_sliding_window1.yaml", wolf_root); + ParamsServer server = ParamsServer(parser.getParams()); + + ProblemPtr P = Problem::autoSetup(server); + P->applyPriorOptions(0); + + // FRAME 1 ---------------------------------------------------------- + auto F1 = P->getTrajectory()->getLastKeyFrame(); + ASSERT_TRUE(F1 != nullptr); + + Vector7d state = F1->getStateVector(); + Vector7d zero_disp(state); + Matrix6d cov = Matrix6d::Identity(); + + // FRAME 2 ---------------------------------------------------------- + auto F2 = P->emplaceFrame(KEY, TimeStamp(2), "PO", 3, state); + P->keyFrameCallback(F2, nullptr, 0); + + // absolute factor + auto C2 = CaptureBase::emplace<CaptureVoid>(F2, TimeStamp(2), nullptr); + auto f2 = FeatureBase::emplace<FeatureBase>(C2, "absolute", state, cov); + auto c2 = FactorBase::emplace<FactorPose3d>(f2, f2, nullptr, false); + // displacement + auto C12 = CaptureBase::emplace<CaptureVoid>(F2, TimeStamp(2), nullptr); + auto f12 = FeatureBase::emplace<FeatureBase>(C12, "odom", zero_disp, cov); + auto c12 = FactorBase::emplace<FactorOdom3d>(f12, f12, F1, nullptr, false); + + // Check no frame removed + ASSERT_FALSE(F1->isRemoving()); + + // FRAME 3 ---------------------------------------------------------- + auto F3 = P->emplaceFrame(KEY, TimeStamp(3), "PO", 3, state); + P->keyFrameCallback(F3, nullptr, 0); + + // absolute factor + auto C3 = CaptureBase::emplace<CaptureVoid>(F3, TimeStamp(3), nullptr); + auto f3 = FeatureBase::emplace<FeatureBase>(C3, "absolute", state, cov); + auto c3 = FactorBase::emplace<FactorPose3d>(f3, f3, nullptr, false); + // displacement + auto C23 = CaptureBase::emplace<CaptureVoid>(F3, TimeStamp(3), nullptr); + auto f23 = FeatureBase::emplace<FeatureBase>(C23, "odom", zero_disp, cov); + auto c23 = FactorBase::emplace<FactorOdom3d>(f23, f23, F2, nullptr, false); + + // Check no frame removed + ASSERT_FALSE(F1->isRemoving()); + + // FRAME 4 ---------------------------------------------------------- + auto F4 = P->emplaceFrame(KEY, TimeStamp(4), "PO", 3, state); + P->keyFrameCallback(F4, nullptr, 0); + + // absolute factor + auto C4 = CaptureBase::emplace<CaptureVoid>(F4, TimeStamp(4), nullptr); + auto f4 = FeatureBase::emplace<FeatureBase>(C4, "absolute", state, cov); + auto c4 = FactorBase::emplace<FactorPose3d>(f4, f4, nullptr, false); + // displacement + auto C34 = CaptureBase::emplace<CaptureVoid>(F4, TimeStamp(4), nullptr); + auto f34 = FeatureBase::emplace<FeatureBase>(C34, "odom", zero_disp, cov); + auto c34 = FactorBase::emplace<FactorOdom3d>(f34, f34, F3, nullptr, false); + + // Checks + ASSERT_TRUE(F1->isRemoving()); + ASSERT_TRUE(c12->isRemoving()); + ASSERT_TRUE(C12->isRemoving()); //Virally removed + ASSERT_TRUE(f12->isRemoving()); //Virally removed + ASSERT_TRUE(F2->isFixed()); //Fixed + + // FRAME 5 ---------------------------------------------------------- + auto F5 = P->emplaceFrame(KEY, TimeStamp(5), "PO", 3, state); + P->keyFrameCallback(F5, nullptr, 0); + + // absolute factor + auto C5 = CaptureBase::emplace<CaptureVoid>(F5, TimeStamp(5), nullptr); + auto f5 = FeatureBase::emplace<FeatureBase>(C5, "absolute", state, cov); + auto c5 = FactorBase::emplace<FactorPose3d>(f5, f5, nullptr, false); + // displacement + auto C45 = CaptureBase::emplace<CaptureVoid>(F5, TimeStamp(5), nullptr); + auto f45 = FeatureBase::emplace<FeatureBase>(C45, "odom", zero_disp, cov); + auto c45 = FactorBase::emplace<FactorOdom3d>(f45, f45, F4, nullptr, false); + + // Checks + ASSERT_TRUE(F1->isRemoving()); + ASSERT_TRUE(c12->isRemoving()); + ASSERT_TRUE(C12->isRemoving()); //Virally removed + ASSERT_TRUE(f12->isRemoving()); //Virally removed + ASSERT_TRUE(F2->isRemoving()); + ASSERT_TRUE(c2->isRemoving()); + ASSERT_TRUE(C2->isRemoving()); //Virally removed + ASSERT_TRUE(f2->isRemoving()); //Virally removed + ASSERT_TRUE(c23->isRemoving()); + ASSERT_TRUE(C23->isRemoving()); //Virally removed + ASSERT_TRUE(f23->isRemoving()); //Virally removed + ASSERT_TRUE(F3->isFixed()); //Fixed +} + +TEST(TreeManagerSlidingWindow, slidingWindowNoFixNoViral) +{ + ParserYAML parser = ParserYAML("test/yaml/params_tree_manager_sliding_window2.yaml", wolf_root); + ParamsServer server = ParamsServer(parser.getParams()); + + ProblemPtr P = Problem::autoSetup(server); + P->applyPriorOptions(0); + + // FRAME 1 (prior) ---------------------------------------------------------- + auto F1 = P->getTrajectory()->getLastKeyFrame(); + ASSERT_TRUE(F1 != nullptr); + + Vector7d state = F1->getStateVector(); + Vector7d zero_disp(state); + Matrix6d cov = Matrix6d::Identity(); + + // FRAME 2 ---------------------------------------------------------- + auto F2 = P->emplaceFrame(KEY, TimeStamp(2), "PO", 3, state); + P->keyFrameCallback(F2, nullptr, 0); + + // absolute factor + auto C2 = CaptureBase::emplace<CaptureVoid>(F2, TimeStamp(2), nullptr); + auto f2 = FeatureBase::emplace<FeatureBase>(C2, "absolute", state, cov); + auto c2 = FactorBase::emplace<FactorPose3d>(f2, f2, nullptr, false); + // displacement + auto C12 = CaptureBase::emplace<CaptureVoid>(F2, TimeStamp(2), nullptr); + auto f12 = FeatureBase::emplace<FeatureBase>(C12, "odom", zero_disp, cov); + auto c12 = FactorBase::emplace<FactorOdom3d>(f12, f12, F1, nullptr, false); + + // Check no frame removed + ASSERT_FALSE(F1->isRemoving()); + + // FRAME 3 ---------------------------------------------------------- + auto F3 = P->emplaceFrame(KEY, TimeStamp(3), "PO", 3, state); + P->keyFrameCallback(F3, nullptr, 0); + + // absolute factor + auto C3 = CaptureBase::emplace<CaptureVoid>(F3, TimeStamp(3), nullptr); + auto f3 = FeatureBase::emplace<FeatureBase>(C3, "absolute", state, cov); + auto c3 = FactorBase::emplace<FactorPose3d>(f3, f3, nullptr, false); + // displacement + auto C23 = CaptureBase::emplace<CaptureVoid>(F3, TimeStamp(3), nullptr); + auto f23 = FeatureBase::emplace<FeatureBase>(C23, "odom", zero_disp, cov); + auto c23 = FactorBase::emplace<FactorOdom3d>(f23, f23, F2, nullptr, false); + + // Check no frame removed + ASSERT_FALSE(F1->isRemoving()); + + // FRAME 4 ---------------------------------------------------------- + auto F4 = P->emplaceFrame(KEY, TimeStamp(4), "PO", 3, state); + P->keyFrameCallback(F4, nullptr, 0); + + // absolute factor + auto C4 = CaptureBase::emplace<CaptureVoid>(F4, TimeStamp(4), nullptr); + auto f4 = FeatureBase::emplace<FeatureBase>(C4, "absolute", state, cov); + auto c4 = FactorBase::emplace<FactorPose3d>(f4, f4, nullptr, false); + // displacement + auto C34 = CaptureBase::emplace<CaptureVoid>(F4, TimeStamp(4), nullptr); + auto f34 = FeatureBase::emplace<FeatureBase>(C34, "odom", zero_disp, cov); + auto c34 = FactorBase::emplace<FactorOdom3d>(f34, f34, F3, nullptr, false); + + // Checks + ASSERT_TRUE(F1->isRemoving()); + ASSERT_TRUE(c12->isRemoving()); + ASSERT_FALSE(C12->isRemoving()); //Not virally removed + ASSERT_FALSE(f12->isRemoving()); //Not virally removed + ASSERT_FALSE(F2->isFixed()); //Not fixed + + // FRAME 5 ---------------------------------------------------------- + auto F5 = P->emplaceFrame(KEY, TimeStamp(5), "PO", 3, state); + P->keyFrameCallback(F5, nullptr, 0); + + // absolute factor + auto C5 = CaptureBase::emplace<CaptureVoid>(F5, TimeStamp(5), nullptr); + auto f5 = FeatureBase::emplace<FeatureBase>(C5, "absolute", state, cov); + auto c5 = FactorBase::emplace<FactorPose3d>(f5, f5, nullptr, false); + // displacement + auto C45 = CaptureBase::emplace<CaptureVoid>(F5, TimeStamp(5), nullptr); + auto f45 = FeatureBase::emplace<FeatureBase>(C45, "odom", zero_disp, cov); + auto c45 = FactorBase::emplace<FactorOdom3d>(f45, f45, F4, nullptr, false); + + // Checks + ASSERT_TRUE(F1->isRemoving()); + ASSERT_TRUE(c12->isRemoving()); + ASSERT_TRUE(C12->isRemoving()); + ASSERT_TRUE(f12->isRemoving()); + ASSERT_TRUE(F2->isRemoving()); + ASSERT_TRUE(c2->isRemoving()); + ASSERT_TRUE(C2->isRemoving()); + ASSERT_TRUE(f2->isRemoving()); + ASSERT_TRUE(c23->isRemoving()); + ASSERT_FALSE(C23->isRemoving()); //Not virally removed + ASSERT_FALSE(f23->isRemoving()); //Not virally removed + ASSERT_FALSE(F3->isFixed()); //Not fixed +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/yaml/params_tree_manager1.yaml b/test/yaml/params_tree_manager1.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d8f443220bf71786c1e95ca77ae9e68705d1d576 --- /dev/null +++ b/test/yaml/params_tree_manager1.yaml @@ -0,0 +1,49 @@ +config: + problem: + frame_structure: "POV" + dimension: 3 + prior: + mode: "factor" + # state: [0,0,0,0,0,0,1,0,0,0] + # cov: [[9,9],.1,0,0,0,0,0,0,0,0, 0,.1,0,0,0,0,0,0,0, 0,0,.1,0,0,0,0,0,0, 0,0,0,.1,0,0,0,0,0, 0,0,0,0,.1,0,0,0,0, 0,0,0,0,0,.1,0,0,0, 0,0,0,0,0,0,.1,0,0, 0,0,0,0,0,0,0,.1,0, 0,0,0,0,0,0,0,0,.1] + $state: + P: [0,0,0] + O: [0,0,0,1] + V: [0,0,0] + $sigma: + P: [0.31, 0.31, 0.31] + O: [0.31, 0.31, 0.31] + V: [0.31, 0.31, 0.31] + time_tolerance: 0.1 + tree_manager: + type: "TreeManagerDummy" + toy_param: 0 + sensors: + - + type: "SensorOdom3d" + name: "odom" + plugin: "core" + k_disp_to_disp: 0.1 + k_disp_to_rot: 0.1 + k_rot_to_rot: 0.1 + min_disp_var: 0.1 + min_rot_var: 0.1 + extrinsic: + pose: [1,2,3,0,0,0,1] + processors: + - + type: "ProcessorOdom3d" + name: "my_proc_odom3d" + sensor_name: "odom" + plugin: "core" + apply_loss_function: false + time_tolerance: 0.01 # seconds + keyframe_vote: + voting_active: false + voting_aux_active: false + max_time_span: 0.2 # seconds + max_buff_length: 10 # motion deltas + dist_traveled: 0.5 # meters + angle_turned: 0.1 # radians (1 rad approx 57 deg, approx 60 deg) + + unmeasured_perturbation_std: 0.00111 diff --git a/test/yaml/params_tree_manager2.yaml b/test/yaml/params_tree_manager2.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b61f9936d4ccb8fc705d2ca92717f2a2ad67c402 --- /dev/null +++ b/test/yaml/params_tree_manager2.yaml @@ -0,0 +1,48 @@ +config: + problem: + frame_structure: "POV" + dimension: 3 + prior: + mode: "factor" + # state: [0,0,0,0,0,0,1,0,0,0] + # cov: [[9,9],.1,0,0,0,0,0,0,0,0, 0,.1,0,0,0,0,0,0,0, 0,0,.1,0,0,0,0,0,0, 0,0,0,.1,0,0,0,0,0, 0,0,0,0,.1,0,0,0,0, 0,0,0,0,0,.1,0,0,0, 0,0,0,0,0,0,.1,0,0, 0,0,0,0,0,0,0,.1,0, 0,0,0,0,0,0,0,0,.1] + $state: + P: [0,0,0] + O: [0,0,0,1] + V: [0,0,0] + $sigma: + P: [0.31, 0.31, 0.31] + O: [0.31, 0.31, 0.31] + V: [0.31, 0.31, 0.31] + time_tolerance: 0.1 + tree_manager: + type: "None" + sensors: + - + type: "SensorOdom3d" + name: "odom" + plugin: "core" + k_disp_to_disp: 0.1 + k_disp_to_rot: 0.1 + k_rot_to_rot: 0.1 + min_disp_var: 0.1 + min_rot_var: 0.1 + extrinsic: + pose: [1,2,3,0,0,0,1] + processors: + - + type: "ProcessorOdom3d" + name: "my_proc_odom3d" + sensor_name: "odom" + plugin: "core" + apply_loss_function: false + time_tolerance: 0.01 # seconds + keyframe_vote: + voting_active: false + voting_aux_active: false + max_time_span: 0.2 # seconds + max_buff_length: 10 # motion deltas + dist_traveled: 0.5 # meters + angle_turned: 0.1 # radians (1 rad approx 57 deg, approx 60 deg) + + unmeasured_perturbation_std: 0.00111 diff --git a/test/yaml/params_tree_manager_sliding_window1.yaml b/test/yaml/params_tree_manager_sliding_window1.yaml new file mode 100644 index 0000000000000000000000000000000000000000..96ad94f72af7e8de1b9200a8e5ea44e3bc952a85 --- /dev/null +++ b/test/yaml/params_tree_manager_sliding_window1.yaml @@ -0,0 +1,49 @@ +config: + problem: + frame_structure: "PO" + dimension: 3 + prior: + mode: "factor" + # state: [0,0,0,0,0,0,1] + # cov: [[6,6],.1,0,0,0,0,0, 0,.1,0,0,0,0, 0,0,.1,0,0,0, 0,0,0,.1,0,0, 0,0,0,0,.1,0, 0,0,0,0,0,.1] + $state: + P: [0,0,0] + O: [0,0,0,1] + $sigma: + P: [0.31, 0.31, 0.31] + O: [0.31, 0.31, 0.31] + time_tolerance: 0.1 + tree_manager: + type: "TreeManagerSlidingWindow" + n_key_frames: 3 + fix_first_key_frame: true + viral_remove_empty_parent: true + sensors: + - + type: "SensorOdom3d" + name: "odom" + plugin: "core" + k_disp_to_disp: 0.1 + k_disp_to_rot: 0.1 + k_rot_to_rot: 0.1 + min_disp_var: 0.1 + min_rot_var: 0.1 + extrinsic: + pose: [1,2,3,0,0,0,1] + processors: + - + type: "ProcessorOdom3d" + name: "my_proc_odom3d" + sensor_name: "odom" + plugin: "core" + apply_loss_function: false + time_tolerance: 0.01 # seconds + keyframe_vote: + voting_active: false + voting_aux_active: false + max_time_span: 0.2 # seconds + max_buff_length: 10 # motion deltas + dist_traveled: 0.5 # meters + angle_turned: 0.1 # radians (1 rad approx 57 deg, approx 60 deg) + + unmeasured_perturbation_std: 0.00111 diff --git a/test/yaml/params_tree_manager_sliding_window2.yaml b/test/yaml/params_tree_manager_sliding_window2.yaml new file mode 100644 index 0000000000000000000000000000000000000000..9ae33a2af5ab0695bd44948d33d2f9aa104cbc74 --- /dev/null +++ b/test/yaml/params_tree_manager_sliding_window2.yaml @@ -0,0 +1,49 @@ +config: + problem: + frame_structure: "PO" + dimension: 3 + prior: + mode: "factor" + # state: [0,0,0,0,0,0,1] + # cov: [[6,6],.1,0,0,0,0,0, 0,.1,0,0,0,0, 0,0,.1,0,0,0, 0,0,0,.1,0,0, 0,0,0,0,.1,0, 0,0,0,0,0,.1] + $state: + P: [0,0,0] + O: [0,0,0,1] + $sigma: + P: [0.31, 0.31, 0.31] + O: [0.31, 0.31, 0.31] + time_tolerance: 0.1 + tree_manager: + type: "TreeManagerSlidingWindow" + n_key_frames: 3 + fix_first_key_frame: false + viral_remove_empty_parent: false + sensors: + - + type: "SensorOdom3d" + name: "odom" + plugin: "core" + k_disp_to_disp: 0.1 + k_disp_to_rot: 0.1 + k_rot_to_rot: 0.1 + min_disp_var: 0.1 + min_rot_var: 0.1 + extrinsic: + pose: [1,2,3,0,0,0,1] + processors: + - + type: "ProcessorOdom3d" + name: "my_proc_odom3d" + sensor_name: "odom" + plugin: "core" + apply_loss_function: false + time_tolerance: 0.01 # seconds + keyframe_vote: + voting_active: false + voting_aux_active: false + max_time_span: 0.2 # seconds + max_buff_length: 10 # motion deltas + dist_traveled: 0.5 # meters + angle_turned: 0.1 # radians (1 rad approx 57 deg, approx 60 deg) + + unmeasured_perturbation_std: 0.00111 diff --git a/test/yaml/processor_odom_3d.yaml b/test/yaml/processor_odom_3d.yaml index 65b00b967a1b3c1ed870f979479db930caf78b5e..672421b5d074b7fd627bf955a879e3f10a3544e0 100644 --- a/test/yaml/processor_odom_3d.yaml +++ b/test/yaml/processor_odom_3d.yaml @@ -1,4 +1,4 @@ -type: "ProcessorOdom3d" # This must match the KEY used in the SensorFactory. Otherwise it is an error. +type: "ProcessorOdom3d" # This must match the KEY used in the FactorySensor. Otherwise it is an error. time_tolerance: 0.01 # seconds diff --git a/test/yaml/sensor_odom_2d.yaml b/test/yaml/sensor_odom_2d.yaml index 0841d40b310d90064de6131e32ccaee189ab104c..2d26af901956a324988ac86a67a78dacb5ae8a67 100644 --- a/test/yaml/sensor_odom_2d.yaml +++ b/test/yaml/sensor_odom_2d.yaml @@ -1,4 +1,4 @@ -type: "SensorOdom2d" # This must match the KEY used in the SensorFactory. Otherwise it is an error. +type: "SensorOdom2d" # This must match the KEY used in the FactorySensor. Otherwise it is an error. k_disp_to_disp: 0.02 # m^2 / m k_rot_to_rot: 0.01 # rad^2 / rad diff --git a/test/yaml/sensor_odom_3d.yaml b/test/yaml/sensor_odom_3d.yaml index 58db1c088fbc80339a78ba815fddbaf69674d3b6..8eb2b235011cb3cfe4f35b1f73da6344991af0da 100644 --- a/test/yaml/sensor_odom_3d.yaml +++ b/test/yaml/sensor_odom_3d.yaml @@ -1,4 +1,4 @@ -type: "SensorOdom3d" # This must match the KEY used in the SensorFactory. Otherwise it is an error. +type: "SensorOdom3d" # This must match the KEY used in the FactorySensor. Otherwise it is an error. k_disp_to_disp: 0.02 # m^2 / m k_disp_to_rot: 0.02 # rad^2 / m diff --git a/wolf_scripts/sed_rename.sh b/wolf_scripts/sed_rename.sh new file mode 100755 index 0000000000000000000000000000000000000000..53d20f2bba1f57a7c4569d1dd27b8d5ec09974ea --- /dev/null +++ b/wolf_scripts/sed_rename.sh @@ -0,0 +1,28 @@ +#!/bin/bash +#$1 flag telling whether we are in test mode or not + +modify=$1 +apply=false + +if [[ "$modify" = true || "$modify" = t ]]; then + read -p "Are you sure? " -n 1 -r + echo # (optional) move to a new line + if [[ $REPLY =~ ^[Yy]$ ]] + then + apply=true + echo "Modifying..." + fi +fi + +string="StringToBeReplaced" +replace="ReplacementString" + +for file in $(find include/ src/ test/ demos/ -type f); do + if [ "$apply" = true ]; then + # echo "APPLYING" + sed -Ei 's%'$string'%'$replace'%g' $file + else + # echo "NOT APPLYING" + sed -En 's%'$string'%'$replace'%gp' $file + fi +done