diff --git a/CMakeLists.txt b/CMakeLists.txt index 0910fe579821a1fc1ab7e2df324c754212584123..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) @@ -217,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 ) @@ -227,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 ) @@ -318,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 @@ -338,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 ) @@ -444,6 +443,18 @@ ADD_LIBRARY(${PROJECT_NAME} ${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 #============================================================= diff --git a/demos/hello_wolf/factor_bearing.h b/demos/hello_wolf/factor_bearing.h index 6975a798db580e1c127b0215609f49904b29ae40..f5c5dd95887add0562377c360e7087a8f975665d 100644 --- a/demos/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/demos/hello_wolf/factor_range_bearing.h b/demos/hello_wolf/factor_range_bearing.h index 436b79e4a0eee67aa8ddd97de34ec14127251d01..226a6335e7966a0d3bdd7042c017913bc64b419b 100644 --- a/demos/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/demos/hello_wolf/hello_wolf.cpp b/demos/hello_wolf/hello_wolf.cpp index 1089e4ae64f96db351e5f2aee74423b26642f0ed..a0af310caa518d2a956d5bd80e587a2ec9d39314 100644 --- a/demos/hello_wolf/hello_wolf.cpp +++ b/demos/hello_wolf/hello_wolf.cpp @@ -139,8 +139,10 @@ int main() // initialize TimeStamp t(0.0); // t : 0.0 - Vector3d x(0,0,0); - Matrix3d P = Matrix3d::Identity() * 0.1; + // 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); diff --git a/demos/hello_wolf/processor_range_bearing.cpp b/demos/hello_wolf/processor_range_bearing.cpp index 9510807d443da2458299fe3522fa8c5f49cf0bf5..08e77f76c8d7d2ec70c9b1ac6689e724a67e5c7c 100644 --- a/demos/hello_wolf/processor_range_bearing.cpp +++ b/demos/hello_wolf/processor_range_bearing.cpp @@ -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; } diff --git a/demos/hello_wolf/yaml/hello_wolf_config.yaml b/demos/hello_wolf/yaml/hello_wolf_config.yaml index 90e1c1616c1d32955bc50ccf04eae73e0ef01159..f2e4f8db31f97ef8059b4d59483a747456e6d19c 100644 --- a/demos/hello_wolf/yaml/hello_wolf_config.yaml +++ b/demos/hello_wolf/yaml/hello_wolf_config.yaml @@ -11,8 +11,14 @@ config: dimension: 2 # space is 2d prior: mode: "factor" - state: [0,0,0] - cov: [[3,3],.01,0,0,0,.01,0,0,0,.01] + # 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: diff --git a/include/core/capture/capture_base.h b/include/core/capture/capture_base.h index dbabbdefe4ee96de47685fcd519abe28127ed120..413aaed7d3fbac71f4b9142c3b139acc2b34cbb9 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,10 +92,6 @@ class CaptureBase : public NodeBase, public HasStateBlocks, public std::enable_s virtual void fix() override; virtual void unfix() override; - bool hasCalibration() const {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> @@ -119,15 +114,9 @@ class CaptureBase : public NodeBase, public HasStateBlocks, public std::enable_s 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; - protected: - virtual SizeEigen computeCalibSize() const; - private: FeatureBasePtr addFeature(FeatureBasePtr _ft_ptr); void removeFeature(FeatureBasePtr _ft_ptr); - - private: - void updateCalibSize(); }; } @@ -147,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 72ed561c556275804b89b8bb9a54c876506d1926..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,19 +84,18 @@ 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, // @@ -160,12 +155,6 @@ 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 -{ - 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; -} - inline wolf::CaptureBasePtr CaptureMotion::getOriginCapture() { return capture_origin_ptr_.lock(); 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/common/wolf.h b/include/core/common/wolf.h index a3ec1b9e9018e041f0ab0aef448894858c265324..0e54191e5c546b18bf7f92e34054afa375faa696 100644 --- a/include/core/common/wolf.h +++ b/include/core/common/wolf.h @@ -288,7 +288,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 03fc5fbb407c1f2c6914f871ede6834701af2bab..dce0203c894704953ff3001732f418b2636343a3 100644 --- a/include/core/factor/factor_autodiff.h +++ b/include/core/factor/factor_autodiff.h @@ -64,6 +64,7 @@ class FactorAutodiff : public FactorBase /** \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, @@ -83,7 +84,7 @@ class FactorAutodiff : public FactorBase StateBlockPtr _state9Ptr, StateBlockPtr _state10Ptr, StateBlockPtr _state11Ptr) : - 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_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr,_state10Ptr,_state11Ptr}) { // asserts for null states @@ -361,6 +362,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,0> : public Fact 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, @@ -379,7 +381,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,0> : public Fact StateBlockPtr _state8Ptr, StateBlockPtr _state9Ptr, StateBlockPtr _state10Ptr) : - 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_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr,_state10Ptr}) { // asserts for null states @@ -624,6 +626,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,0,0> : public Factor 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, @@ -641,7 +644,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,0,0> : public Factor 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_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr}) { // asserts for null states @@ -877,6 +880,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0,0,0> : public FactorB 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, @@ -893,7 +897,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0,0,0> : public FactorB 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), + 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 @@ -1120,6 +1124,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0,0,0> : public FactorBa 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, @@ -1135,7 +1140,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0,0,0> : public FactorBa 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), + 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 @@ -1353,6 +1358,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0,0,0> : public FactorBas 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, @@ -1367,7 +1373,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0,0,0> : public FactorBas 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), + 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 @@ -1576,6 +1582,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0,0,0> : public FactorBase 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, @@ -1589,7 +1596,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,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), + 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 @@ -1784,6 +1791,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0,0,0> : public FactorBase 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, @@ -1796,7 +1804,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,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), + 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 @@ -1982,6 +1990,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0,0,0> : public FactorBase 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, @@ -1993,7 +2002,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,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), + 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 @@ -2174,6 +2183,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0,0,0> : public FactorBase 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, @@ -2184,7 +2194,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,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), + 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 @@ -2356,6 +2366,7 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0,0,0> : public FactorBase 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, @@ -2365,7 +2376,7 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,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), + 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 @@ -2528,6 +2539,7 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0,0,0> : public FactorBase 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, @@ -2536,7 +2548,7 @@ class FactorAutodiff<FacT,RES,B0,0,0,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), + 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 diff --git a/include/core/factor/factor_autodiff_distance_3d.h b/include/core/factor/factor_autodiff_distance_3d.h index 1ef90ba493d3d3922685f7f42ff2b14402d7a546..320f7ac270cdd151f078c520561e509f108296d8 100644 --- a/include/core/factor/factor_autodiff_distance_3d.h +++ b/include/core/factor/factor_autodiff_distance_3d.h @@ -24,7 +24,8 @@ class FactorAutodiffDistance3d : public FactorAutodiff<FactorAutodiffDistance3d, bool _apply_loss_function, FactorStatus _status) : FactorAutodiff("FactorAutodiffDistance3d", - _frm_other, + _feat, + _frm_other, nullptr, nullptr, nullptr, diff --git a/include/core/factor/factor_base.h b/include/core/factor/factor_base.h index b58f4e9b337d169e013bea389fe841c382d5f8a2..9b19020f716da69341664ada97ae5c7a9a7f395b 100644 --- a/include/core/factor/factor_base.h +++ b/include/core/factor/factor_base.h @@ -54,7 +54,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: @@ -66,6 +68,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, @@ -75,6 +78,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, @@ -126,15 +130,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; @@ -256,7 +256,6 @@ std::shared_ptr<classType> FactorBase::emplace(FeatureBasePtr _ftr_ptr, T&&... a return ctr; } - inline unsigned int FactorBase::id() const { return factor_id_; @@ -309,7 +308,6 @@ inline LandmarkBasePtr FactorBase::getLandmarkOther() const return landmark_other_list_.front().lock(); } - inline ProcessorBasePtr FactorBase::getProcessor() const { return processor_ptr_.lock(); @@ -320,5 +318,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 4ff0a96e89ee4bb9b6b5a77534e6656da24d7269..143308af2988a74d754f865c305e1ba089f4f778 100644 --- a/include/core/factor/factor_block_absolute.h +++ b/include/core/factor/factor_block_absolute.h @@ -33,11 +33,13 @@ class FactorBlockAbsolute : public FactorAnalytic * \param _sb_ptr the constrained state block * */ - FactorBlockAbsolute(StateBlockPtr _sb_ptr, + 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, @@ -63,13 +65,15 @@ class FactorBlockAbsolute : public FactorAnalytic * \param _start_idx the size of the state segment that is constrained, -1 = all the * */ - FactorBlockAbsolute(StateBlockPtr _sb_ptr, + 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 7b189e4424b419b655833020ff9a94c71952748e..e267fb507ebfd811a0c17b1b6446267223510198 100644 --- a/include/core/factor/factor_diff_drive.h +++ b/include/core/factor/factor_diff_drive.h @@ -32,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: @@ -55,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, diff --git a/include/core/factor/factor_odom_2d.h b/include/core/factor/factor_odom_2d.h index 1ce2a375c131cea5234a5e603cdf2808764bc4cc..d8cfa08a9a9bf70c8b580f407f0983f60e791566 100644 --- a/include/core/factor/factor_odom_2d.h +++ b/include/core/factor/factor_odom_2d.h @@ -17,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()) { // } diff --git a/include/core/factor/factor_odom_2d_closeloop.h b/include/core/factor/factor_odom_2d_closeloop.h index 85a1785440a03a15a899117b619d3d07aaa3eb39..a4ea7b1dff8484a89885edd424a6ac899331d3d7 100644 --- a/include/core/factor/factor_odom_2d_closeloop.h +++ b/include/core/factor/factor_odom_2d_closeloop.h @@ -21,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()) { // } 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 f11b674e7775c78c0f0f306be69c85c832e328de..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, @@ -58,7 +59,7 @@ inline bool FactorPose2d::operator ()(const T* const _p, const T* const _o, T* _ // 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 aca1f7f966aa33e3f970e630b984b7fe145781ed..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, + FactorQuaternionAbsolute(FeatureBasePtr _ftr_ptr, + StateBlockPtr _sb_ptr, ProcessorBasePtr _processor_ptr, bool _apply_loss_function, FactorStatus _status = FAC_ACTIVE) : 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 2dba90bc6d4ead00634f601bf232d4471860c418..e4ccf958c00e0e6185e0cf97a20c8072517c2756 100644 --- a/include/core/factor/factor_relative_2d_analytic.h +++ b/include/core/factor/factor_relative_2d_analytic.h @@ -19,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_other_ptr, - const ProcessorBasePtr& _processor_ptr, - bool _apply_loss_function, - FactorStatus _status = FAC_ACTIVE) : - FactorAnalytic(_tp, _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()) + 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()) { // } @@ -32,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() ) { // } @@ -45,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_other_ptr, - const ProcessorBasePtr& _processor_ptr, - bool _apply_loss_function, - FactorStatus _status = FAC_ACTIVE) : - FactorAnalytic(_tp, 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()) + 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()) { // } diff --git a/include/core/factor/factor_relative_pose_2d_with_extrinsics.h b/include/core/factor/factor_relative_pose_2d_with_extrinsics.h index be13135c9c7e3e0899ac2bb9043f4dd1b7b60ef2..704cc3e7bc906a84a6702b6e8fdcad38766562ee 100644 --- a/include/core/factor/factor_relative_pose_2d_with_extrinsics.h +++ b/include/core/factor/factor_relative_pose_2d_with_extrinsics.h @@ -22,6 +22,7 @@ class FactorRelativePose2dWithExtrinsics : public FactorAutodiff<FactorRelativeP 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, @@ -46,13 +47,23 @@ class FactorRelativePose2dWithExtrinsics : public FactorAutodiff<FactorRelativeP } 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, + 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 +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 diff --git a/include/core/feature/feature_base.h b/include/core/feature/feature_base.h index da1f68b8400cb94f87d1cc5ee460fbf8440b7bee..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; @@ -191,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 5ed1abdcfbd9192f4a7f44424c0e66f01842df1c..37fc3a0ea2ea96144c6ab11d016250197a20dd0c 100644 --- a/include/core/frame/frame_base.h +++ b/include/core/frame/frame_base.h @@ -57,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); //Auxiliary constructor, needed to put frametype in front FrameBase(const FrameType & _tp, const std::string _frame_structure, const SizeEigen _dim, const TimeStamp& _ts, const Eigen::VectorXd& _x); 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/problem/problem.h b/include/core/problem/problem.h index ee71997cd37847bef9f1f7a1483418b7e596beb8..863a43571478656496f9035bcefca96c29756cfc 100644 --- a/include/core/problem/problem.h +++ b/include/core/problem/problem.h @@ -22,6 +22,7 @@ struct ParamsProcessorBase; #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> @@ -37,8 +38,8 @@ enum Notification struct PriorOptions { std::string mode = ""; - Eigen::VectorXd state; - Eigen::MatrixXd cov; + VectorComposite state; + MatrixComposite cov; double time_tolerance; }; WOLF_STRUCT_PTR_TYPEDEFS(PriorOptions); @@ -64,7 +65,7 @@ class Problem : public std::enable_shared_from_this<Problem> std::map<StateBlockPtr, Notification> state_block_notification_map_; mutable std::mutex mut_notifications_; mutable std::mutex mut_covariances_; - std::string frame_structure_; + StateStructure frame_structure_; PriorOptionsPtr prior_options_; private: // CAUTION: THESE METHODS ARE PRIVATE, DO NOT MAKE THEM PUBLIC !! @@ -77,16 +78,27 @@ 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; @@ -169,76 +181,127 @@ class Problem : public std::enable_shared_from_this<Problem> IsMotionPtr getProcessorIsMotion(); std::list<IsMotionPtr> getProcessorIsMotionList(); + + + // Trajectory branch ---------------------------------- TrajectoryBasePtr getTrajectory() const; // Prior bool isPriorSet() const; void setPriorOptions(const std::string& _mode, - const double _time_tolerance = 0, - const Eigen::VectorXd& _state = Eigen::VectorXd(0), - const Eigen::MatrixXd& _cov = Eigen::MatrixXd(0,0)); + const double _time_tolerance = 0, + const VectorComposite& _state = VectorComposite(), + const VectorComposite& _cov = VectorComposite()); FrameBasePtr applyPriorOptions(const TimeStamp& _ts); - FrameBasePtr setPriorFactor(const Eigen::VectorXd &_state, - const Eigen::MatrixXd &_cov, + FrameBasePtr setPriorFactor(const VectorComposite &_state, + const VectorComposite &_sigma, const TimeStamp &_ts, const double &_time_tol); - FrameBasePtr setPriorFix(const Eigen::VectorXd &_state, + FrameBasePtr setPriorFix(const VectorComposite &_state, const TimeStamp &_ts, const double &_time_tol); - FrameBasePtr setPriorInitialGuess(const Eigen::VectorXd &_state, + FrameBasePtr setPriorInitialGuess(const VectorComposite &_state, const TimeStamp &_ts, const double &_time_tol); - /** \brief Emplace frame from string frame_structure + /** \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 emplaceKeyFrame(const std::string& _frame_structure, // + FrameBasePtr emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const StateStructure& _frame_structure, // const SizeEigen _dim, // - 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 emplaceKeyFrame(const std::string& _frame_structure, // - const SizeEigen _dim, // - 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 _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 + * - 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 SizeEigen _dim); + + /** \brief Emplace frame from state vector * \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_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 emplaceKeyFrame(const Eigen::VectorXd& _frame_state, // - const TimeStamp& _time_stamp); + FrameBasePtr emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const Eigen::VectorXd& _frame_state); - /** \brief Emplace frame from string frame_structure without structure nor 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 * - Add it to Trajectory @@ -285,15 +348,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; - // Perturb state - void perturb(double amplitude = 0.01); + VectorComposite stateZero ( const StateStructure& _structure = "" ) const; + + + // Map branch ----------------------------------------- MapBasePtr getMap() const; @@ -301,7 +364,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); @@ -313,6 +382,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 @@ -367,10 +438,6 @@ class Problem : public std::enable_shared_from_this<Problem> bool metric = true, // bool state_blocks = false, std::ostream& stream = std::cout) const; - void print(const std::string& depth, // - bool constr_by = false, // - bool metric = true, // - bool state_blocks = false) const; bool check(int verbose_level = 0) const; bool check(bool verbose, std::ostream& stream) const; diff --git a/include/core/processor/is_motion.h b/include/core/processor/is_motion.h index 3ba3f97ad15249f425e357b7901a1494a5e56073..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,24 +25,9 @@ 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;}; @@ -63,27 +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/processor_diff_drive.h b/include/core/processor/processor_diff_drive.h index bcbf3f6034250a3ffd0ac3e00b73501643d1b69b..e3e504f36b50d95c69bf13d0a99c0107f5207b27 100644 --- a/include/core/processor/processor_diff_drive.h +++ b/include/core/processor/processor_diff_drive.h @@ -60,7 +60,8 @@ 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: ParamsProcessorDiffDrivePtr params_prc_diff_drv_selfcal_; @@ -68,6 +69,17 @@ class ProcessorDiffDrive : public ProcessorOdom2d }; +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 cbd8fa378738ad55d1072d63b7a6162a169077fa..4b22ba3985cf04a1c5c1f7658419ea9ed384f390 100644 --- a/include/core/processor/processor_loopclosure.h +++ b/include/core/processor/processor_loopclosure.h @@ -47,7 +47,6 @@ class ProcessorLoopClosure : public ProcessorBase protected: ParamsProcessorLoopClosurePtr params_loop_closure_; - int _dim; public: diff --git a/include/core/processor/processor_motion.h b/include/core/processor/processor_motion.h index d55c279fc3fd9ce5d083529b41d3448191f1f395..8769e1cc070e6fd1b12d153d4d88771cc3e9f4cb 100644 --- a/include/core/processor/processor_motion.h +++ b/include/core/processor/processor_motion.h @@ -165,23 +165,9 @@ class ProcessorMotion : public ProcessorBase, public IsMotion 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().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 @@ -212,7 +198,7 @@ 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(); @@ -395,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. @@ -411,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 @@ -439,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;} @@ -513,20 +521,6 @@ 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().back().delta_integr_cov_; diff --git a/include/core/processor/processor_odom_2d.h b/include/core/processor/processor_odom_2d.h index 567c739200d7effaece6fe95cc6f17ce36f50c0c..0b873564bb7339e9acf63f1739076b9baa4ec29a 100644 --- a/include/core/processor/processor_odom_2d.h +++ b/include/core/processor/processor_odom_2d.h @@ -13,6 +13,7 @@ #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 { @@ -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,6 +87,8 @@ 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: 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 ca0a9619d06dbd285bb9bf8da88943286d87e0bb..49eaf4fad2788dde0499021ec89fb58d228cb65b 100644 --- a/include/core/processor/processor_odom_3d.h +++ b/include/core/processor/processor_odom_3d.h @@ -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,6 +108,8 @@ 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: ParamsProcessorOdom3dPtr params_odom_3d_; diff --git a/include/core/processor/processor_tracker.h b/include/core/processor/processor_tracker.h index 09072ab7fc397412c21e57b6cbf7060c111455be..6dea1c98d36d6b444f6f7f28bc46a1d1f2332649 100644 --- a/include/core/processor/processor_tracker.h +++ b/include/core/processor/processor_tracker.h @@ -108,14 +108,17 @@ class ProcessorTracker : public ProcessorBase 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, 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); @@ -304,6 +307,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 4cb706c5c3de26da86f3653ef6234251bafb3f7c..b69599ef55fce9f4624b6fe9115722aeb86aa3ca 100644 --- a/include/core/processor/processor_tracker_feature.h +++ b/include/core/processor/processor_tracker_feature.h @@ -85,6 +85,7 @@ class ProcessorTrackerFeature : public ProcessorTracker /** \brief Constructor with type */ ProcessorTrackerFeature(const std::string& _type, + const StateStructure& _structure, int _dim, ParamsProcessorTrackerFeaturePtr _params_tracker_feature); virtual ~ProcessorTrackerFeature(); diff --git a/include/core/processor/processor_tracker_landmark.h b/include/core/processor/processor_tracker_landmark.h index b4e7f7a41ae8bbe68d53da08288b85cda87edeab..6181810bde23395d70c8e28cabc2457f4b13f41b 100644 --- a/include/core/processor/processor_tracker_landmark.h +++ b/include/core/processor/processor_tracker_landmark.h @@ -81,6 +81,7 @@ class ProcessorTrackerLandmark : public ProcessorTracker { public: ProcessorTrackerLandmark(const std::string& _type, + const StateStructure& _structure, ParamsProcessorTrackerLandmarkPtr _params_tracker_landmark); virtual ~ProcessorTrackerLandmark(); 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_block.h b/include/core/state_block/state_block.h index 5d3aa1fc2e9694211d388592c8aa2605cee00824..c8706e2b6d081802d4a3b2590538b2e45df0584b 100644 --- a/include/core/state_block/state_block.h +++ b/include/core/state_block/state_block.h @@ -146,22 +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); - /** \brief Factory creator - * - */ static StateBlockPtr create (const Eigen::VectorXd& _state, bool _fixed = false); + }; } // namespace wolf @@ -297,6 +296,25 @@ 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); 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 f9a0c099841c025671bff1b51d50df86fccff51a..ec42d19e188593b61db2a78b8f6ecbf35680216d 100644 --- a/include/core/state_block/state_homogeneous_3d.h +++ b/include/core/state_block/state_homogeneous_3d.h @@ -20,6 +20,9 @@ class StateHomogeneous3d : public StateBlock 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); }; @@ -42,6 +45,17 @@ 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); diff --git a/include/core/state_block/state_quaternion.h b/include/core/state_block/state_quaternion.h index 817d436aef72c9b128ce97dd8569f380a575ce1b..1533607134e89684674a4eec1d88d7cc83c9e6f0 100644 --- a/include/core/state_block/state_quaternion.h +++ b/include/core/state_block/state_quaternion.h @@ -21,6 +21,9 @@ class StateQuaternion : public StateBlock 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); }; @@ -47,6 +50,17 @@ 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); diff --git a/include/core/trajectory/trajectory_base.h b/include/core/trajectory/trajectory_base.h index 7adcb70aefe9db68c44a5ac08c4d42e47162a921..a5fca0aa7338af088a33622a83a348ef9ddbf567 100644 --- a/include/core/trajectory/trajectory_base.h +++ b/include/core/trajectory/trajectory_base.h @@ -64,12 +64,9 @@ class TrajectoryBase : public NodeBase, public std::enable_shared_from_this<Traj // 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 FrameList& getFrameList() const; FrameBasePtr getLastFrame() const; @@ -146,11 +143,6 @@ inline FrameBasePtr TrajectoryBase::getLastKeyFrame() const else return nullptr; } -inline std::string TrajectoryBase::getFrameStructure() const -{ - return frame_structure_; -} - } // namespace wolf #endif 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/src/capture/capture_base.cpp b/src/capture/capture_base.cpp index 072a729a6d0cc8ec278f0b30e33141bbf7ca16db..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() @@ -151,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(); @@ -175,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) @@ -312,7 +263,7 @@ void CaptureBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _s { _stream << _tabs << (isFixed() ? "Fix" : "Est") << ", ts=" << std::setprecision(5) << getTimeStamp(); - _stream << ",\t x= ( " << std::setprecision(2) << getState().transpose() << " )"; + _stream << ",\t x= ( " << std::setprecision(2) << getStateVector() << " )"; _stream << std::endl; } else if (_state_blocks) @@ -326,22 +277,8 @@ void CaptureBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _s _stream << std::endl; } } - - - -// if (_state_blocks) -// for (const auto& sb : getStateBlockVec()) -// { -// if(sb != nullptr) -// { -// _stream << " sb: "; -// _stream << (sb->isFixed() ? "Fix" : "Est"); -// if (_metric) -// _stream << std::setprecision(2) << " (" << sb->getState().transpose() << " )"; -// _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); 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 aa7d4f23a633a01090c9a0d042e46ff153613bd6..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,26 +47,29 @@ 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().back().delta_integr_; - MatrixXd jac_calib = getBuffer().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; -Eigen::VectorXd CaptureMotion::getDeltaCorrected(const VectorXd& _calib_current, const TimeStamp& _ts) 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; + // 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; } + + + void CaptureMotion::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const { _stream << _tabs << "CapM" << id() << " " << getType(); @@ -114,13 +113,13 @@ void CaptureMotion::printHeader(int _depth, bool _constr_by, bool _metric, bool 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; - } +// 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/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 0c9286337d850796006c208a67aba4c2775e137e..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,6 +68,10 @@ 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(); } @@ -97,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); } } @@ -108,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); } } @@ -119,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); } } @@ -130,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); } } @@ -139,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"); @@ -249,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"); @@ -264,16 +251,15 @@ void FactorBase::link(FeatureBasePtr _ftr_ptr) { WOLF_WARN("Linking with nullptr"); return; - - // if frame, should not be not-key - if (getCapture() and getFrame()) - assert(getFrame()->isKey() && "Forbidden: linking a factor with a non-key frame."); } // link with feature _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."); diff --git a/src/feature/feature_base.cpp b/src/feature/feature_base.cpp index 86d56b3e46bf20390a7083d695b0151b910d17ee..69133345e0f57c28e3135aa3b50e0d99e179be50 100644 --- a/src/feature/feature_base.cpp +++ b/src/feature/feature_base.cpp @@ -147,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); diff --git a/src/frame/frame_base.cpp b/src/frame/frame_base.cpp index a8c27ed499faf27eeb1e0c5e3231f1c6cf62dbf5..aed4c7bc69b99233426faeb6baa592844e0fa63a 100644 --- a/src/frame/frame_base.cpp +++ b/src/frame/frame_base.cpp @@ -6,12 +6,68 @@ #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 FrameType & _tp, const TimeStamp& _ts, StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, StateBlockPtr _v_ptr) : +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) +{ + for (const auto& pair_key_vec : _state) + { + 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); + } +} + + +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) + { + 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", "FrameBase"), HasStateBlocks(""), trajectory_ptr_(), @@ -33,7 +89,11 @@ 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) : +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_(), @@ -321,7 +381,10 @@ void FrameBase::setProblem(ProblemPtr _problem) void FrameBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const { - _stream << _tabs << (isKey() ? (isKey() ? "KFrm" : "AFrm") : "Frm") << id() << ((_depth < 2) ? " -- " + std::to_string(getCaptureList().size()) + "C " : ""); + _stream << _tabs << (isKey() ? "KFrm" : "Frm") << id() + << " " << getStructure() + << " ts = " << std::setprecision(3) << getTimeStamp() + << ((_depth < 2) ? " -- " + std::to_string(getCaptureList().size()) + "C " : ""); if (_constr_by) { _stream << " <-- "; @@ -330,18 +393,21 @@ void FrameBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _sta } _stream << std::endl; - if (_metric && _state_blocks){ + if (_metric && _state_blocks) + { for (const auto& key : getStructure()) { auto sb = getStateBlock(key); - _stream << " " << key << "[" << (sb->isFixed() ? "Fix" : "Est") << "] = ( " << sb->getState().transpose() << " )" << std::endl; + _stream << _tabs << " " << key + << "[" << (sb->isFixed() ? "Fix" : "Est") + << "] = ( " << std::setprecision(3) << sb->getState().transpose() << " )" + << std::endl; } } else if (_metric) { - _stream << _tabs << " " << (isFixed() ? "Fix" : "Est") << ", ts=" << std::setprecision(5) - << getTimeStamp(); - _stream << ",\t x = ( " << std::setprecision(2) << getState().transpose() << " )"; + _stream << _tabs << " " << (isFixed() ? "Fix" : "Est"); + _stream << ",\t x = ( " << std::setprecision(3) << getStateVector().transpose() << " )"; _stream << std::endl; } else if (_state_blocks) diff --git a/src/landmark/landmark_base.cpp b/src/landmark/landmark_base.cpp index a89afb2fda060dcaf503501ea81f34c03b3f5324..ada2bef9648e15ca6a2809d9bf35dc88f2e454ac 100644 --- a/src/landmark/landmark_base.cpp +++ b/src/landmark/landmark_base.cpp @@ -179,7 +179,7 @@ void LandmarkBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _ else if (_metric) { _stream << _tabs << " " << (isFixed() ? "Fix" : "Est"); - _stream << ",\t x = ( " << std::setprecision(2) << getState().transpose() << " )"; + _stream << ",\t x = ( " << std::setprecision(2) << getStateVector().transpose() << " )"; _stream << std::endl; } else if (_state_blocks) diff --git a/src/problem/problem.cpp b/src/problem/problem.cpp index 8ef2d8183a4e479d7a43fcbb6dadeac08a521d01..535a60350ec1e2ef84671c6e0644f478d2cfbf98 100644 --- a/src/problem/problem.cpp +++ b/src/problem/problem.cpp @@ -23,6 +23,7 @@ #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 @@ -42,7 +43,7 @@ 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>()), frame_structure_(_frame_structure), @@ -184,15 +185,18 @@ ProblemPtr Problem::autoSetup(ParamsServer &_server) { problem->setPriorOptions(prior_mode, _server.getParam<double>("problem/prior/time_tolerance"), - _server.getParam<Eigen::VectorXd>("problem/prior/state"), - _server.getParam<Eigen::MatrixXd>("problem/prior/cov")); + _server.getParam<VectorComposite>("problem/prior/state"), + _server.getParam<VectorComposite>("problem/prior/sigma")); + + + } else { WOLF_TRACE("Prior mode: ", prior_mode); problem->setPriorOptions(prior_mode, _server.getParam<double>("problem/prior/time_tolerance"), - _server.getParam<Eigen::VectorXd>("problem/prior/state")); + _server.getParam<VectorComposite>("problem/prior/state")); } // Done @@ -321,176 +325,183 @@ SensorBasePtr Problem::getSensor(const std::string& _sensor_name) const return (*sen_it); } -FrameBasePtr Problem::emplaceKeyFrame(const std::string& _frame_structure, // +FrameBasePtr Problem::emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const StateStructure& _frame_structure, // const SizeEigen _dim, // - const Eigen::VectorXd& _frame_state, // - const TimeStamp& _time_stamp) -{ - auto frm = FrameBase::emplaceKeyFrame<FrameBase>(trajectory_ptr_, _frame_structure, _dim, _time_stamp, _frame_state); + const Eigen::VectorXd& _frame_state) +{ + auto frm = FrameBase::emplace<FrameBase>(trajectory_ptr_, + _frame_key_type, + _time_stamp, + _frame_structure, + _dim, + _frame_state); return frm; } -FrameBasePtr Problem::emplaceKeyFrame(const std::string& _frame_structure, // - const SizeEigen _dim, // - const TimeStamp& _time_stamp) +FrameBasePtr Problem::emplaceFrame(FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const StateStructure& _frame_structure, // + const SizeEigen _dim) { - return emplaceKeyFrame(_frame_structure, _dim, getState(_time_stamp), _time_stamp); + return emplaceFrame(_frame_key_type, + _time_stamp, + _frame_structure, + getState(_time_stamp)); } -FrameBasePtr Problem::emplaceKeyFrame(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 emplaceKeyFrame(this->getFrameStructure(), this->getDim(), _frame_state, _time_stamp); + return FrameBase::emplace<FrameBase>(getTrajectory(), + _frame_key_type, + _time_stamp, + _frame_structure, + _frame_state); } -FrameBasePtr Problem::emplaceKeyFrame(const TimeStamp& _time_stamp) +FrameBasePtr Problem::emplaceFrame (FrameType _frame_key_type, // + const TimeStamp& _time_stamp, // + const VectorComposite& _frame_state) { - return emplaceKeyFrame(this->getFrameStructure(), this->getDim(), _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_->rbegin() != trajectory_ptr_->rend()) + else { - // kind of redundant with getState(_ts, _state) - auto last = trajectory_ptr_->rbegin(); - (*last)->getState(_state); - (*last)->getTimeStamp(_ts); + 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_->closestKeyFrameToTimeStamp(_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_) + 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_) { - 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; - } - } + 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(); - } - // 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; - + // 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)); } } -} -Eigen::VectorXd Problem::getState(const TimeStamp& _ts) const -{ - Eigen::VectorXd state(getFrameStructureSize()); - getState(_ts, state); return state; } -SizeEigen Problem::getFrameStructureSize() const +VectorComposite Problem::getState (const TimeStamp& _ts, const StateStructure& _structure) const { - return state_size_; -} + StateStructure structure = (_structure == "" ? getFrameStructure() : _structure); -void Problem::getFrameStructureSize(SizeEigen& _x_size, SizeEigen& _cov_size) const -{ - _x_size = state_size_; - _cov_size = state_cov_size_; + 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); + } + } + + 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::getDim() const { return dim_; } -std::string Problem::getFrameStructure() const +StateStructure Problem::getFrameStructure() const { return frame_structure_; } +void Problem::appendToStructure(const StateStructure& _structure) +{ + for (const auto& ckey : _structure) + if (frame_structure_.find(ckey) == std::string::npos) // now key not found in problem structure -> append! + frame_structure_ += ckey; +} + void Problem::setTreeManager(TreeManagerBasePtr _gm) { if (tree_manager_) @@ -503,6 +514,7 @@ void Problem::setTreeManager(TreeManagerBasePtr _gm) 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) @@ -511,16 +523,33 @@ void Problem::clearProcessorIsMotion(IsMotionPtr 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()); - - // Set the quaternion identity for 3d states. Set only the real part to 1: - if(this->getDim() == 3) - state(6) = 1.0; + StateStructure structure = (_structure == "" ? getFrameStructure() : _structure); + 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; } @@ -890,9 +919,9 @@ FrameBasePtr Problem::closestKeyFrameToTimeStamp(const TimeStamp& _ts) const } void Problem::setPriorOptions(const std::string& _mode, - const double _time_tolerance, - const Eigen::VectorXd& _state, - const Eigen::MatrixXd& _cov) + const double _time_tolerance , + const VectorComposite& _state , + const VectorComposite& _sigma ) { assert(prior_options_ != nullptr && "prior options have already been applied"); assert(prior_options_->mode == "" && "prior options have already been set"); @@ -906,16 +935,30 @@ void Problem::setPriorOptions(const std::string& _mode, { assert(_time_tolerance > 0 && "time tolerance should be bigger than 0"); - WOLF_TRACE("prior state: ", _state.transpose()); + 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") { - assert(isCovariance(_cov) && "cov is not a covariance matrix (symmetric and Pos Def)"); - WOLF_TRACE("prior covariance:\n" , _cov); - prior_options_->cov = _cov; + 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; } } } @@ -928,56 +971,51 @@ FrameBasePtr Problem::applyPriorOptions(const TimeStamp& _ts) if (prior_options_->mode != "nothing" and prior_options_->mode != "") { - prior_keyframe = emplaceKeyFrame(this->getFrameStructure(), - this->getDim(), - prior_options_->state, - _ts); + prior_keyframe = emplaceFrame(KEY, + _ts, + prior_options_->state); if (prior_options_->mode == "fix") prior_keyframe->fix(); else if (prior_options_->mode == "factor") { - // FIXME: change whenever state is changed to a map<string,vector> // 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 - int state_idx = 0; - int cov_idx = 0; - for (auto sb : prior_keyframe->getStateBlockVec()) + for (const auto& pair_key_sb : prior_keyframe->getStateBlockMap()) { - assert(sb != nullptr); - assert(state_idx+sb->getSize() <= prior_options_->state.size() && "prior_options state wrong size (dimension too small)"); - assert(cov_idx+sb->getLocalSize() <= prior_options_->cov.rows() && "prior_options cov wrong size (dimension too small)"); + const auto& key = pair_key_sb.first; + const auto& sb = pair_key_sb.second; - // state block segment - Eigen::VectorXd state_segment = prior_options_->state.segment(state_idx, sb->getSize()); - Eigen::MatrixXd cov_block = prior_options_->cov.block(cov_idx, cov_idx, sb->getLocalSize(), sb->getLocalSize()); + const auto& state_blk = prior_options_->state.at(key); + const auto& covar_blk = prior_options_->cov.at(key,key); + + assert(sb->getSize() == state_blk.size() && "prior_options state wrong size"); + assert(sb->getLocalSize() == covar_blk.rows() && "prior_options cov. wrong size"); // feature - auto prior_fea = FeatureBase::emplace<FeatureBase>(prior_cap, "prior", state_segment, cov_block); + auto prior_fea = FeatureBase::emplace<FeatureBase>(prior_cap, "Prior " + key, state_blk, covar_blk); // factor if (sb->hasLocalParametrization()) { if (std::dynamic_pointer_cast<StateQuaternion>(sb) != nullptr) - auto prior_fac = FactorBase::emplace<FactorQuaternionAbsolute>(prior_fea, sb, nullptr, false); + 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, sb, nullptr, false); + 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, sb, nullptr, false); + auto prior_fac = FactorBase::emplace<FactorBlockAbsolute>(prior_fea, prior_fea, sb, nullptr, false); } - state_idx += sb->getSize(); - cov_idx += sb->getLocalSize(); + } - assert(state_idx == prior_options_->state.size() && "prior_options state wrong size (dimension too big)"); - assert(cov_idx == prior_options_->cov.rows() && "prior_options cov wrong size (dimension too big)"); + } else assert(prior_options_->mode == "initial_guess" && "wrong prior_options->mode"); @@ -991,17 +1029,17 @@ FrameBasePtr Problem::applyPriorOptions(const TimeStamp& _ts) return prior_keyframe; } -FrameBasePtr Problem::setPriorFactor(const Eigen::VectorXd &_state, - const Eigen::MatrixXd &_cov, +FrameBasePtr Problem::setPriorFactor(const VectorComposite &_state, + const VectorComposite &_sigma, const TimeStamp &_ts, const double &_time_tol) { - setPriorOptions("factor", _time_tol, _state, _cov); + setPriorOptions("factor", _time_tol, _state, _sigma); return applyPriorOptions(_ts); } -FrameBasePtr Problem::setPriorFix(const Eigen::VectorXd &_state, +FrameBasePtr Problem::setPriorFix(const VectorComposite &_state, const TimeStamp &_ts, const double &_time_tol) { @@ -1009,7 +1047,7 @@ FrameBasePtr Problem::setPriorFix(const Eigen::VectorXd &_state, return applyPriorOptions(_ts); } -FrameBasePtr Problem::setPriorInitialGuess(const Eigen::VectorXd &_state, +FrameBasePtr Problem::setPriorInitialGuess(const VectorComposite &_state, const TimeStamp &_ts, const double &_time_tol) { @@ -1087,21 +1125,6 @@ bool Problem::check(int _verbose_level) const { return check((_verbose_level > 0), std::cout); } -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/processor_diff_drive.cpp b/src/processor/processor_diff_drive.cpp index 55841ede92a1bb5dbf4d49bc190b53ab3392cb64..43f15c52d8e0eee217a4c824c67bca1e9ae5b9e3 100644 --- a/src/processor/processor_diff_drive.cpp +++ b/src/processor/processor_diff_drive.cpp @@ -138,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; @@ -168,7 +168,6 @@ FactorBasePtr ProcessorDiffDrive::emplaceFactor(FeatureBasePtr _feature, return fac_odom; } - } /* namespace wolf */ diff --git a/src/processor/processor_loopclosure.cpp b/src/processor/processor_loopclosure.cpp index 9d8589a239466f2ba7bbd30473186c7dbdba52f7..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, ParamsProcessorLoopClosurePtr _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 817dfb367f6aacee7d8be66231f5d2e7e4d56c29..a1006ed3838b21a66afaa6f25467b001e53d0dbc 100644 --- a/src/processor/processor_motion.cpp +++ b/src/processor/processor_motion.cpp @@ -73,7 +73,7 @@ void ProcessorMotion::splitBuffer(const wolf::CaptureMotionPtr& _capture_source, _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); @@ -107,13 +107,13 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) case FIRST_TIME_WITHOUT_KF : { // There is no KF: create own origin - setOrigin(getProblem()->zeroState(), _incoming_ptr->getTimeStamp()); + 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()->zeroState(), _incoming_ptr->getTimeStamp()); + setOrigin(getProblem()->getState(getStateStructure()), _incoming_ptr->getTimeStamp()); break; } case FIRST_TIME_WITH_KF_ON_INCOMING : @@ -125,7 +125,7 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) case FIRST_TIME_WITH_KF_AFTER_INCOMING : { // cannot joint to the KF: create own origin - setOrigin(getProblem()->zeroState(), _incoming_ptr->getTimeStamp()); + setOrigin(getProblem()->getState(getStateStructure()), _incoming_ptr->getTimeStamp()); break; } case RUNNING_WITHOUT_KF : @@ -178,7 +178,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(); @@ -204,17 +204,24 @@ 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().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.) + // 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; } @@ -263,7 +270,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(); @@ -303,9 +310,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()) { @@ -352,19 +360,18 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr) auto factor = emplaceFactor(key_feature, origin_ptr_); // create a new frame - auto prb_ptr = getProblem(); - auto frame_new = FrameBase::createNonKeyFrame<FrameBase>(prb_ptr->getFrameStructure(), - prb_ptr->getDim(), - getCurrentTimeStamp(), - prb_ptr->getCurrentState()); + auto frame_new = getProblem()->emplaceFrame(NON_ESTIMATED, + 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().push_back( motionZero(key_frame->getTimeStamp()) ) ; @@ -389,55 +396,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()) + + 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. { - // timestamp found in the current processor buffer - capture_motion = last_ptr_; + WOLF_ERROR("Processor has no state. Returning an empty VectorComposite with no blocks"); + return VectorComposite(); // return empty state } - else + + + // 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()) { - // We need to search in previous keyframes for the capture containing a motion buffer with the queried time stamp - capture_motion = findCaptureContainingTimeStamp(_ts); + return last_ptr_->getFrame()->getState(state_structure_); } - if (capture_motion) // We found a CaptureMotion whose buffer contains the time stamp + /* 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 origin state and calibration - CaptureBasePtr cap_orig = capture_motion->getOriginCapture(); - VectorXd state_0 = cap_orig->getFrame()->getState(state_structure_); - VectorXd calib = cap_orig->getCalibration(); + // Get current calibration -- from origin capture + const auto& calib = getCalibration(origin_ptr_); - // Get delta and correct it with new calibration params - VectorXd calib_preint = capture_motion->getCalibrationPreint(); - Motion motion = capture_motion->getBuffer().getMotion(_ts); + // get Jacobian of delta wrt calibration + const auto& J_delta_calib = motion.jacobian_calib_; - VectorXd delta_step = motion.jacobian_calib_ * (calib - calib_preint); - VectorXd delta = capture_motion->correctDelta( motion.delta_integr_, delta_step); + // compute delta change + const auto& delta_step = J_delta_calib * (calib - calib_preint); - // ensure proper size of the provided reference - _x.resize( state_0.size() ); + // correct delta // this is (+) + const auto& delta_corrected = correctDelta(delta_preint, delta_step); - // Compose on top of origin state using the buffered time stamp, not the query time stamp - double dt = motion.ts_ - capture_motion->getBuffer().front().ts_; - statePlusDelta(state_0, delta, dt, _x); + // 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()->emplaceKeyFrame(_x_origin, _ts_origin); + FrameBasePtr key_frame_ptr = getProblem()->emplaceFrame(KEY, + _ts_origin, + getStateStructure(), + _x_origin); setOrigin(key_frame_ptr); return key_frame_ptr; @@ -465,11 +581,10 @@ void ProcessorMotion::setOrigin(FrameBasePtr _origin_frame) // ---------- LAST ---------- // Make non-key-frame for last Capture - auto prb_ptr = getProblem(); - auto new_frame_ptr = FrameBase::createNonKeyFrame<FrameBase>(prb_ptr->getFrameStructure(), - prb_ptr->getDim(), - origin_ts, - _origin_frame->getState()); + auto new_frame_ptr = getProblem()->emplaceFrame(NON_ESTIMATED, + origin_ts, + getStateStructure(), + _origin_frame->getState()); // emplace (emtpy) last Capture last_ptr_ = emplaceCapture(new_frame_ptr, @@ -515,7 +630,7 @@ 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().back().jacobian_calib_ @@ -529,15 +644,15 @@ void ProcessorMotion::integrateOneStep() // push all into buffer 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_); + 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) @@ -621,7 +736,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().empty() and _ts >= capture_motion->getBuffer().front().ts_) + + if (capture_motion->containsTimeStamp(_ts, params_->time_tolerance)) { // Found time stamp satisfying rule 3 above !! ==> break for loop break; @@ -677,17 +793,15 @@ PackKeyFramePtr ProcessorMotion::computeProcessingStep() if (pack) { if (buffer_pack_kf_.checkTimeTolerance(pack->key_frame->getTimeStamp(), pack->time_tolerance, origin_ptr_->getTimeStamp(), params_motion_->time_tolerance)) - { - 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_KF_ON_ORIGIN; - } + else if (pack->key_frame->getTimeStamp() < origin_ptr_->getTimeStamp()) + processing_step_ = RUNNING_WITH_KF_BEFORE_ORIGIN; else + processing_step_ = RUNNING_WITH_KF_AFTER_ORIGIN; } @@ -710,6 +824,20 @@ 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; @@ -723,4 +851,5 @@ void ProcessorMotion::printHeader(int _depth, bool _constr_by, bool _metric, boo _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 931efc2e3ea522f4afde3a1647e329d26507859d..284090e238f3c75327424cb76f3946e277e23bdf 100644 --- a/src/processor/processor_odom_2d.cpp +++ b/src/processor/processor_odom_2d.cpp @@ -1,6 +1,7 @@ #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 { @@ -84,15 +85,16 @@ 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 @@ -133,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; diff --git a/src/processor/processor_odom_3d.cpp b/src/processor/processor_odom_3d.cpp index d8f2781f4667989b155ad65e5640a01e4aa52db3..5b01e98b3ad8fbbe6f31bedc4f25b1a9cfe76747 100644 --- a/src/processor/processor_odom_3d.cpp +++ b/src/processor/processor_odom_3d.cpp @@ -1,4 +1,6 @@ #include "core/processor/processor_odom_3d.h" +#include "core/math/SE3.h" + namespace wolf { @@ -138,23 +140,20 @@ 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 +void ProcessorOdom3d::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"); //we need a state vector which size is at least x_size_ 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(); } @@ -207,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; @@ -222,6 +221,14 @@ FeatureBasePtr ProcessorOdom3d::emplaceFeature(CaptureMotionPtr _capture_motion) 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, @@ -232,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) +{ } +} // namespace wolf + // Register in the FactorySensor #include "core/processor/factory_processor.h" namespace wolf { 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 18464e22ea8c904e2b091aed51f1d2e2d42649a5..be506f6da3a3369578164002b2f6a21590ba1c6f 100644 --- a/src/processor/processor_tracker.cpp +++ b/src/processor/processor_tracker.cpp @@ -15,6 +15,7 @@ namespace wolf { ProcessorTracker::ProcessorTracker(const std::string& _type, + const StateStructure& _structure, int _dim, ParamsProcessorTrackerPtr _params_tracker) : ProcessorBase(_type, _dim, _params_tracker), @@ -26,6 +27,7 @@ ProcessorTracker::ProcessorTracker(const std::string& _type, origin_frame_ptr_(nullptr), last_frame_ptr_(nullptr), incoming_frame_ptr_(nullptr) + state_structure_(_structure) { // } @@ -81,7 +83,10 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) { WOLF_DEBUG( "PT ", getName(), " FIRST_TIME_WITHOUT_PACK" ); - FrameBasePtr kfrm = getProblem()->emplaceKeyFrame(incoming_ptr_->getTimeStamp()); + FrameBasePtr kfrm = getProblem()->emplaceFrame(KEY, + incoming_ptr_->getTimeStamp(), + getStateStructure(), + getProblem()->getState(getStateStructure())); incoming_ptr_->link(kfrm); // Process info @@ -110,12 +115,9 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) case SECOND_TIME_WITHOUT_PACK : { WOLF_DEBUG( "PT ", getName(), " SECOND_TIME_WITHOUT_PACK" ); - auto prb_ptr = getProblem(); - auto incoming_ts = incoming_ptr_->getTimeStamp(); - FrameBasePtr frm = FrameBase::createNonKeyFrame<FrameBase>(prb_ptr->getFrameStructure(), - prb_ptr->getDim(), - incoming_ts, - prb_ptr->getState(incoming_ts)); + + FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, + incoming_ptr_->getTimeStamp()); incoming_ptr_->link(frm); incoming_frame_ptr_ = frm; // We have a last_ Capture with no features, so we do not process known features, and we do not vote for KF. @@ -153,12 +155,8 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) last_old_frame->remove(); // Create new frame - auto prb_ptr = getProblem(); - auto incoming_ts = incoming_ptr_->getTimeStamp(); - FrameBasePtr frm = FrameBase::createNonKeyFrame<FrameBase>(prb_ptr->getFrameStructure(), - prb_ptr->getDim(), - incoming_ts, - prb_ptr->getState(incoming_ts)); + FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, + incoming_ptr_->getTimeStamp()); incoming_ptr_->link(frm); incoming_frame_ptr_ = frm; @@ -211,11 +209,9 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) resetDerived(); // make F; append incoming to new F - auto prb_ptr = getProblem(); - FrameBasePtr frm = FrameBase::createNonKeyFrame<FrameBase>(prb_ptr->getFrameStructure(), - prb_ptr->getDim(), - incoming_ptr_->getTimeStamp(), - last_ptr_->getFrame()->getState()); + FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, + incoming_ptr_->getTimeStamp(), + last_ptr_->getFrame()->getStateVector()); incoming_ptr_->link(frm); incoming_frame_ptr_ = frm; @@ -266,11 +262,9 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr) advanceDerived(); // Replace last frame for a new one in incoming - auto prb_ptr = getProblem(); - FrameBasePtr frm = FrameBase::createNonKeyFrame<FrameBase>(prb_ptr->getFrameStructure(), - prb_ptr->getDim(), - incoming_ptr_->getTimeStamp(), - last_ptr_->getFrame()->getState()); + FrameBasePtr frm = getProblem()->emplaceFrame(NON_ESTIMATED, + incoming_ptr_->getTimeStamp(), + last_ptr_->getFrame()->getStateVector()); incoming_ptr_->link(frm); incoming_frame_ptr_ = frm; last_ptr_->getFrame()->remove(); // implicitly calling last_ptr_->remove(); diff --git a/src/processor/processor_tracker_feature.cpp b/src/processor/processor_tracker_feature.cpp index 5b3abbf52bbc5715b9613635494a1719f94f17e8..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, ParamsProcessorTrackerFeaturePtr _params_tracker_feature) : - ProcessorTracker(_type, _dim, _params_tracker_feature), + ProcessorTracker(_type, _structure, _dim, _params_tracker_feature), params_tracker_feature_(_params_tracker_feature) { } diff --git a/src/processor/processor_tracker_landmark.cpp b/src/processor/processor_tracker_landmark.cpp index 0e593a917d9c7715cb16a62a43154cbd53992d58..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, + const StateStructure& _structure, ParamsProcessorTrackerLandmarkPtr _params_tracker_landmark) : - ProcessorTracker(_type, 0, _params_tracker_landmark), + ProcessorTracker(_type, + _structure, + 0, + _params_tracker_landmark), params_tracker_landmark_(_params_tracker_landmark) { // diff --git a/src/sensor/sensor_base.cpp b/src/sensor/sensor_base.cpp index e96a3afdfe1a4618baf113f0114ac4f0330eb974..5ccf914d7aac8e0aa74b38adb3adffe973494b19 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, nullptr, false); + FactorBase::emplace<FactorQuaternionAbsolute>(ftr_prior, ftr_prior, _sb, nullptr, false); else - FactorBase::emplace<FactorBlockAbsolute>(ftr_prior, _sb, _start_idx, _size, nullptr, false); + 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; diff --git a/src/sensor/sensor_diff_drive.cpp b/src/sensor/sensor_diff_drive.cpp index 03634eb0938d9ae7c6a20b5d5a5d11a201989101..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,17 +31,13 @@ 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 } 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 030febd46ba50917d8681bd2ce3bb6ee8be55e23..ea2c9a4cd4f32b4a1c49e1bfec6ad28efb397cbe 100644 --- a/src/state_block/state_block.cpp +++ b/src/state_block/state_block.cpp @@ -26,31 +26,22 @@ 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); } } 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 be5d2c3fbe75a756d92624e3cb9a529f85881ca0..4d0b6de19dc18a77d8c62f7e6b7fa329965fba3f 100644 --- a/src/trajectory/trajectory_base.cpp +++ b/src/trajectory/trajectory_base.cpp @@ -3,7 +3,7 @@ namespace wolf { -TrajectoryBase::TrajectoryBase(const std::string& _frame_structure) : +TrajectoryBase::TrajectoryBase() : NodeBase("TRAJECTORY", "TrajectoryBase"), frame_structure_(_frame_structure) // last_key_frame_ptr_(nullptr), diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cb9421c5ed18c64af24816a7ba14c13d92ea3471..05717bad197c33e241146a8cf4d08fc337d99ea2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -125,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) @@ -142,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}) diff --git a/test/dummy/factor_dummy_zero_1.h b/test/dummy/factor_dummy_zero_1.h index ffe372f0cb9f5671cc491f295d38ec24b305da3b..1ebe1b8fe2e4eba79fe2c9fbf236da5844327189 100644 --- a/test/dummy/factor_dummy_zero_1.h +++ b/test/dummy/factor_dummy_zero_1.h @@ -13,13 +13,17 @@ WOLF_PTR_TYPEDEFS(FactorDummyZero1); //class class FactorDummyZero1 : public FactorAutodiff<FactorDummyZero1, 1, 1> { + using Base = FactorAutodiff<FactorDummyZero1, 1, 1>; public: - FactorDummyZero1(const StateBlockPtr& _sb_ptr) : - FactorAutodiff<FactorDummyZero1, 1, 1>("FactorDummy1", - nullptr, nullptr, nullptr, nullptr, - nullptr, - false, FAC_ACTIVE, - _sb_ptr) + FactorDummyZero1(const FeatureBasePtr& _ftr_ptr, + const StateBlockPtr& _sb_ptr) : + Base("FactorDummy1", + _ftr_ptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, + false, + FAC_ACTIVE, + _sb_ptr) { // } diff --git a/test/dummy/factor_dummy_zero_12.h b/test/dummy/factor_dummy_zero_12.h index 3a57aa386d20524fbbec30aa154f555af0fbb9a1..c60b9ce3232aa5c18807e80fbfb766cde275c953 100644 --- a/test/dummy/factor_dummy_zero_12.h +++ b/test/dummy/factor_dummy_zero_12.h @@ -12,9 +12,11 @@ namespace wolf { 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 StateBlockPtr& _sb1_ptr, + FactorDummyZero12(const FeatureBasePtr& _ftr_ptr, + const StateBlockPtr& _sb1_ptr, const StateBlockPtr& _sb2_ptr, const StateBlockPtr& _sb3_ptr, const StateBlockPtr& _sb4_ptr, @@ -26,22 +28,24 @@ class FactorDummyZero12 : public FactorAutodiff<FactorDummyZero12<ID>, ID, 1, 2, const StateBlockPtr& _sb10_ptr, const StateBlockPtr& _sb11_ptr, const StateBlockPtr& _sb12_ptr) : - FactorAutodiff<FactorDummyZero12<ID>, ID, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12>("FactorDummy12", - 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) + 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); } 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.h b/test/dummy/processor_tracker_feature_dummy.h index c6f651ea013d2fac02164e0d3ea2cb96182fb6b2..d06ac67503acfda0a55d9418bac339359b3d9625 100644 --- a/test/dummy/processor_tracker_feature_dummy.h +++ b/test/dummy/processor_tracker_feature_dummy.h @@ -22,7 +22,8 @@ struct ParamsProcessorTrackerFeatureDummy : public ParamsProcessorTrackerFeature unsigned int n_tracks_lost; ///< number of tracks lost each time track is called (the first ones) ParamsProcessorTrackerFeatureDummy() = default; - ParamsProcessorTrackerFeatureDummy(std::string _unique_name, const wolf::ParamsServer & _server): + 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"); @@ -43,7 +44,7 @@ class ProcessorTrackerFeatureDummy : public ProcessorTrackerFeature // Factory method for high level API WOLF_PROCESSOR_CREATE(ProcessorTrackerFeatureDummy, ParamsProcessorTrackerFeatureDummy); - virtual void configure(SensorBasePtr _sensor) { }; + virtual void configure(SensorBasePtr _sensor) override { }; protected: @@ -63,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 * @@ -79,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) @@ -97,18 +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); + virtual FactorBasePtr emplaceFactor(FeatureBasePtr _feature_ptr, + FeatureBasePtr _feature_other_ptr) override; }; inline ProcessorTrackerFeatureDummy::ProcessorTrackerFeatureDummy(ParamsProcessorTrackerFeatureDummyPtr _params_tracker_feature_dummy) : - ProcessorTrackerFeature("ProcessorTrackerFeatureDummy", 0, _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 472b21ab150a7945987d0d64d5cd171bdf9975eb..d36efd3f804cd71ff38fc7b835dc1b5230c59885 100644 --- a/test/dummy/processor_tracker_landmark_dummy.cpp +++ b/test/dummy/processor_tracker_landmark_dummy.cpp @@ -13,7 +13,7 @@ namespace wolf { ProcessorTrackerLandmarkDummy::ProcessorTrackerLandmarkDummy(ParamsProcessorTrackerLandmarkDummyPtr _params_tracker_landmark_dummy) : - ProcessorTrackerLandmark("ProcessorTrackerLandmarkDummy", _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; diff --git a/test/dummy/processor_tracker_landmark_dummy.h b/test/dummy/processor_tracker_landmark_dummy.h index b9485b3378e7644aa9206213dc3466fd41b83340..5140a2b2762db740944019ac1595e7d37bf07a2c 100644 --- a/test/dummy/processor_tracker_landmark_dummy.h +++ b/test/dummy/processor_tracker_landmark_dummy.h @@ -38,7 +38,7 @@ class ProcessorTrackerLandmarkDummy : public ProcessorTrackerLandmark // Factory method for high level API WOLF_PROCESSOR_CREATE(ProcessorTrackerLandmarkDummy, ParamsProcessorTrackerLandmarkDummy); - virtual void configure(SensorBasePtr _sensor) { }; + virtual void configure(SensorBasePtr _sensor) override { }; protected: @@ -58,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 * @@ -67,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) @@ -85,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 @@ -99,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 index 0e6a1956b97728e8440edca7931c6d5ac32c3bc0..fe62d065c64fbf2f4c37f58b00ff4f51ea2a0ef1 100644 --- a/test/dummy/solver_manager_dummy.h +++ b/test/dummy/solver_manager_dummy.h @@ -26,7 +26,7 @@ class SolverManagerDummy : public SolverManager { }; - bool isStateBlockRegistered(const StateBlockPtr& st) + bool isStateBlockRegistered(const StateBlockPtr& st) override { return state_blocks_.find(st)!=state_blocks_.end(); }; @@ -36,7 +36,7 @@ class SolverManagerDummy : public SolverManager return state_block_fixed_.at(st); }; - bool isFactorRegistered(const FactorBasePtr& fac_ptr) const + bool isFactorRegistered(const FactorBasePtr& fac_ptr) const override { return std::find(factors_.begin(), factors_.end(), fac_ptr) != factors_.end(); }; @@ -51,46 +51,46 @@ class SolverManagerDummy : public SolverManager 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;}; + 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() { return true; } - SizeStd iterations() { return 1; } - double initialCost() { return double(1); } - double finalCost() { return double(0); } + 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){ return std::string("");}; - virtual void addFactorDerived(const FactorBasePtr& fac_ptr) + 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) + virtual void removeFactorDerived(const FactorBasePtr& fac_ptr) override { factors_.remove(fac_ptr); }; - virtual void addStateBlockDerived(const StateBlockPtr& state_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) + 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) + virtual void updateStateBlockStatusDerived(const StateBlockPtr& state_ptr) override { state_block_fixed_[state_ptr] = state_ptr->isFixed(); }; - virtual void updateStateBlockLocalParametrizationDerived(const StateBlockPtr& state_ptr) + virtual void updateStateBlockLocalParametrizationDerived(const StateBlockPtr& state_ptr) override { if (state_ptr->getLocalParametrization() == nullptr) state_block_local_param_.erase(state_ptr); 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_ceres_manager.cpp b/test/gtest_ceres_manager.cpp index fc7d37ad3bb46fe16f50c4cdec38387a317c0b9d..d2b5c7e01b70fa65472f3e18bbfa7b38d8989679 100644 --- a/test/gtest_ceres_manager.cpp +++ b/test/gtest_ceres_manager.cpp @@ -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->emplaceKeyFrame(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); @@ -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->emplaceKeyFrame(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); @@ -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->emplaceKeyFrame(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); @@ -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->emplaceKeyFrame(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); @@ -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->emplaceKeyFrame(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); @@ -546,11 +546,11 @@ TEST(CeresManager, FactorsRemoveLocalParam) CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P); // Create (and add) 2 factors quaternion - FrameBasePtr F = P->emplaceKeyFrame(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(); @@ -588,11 +588,11 @@ TEST(CeresManager, FactorsUpdateLocalParam) CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P); // Create (and add) 2 factors quaternion - FrameBasePtr F = P->emplaceKeyFrame(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(); diff --git a/test/gtest_factor_absolute.cpp b/test/gtest_factor_absolute.cpp index 1e9f1019dba9e192e522b204519964e3790de9fb..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->emplaceKeyFrame(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(), nullptr, false); + 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, nullptr, false); + 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(), nullptr, false); + 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(), nullptr, false); + 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 68712f969a298f5986b93378480f1a66e03cafe1..0acd77891bf1bae60fe41575edec629e9864999b 100644 --- a/test/gtest_factor_autodiff.cpp +++ b/test/gtest_factor_autodiff.cpp @@ -23,8 +23,9 @@ using namespace Eigen; TEST(FactorAutodiff, AutodiffDummy1) { 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>(sb); + auto fac = std::make_shared<FactorDummyZero1>(ftr, sb); // COMPUTE JACOBIANS std::vector<const double*> states_ptr({sb->getStateData()}); @@ -56,9 +57,10 @@ TEST(FactorAutodiff, AutodiffDummy12) 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>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<1>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -82,7 +84,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 2 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<2>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<2>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -106,7 +108,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 3 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<3>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<3>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -130,7 +132,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 4 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<4>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<4>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -154,7 +156,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 5 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<5>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<5>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -178,7 +180,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 6 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<6>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<6>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -202,7 +204,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 7 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<7>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<7>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -226,7 +228,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 8 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<8>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<8>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -250,7 +252,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 9 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<9>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<9>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -274,7 +276,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 10 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<10>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<10>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -298,7 +300,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 11 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<11>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<11>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -322,7 +324,7 @@ TEST(FactorAutodiff, AutodiffDummy12) } // 12 ------------------------------------------------------------------------ - fac = std::make_shared<FactorDummyZero12<12>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); + fac = std::make_shared<FactorDummyZero12<12>>(ftr,sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12); i = fac->getSize(); // Jacobian @@ -523,7 +525,6 @@ TEST(FactorAutodiff, 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 d089b4dbddfe4e6b84334c6ddcc2a3b0fc47ff09..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->emplaceKeyFrame (pose1, 1.0); + F1 = problem->emplaceFrame (KEY, 1.0, pose1); - F2 = problem->emplaceKeyFrame (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 51e017e9032955950818cbd3b413d6971673023e..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>(NON_ESTIMATED, 0.0, nullptr); - F1 = std::make_shared<FrameBase>(NON_ESTIMATED, 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 bc7b92005a0aa81262599264986ae3497dec7241..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,19 +49,19 @@ 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(); + // 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(), nullptr, false); - KF1_ = problem_->emplaceKeyFrame(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 {} @@ -68,20 +69,16 @@ class FixtureFactorBlockDifference : public testing::Test TEST_F(FixtureFactorBlockDifference, CheckFactorType) { - // Feat_->setMeasurement() - FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>( - Feat_, KF0_->getP(), KF1_->getP() - ); - ASSERT_EQ(Fac->getType(), "FactorBlockDifference"); + 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()); @@ -90,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()); @@ -106,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()); @@ -126,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()); @@ -154,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()); @@ -171,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()); @@ -201,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 3fb12bb38ca2f3ea4157842aa4c9e6a6348bccf5..0413c21cb2c30bb91b1a03dabac0b595d1843349 100644 --- a/test/gtest_factor_diff_drive.cpp +++ b/test/gtest_factor_diff_drive.cpp @@ -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 @@ -162,16 +159,18 @@ class FactorDiffDriveTest : public testing::Test processor = std::static_pointer_cast<ProcessorDiffDrivePublic>(prc); // frames - F0 = FrameBase::emplaceKeyFrame<FrameBase>(trajectory, - "PO", - 2, - 0.0, - Vector3d(0,0,0)); - F1 = FrameBase::emplaceKeyFrame<FrameBase>(trajectory, - "PO", - 2, - 1.0, - Vector3d(1,0,0)); + F0 = FrameBase::emplace<FrameBase>(trajectory, + KEY, + 0.0, + "PO", + 2, + Vector3d(0,0,0)); + F1 = FrameBase::emplace<FrameBase>(trajectory, + KEY, + 1.0, + "PO", + 2, + Vector3d(1,0,0)); // captures C0 = CaptureBase::emplace<CaptureDiffDrive>(F0, @@ -199,7 +198,7 @@ class FactorDiffDriveTest : public testing::Test "FeatureDiffDrive", delta1, delta1_cov, - C0->getCalibration(), + processor->getCalibration(C0), Matrix3d::Identity()); // TODO Jacobian? @@ -288,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 @@ -315,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 @@ -326,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); } @@ -353,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 @@ -365,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); @@ -441,13 +464,14 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics_gt) 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}); // set prior at t=0 and processor origin - auto F0 = problem->setPriorFactor(x0, P0, t, 0.1); + 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) @@ -492,16 +516,16 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics_gt) 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; @@ -573,13 +597,15 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics) 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}); // set prior at t=0 and processor origin - auto F0 = problem->setPriorFactor(x0, P0, t, 0.1); + 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) @@ -614,7 +640,8 @@ 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(); @@ -624,16 +651,16 @@ TEST(FactorDiffDrive, preintegrate_and_solve_sensor_intrinsics) 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 index 954dcc47b185a30f3c1bdaec54c02069a664a505..8c0b11e3b428cfbfa99c91c29bffe53ceeeb1d92 100644 --- a/test/gtest_factor_odom_2d.cpp +++ b/test/gtest_factor_odom_2d.cpp @@ -19,13 +19,11 @@ ProblemPtr problem_ptr = Problem::create("PO", 2); CeresManager ceres_mgr(problem_ptr); // Two frames -FrameBasePtr frm0 = problem_ptr->emplaceKeyFrame(Vector3d::Zero(), TimeStamp(0)); -FrameBasePtr frm1 = problem_ptr->emplaceKeyFrame(Vector3d::Zero(), TimeStamp(1)); +FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, TimeStamp(0), Vector3d::Zero()); +FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, TimeStamp(1), Vector3d::Zero()); -// Capture, feature and factor from frm1 to frm0 +// Capture from frm1 to frm0 auto cap1 = CaptureBase::emplace<CaptureOdom2d>(frm1, 1, nullptr, Vector3d::Zero(), data_cov); -auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", Vector3d::Zero(), data_cov); -auto fac1 = FactorBase::emplace<FactorOdom2d>(fea1, fea1, frm0, nullptr, false); // create and add TEST(FactorOdom2d, check_tree) { @@ -49,11 +47,14 @@ TEST(FactorOdom2d, fix_0_solve) x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>(); x1(2) = pi2pi(x0(2) + delta(2)); - // Set states and measurement + // Set states frm0->setState(x0); frm1->setState(x1); cap1->setData(delta); - fea1->setMeasurement(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(); @@ -63,7 +64,10 @@ TEST(FactorOdom2d, fix_0_solve) // solve for frm1 std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); - ASSERT_POSE2d_APPROX(frm1->getState(), x1, 1e-6); + ASSERT_POSE2d_APPROX(frm1->getStateVector(), x1, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); } } @@ -84,11 +88,14 @@ TEST(FactorOdom2d, fix_1_solve) x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>(); x1(2) = pi2pi(x0(2) + delta(2)); - // Set states and measurement + // Set states frm0->setState(x0); frm1->setState(x1); cap1->setData(delta); - fea1->setMeasurement(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(); @@ -98,7 +105,10 @@ TEST(FactorOdom2d, fix_1_solve) // solve for frm0 std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); - ASSERT_POSE2d_APPROX(frm0->getState(), x0, 1e-6); + ASSERT_POSE2d_APPROX(frm0->getStateVector(), x0, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); } } diff --git a/test/gtest_factor_odom_3d.cpp b/test/gtest_factor_odom_3d.cpp index b24a074a3262884d6364df47c6253e98bd2c41a8..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->emplaceKeyFrame(problem_ptr->zeroState(), TimeStamp(0)); -FrameBasePtr frm1 = problem_ptr->emplaceKeyFrame(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 a302bf7721c587762c8566180fa5168ef3bb9095..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->emplaceKeyFrame(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 c9e95cca169bb9db68a82b8742d280dc31b22b40..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->emplaceKeyFrame(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 index 2a9575ac9e19c72f49fcc9284a47eb9057fe19cd..c461bbb94743c9ee8b3665650fb00686d979fc20 100644 --- a/test/gtest_factor_relative_2d_analytic.cpp +++ b/test/gtest_factor_relative_2d_analytic.cpp @@ -19,13 +19,11 @@ ProblemPtr problem_ptr = Problem::create("PO", 2); CeresManager ceres_mgr(problem_ptr); // Two frames -FrameBasePtr frm0 = problem_ptr->emplaceKeyFrame(Vector3d::Zero(), TimeStamp(0)); -FrameBasePtr frm1 = problem_ptr->emplaceKeyFrame(Vector3d::Zero(), TimeStamp(1)); +FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, 0.0, Vector3d::Zero()); +FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, 1.0, Vector3d::Zero()); -// Capture, feature and factor from frm1 to frm0 +// Capture from frm1 to frm0 auto cap1 = CaptureBase::emplace<CaptureOdom2d>(frm1, 1, nullptr, Vector3d::Zero(), data_cov); -auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", Vector3d::Zero(), data_cov); -auto fac1 = FactorBase::emplace<FactorRelative2dAnalytic>(fea1, "odom2d", fea1, frm0, nullptr, false); // create and add TEST(FactorRelative2dAnalytic, check_tree) { @@ -53,7 +51,10 @@ TEST(FactorRelative2dAnalytic, fix_0_solve) frm0->setState(x0); frm1->setState(x1); cap1->setData(delta); - fea1->setMeasurement(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(); @@ -63,7 +64,10 @@ TEST(FactorRelative2dAnalytic, fix_0_solve) // solve for frm1 std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); - ASSERT_POSE2d_APPROX(frm1->getState(), x1, 1e-6); + ASSERT_POSE2d_APPROX(frm1->getStateVector(), x1, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); } } @@ -88,7 +92,10 @@ TEST(FactorRelative2dAnalytic, fix_1_solve) frm0->setState(x0); frm1->setState(x1); cap1->setData(delta); - fea1->setMeasurement(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(); @@ -98,7 +105,10 @@ TEST(FactorRelative2dAnalytic, fix_1_solve) // solve for frm0 std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); - ASSERT_POSE2d_APPROX(frm0->getState(), x0, 1e-6); + ASSERT_POSE2d_APPROX(frm0->getStateVector(), x0, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); } } diff --git a/test/gtest_factor_relative_pose_2d_with_extrinsics.cpp b/test/gtest_factor_relative_pose_2d_with_extrinsics.cpp index 756e1f9ecc4244756cd60d354270e73ec5196f78..b9ad5bbe208d981a4ca69aa3eab8eac806f62e14 100644 --- a/test/gtest_factor_relative_pose_2d_with_extrinsics.cpp +++ b/test/gtest_factor_relative_pose_2d_with_extrinsics.cpp @@ -27,13 +27,11 @@ auto sensor_odom2d = problem_ptr->installSensor("SensorOdom2d", "odom", Vector3d auto processor_odom2d = problem_ptr->installProcessor("ProcessorOdom2d", "odom", sensor_odom2d, std::make_shared<ParamsProcessorOdom2d>()); // Two frames -FrameBasePtr frm0 = problem_ptr->emplaceKeyFrame(Vector3d::Zero(), TimeStamp(0)); -FrameBasePtr frm1 = problem_ptr->emplaceKeyFrame(Vector3d::Zero(), TimeStamp(1)); +FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, 0, Vector3d::Zero() ); +FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, 1, Vector3d::Zero() ); -// Capture, feature and factor from frm1 to frm0 +// Capture from frm1 to frm0 auto cap1 = CaptureBase::emplace<CaptureOdom2d>(frm1, 1, sensor_odom2d, Vector3d::Zero(), data_cov); -auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", Vector3d::Zero(), data_cov); -auto fac1 = FactorBase::emplace<FactorRelativePose2dWithExtrinsics>(fea1, fea1, frm0, processor_odom2d, false); // create and add TEST(FactorRelativePose2dWithExtrinsics, check_tree) { @@ -61,13 +59,16 @@ TEST(FactorRelativePose2dWithExtrinsics, fix_0_solve) 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 and measurement + // Set states frm0->setState(x0); frm1->setState(x1); cap1->setData(delta); - fea1->setMeasurement(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(); @@ -78,7 +79,10 @@ TEST(FactorRelativePose2dWithExtrinsics, fix_0_solve) // solve for frm1 std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); - ASSERT_POSE2d_APPROX(frm1->getState(), x1, 1e-6); + ASSERT_POSE2d_APPROX(frm1->getStateVector(), x1, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); } } @@ -103,13 +107,16 @@ TEST(FactorRelativePose2dWithExtrinsics, fix_1_solve) 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 and measurement + // Set states frm0->setState(x0); frm1->setState(x1); cap1->setData(delta); - fea1->setMeasurement(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(); @@ -120,7 +127,10 @@ TEST(FactorRelativePose2dWithExtrinsics, fix_1_solve) // solve for frm0 std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); - ASSERT_POSE2d_APPROX(frm0->getState(), x0, 1e-6); + ASSERT_POSE2d_APPROX(frm0->getStateVector(), x0, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); } } @@ -145,13 +155,16 @@ TEST(FactorRelativePose2dWithExtrinsics, extrinsics_p_solve) 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 and measurement + // Set states frm0->setState(x0); frm1->setState(x1); cap1->setData(delta); - fea1->setMeasurement(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(); @@ -162,7 +175,10 @@ TEST(FactorRelativePose2dWithExtrinsics, extrinsics_p_solve) // solve for frm0 std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); - ASSERT_POSE2d_APPROX(sensor_odom2d->getState(), xs, 1e-6); + ASSERT_POSE2d_APPROX(sensor_odom2d->getStateVector(), xs, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); } } @@ -187,14 +203,15 @@ TEST(FactorRelativePose2dWithExtrinsics, extrinsics_o_solve) 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 and measurement + // Set states frm0->setState(x0); frm1->setState(x1); cap1->setData(delta); - fea1->setMeasurement(delta); sensor_odom2d->setState(xs); - //std::cout << "Sensor O: " << sensor_odom2d->getO()->getState().transpose() << std::endl; + // 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(); @@ -208,7 +225,10 @@ TEST(FactorRelativePose2dWithExtrinsics, extrinsics_o_solve) // solve for frm0 std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF); - ASSERT_POSE2d_APPROX(sensor_odom2d->getState(), xs, 1e-6); + ASSERT_POSE2d_APPROX(sensor_odom2d->getStateVector(), xs, 1e-6); + + // remove feature (and factor) for the next loop + fea1->remove(); } } 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 4845f757c046bd57cea373b4f26a6d4f6e6e5001..df0c7ce316ecef3897f990a24a970a38ef042d11 100644 --- a/test/gtest_frame_base.cpp +++ b/test/gtest_frame_base.cpp @@ -69,9 +69,9 @@ 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::emplaceKeyFrame<FrameBase>(T, 1, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); - auto F2 = FrameBase::emplaceKeyFrame<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 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()); @@ -145,15 +145,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_odom_2d.cpp b/test/gtest_odom_2d.cpp index 84e0e45f3d3ab6953de7841bc80c5f8427af052d..8ef700a29dca74d56baeee8e7869c7fb04f67947 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->setPriorFactor(x0, P0,t0, dt/2); + FrameBasePtr F0 = Pr->setPriorFactor(x0, s0,t0, dt/2); // KF1 and motion from KF0 t += dt; - FrameBasePtr F1 = Pr->emplaceKeyFrame(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->emplaceKeyFrame(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; @@ -217,8 +220,10 @@ TEST(Odom2d, VoteForKfAndSolve) // Ceres wrapper CeresManager ceres_manager(problem); - // Origin Key Frame (in t1 to let processor motion to join the KF) - problem->setPriorFactor(x0, P0, t+dt, dt/2); + // Origin Key Frame + 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); @@ -227,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); @@ -283,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); @@ -296,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; @@ -303,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; @@ -321,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 @@ -353,13 +360,13 @@ TEST(Odom2d, KF_callback) // Ceres wrapper CeresManager ceres_manager(problem); - // Origin Key Frame (in t1 to let processor motion to join the KF) - FrameBasePtr keyframe_0 = problem->setPriorFactor(x0, x0_cov, t0+dt, dt/2); + // Origin Key Frame + 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); @@ -415,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->emplaceKeyFrame(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(), 2); @@ -439,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); @@ -452,8 +459,8 @@ TEST(Odom2d, KF_callback) problem->print(4,1,1,1); - x_split = processor_odom2d->getState(t_split); - FrameBasePtr keyframe_1 = problem->emplaceKeyFrame(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); @@ -480,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 @@ -494,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_problem.cpp b/test/gtest_problem.cpp index 625ea44beae19a6d91e3d1307f447e0a48c1d331..7778f7b46b98a94c204e67f65bc3ef72442388d8 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" @@ -45,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) @@ -106,10 +106,12 @@ 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(Eigen::MatrixXd::Identity(3,3) * 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, P0, t0, 1.0); + P->setPriorFactor(x0, s0, t0, 1.0); P->print(4,1,1,1); @@ -117,14 +119,14 @@ TEST(Problem, SetOrigin_PO_2d) 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(); FrameBasePtr F = P->getLastFrame(); CaptureBasePtr C = F->getCaptureList().front(); - FeatureBasePtr fp = C->getFeatureList().front(); - FeatureBasePtr fo = 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); @@ -145,12 +147,15 @@ TEST(Problem, SetOrigin_PO_2d) 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.head<2>(), fp->getMeasurement(), Constants::EPS_SMALL ); - ASSERT_MATRIX_APPROX(x0.tail<1>(), fo->getMeasurement(), Constants::EPS_SMALL ); - ASSERT_MATRIX_APPROX(P0.topLeftCorner(2,2), fp->getMeasurementCovariance(), Constants::EPS_SMALL ); - ASSERT_MATRIX_APPROX(P0.bottomRightCorner(1,1), fo->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); } @@ -159,23 +164,28 @@ 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; // not normalized quaternion, this is not what's tested - 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->setPriorFactor(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(); FrameBasePtr F = P->getLastFrame(); CaptureBasePtr C = F->getCaptureList().front(); - FeatureBasePtr fp = C->getFeatureList().front(); - FeatureBasePtr fo = C->getFeatureList().back(); + // 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); @@ -197,11 +207,14 @@ TEST(Problem, SetOrigin_PO_3d) 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.head<3>(), fp->getMeasurement(), Constants::EPS_SMALL ); - ASSERT_MATRIX_APPROX(x0.tail<4>(), fo->getMeasurement(), Constants::EPS_SMALL ); - ASSERT_MATRIX_APPROX(P0.topLeftCorner(3,3), fp->getMeasurementCovariance(), Constants::EPS_SMALL ); - ASSERT_MATRIX_APPROX(P0.bottomRightCorner(3,3), fo->getMeasurementCovariance(), 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); } @@ -210,9 +223,9 @@ TEST(Problem, emplaceFrame_factory) { ProblemPtr P = Problem::create("PO", 2); - FrameBasePtr f0 = P->emplaceKeyFrame("PO", 2, VectorXd(3), TimeStamp(0.0)); - FrameBasePtr f1 = P->emplaceKeyFrame("PO", 3, VectorXd(7), TimeStamp(1.0)); - FrameBasePtr f2 = P->emplaceKeyFrame("POV", 3, 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; @@ -251,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->emplaceKeyFrame("PO", 3, xs3d, 0); + auto KF = P->emplaceFrame(KEY, 0, "PO", 3, xs3d ); ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd)(2 + 2)); // Notifications @@ -310,7 +323,7 @@ TEST(Problem, Covariances) // 4 state blocks, estimated St->unfixExtrinsics(); - FrameBasePtr F = P->emplaceKeyFrame("PO", 3, 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->emplaceKeyFrame(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->emplaceKeyFrame(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 25da38b6b7452d810cb29c8dca795b8edcd27c18..a47822ae81f8df9f6682a91807aaaf9837e31a02 100644 --- a/test/gtest_processor_base.cpp +++ b/test/gtest_processor_base.cpp @@ -96,8 +96,10 @@ TEST(ProcessorBase, KeyFrameCallback) // initialize TimeStamp t(0.0); - Vector3d x(0,0,0); - Matrix3d P = Matrix3d::Identity() * 0.1; + // 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)); @@ -132,7 +134,7 @@ TEST(ProcessorBase, KeyFrameCallback) 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 ); } } diff --git a/test/gtest_processor_diff_drive.cpp b/test/gtest_processor_diff_drive.cpp index 7704ec8c4e720ae0060f22dfdccaed512383692e..ee908013b9eadd216363d528d7f60757ea331f29 100644 --- a/test/gtest_processor_diff_drive.cpp +++ b/test/gtest_processor_diff_drive.cpp @@ -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); } @@ -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,8 +309,10 @@ 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->setPriorFactor(x, P, t, 0.1); processor->setOrigin(F0); @@ -326,7 +329,7 @@ TEST_F(ProcessorDiffDriveTest, process) t += dt; C->setTimeStamp(t); C->process(); - WOLF_TRACE("t = ", t, "; x = ", processor->getCurrentState().transpose()); + WOLF_TRACE("t = ", t, "; x = ", processor->getState().vector("PO").transpose()); } problem->print(4,1,1,1); @@ -337,8 +340,10 @@ 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->setPriorFactor(x, P, t, 0.1); processor->setOrigin(F0); @@ -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,8 +368,10 @@ 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->setPriorFactor(x, P, t, 0.1); processor->setOrigin(F0); @@ -376,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; @@ -384,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 1e8246ee2de40852e7ce3a3df31fec55c32d8619..9ca6f9850a22cafef2fc58168c1351910b07ebe2 100644 --- a/test/gtest_processor_loopclosure.cpp +++ b/test/gtest_processor_loopclosure.cpp @@ -29,10 +29,10 @@ public: 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()) 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; }; @@ -77,14 +78,16 @@ TEST(ProcessorLoopClosure, installProcessor) // initialize TimeStamp t(0.0); - Vector3d x(0,0,0); - Matrix3d P = Matrix3d::Identity() * 0.1; + // 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->emplaceKeyFrame(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 fa989be48e578e94046d10702197db0447f24094..839c8d1ffb27e04a58340b4221b4571e383aa4ec 100644 --- a/test/gtest_processor_motion.cpp +++ b/test/gtest_processor_motion.cpp @@ -71,7 +71,7 @@ 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); + capture = std::make_shared<CaptureMotion>("CaptureOdom2d", 0.0, sensor, data, data_cov, nullptr); } virtual void TearDown(){} @@ -95,10 +95,10 @@ TEST_F(ProcessorMotion_test, IntegrateStraightAutoPrior) 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()<<9,0,0).finished(), 1e-8); + ASSERT_MATRIX_APPROX(problem->getState().vector("PO"), (Vector3d()<<9,0,0).finished(), 1e-8); } @@ -106,9 +106,11 @@ TEST_F(ProcessorMotion_test, IntegrateStraightFactorPrior) { // Prior TimeStamp t(0.0); - Vector3d x0; x0 << 0, 0, 0; - Matrix3d P0; P0.setIdentity(); - auto KF_0 = problem->setPriorFactor(x0, P0, t, 0.01); + // 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 @@ -121,18 +123,20 @@ TEST_F(ProcessorMotion_test, IntegrateStraightFactorPrior) 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()<<9,0,0).finished(), 1e-8); + 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(); + // 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); @@ -146,10 +150,10 @@ TEST_F(ProcessorMotion_test, IntegrateStraightFixPrior) 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()<<9,0,0).finished(), 1e-8); + ASSERT_MATRIX_APPROX(problem->getState().vector("PO"), (Vector3d()<<9,0,0).finished(), 1e-8); } TEST_F(ProcessorMotion_test, IntegrateCircleAutoPrior) @@ -169,19 +173,21 @@ TEST_F(ProcessorMotion_test, IntegrateCircleAutoPrior) 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, IntegrateCircleFactorPrior) { // Prior TimeStamp t(0.0); - Vector3d x0; x0 << 0, 0, 0; - Matrix3d P0; P0.setIdentity(); - auto KF_0 = problem->setPriorFactor(x0, P0, t, 0.01); + // 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 @@ -194,18 +200,20 @@ TEST_F(ProcessorMotion_test, IntegrateCircleFactorPrior) 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, IntegrateCircleFixPrior) { // Prior TimeStamp t(0.0); - Vector3d x0; x0 << 0, 0, 0; - Matrix3d P0; P0.setIdentity(); + // 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); @@ -219,10 +227,10 @@ TEST_F(ProcessorMotion_test, IntegrateCircleFixPrior) 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, splitBufferAutoPrior) @@ -242,7 +250,7 @@ TEST_F(ProcessorMotion_test, splitBufferAutoPrior) 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(); @@ -255,8 +263,6 @@ TEST_F(ProcessorMotion_test, splitBufferAutoPrior) t_target, sensor, data, - 3, - 3, nullptr); processor->splitBuffer(C_source, @@ -272,9 +278,11 @@ TEST_F(ProcessorMotion_test, splitBufferFactorPrior) { // Prior TimeStamp t(0.0); - Vector3d x0; x0 << 0, 0, 0; - Matrix3d P0; P0.setIdentity(); - auto KF_0 = problem->setPriorFactor(x0, P0, t, 0.01); + // 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 @@ -287,7 +295,7 @@ TEST_F(ProcessorMotion_test, splitBufferFactorPrior) 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(); @@ -300,8 +308,6 @@ TEST_F(ProcessorMotion_test, splitBufferFactorPrior) t_target, sensor, data, - 3, - 3, nullptr); processor->splitBuffer(C_source, @@ -317,8 +323,10 @@ TEST_F(ProcessorMotion_test, splitBufferFixPrior) { // Prior TimeStamp t(0.0); - Vector3d x0; x0 << 0, 0, 0; - Matrix3d P0; P0.setIdentity(); + // 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); @@ -332,7 +340,7 @@ TEST_F(ProcessorMotion_test, splitBufferFixPrior) 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(); @@ -345,8 +353,6 @@ TEST_F(ProcessorMotion_test, splitBufferFixPrior) t_target, sensor, data, - 3, - 3, nullptr); processor->splitBuffer(C_source, diff --git a/test/gtest_solver_manager.cpp b/test/gtest_solver_manager.cpp index 6210ff07938b29e0dbd30e8d8b2092c82e932366..382f08108aa7fcf503fddd53730382e11bae0b93 100644 --- a/test/gtest_solver_manager.cpp +++ b/test/gtest_solver_manager.cpp @@ -431,7 +431,7 @@ TEST(SolverManager, AddFactor) StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceKeyFrame(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()); auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); @@ -458,7 +458,7 @@ TEST(SolverManager, RemoveFactor) StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceKeyFrame(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()); auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); @@ -491,7 +491,7 @@ TEST(SolverManager, AddRemoveFactor) StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state); // Create (and add) factor point 2d - FrameBasePtr F = P->emplaceKeyFrame(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()); @@ -525,8 +525,8 @@ TEST(SolverManager, DoubleRemoveFactor) Vector2d state; state << 1, 2; StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state); - // Create (and add) factor pose 2d - FrameBasePtr F = P->emplaceKeyFrame(P->zeroState(), TimeStamp(0)); + // Create (and add) factor point 2d + 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()); @@ -572,7 +572,7 @@ TEST(SolverManager, MultiThreadingTruncatedNotifications) while (true) { // Emplace Frame, Capture, feature and factor pose 2d - FrameBasePtr F = P->emplaceKeyFrame(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, "FeaturePose2d", Vector3d::Zero(), Matrix3d::Identity()); auto c = FactorBase::emplace<FactorPose2d>(f, f, nullptr, false); 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 fed1010e8d193c15e4bf247e24a98464340081e4..689c167522f7884d27b3e9fdde5e88fb01ba7b27 100644 --- a/test/gtest_track_matrix.cpp +++ b/test/gtest_track_matrix.cpp @@ -37,11 +37,11 @@ class TrackMatrixTest : public testing::Test // unlinked frames // Some warnings will be thrown "linking with nullptr" for emplacing without providing frame pointer - F0 = FrameBase::createNonKeyFrame<FrameBase>(0.0, nullptr); - F1 = FrameBase::createNonKeyFrame<FrameBase>(1.0, nullptr); - F2 = FrameBase::createNonKeyFrame<FrameBase>(2.0, nullptr); - F3 = FrameBase::createNonKeyFrame<FrameBase>(3.0, nullptr); - F4 = FrameBase::createNonKeyFrame<FrameBase>(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 0fe2717c4ba795e215d7be8f36d8d6979c36f8d8..b8fc8608ccc1118bce118b28a7a9957ad688e16a 100644 --- a/test/gtest_trajectory.cpp +++ b/test/gtest_trajectory.cpp @@ -32,11 +32,10 @@ TEST(TrajectoryBase, ClosestKeyFrame) // 1 2 3 4 time stamps // --+-----+-----+-----+---> time - FrameBasePtr F1 = P->emplaceKeyFrame(Eigen::Vector3d::Zero(), 1); - FrameBasePtr F2 = P->emplaceKeyFrame(Eigen::Vector3d::Zero(), 2); - //WARNING! MIGHT NEED TO ROLLBACK THIS TO AUXILIARY, FELLA - FrameBasePtr F3 = FrameBase::createNonKeyFrame<FrameBase>(P->getFrameStructure(), P->getDim(), 3, Eigen::Vector3d::Zero()); - FrameBasePtr F4 = FrameBase::createNonKeyFrame<FrameBase>(P->getFrameStructure(), P->getDim(), 4, Eigen::Vector3d::Zero()); + 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 @@ -76,24 +75,21 @@ TEST(TrajectoryBase, Add_Remove_Frame) std::cout << __LINE__ << std::endl; // add F1 - FrameBasePtr F1 = P->emplaceKeyFrame(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->emplaceKeyFrame(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 = FrameBase::createNonKeyFrame<FrameBase>(P->getFrameStructure(), - P->getDim(), - 3, - Eigen::Vector3d::Zero()); // 1 fixed, 1 not + FrameBasePtr F3 = P->emplaceFrame(NON_ESTIMATED, 3, Eigen::Vector3d::Zero()); if (debug) P->print(2,0,0,0); ASSERT_EQ(T->getFrameList(). size(), (SizeStd) 2); ASSERT_EQ(P->getStateBlockNotificationMapSize(), (SizeStd) 4); diff --git a/test/gtest_tree_manager.cpp b/test/gtest_tree_manager.cpp index 08cd9f8cfb240fe58bf94a8c52fb19aad365635f..507d2104e14bf43f57d563dc4873481322f57090 100644 --- a/test/gtest_tree_manager.cpp +++ b/test/gtest_tree_manager.cpp @@ -94,7 +94,7 @@ TEST(TreeManager, keyFrameCallback) ASSERT_EQ(GM->n_KF_, 0); - auto F0 = P->emplaceKeyFrame("PO", 3, VectorXd(7), TimeStamp(0.0)); + auto F0 = P->emplaceFrame(KEY, 0, "PO", 3, VectorXd(7) ); P->keyFrameCallback(F0, nullptr, 0); ASSERT_EQ(GM->n_KF_, 1); diff --git a/test/gtest_tree_manager_sliding_window.cpp b/test/gtest_tree_manager_sliding_window.cpp index f171dbcff79a31e07f71b1045f44ec71f9e62a8f..8909987f091831fddc686c585e827035ce629ebd 100644 --- a/test/gtest_tree_manager_sliding_window.cpp +++ b/test/gtest_tree_manager_sliding_window.cpp @@ -82,12 +82,12 @@ TEST(TreeManagerSlidingWindow, slidingWindowFixViral) auto F1 = P->getTrajectory()->getLastKeyFrame(); ASSERT_TRUE(F1 != nullptr); - Vector7d state = F1->getState(); + Vector7d state = F1->getStateVector(); Vector7d zero_disp(state); Matrix6d cov = Matrix6d::Identity(); // FRAME 2 ---------------------------------------------------------- - auto F2 = P->emplaceKeyFrame("PO", 3, state, TimeStamp(2)); + auto F2 = P->emplaceFrame(KEY, TimeStamp(2), "PO", 3, state); P->keyFrameCallback(F2, nullptr, 0); // absolute factor @@ -103,7 +103,7 @@ TEST(TreeManagerSlidingWindow, slidingWindowFixViral) ASSERT_FALSE(F1->isRemoving()); // FRAME 3 ---------------------------------------------------------- - auto F3 = P->emplaceKeyFrame("PO", 3, state, TimeStamp(3)); + auto F3 = P->emplaceFrame(KEY, TimeStamp(3), "PO", 3, state); P->keyFrameCallback(F3, nullptr, 0); // absolute factor @@ -119,7 +119,7 @@ TEST(TreeManagerSlidingWindow, slidingWindowFixViral) ASSERT_FALSE(F1->isRemoving()); // FRAME 4 ---------------------------------------------------------- - auto F4 = P->emplaceKeyFrame("PO", 3, state, TimeStamp(4)); + auto F4 = P->emplaceFrame(KEY, TimeStamp(4), "PO", 3, state); P->keyFrameCallback(F4, nullptr, 0); // absolute factor @@ -139,7 +139,7 @@ TEST(TreeManagerSlidingWindow, slidingWindowFixViral) ASSERT_TRUE(F2->isFixed()); //Fixed // FRAME 5 ---------------------------------------------------------- - auto F5 = P->emplaceKeyFrame("PO", 3, state, TimeStamp(5)); + auto F5 = P->emplaceFrame(KEY, TimeStamp(5), "PO", 3, state); P->keyFrameCallback(F5, nullptr, 0); // absolute factor @@ -178,12 +178,12 @@ TEST(TreeManagerSlidingWindow, slidingWindowNoFixNoViral) auto F1 = P->getTrajectory()->getLastKeyFrame(); ASSERT_TRUE(F1 != nullptr); - Vector7d state = F1->getState(); + Vector7d state = F1->getStateVector(); Vector7d zero_disp(state); Matrix6d cov = Matrix6d::Identity(); // FRAME 2 ---------------------------------------------------------- - auto F2 = P->emplaceKeyFrame("PO", 3, state, TimeStamp(2)); + auto F2 = P->emplaceFrame(KEY, TimeStamp(2), "PO", 3, state); P->keyFrameCallback(F2, nullptr, 0); // absolute factor @@ -199,7 +199,7 @@ TEST(TreeManagerSlidingWindow, slidingWindowNoFixNoViral) ASSERT_FALSE(F1->isRemoving()); // FRAME 3 ---------------------------------------------------------- - auto F3 = P->emplaceKeyFrame("PO", 3, state, TimeStamp(3)); + auto F3 = P->emplaceFrame(KEY, TimeStamp(3), "PO", 3, state); P->keyFrameCallback(F3, nullptr, 0); // absolute factor @@ -215,7 +215,7 @@ TEST(TreeManagerSlidingWindow, slidingWindowNoFixNoViral) ASSERT_FALSE(F1->isRemoving()); // FRAME 4 ---------------------------------------------------------- - auto F4 = P->emplaceKeyFrame("PO", 3, state, TimeStamp(4)); + auto F4 = P->emplaceFrame(KEY, TimeStamp(4), "PO", 3, state); P->keyFrameCallback(F4, nullptr, 0); // absolute factor @@ -235,7 +235,7 @@ TEST(TreeManagerSlidingWindow, slidingWindowNoFixNoViral) ASSERT_FALSE(F2->isFixed()); //Not fixed // FRAME 5 ---------------------------------------------------------- - auto F5 = P->emplaceKeyFrame("PO", 3, state, TimeStamp(5)); + auto F5 = P->emplaceFrame(KEY, TimeStamp(5), "PO", 3, state); P->keyFrameCallback(F5, nullptr, 0); // absolute factor diff --git a/test/yaml/params_tree_manager1.yaml b/test/yaml/params_tree_manager1.yaml index 085015b89c62f913f7bbf6ab3d6241ddde132dff..d8f443220bf71786c1e95ca77ae9e68705d1d576 100644 --- a/test/yaml/params_tree_manager1.yaml +++ b/test/yaml/params_tree_manager1.yaml @@ -4,8 +4,16 @@ config: 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: [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" @@ -38,4 +46,4 @@ config: dist_traveled: 0.5 # meters angle_turned: 0.1 # radians (1 rad approx 57 deg, approx 60 deg) - unmeasured_perturbation_std: 0.00111 \ No newline at end of file + unmeasured_perturbation_std: 0.00111 diff --git a/test/yaml/params_tree_manager2.yaml b/test/yaml/params_tree_manager2.yaml index 80b5af47ac509b0746ffb8f66775d87742e1e927..b61f9936d4ccb8fc705d2ca92717f2a2ad67c402 100644 --- a/test/yaml/params_tree_manager2.yaml +++ b/test/yaml/params_tree_manager2.yaml @@ -4,8 +4,16 @@ config: 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: [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" @@ -37,4 +45,4 @@ config: dist_traveled: 0.5 # meters angle_turned: 0.1 # radians (1 rad approx 57 deg, approx 60 deg) - unmeasured_perturbation_std: 0.00111 \ No newline at end of file + 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 index 3a0f421c5c0048125d0a8afa742e873f79e703f6..96ad94f72af7e8de1b9200a8e5ea44e3bc952a85 100644 --- a/test/yaml/params_tree_manager_sliding_window1.yaml +++ b/test/yaml/params_tree_manager_sliding_window1.yaml @@ -4,8 +4,14 @@ config: 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: [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" @@ -40,4 +46,4 @@ config: dist_traveled: 0.5 # meters angle_turned: 0.1 # radians (1 rad approx 57 deg, approx 60 deg) - unmeasured_perturbation_std: 0.00111 \ No newline at end of file + 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 index 894dadf651dfe18919881ca44a296f3df447246a..9ae33a2af5ab0695bd44948d33d2f9aa104cbc74 100644 --- a/test/yaml/params_tree_manager_sliding_window2.yaml +++ b/test/yaml/params_tree_manager_sliding_window2.yaml @@ -4,8 +4,14 @@ config: 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: [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" @@ -40,4 +46,4 @@ config: dist_traveled: 0.5 # meters angle_turned: 0.1 # radians (1 rad approx 57 deg, approx 60 deg) - unmeasured_perturbation_std: 0.00111 \ No newline at end of file + unmeasured_perturbation_std: 0.00111