diff --git a/src/capture_motion.cpp b/src/capture_motion.cpp index 93203d74dffb7ade049df63a2874d3882082e320..a4d74cbfbb67a5f60e9ec5debbcbbf72a6cc83ff 100644 --- a/src/capture_motion.cpp +++ b/src/capture_motion.cpp @@ -41,7 +41,7 @@ CaptureMotion::CaptureMotion(const TimeStamp& _ts, buffer_(_data.size(), _delta_size, _delta_cov_size, computeCalibSize()), origin_frame_ptr_(_origin_frame_ptr) { - // TODO put something in the buffer to start! + // } diff --git a/src/examples/test_2_lasers_offline.cpp b/src/examples/test_2_lasers_offline.cpp index d0b262886d00266461bafb2d34b6a0d6e443fd16..b72c7f4c741e3b650e78fbd761ab983e8ce231ac 100644 --- a/src/examples/test_2_lasers_offline.cpp +++ b/src/examples/test_2_lasers_offline.cpp @@ -169,7 +169,7 @@ int main(int argc, char** argv) odom_trajectory.head(3) = ground_truth_pose; // Origin Key Frame with covariance - problem.setPrior(ground_truth_pose, Eigen::Matrix3s::Identity() * 0.1, ts); + problem.setPrior(ground_truth_pose, Eigen::Matrix3s::Identity() * 0.1, ts, 0.1); // Ceres wrapper ceres::Solver::Options ceres_options; diff --git a/src/feature_base.cpp b/src/feature_base.cpp index 6cf91674418086f3d1d884c7f831bb4fa996e500..34f625fa16e5efc5f7a4feb1b64dd03e4a79b690 100644 --- a/src/feature_base.cpp +++ b/src/feature_base.cpp @@ -58,7 +58,7 @@ ConstraintBasePtr FeatureBase::addConstraint(ConstraintBasePtr _co_ptr) if (getProblem() != nullptr) getProblem()->addConstraintPtr(_co_ptr); else - std::cout << "WARNING: ADDING CONSTRAINT TO A FEATURE NOT CONNECTED WITH PROBLEM." << std::endl; + WOLF_TRACE("WARNING: ADDING CONSTRAINT ", _co_ptr->id(), " TO FEATURE ", this->id(), " NOT CONNECTED WITH PROBLEM."); return _co_ptr; } diff --git a/src/frame_base.cpp b/src/frame_base.cpp index 326cc899c810a962689807bac2dc59cc3c0fe1bf..3318d01708db96e5bbd836cb92ecfb2437dda804 100644 --- a/src/frame_base.cpp +++ b/src/frame_base.cpp @@ -23,11 +23,15 @@ FrameBase::FrameBase(const TimeStamp& _ts, StateBlockPtr _p_ptr, StateBlockPtr _ state_block_vec_[0] = _p_ptr; state_block_vec_[1] = _o_ptr; state_block_vec_[2] = _v_ptr; - // -// if (isKey()) -// std::cout << "constructed +KF" << id() << std::endl; + +// if ( isKey() ) +// { +// WOLF_DEBUG("New KF", this->id() ); +// } // else -// std::cout << "constructed +F" << id() << std::endl; +// { +// WOLF_DEBUG("New F", this->id() ); +// } } FrameBase::FrameBase(const FrameType & _tp, const TimeStamp& _ts, StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, StateBlockPtr _v_ptr) : @@ -43,10 +47,14 @@ FrameBase::FrameBase(const FrameType & _tp, const TimeStamp& _ts, StateBlockPtr state_block_vec_[1] = _o_ptr; state_block_vec_[2] = _v_ptr; -// if (isKey()) -// std::cout << "constructed +KF" << id() << std::endl; +// if ( isKey() ) +// { +// WOLF_DEBUG("New KF", this->id() ); +// } // else -// std::cout << "constructed +F" << id() << std::endl; +// { +// WOLF_DEBUG("New F", this->id() ); +// } } FrameBase::~FrameBase() @@ -124,6 +132,8 @@ void FrameBase::setKey() getTrajectoryPtr()->setLastKeyFramePtr(shared_from_this()); getTrajectoryPtr()->sortFrame(shared_from_this()); + + WOLF_DEBUG("Set KF", this->id()); } } diff --git a/src/hello_wolf/hello_wolf.cpp b/src/hello_wolf/hello_wolf.cpp index f424fedc230a8c9186eb12ad0390ed49517010d2..27eb81987b9918e570c7a94420581f18b87b1651 100644 --- a/src/hello_wolf/hello_wolf.cpp +++ b/src/hello_wolf/hello_wolf.cpp @@ -167,7 +167,7 @@ int main() TimeStamp t(0.0); Vector3s x(0,0,0); Matrix3s P = Matrix3s::Identity() * 0.1; - problem->setPrior(x, P, t); // KF1 + problem->setPrior(x, P, t, 0.5); // KF1 // observe lmks ids.resize(1); ranges.resize(1); bearings.resize(1); diff --git a/src/hello_wolf/processor_range_bearing.cpp b/src/hello_wolf/processor_range_bearing.cpp index 0974d8b0d99d4e6d883ab238427f42dfc2fad390..3991741d59036ae0fb476e0edbca531866ff5d78 100644 --- a/src/hello_wolf/processor_range_bearing.cpp +++ b/src/hello_wolf/processor_range_bearing.cpp @@ -22,6 +22,18 @@ ProcessorRangeBearing::ProcessorRangeBearing(const SensorRangeBearingPtr _sensor void ProcessorRangeBearing::process(CaptureBasePtr _capture) { + + if ( !kf_pack_buffer_.empty() ) + { + // Select using incoming_ptr + KFPackPtr pack = kf_pack_buffer_.selectPack( _capture->getTimeStamp(), time_tolerance_ ); + + if (pack!=nullptr) + keyFrameCallback(pack->key_frame,pack->time_tolerance); + + kf_pack_buffer_.removeUpTo( _capture->getTimeStamp() ); + } + CaptureRangeBearingPtr capture = std::static_pointer_cast<CaptureRangeBearing>(_capture); // 1. get KF -- we assume a KF is available to hold this _capture (checked in assert below) diff --git a/src/hello_wolf/processor_range_bearing.h b/src/hello_wolf/processor_range_bearing.h index 804cdd402d2c2312029667b55154d22be958c4f7..d21f59052da4ff6c10f05feec483f8c34e8c8ce6 100644 --- a/src/hello_wolf/processor_range_bearing.h +++ b/src/hello_wolf/processor_range_bearing.h @@ -45,7 +45,7 @@ class ProcessorRangeBearing : public ProcessorBase // Implementation of pure virtuals from ProcessorBase virtual void process (CaptureBasePtr _capture) override; virtual bool voteForKeyFrame () override {return false;} - virtual bool keyFrameCallback (FrameBasePtr _key_frame, const Scalar& _time_tolerance) override; + virtual bool keyFrameCallback (FrameBasePtr _key_frame, const Scalar& _time_tolerance) ; // landmark observation models -- they would be better off in a separate library e.g. range_bearing_tools.h Eigen::Vector2s observe (const Eigen::Vector2s& lmk_w) const; diff --git a/src/motion_buffer.cpp b/src/motion_buffer.cpp index a6c9ad4f1b4360a514e21736ca784fdf4d7e91bd..5356ea9f804a6d85442a2522c299e55c90eae8b8 100644 --- a/src/motion_buffer.cpp +++ b/src/motion_buffer.cpp @@ -73,6 +73,7 @@ MotionBuffer::MotionBuffer(Size _data_size, calib_size_(_calib_size), calib_preint_(_calib_size) { + container_.clear(); } const Motion& MotionBuffer::getMotion(const TimeStamp& _ts) const diff --git a/src/problem.cpp b/src/problem.cpp index e801e145080c655d08a7db25feb8c2649881b9d3..63775a5ad6fedd519e993604ea745679c37a3f2d 100644 --- a/src/problem.cpp +++ b/src/problem.cpp @@ -31,7 +31,7 @@ Problem::Problem(const std::string& _frame_structure) : trajectory_ptr_(std::make_shared<TrajectoryBase>(_frame_structure)), map_ptr_(std::make_shared<MapBase>()), processor_motion_ptr_(), - origin_is_set_(false), + prior_is_set_(false), state_size_(0), state_cov_size_(0) { @@ -121,7 +121,7 @@ ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, // _corresponding_sensor_ptr->addProcessor(prc_ptr); // setting the origin in all processor motion if origin already setted - if (prc_ptr->isMotion() && origin_is_set_) + if (prc_ptr->isMotion() && prior_is_set_) (std::static_pointer_cast<ProcessorMotion>(prc_ptr))->setOrigin(getLastKeyFramePtr()); // setting the main processor motion @@ -330,7 +330,8 @@ bool Problem::permitKeyFrame(ProcessorBasePtr _processor_ptr) void Problem::keyFrameCallback(FrameBasePtr _keyframe_ptr, ProcessorBasePtr _processor_ptr, const Scalar& _time_tolerance) { - //std::cout << "Problem::keyFrameCallback: processor " << _processor_ptr->getName() << std::endl; + WOLF_DEBUG((_processor_ptr->isMotion() ? "PM " : "PT "), _processor_ptr->getName(), ": KF", _keyframe_ptr->id(), " Callback emitted with ts = ", _keyframe_ptr->getTimeStamp()); + for (auto sensor : hardware_ptr_->getSensorList()) for (auto processor : sensor->getProcessorList()) if (processor && (processor != _processor_ptr) ) @@ -628,12 +629,12 @@ StateBlockList& Problem::getStateBlockList() -FrameBasePtr Problem::setPrior(const Eigen::VectorXs& _prior_state, const Eigen::MatrixXs& _prior_cov, const TimeStamp& _ts) +FrameBasePtr Problem::setPrior(const Eigen::VectorXs& _prior_state, const Eigen::MatrixXs& _prior_cov, const TimeStamp& _ts, const Scalar _time_tolerance) { - if (!origin_is_set_) + if ( ! prior_is_set_ ) { // Create origin frame - FrameBasePtr origin_frame_ptr = emplaceFrame(KEY_FRAME, _prior_state, _ts); + FrameBasePtr origin_keyframe = emplaceFrame(KEY_FRAME, _prior_state, _ts); // create origin capture with the given state as data // Capture fix only takes 3D position and Quaternion orientation @@ -643,20 +644,27 @@ FrameBasePtr Problem::setPrior(const Eigen::VectorXs& _prior_state, const Eigen: else init_capture = std::make_shared<CapturePose>(_ts, nullptr, _prior_state, _prior_cov); - origin_frame_ptr->addCapture(init_capture); + origin_keyframe->addCapture(init_capture); // emplace feature and constraint init_capture->emplaceFeatureAndConstraint(); - // notify all motion processors about the origin keyframe - for (auto sensor_ptr : hardware_ptr_->getSensorList()) - for (auto processor_ptr : sensor_ptr->getProcessorList()) - if (processor_ptr->isMotion()) - (std::static_pointer_cast<ProcessorMotion>(processor_ptr))->setOrigin(origin_frame_ptr); + // Notify all processors about the prior KF + for (auto sensor : hardware_ptr_->getSensorList()) + for (auto processor : sensor->getProcessorList()) + if (processor->isMotion()) + // Motion processors will set its origin at the KF + (std::static_pointer_cast<ProcessorMotion>(processor))->setOrigin(origin_keyframe); + + prior_is_set_ = true; - origin_is_set_ = true; + // Notify all other processors about the origin KF --> they will join it or not depending on their received data + for (auto sensor : hardware_ptr_->getSensorList()) + for (auto processor : sensor->getProcessorList()) + if ( !processor->isMotion() ) + processor->keyFrameCallback(origin_keyframe, _time_tolerance); - return origin_frame_ptr; + return origin_keyframe; } else throw std::runtime_error("Origin already set!"); @@ -696,7 +704,7 @@ void Problem::print(int depth, bool constr_by, bool metric, bool state_blocks) { if (i==0) cout << " Extr " << (S->isExtrinsicDynamic() ? "[Dyn]" : "[Sta]") << " = ["; if (i==2) cout << " Intr " << (S->isIntrinsicDynamic() ? "[Dyn]" : "[Sta]") << " = ["; - auto sb = S->getStateBlockPtrAuto(i); + auto sb = S->getStateBlockPtrDynamic(i); if (sb) { cout << (sb->isFixed() ? " Fix( " : " Est( ") << sb->getState().transpose() << " )"; @@ -735,10 +743,10 @@ void Problem::print(int depth, bool constr_by, bool metric, bool state_blocks) std::cout << " pm" << p->id() << " " << p->getType() << endl; ProcessorMotionPtr pm = std::static_pointer_cast<ProcessorMotion>(p); if (pm->getOriginPtr()) - cout << " o: C" << pm->getOriginPtr()->id() << " - F" + cout << " o: C" << pm->getOriginPtr()->id() << " - " << (pm->getOriginPtr()->getFramePtr()->isKey() ? " KF" : " F") << pm->getOriginPtr()->getFramePtr()->id() << endl; if (pm->getLastPtr()) - cout << " l: C" << pm->getLastPtr()->id() << " - F" + cout << " l: C" << pm->getLastPtr()->id() << " - " << (pm->getLastPtr()->getFramePtr()->isKey() ? " KF" : " F") << pm->getLastPtr()->getFramePtr()->id() << endl; if (pm->getIncomingPtr()) cout << " i: C" << pm->getIncomingPtr()->id() << endl; @@ -750,10 +758,10 @@ void Problem::print(int depth, bool constr_by, bool metric, bool state_blocks) if (pt) { if (pt->getOriginPtr()) - cout << " o: C" << pt->getOriginPtr()->id() << " - F" + cout << " o: C" << pt->getOriginPtr()->id() << " - " << (pt->getOriginPtr()->getFramePtr()->isKey() ? " KF" : " F") << pt->getOriginPtr()->getFramePtr()->id() << endl; if (pt->getLastPtr()) - cout << " l: C" << pt->getLastPtr()->id() << " - F" + cout << " l: C" << pt->getLastPtr()->id() << " - " << (pt->getLastPtr()->getFramePtr()->isKey() ? " KF" : " F") << pt->getLastPtr()->getFramePtr()->id() << endl; if (pt->getIncomingPtr()) cout << " i: C" << pt->getIncomingPtr()->id() << endl; @@ -833,9 +841,9 @@ void Problem::print(int depth, bool constr_by, bool metric, bool state_blocks) try { CaptureMotionPtr CM = std::static_pointer_cast<CaptureMotion>(C); + cout << " buffer size : " << CM->getBuffer().get().size() << endl; if ( CM->getCalibSize() > 0 && ! CM->getBuffer().get().empty()) { - cout << " buffer size : " << CM->getBuffer().get().size() << endl; cout << " delta preint : (" << CM->getDeltaPreint().transpose() << ")" << endl; cout << " calib preint : (" << CM->getCalibrationPreint().transpose() << ")" << endl; cout << " jacob preint : (" << CM->getJacobianCalib().row(0) << ")" << endl; @@ -853,7 +861,7 @@ void Problem::print(int depth, bool constr_by, bool metric, bool state_blocks) // Features for (auto f : C->getFeatureList()) { - cout << " f" << f->id() << " " << f->getType() << ((depth < 4) ? " -- " + std::to_string(f->getConstraintList().size()) + "c " : ""); + cout << " f" << f->id() << " trk" << f->trackId() << " " << f->getType() << ((depth < 4) ? " -- " + std::to_string(f->getConstraintList().size()) + "c " : ""); if (constr_by) { cout << " <--\t"; diff --git a/src/problem.h b/src/problem.h index af39c70369a732e7ab624d00b3113859f2450565..adaa9c823bd21f59a710dbf613b081f0c6fbf7c8 100644 --- a/src/problem.h +++ b/src/problem.h @@ -54,7 +54,7 @@ class Problem : public std::enable_shared_from_this<Problem> std::map<std::pair<StateBlockPtr, StateBlockPtr>, Eigen::MatrixXs> covariances_; std::list<StateBlockNotification> state_block_notification_list_; std::list<ConstraintNotification> constraint_notification_list_; - bool origin_is_set_; + bool prior_is_set_; Size state_size_, state_cov_size_; private: // CAUTION: THESE METHODS ARE PRIVATE, DO NOT MAKE THEM PUBLIC !! @@ -143,7 +143,8 @@ class Problem : public std::enable_shared_from_this<Problem> TrajectoryBasePtr getTrajectoryPtr(); virtual FrameBasePtr setPrior(const Eigen::VectorXs& _prior_state, // const Eigen::MatrixXs& _prior_cov, // - const TimeStamp& _ts); + const TimeStamp& _ts, + const Scalar _time_tolerance); /** \brief Emplace frame from string frame_structure * \param _frame_structure String indicating the frame structure. @@ -311,6 +312,10 @@ class Problem : public std::enable_shared_from_this<Problem> bool state_blocks = false); bool check(int verbose_level = 0); + bool priorIsSet() const + { + return prior_is_set_; + } }; } // namespace wolf diff --git a/src/processor_base.cpp b/src/processor_base.cpp index b14237b0366db2f567c8582f6969db8a20cbf933..785cccc5e14383d41774d6ea322b0dd131d681a6 100644 --- a/src/processor_base.cpp +++ b/src/processor_base.cpp @@ -9,10 +9,10 @@ unsigned int ProcessorBase::processor_id_count_ = 0; ProcessorBase::ProcessorBase(const std::string& _type, const Scalar& _time_tolerance) : NodeBase("PROCESSOR", _type), - sensor_ptr_(), - is_removing_(false), processor_id_(++processor_id_count_), - time_tolerance_(_time_tolerance) + time_tolerance_(_time_tolerance), + sensor_ptr_(), + is_removing_(false) { // WOLF_DEBUG("constructed +p" , id()); } @@ -45,6 +45,13 @@ FrameBasePtr ProcessorBase::emplaceFrame(FrameType _type, CaptureBasePtr _captur return new_frame_ptr; } +void ProcessorBase::keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tol_other) +{ + if (_keyframe_ptr != nullptr) + kf_pack_buffer_.add(_keyframe_ptr,_time_tol_other); + +} + void ProcessorBase::remove() { if (!is_removing_) @@ -67,4 +74,113 @@ void ProcessorBase::remove() } } + + +///////////////////////////////////////////////////////////////////////////////////////// + +void KFPackBuffer::removeUpTo(const TimeStamp& _time_stamp) +{ + KFPackBuffer::Iterator post = container_.upper_bound(_time_stamp); + container_.erase(container_.begin(), post); // erasing by range +} + +void KFPackBuffer::add(const FrameBasePtr& _key_frame, const Scalar& _time_tolerance) +{ + TimeStamp time_stamp = _key_frame->getTimeStamp(); + KFPackPtr kfpack = std::make_shared<KFPack>(_key_frame, _time_tolerance); + container_.emplace(time_stamp, kfpack); +} + +KFPackPtr KFPackBuffer::selectPack(const TimeStamp& _time_stamp, const Scalar& _time_tolerance) +{ + if (container_.empty()) + return nullptr; + + KFPackBuffer::Iterator post = container_.upper_bound(_time_stamp); + + bool prev_exists = (post != container_.begin()); + bool post_exists = (post != container_.end()); + + bool post_ok = post_exists && checkTimeTolerance(post->first, post->second->time_tolerance, _time_stamp, _time_tolerance); + + if (prev_exists) + { + KFPackBuffer::Iterator prev = std::prev(post); + + bool prev_ok = checkTimeTolerance(prev->first, prev->second->time_tolerance, _time_stamp, _time_tolerance); + + if (prev_ok && !post_ok) + return prev->second; + + else if (!prev_ok && post_ok) + return post->second; + + else if (prev_ok && post_ok) + { + if (std::fabs(post->first - _time_stamp) < std::fabs(prev->first - _time_stamp)) + return post->second; + else + return prev->second; + } + } + else if (post_ok) + return post->second; + + return nullptr; +} +KFPackPtr KFPackBuffer::selectPack(const CaptureBasePtr _capture, const Scalar& _time_tolerance) +{ + return selectPack(_capture->getTimeStamp(), _time_tolerance); +} + +KFPackPtr KFPackBuffer::selectPackBefore(const TimeStamp& _time_stamp, const Scalar& _time_tolerance) +{ + if (container_.empty()) + return nullptr; + + KFPackBuffer::Iterator post = container_.upper_bound(_time_stamp); + + bool prev_exists = (post != container_.begin()); + + if (prev_exists) + return container_.begin()->second; + + else + { + bool post_exists = (post != container_.end()); + bool post_ok = post_exists && checkTimeTolerance(post->first, post->second->time_tolerance, _time_stamp, _time_tolerance); + + if (post_ok) + return post->second; + } + + return nullptr; +} + +KFPackPtr KFPackBuffer::selectPackBefore(const CaptureBasePtr _capture, const Scalar& _time_tolerance) +{ + return selectPackBefore(_capture->getTimeStamp(), _time_tolerance); +} + +void KFPackBuffer::print(void) +{ + std::cout << "[ "; + for (auto iter : container_) + { + std::cout << "( tstamp: " << iter.first << ", id: " << iter.second->key_frame->id() << ") "; + } + std::cout << "]" << std::endl; +} + +bool KFPackBuffer::checkTimeTolerance(const TimeStamp& _time_stamp1, const Scalar& _time_tolerance1, + const TimeStamp& _time_stamp2, const Scalar& _time_tolerance2) +{ + Scalar time_diff = std::fabs(_time_stamp1 - _time_stamp2); + Scalar time_tol = std::min(_time_tolerance1, _time_tolerance2); + bool pass = time_diff <= time_tol; + return pass; +} + + + } // namespace wolf diff --git a/src/processor_base.h b/src/processor_base.h index e04aba1e24309e17e3bacd23beead112ac50c9a1..ce506925f2bb06118633912d70dfbfd44f5c9237 100644 --- a/src/processor_base.h +++ b/src/processor_base.h @@ -6,16 +6,99 @@ namespace wolf{ class SensorBase; } -//Wolf includes +// Wolf includes #include "wolf.h" #include "node_base.h" +#include "time_stamp.h" // std #include <memory> +#include <map> namespace wolf { +/** \brief Key frame class pack + * + * To store a key_frame with an associated time tolerance. + */ +class KFPack +{ + public: + KFPack(const FrameBasePtr _key_frame, const Scalar _time_tolerance) : key_frame(_key_frame), time_tolerance(_time_tolerance) {}; + ~KFPack(){}; + FrameBasePtr key_frame; + Scalar time_tolerance; +}; + +WOLF_PTR_TYPEDEFS(KFPack); + + + +/** \brief Buffer of Key frame class objects + * + * Object and functions to manage a buffer of KFPack objects. + */ +class KFPackBuffer +{ + public: + + typedef std::map<TimeStamp,KFPackPtr>::iterator Iterator; // buffer iterator + + KFPackBuffer(void); + ~KFPackBuffer(void); + + /**\brief Select a Pack from the buffer + * + * Select from the buffer the closest pack (w.r.t. time stamp), + * respecting a defined time tolerances + */ + KFPackPtr selectPack(const TimeStamp& _time_stamp, const Scalar& _time_tolerance); + KFPackPtr selectPack(const CaptureBasePtr _capture, const Scalar& _time_tolerance); + + KFPackPtr selectPackBefore(const TimeStamp& _time_stamp, const Scalar& _time_tolerance); + KFPackPtr selectPackBefore(const CaptureBasePtr _capture, const Scalar& _time_tolerance); + + /**\brief Buffer size + * + */ + size_t size(void); + + /**\brief Add a pack to the buffer + * + */ + void add(const FrameBasePtr& _key_frame, const Scalar& _time_tolerance); + + /**\brief Remove all packs in the buffer with a time stamp older than the specified + * + */ + void removeUpTo(const TimeStamp& _time_stamp); + + /**\brief Check time tolerance + * + * Check if the time distance between two time stamps is smaller than + * the minimum time tolerance of the two frames. + */ + bool checkTimeTolerance(const TimeStamp& _time_stamp1, const Scalar& _time_tolerance1, const TimeStamp& _time_stamp2, const Scalar& _time_tolerance2); + + /**\brief Clear the buffer + * + */ + void clear(); + /**\brief Empty the buffer + * + */ + bool empty(); + + /**\brief Print buffer information + * + */ + void print(); + + private: + + std::map<TimeStamp,KFPackPtr> container_; // Main buffer container +}; /** \brief base struct for processor parameters * @@ -34,6 +117,11 @@ struct ProcessorParamsBase //class ProcessorBase class ProcessorBase : public NodeBase, public std::enable_shared_from_this<ProcessorBase> { + protected: + unsigned int processor_id_; + Scalar time_tolerance_; ///< self time tolerance for adding a capture into a frame + KFPackBuffer kf_pack_buffer_; + private: SensorBaseWPtr sensor_ptr_; @@ -78,7 +166,9 @@ class ProcessorBase : public NodeBase, public std::enable_shared_from_this<Proce */ FrameBasePtr emplaceFrame(FrameType _type, CaptureBasePtr _capture_ptr, const Eigen::VectorXs& _state); - virtual bool keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tolerance) = 0; +// virtual bool keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tolerance) = 0; + + void keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tol_other); SensorBasePtr getSensorPtr(); const SensorBasePtr getSensorPtr() const; @@ -88,9 +178,6 @@ class ProcessorBase : public NodeBase, public std::enable_shared_from_this<Proce void setTimeTolerance(Scalar _time_tolerance); - protected: - unsigned int processor_id_; - Scalar time_tolerance_; ///< self time tolerance for adding a capture into a frame }; } @@ -125,6 +212,31 @@ inline void ProcessorBase::setTimeTolerance(Scalar _time_tolerance) time_tolerance_ = _time_tolerance; } +inline KFPackBuffer::KFPackBuffer(void) +{ + +} + +inline KFPackBuffer::~KFPackBuffer(void) +{ + +} + +inline void KFPackBuffer::clear() +{ + container_.clear(); +} + +inline bool KFPackBuffer::empty() +{ + return container_.empty(); +} + +inline size_t KFPackBuffer::size(void) +{ + return container_.size(); +} + } // namespace wolf #endif diff --git a/src/processor_capture_holder.h b/src/processor_capture_holder.h index dd3b6bd71c146be7d8652fce423751e4658ae973..def28671964c642e1411f57c6ed4b2b857b09ddb 100644 --- a/src/processor_capture_holder.h +++ b/src/processor_capture_holder.h @@ -48,7 +48,7 @@ public: virtual bool voteForKeyFrame() override { return false; } virtual bool keyFrameCallback(FrameBasePtr _keyframe_ptr, - const Scalar& _time_tolerance) override; + const Scalar& _time_tolerance) ; /** * \brief Finds the capture that contains the closest previous motion of _ts diff --git a/src/processor_image_feature.cpp b/src/processor_image_feature.cpp index 0fe5993ca0076ad5cb750ee4f2fa6865e3c63d6a..c728686d73a4d9ce85ef5c61cf6dfd381522a1b6 100644 --- a/src/processor_image_feature.cpp +++ b/src/processor_image_feature.cpp @@ -214,8 +214,6 @@ unsigned int ProcessorImageFeature::trackFeatures(const FeatureBaseList& _featur incoming_point_ptr->setIsKnown(feature_ptr->isKnown()); _feature_list_out.push_back(incoming_point_ptr); - incoming_point_ptr->setTrackId(feature_ptr->trackId()); - _feature_matches[incoming_point_ptr] = std::make_shared<FeatureMatch>(FeatureMatch({feature_base_ptr, normalized_score})); } else @@ -321,7 +319,6 @@ unsigned int ProcessorImageFeature::detectNewFeatures(const unsigned int& _max_n new_descriptors.row(index), Eigen::Matrix2s::Identity()*params_.noise.pixel_noise_var); point_ptr->setIsKnown(false); - point_ptr->setTrackId(point_ptr->id()); addNewFeatureLast(point_ptr); active_search_grid_.hitCell(new_keypoints[0]); @@ -369,10 +366,10 @@ unsigned int ProcessorImageFeature::detect(cv::Mat _image, cv::Rect& _roi, std:: detector_descriptor_ptr_->detect(_image_roi, _new_keypoints); detector_descriptor_ptr_->compute(_image_roi, _new_keypoints, new_descriptors); - for (unsigned int i = 0; i < _new_keypoints.size(); i++) + for (auto point : _new_keypoints) { - _new_keypoints[i].pt.x = _new_keypoints[i].pt.x + _roi.x; - _new_keypoints[i].pt.y = _new_keypoints[i].pt.y + _roi.y; + point.pt.x += _roi.x; + point.pt.y += _roi.y; } return _new_keypoints.size(); } diff --git a/src/processor_image_feature.h b/src/processor_image_feature.h index e489c5a4a1e89346c2182b3661c93646168ed1d9..aa007e00780b8372c1493e15541a264d5fbe68e1 100644 --- a/src/processor_image_feature.h +++ b/src/processor_image_feature.h @@ -87,15 +87,15 @@ class ProcessorImageFeature : public ProcessorTrackerFeature */ void postProcess(); - void advance() + void advanceDerived() { - ProcessorTrackerFeature::advance(); + ProcessorTrackerFeature::advanceDerived(); image_last_ = image_incoming_; } - void reset() + void resetDerived() { - ProcessorTrackerFeature::reset(); + ProcessorTrackerFeature::resetDerived(); image_last_ = image_incoming_; } diff --git a/src/processor_image_landmark.h b/src/processor_image_landmark.h index a3732ba631b1b1ec3b28bbacf5fe324395c52832..489502b529eaf72dead7ff4938b3c32514ca437c 100644 --- a/src/processor_image_landmark.h +++ b/src/processor_image_landmark.h @@ -101,15 +101,15 @@ class ProcessorImageLandmark : public ProcessorTrackerLandmark */ void preProcess(); - void advance() + void advanceDerived() { - ProcessorTrackerLandmark::advance(); + ProcessorTrackerLandmark::advanceDerived(); image_last_ = image_incoming_; } - void reset() + void resetDerived() { - ProcessorTrackerLandmark::reset(); + ProcessorTrackerLandmark::resetDerived(); image_last_ = image_incoming_; } diff --git a/src/processor_loopclosure_base.h b/src/processor_loopclosure_base.h index 3b7e24fafe4320610f0d11de804db24f2f35cd8d..8c5f1493865816820ace7e78b4e556a7ccd8bde2 100644 --- a/src/processor_loopclosure_base.h +++ b/src/processor_loopclosure_base.h @@ -57,7 +57,7 @@ public: virtual void process(CaptureBasePtr _incoming_ptr) override; virtual bool keyFrameCallback(FrameBasePtr _keyframe_ptr, - const Scalar& _time_tol_other) override; + const Scalar& _time_tol_other) ; const std::vector<FrameBasePtr>& getCandidates() const noexcept; diff --git a/src/processor_motion.cpp b/src/processor_motion.cpp index a8e94f2432955dc03d0068f8f9f46a4079d7cb78..731cb7f2f635dc405c0e6ff50cb1e06fc1f8d451 100644 --- a/src/processor_motion.cpp +++ b/src/processor_motion.cpp @@ -10,6 +10,7 @@ ProcessorMotion::ProcessorMotion(const std::string& _type, Scalar _time_tolerance, Size _calib_size) : ProcessorBase(_type, _time_tolerance), + processing_step_(RUNNING_WITHOUT_PACK), x_size_(_state_size), data_size_(_data_size), delta_size_(_delta_size), @@ -40,57 +41,171 @@ ProcessorMotion::~ProcessorMotion() void ProcessorMotion::process(CaptureBasePtr _incoming_ptr) { - if (_incoming_ptr == nullptr) - { - WOLF_ERROR("Process got a nullptr !"); - return; - } + if (_incoming_ptr == nullptr) + { + WOLF_ERROR("Received capture is nullptr."); + return; + } + + incoming_ptr_ = std::static_pointer_cast<CaptureMotion>(_incoming_ptr); + + preProcess(); // Derived class operations + + KFPackPtr pack = computeProcessingStep(); + if (pack) + kf_pack_buffer_.removeUpTo( pack->key_frame->getTimeStamp() ); - if (status_ == IDLE) + switch(processing_step_) { - TimeStamp t0 = _incoming_ptr->getTimeStamp(); - if (origin_ptr_ == nullptr) + case RUNNING_WITHOUT_PACK : + case RUNNING_WITH_PACK_ON_ORIGIN : + break; + + case RUNNING_WITH_PACK_BEFORE_ORIGIN : { - auto frm = getProblem()->getTrajectoryPtr()->closestKeyFrameToTimeStamp(t0); - if (frm && fabs(frm->getTimeStamp() - t0) < time_tolerance_) + // extract pack elements + FrameBasePtr keyframe_from_callback = pack->key_frame; + TimeStamp ts_from_callback = keyframe_from_callback->getTimeStamp(); + + // find the capture whose buffer is affected by the new keyframe + auto existing_capture = findCaptureContainingTimeStamp(ts_from_callback); + + // Find the frame acting as the capture's origin + auto keyframe_origin = existing_capture->getOriginFramePtr(); + + // emplace a new motion capture to the new keyframe + auto capture_for_keyframe_callback = emplaceCapture(keyframe_from_callback, + getSensorPtr(), + ts_from_callback, + Eigen::VectorXs::Zero(data_size_), + existing_capture->getDataCovariance(), + existing_capture->getCalibration(), + existing_capture->getCalibration(), + keyframe_origin); + + // split the buffer + // and give the part of the buffer before the new keyframe to the capture for the KF callback + existing_capture->getBuffer().split(ts_from_callback, capture_for_keyframe_callback->getBuffer()); + + + // interpolate individual delta + if (!existing_capture->getBuffer().get().empty() && capture_for_keyframe_callback->getBuffer().get().back().ts_ != ts_from_callback) { - std::cout << "PM: join KF" << std::endl; - // Join existing KF - setOrigin(frm); + // interpolate Motion at the new time stamp + Motion motion_interpolated = interpolate(capture_for_keyframe_callback->getBuffer().get().back(), // last Motion of old buffer + existing_capture->getBuffer().get().front(), // first motion of new buffer + ts_from_callback); + // add to old buffer + capture_for_keyframe_callback->getBuffer().get().push_back(motion_interpolated); } - else + + + // create motion feature and add it to the capture + auto new_feature = emplaceFeature(capture_for_keyframe_callback); + + // create motion constraint and add it to the feature, and constrain to the other capture (origin) + emplaceConstraint(new_feature, keyframe_origin->getCaptureOf(getSensorPtr()) ); + + // Update the existing capture + existing_capture->setOriginFramePtr(keyframe_from_callback); + + // re-integrate existing buffer -- note: the result of re-integration is stored in the same buffer! + reintegrateBuffer(existing_capture); + + // modify existing feature and constraint (if they exist in the existing capture) + if (!existing_capture->getFeatureList().empty()) { - // Create new KF for origin - std::cout << "PM: make KF" << std::endl; - VectorXs x0 = getProblem()->zeroState(); - setOrigin(x0, t0); + auto existing_feature = existing_capture->getFeatureList().back(); // there is only one feature! + + // Modify existing feature -------- + existing_feature->setMeasurement (existing_capture->getBuffer().get().back().delta_integr_); + existing_feature->setMeasurementCovariance(existing_capture->getBuffer().get().back().delta_integr_cov_); + + // Modify existing constraint -------- + // Instead of modifying, we remove one ctr, and create a new one. + auto ctr_to_remove = existing_feature->getConstraintList().back(); // there is only one constraint! + auto new_ctr = emplaceConstraint(existing_feature, capture_for_keyframe_callback); + ctr_to_remove ->remove(); // remove old constraint now (otherwise c->remove() gets propagated to f, C, F, etc.) } + break; } - status_ = RUNNING; - } - incoming_ptr_ = std::static_pointer_cast<CaptureMotion>(_incoming_ptr); - /// @todo Anything else to do ? - if (incoming_ptr_ == nullptr) return; + case RUNNING_WITH_PACK_AFTER_ORIGIN : + { + // extract pack elements + FrameBasePtr keyframe_from_callback = pack->key_frame; + TimeStamp ts_from_callback = keyframe_from_callback->getTimeStamp(); + + // Find the frame acting as the capture's origin + auto keyframe_origin = last_ptr_->getOriginFramePtr(); + + // emplace a new motion capture to the new keyframe + VectorXs calib = last_ptr_->getCalibration(); + auto capture_for_keyframe_callback = emplaceCapture(keyframe_from_callback, + getSensorPtr(), + ts_from_callback, + Eigen::VectorXs::Zero(data_size_), + last_ptr_->getDataCovariance(), + calib, + calib, + keyframe_origin); + + // split the buffer + // and give the part of the buffer before the new keyframe to the capture for the KF callback + last_ptr_->getBuffer().split(ts_from_callback, capture_for_keyframe_callback->getBuffer()); + + // interpolate individual delta + if (!last_ptr_->getBuffer().get().empty() && capture_for_keyframe_callback->getBuffer().get().back().ts_ != ts_from_callback) + { + // interpolate Motion at the new time stamp + Motion motion_interpolated = interpolate(capture_for_keyframe_callback->getBuffer().get().back(), // last Motion of old buffer + last_ptr_->getBuffer().get().front(), // first motion of new buffer + ts_from_callback); + // add to old buffer + capture_for_keyframe_callback->getBuffer().get().push_back(motion_interpolated); + } + + // create motion feature and add it to the capture + auto feature_for_keyframe_callback = emplaceFeature(capture_for_keyframe_callback); + + // create motion constraint and add it to the feature, and constrain to the other capture (origin) + emplaceConstraint(feature_for_keyframe_callback, keyframe_origin->getCaptureOf(getSensorPtr()) ); + + // reset processor origin + origin_ptr_ = capture_for_keyframe_callback; + + // Update the existing capture + last_ptr_->setOriginFramePtr(keyframe_from_callback); + + // re-integrate existing buffer -- note: the result of re-integration is stored in the same buffer! + reintegrateBuffer(last_ptr_); + + break; + } + - preProcess(); + + default : + break; + } + + //////////////////////////////////////////////////// + // NOW on with the received data // integrate data integrateOneStep(); // Update state and time stamps - last_ptr_->setTimeStamp(incoming_ptr_->getTimeStamp()); - last_ptr_->getFramePtr()->setTimeStamp(last_ptr_->getTimeStamp()); + last_ptr_->setTimeStamp(getCurrentTimeStamp()); + last_ptr_->getFramePtr()->setTimeStamp(getCurrentTimeStamp()); last_ptr_->getFramePtr()->setState(getCurrentState()); if (voteForKeyFrame() && permittedKeyFrame()) { // Set the frame of last_ptr as key auto key_frame_ptr = last_ptr_->getFramePtr(); - key_frame_ptr->setState(getCurrentState()); - key_frame_ptr->setTimeStamp(getCurrentTimeStamp()); key_frame_ptr->setKey(); // create motion feature and add it to the key_capture @@ -113,7 +228,6 @@ void ProcessorMotion::process(CaptureBasePtr _incoming_ptr) last_ptr_->getCalibration(), key_frame_ptr); // reset the new buffer - new_capture_ptr->getBuffer().get().clear(); new_capture_ptr->getBuffer().get().push_back( motionZero(key_frame_ptr->getTimeStamp()) ) ; // reset integrals @@ -123,28 +237,30 @@ void ProcessorMotion::process(CaptureBasePtr _incoming_ptr) delta_integrated_cov_ . setZero(); jacobian_calib_ . setZero(); - // reset processor origin to the new keyframe's capture - origin_ptr_ = last_ptr_; - last_ptr_ = new_capture_ptr; - // reset derived things resetDerived(); + // Update pointers + origin_ptr_ = last_ptr_; + last_ptr_ = new_capture_ptr; + // callback to other processors getProblem()->keyFrameCallback(key_frame_ptr, shared_from_this(), time_tolerance_); } - - postProcess(); + resetDerived(); // TODO see where to put this // clear incoming just in case incoming_ptr_ = nullptr; // This line is not really needed, but it makes things clearer. + + postProcess(); } + void ProcessorMotion::getState(const TimeStamp& _ts, Eigen::VectorXs& _x) { CaptureMotionPtr capture_motion; - if (_ts >= origin_ptr_->getTimeStamp()) + if (origin_ptr_ && _ts >= origin_ptr_->getTimeStamp()) // timestamp found in the current processor buffer capture_motion = last_ptr_; else @@ -160,8 +276,12 @@ void ProcessorMotion::getState(const TimeStamp& _ts, Eigen::VectorXs& _x) statePlusDelta(state_0, delta, dt, _x); } else + { // We could not find any CaptureMotion for the time stamp requested - std::runtime_error("Could not find any Capture for the time stamp requested"); + WOLF_ERROR("Could not find any Capture for the time stamp requested. "); + WOLF_TRACE("Did you forget to call Problem::setPrior() in your application?") + throw std::runtime_error("Could not find any Capture for the time stamp requested. Did you forget to call Problem::setPrior() in your application?"); + } } CaptureMotionPtr ProcessorMotion::findCaptureContainingTimeStamp(const TimeStamp& _ts) const @@ -235,7 +355,6 @@ void ProcessorMotion::setOrigin(FrameBasePtr _origin_frame) _origin_frame); // clear and reset buffer - getBuffer().get().clear(); getBuffer().get().push_back(motionZero(_origin_frame->getTimeStamp())); // Reset integrals @@ -249,91 +368,10 @@ void ProcessorMotion::setOrigin(FrameBasePtr _origin_frame) resetDerived(); } -bool ProcessorMotion::keyFrameCallback(FrameBasePtr _new_keyframe, const Scalar& _time_tol_other) -{ - - assert(_new_keyframe->getTrajectoryPtr() != nullptr - && "ProcessorMotion::keyFrameCallback: key frame must be in the trajectory."); - - // get keyframe's time stamp - TimeStamp new_ts = _new_keyframe->getTimeStamp(); - - // find the capture whose buffer is affected by the new keyframe - auto existing_capture = findCaptureContainingTimeStamp(new_ts); - assert(existing_capture != nullptr - && "ProcessorMotion::keyFrameCallback: no motion capture containing the required TimeStamp found"); - - // Find the frame acting as the capture's origin - auto keyframe_origin = existing_capture->getOriginFramePtr(); - - // emplace a new motion capture to the new keyframe - auto new_capture = emplaceCapture(_new_keyframe, - getSensorPtr(), - new_ts, - Eigen::VectorXs::Zero(data_size_), - existing_capture->getDataCovariance(), - existing_capture->getCalibration(), - existing_capture->getCalibration(), - keyframe_origin); - - // split the buffer - // and give the part of the buffer before the new keyframe to the key_capture - existing_capture->getBuffer().split(new_ts, new_capture->getBuffer()); - - // interpolate individual delta - if (!existing_capture->getBuffer().get().empty() && new_capture->getBuffer().get().back().ts_ != new_ts) - { - // interpolate Motion at the new time stamp - Motion motion_interpolated = interpolate(new_capture->getBuffer().get().back(), // last Motion of old buffer - existing_capture->getBuffer().get().front(), // first motion of new buffer - new_ts); - // add to old buffer - new_capture->getBuffer().get().push_back(motion_interpolated); - } - - // create motion feature and add it to the capture - auto new_feature = emplaceFeature(new_capture); -// reintegrateBuffer(new_capture); - - // create motion constraint and add it to the feature, and constrain to the other capture (origin) - emplaceConstraint(new_feature, keyframe_origin->getCaptureOf(getSensorPtr()) ); - - - - ///////////////////////////////////////////////////////// - // Update the existing capture - if (existing_capture == last_ptr_) - // reset processor origin - origin_ptr_ = new_capture; - - existing_capture->setOriginFramePtr(_new_keyframe); - - // reintegrate existing buffer -- note: the result of re-integration is stored in the same buffer! - reintegrateBuffer(existing_capture); - - // modify existing feature and constraint (if they exist in the existing capture) - if (!existing_capture->getFeatureList().empty()) - { - auto existing_feature = existing_capture->getFeatureList().back(); // there is only one feature! - - // Modify existing feature -------- - existing_feature->setMeasurement (existing_capture->getBuffer().get().back().delta_integr_); - existing_feature->setMeasurementCovariance(existing_capture->getBuffer().get().back().delta_integr_cov_); - - // Modify existing constraint -------- - // Instead of modifying, we remove one ctr, and create a new one. - auto ctr_to_remove = existing_feature->getConstraintList().back(); // there is only one constraint! - auto new_ctr = emplaceConstraint(existing_feature, new_capture); - ctr_to_remove ->remove(); // remove old constraint now (otherwise c->remove() gets propagated to f, C, F, etc.) - } - - return true; -} - void ProcessorMotion::integrateOneStep() { // Set dt - updateDt(); + dt_ = updateDt(); // get vector of parameters to calibrate calib_ = getBuffer().getCalibrationPreint(); @@ -524,5 +562,40 @@ FeatureBasePtr ProcessorMotion::emplaceFeature(CaptureMotionPtr _capture_motion) return feature; } +KFPackPtr ProcessorMotion::computeProcessingStep() +{ + if (!getProblem()->priorIsSet()) + { + WOLF_WARN ("||*||"); + WOLF_INFO (" ... It seems you missed something!"); + WOLF_ERROR("ProcessorMotion received data before being initialized."); + WOLF_INFO ("Did you forget to issue a Problem::setPrior()?"); + throw std::runtime_error("ProcessorMotion received data before being initialized."); + } + + KFPackPtr pack = kf_pack_buffer_.selectPackBefore(last_ptr_, time_tolerance_); + + if (pack) + { + if (kf_pack_buffer_.checkTimeTolerance(pack->key_frame->getTimeStamp(), pack->time_tolerance, origin_ptr_->getTimeStamp(), 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_PACK_ON_ORIGIN; + } + else if (pack->key_frame->getTimeStamp() < origin_ptr_->getTimeStamp() - time_tolerance_) + processing_step_ = RUNNING_WITH_PACK_BEFORE_ORIGIN; + + else + processing_step_ = RUNNING_WITH_PACK_AFTER_ORIGIN; + + } + else + processing_step_ = RUNNING_WITHOUT_PACK; + + return pack; +} } diff --git a/src/processor_motion.h b/src/processor_motion.h index 4def813e2b5b2588f95b9b71ccd7998378fb5599..93d1af04a43ee77e02661331d1beb8031e2ed49a 100644 --- a/src/processor_motion.h +++ b/src/processor_motion.h @@ -99,6 +99,17 @@ namespace wolf */ class ProcessorMotion : public ProcessorBase { + public: + typedef enum { + RUNNING_WITHOUT_PACK, + RUNNING_WITH_PACK_BEFORE_ORIGIN, + RUNNING_WITH_PACK_ON_ORIGIN, + RUNNING_WITH_PACK_AFTER_ORIGIN + } ProcessingStep ; + + protected: + ProcessingStep processing_step_; ///< State machine controlling the processing step + private: enum { @@ -119,6 +130,7 @@ class ProcessorMotion : public ProcessorBase // Instructions to the processor: + void process2(CaptureBasePtr _incoming_ptr); void process(CaptureBasePtr _incoming_ptr); virtual void resetDerived(); @@ -182,8 +194,6 @@ class ProcessorMotion : public ProcessorBase */ FrameBasePtr setOrigin(const Eigen::VectorXs& _x_origin, const TimeStamp& _ts_origin); - virtual bool keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tol); - MotionBuffer& getBuffer(); const MotionBuffer& getBuffer() const; @@ -191,7 +201,7 @@ class ProcessorMotion : public ProcessorBase // Helper functions: protected: - void updateDt(); + Scalar updateDt(); void integrateOneStep(); void splitBuffer(const TimeStamp& _t_split, MotionBuffer& _oldest_part); void reintegrateBuffer(CaptureMotionPtr _capture_ptr); @@ -221,6 +231,8 @@ class ProcessorMotion : public ProcessorBase */ virtual void postProcess() { }; + KFPackPtr computeProcessingStep(); + // These are the pure virtual functions doing the mathematics protected: @@ -498,9 +510,9 @@ inline bool ProcessorMotion::isMotion() return true; } -inline void ProcessorMotion::updateDt() +inline Scalar ProcessorMotion::updateDt() { - dt_ = incoming_ptr_->getTimeStamp() - getBuffer().get().back().ts_; + return dt_ = incoming_ptr_->getTimeStamp() - getBuffer().get().back().ts_; } inline const MotionBuffer& ProcessorMotion::getBuffer() const diff --git a/src/processor_tracker.cpp b/src/processor_tracker.cpp index cc2b764e11126f549d8910ae60f838eacc0fb5fe..1268c2debc5c2a7320e1479009657820f728ddcb 100644 --- a/src/processor_tracker.cpp +++ b/src/processor_tracker.cpp @@ -15,7 +15,11 @@ namespace wolf { ProcessorTracker::ProcessorTracker(const std::string& _type, const unsigned int _max_new_features, const Scalar& _time_tolerance) : - ProcessorBase(_type, _time_tolerance), origin_ptr_(nullptr), last_ptr_(nullptr), incoming_ptr_(nullptr), + ProcessorBase(_type, _time_tolerance), + processing_step_(FIRST_TIME_WITHOUT_PACK), + origin_ptr_(nullptr), + last_ptr_(nullptr), + incoming_ptr_(nullptr), max_new_features_(_max_new_features) { // @@ -28,231 +32,230 @@ ProcessorTracker::~ProcessorTracker() void ProcessorTracker::process(CaptureBasePtr const _incoming_ptr) { - using std::abs; + if (_incoming_ptr == nullptr) + { + WOLF_ERROR("Received capture is nullptr."); + return; + } + incoming_ptr_ = _incoming_ptr; - preProcess(); + preProcess(); // Derived class operations - // FIRST TIME - if (origin_ptr_ == nullptr && last_ptr_ == nullptr) + computeProcessingStep(); + + switch(processing_step_) { - WOLF_DEBUG( "FIRST TIME" ); + case FIRST_TIME_WITH_PACK : + { + KFPackPtr pack = kf_pack_buffer_.selectPack( incoming_ptr_, time_tolerance_); + kf_pack_buffer_.removeUpTo( incoming_ptr_->getTimeStamp() ); - // advance - advance(); + WOLF_DEBUG( "PT: KF" , pack->key_frame->id() , " callback received with ts= " , pack->key_frame->getTimeStamp().get() ); - // advance this - last_ptr_ = incoming_ptr_; - incoming_ptr_ = nullptr; + // Append incoming to KF + pack->key_frame->addCapture(incoming_ptr_); - // keyframe creation on last - FrameBasePtr closest_key_frm = getProblem()->getTrajectoryPtr()->closestKeyFrameToTimeStamp(last_ptr_->getTimeStamp()); - if (closest_key_frm && abs(closest_key_frm->getTimeStamp() - last_ptr_->getTimeStamp()) <= time_tolerance_) - { - // Set KF - closest_key_frm->addCapture(last_ptr_); - closest_key_frm->setKey(); - WOLF_DEBUG( "Last appended to existing F, set KF" , closest_key_frm->id() ); + // Process info + // We only process new features in Last, here last = nullptr, so we do not have anything to do. + + // Update pointers + resetDerived(); + origin_ptr_ = incoming_ptr_; + last_ptr_ = incoming_ptr_; + incoming_ptr_ = nullptr; + + break; } - else + case FIRST_TIME_WITHOUT_PACK : { - // Make KF - FrameBasePtr new_frame_ptr = getProblem()->emplaceFrame(KEY_FRAME, - getProblem()->getState(last_ptr_->getTimeStamp()), - last_ptr_->getTimeStamp()); - new_frame_ptr->addCapture(last_ptr_); // Add incoming Capture to the new Frame - WOLF_DEBUG( "Last appended to new KF" , new_frame_ptr->id() ); - - getProblem()->keyFrameCallback(new_frame_ptr, shared_from_this(), time_tolerance_); - } + FrameBasePtr kfrm = getProblem()->emplaceFrame(KEY_FRAME, incoming_ptr_->getTimeStamp()); + kfrm->addCapture(incoming_ptr_); - // Detect new Features, initialize Landmarks, create Constraints, ... - processNew(max_new_features_); - - // Establish constraints from last - establishConstraints(); - } + // Process info + // We only process new features in Last, here last = nullptr, so we do not have anything to do. - // SECOND TIME or after KEY FRAME CALLBACK - else if (origin_ptr_ == nullptr) - { - WOLF_DEBUG("SECOND TIME or after KEY FRAME CALLBACK"); + // Issue KF callback with new KF + getProblem()->keyFrameCallback(kfrm, shared_from_this(), time_tolerance_); - // First we track the known Features - processKnown(); + // Update pointers + resetDerived(); + origin_ptr_ = incoming_ptr_; + last_ptr_ = incoming_ptr_; + incoming_ptr_ = nullptr; - // Create a new non-key Frame in the Trajectory with the incoming Capture - FrameBasePtr closest_key_frm = getProblem()->getTrajectoryPtr()->closestKeyFrameToTimeStamp(incoming_ptr_->getTimeStamp()); - if (closest_key_frm && abs(closest_key_frm->getTimeStamp() - incoming_ptr_->getTimeStamp()) <= time_tolerance_) - { - // Just append the Capture to the existing keyframe - closest_key_frm->addCapture(incoming_ptr_); - WOLF_DEBUG("Incoming appended to F" , closest_key_frm->id() ); + break; } - else + case SECOND_TIME_WITH_PACK : + case SECOND_TIME_WITHOUT_PACK : { - // Create a frame to hold what will become the last Capture - FrameBasePtr new_frame_ptr = getProblem()->emplaceFrame(NON_KEY_FRAME, incoming_ptr_->getTimeStamp()); - new_frame_ptr->addCapture(incoming_ptr_); // Add incoming Capture to the new Frame - WOLF_DEBUG("Incoming in new F" , new_frame_ptr->id() ); - } + FrameBasePtr frm = getProblem()->emplaceFrame(NON_KEY_FRAME, incoming_ptr_->getTimeStamp()); + frm->addCapture(incoming_ptr_); - // Reset the derived Tracker - reset(); + // We have a last_ Capture with no features, so we do not process known features, and we do not vote for KF. - // Reset this - origin_ptr_ = last_ptr_; - last_ptr_ = incoming_ptr_; - incoming_ptr_ = nullptr; // This line is not really needed, but it makes things clearer. + // Process info + processNew(max_new_features_); + // Update pointers + resetDerived(); + origin_ptr_ = last_ptr_; + last_ptr_ = incoming_ptr_; + incoming_ptr_ = nullptr; - } + break; + } + case RUNNING_WITH_PACK : + { + KFPackPtr pack = kf_pack_buffer_.selectPack( last_ptr_ , time_tolerance_); + kf_pack_buffer_.removeUpTo( last_ptr_->getTimeStamp() ); - // OTHER TIMES - else - { - WOLF_DEBUG("OTHER TIMES"); + WOLF_DEBUG( "PT: KF" , pack->key_frame->id() , " callback received with ts= " , pack->key_frame->getTimeStamp().get() ); - // 1. First we track the known Features and create new constraints as needed + processKnown(); - processKnown(); + // Capture last_ is added to the new keyframe + FrameBasePtr last_old_frame = last_ptr_->getFramePtr(); + last_old_frame->unlinkCapture(last_ptr_); + last_old_frame->remove(); + pack->key_frame->addCapture(last_ptr_); - // 2. Then we see if we want and we are allowed to create a KeyFrame - // Three conditions to make a KF: - // - We vote for KF - // - Problem allows us to make keyframe - // - There is no existing KF very close to our Time Stamp <--- NOT SURE OF THIS + // Create new frame + FrameBasePtr frm = getProblem()->emplaceFrame(NON_KEY_FRAME, incoming_ptr_->getTimeStamp()); + frm->addCapture(incoming_ptr_); + + // Detect new Features, initialize Landmarks, create Constraints, ... + processNew(max_new_features_); - FrameBasePtr closest_key_frm_to_last = last_ptr_->getFramePtr(); // start with the same last's frame - if ( ! ( closest_key_frm_to_last && closest_key_frm_to_last->isKey() ) ) // last F is not KF - closest_key_frm_to_last = getProblem()->getTrajectoryPtr()->closestKeyFrameToTimeStamp(last_ptr_->getTimeStamp()); + // Establish constraints + establishConstraints(); - if (closest_key_frm_to_last && abs(closest_key_frm_to_last->getTimeStamp() - last_ptr_->getTimeStamp()) > time_tolerance_) // closest KF is not close enough - closest_key_frm_to_last = nullptr; + // Update pointers + resetDerived(); + origin_ptr_ = last_ptr_; + last_ptr_ = incoming_ptr_; + incoming_ptr_ = nullptr; - if ( !( (voteForKeyFrame() && permittedKeyFrame() ) || closest_key_frm_to_last ) ) + break; + } + case RUNNING_WITHOUT_PACK : { + processKnown(); - // 2.a. We did not create a KeyFrame: + if (voteForKeyFrame() && permittedKeyFrame()) + { + // We create a KF - // advance the derived tracker - advance(); + // set KF on last + last_ptr_->getFramePtr()->setKey(); - // Advance this - last_ptr_->getFramePtr()->addCapture(incoming_ptr_); // Add incoming Capture to the tracker's last Frame - last_ptr_->remove(); - incoming_ptr_->getFramePtr()->setTimeStamp(incoming_ptr_->getTimeStamp()); - last_ptr_ = incoming_ptr_; // Incoming Capture takes the place of last Capture - incoming_ptr_ = nullptr; // This line is not really needed, but it makes things clearer. + // make F; append incoming to new F + FrameBasePtr frm = getProblem()->emplaceFrame(NON_KEY_FRAME, incoming_ptr_->getTimeStamp()); + frm->addCapture(incoming_ptr_); - WOLF_DEBUG("last <-- incoming"); + // process + processNew(max_new_features_); - } - else - { + // Set key + last_ptr_->getFramePtr()->setKey(); - // 2.b. We create a KF + // Set state to the keyframe + last_ptr_->getFramePtr()->setState(getProblem()->getState(last_ptr_->getTimeStamp())); - // Detect new Features, initialize Landmarks, create Constraints, ... - processNew(max_new_features_); + // Establish constraints + establishConstraints(); + + // Call the new keyframe callback in order to let the other processors to establish their constraints + getProblem()->keyFrameCallback(last_ptr_->getFramePtr(), std::static_pointer_cast<ProcessorBase>(shared_from_this()), time_tolerance_); + + // Update pointers + resetDerived(); + origin_ptr_ = last_ptr_; + last_ptr_ = incoming_ptr_; + incoming_ptr_ = nullptr; - FrameBasePtr key_frm = getProblem()->getTrajectoryPtr()->closestKeyFrameToTimeStamp(incoming_ptr_->getTimeStamp()); - if ( abs(key_frm->getTimeStamp() - incoming_ptr_->getTimeStamp() ) < time_tolerance_) - { - // Append incoming to existing key-frame - key_frm->addCapture(incoming_ptr_); - WOLF_DEBUG("Incoming adhered to existing KF" , key_frm->id()); } else { - // Create a new non-key Frame in the Trajectory with the incoming Capture - // Make a non-key-frame to hold incoming - FrameBasePtr new_frame_ptr = getProblem()->emplaceFrame(NON_KEY_FRAME, incoming_ptr_->getTimeStamp()); - new_frame_ptr->addCapture(incoming_ptr_); // Add incoming Capture to the new Frame - WOLF_DEBUG( "Incoming adhered to new F" , key_frm->id() ); - - // Make the last Capture's Frame a KeyFrame - setKeyFrame(last_ptr_); - WOLF_DEBUG( "Set KEY to last F" , key_frm->id() ); - } - - // Establish constraints between last and origin - establishConstraints(); - - // Reset the derived Tracker - reset(); - - // Reset this - origin_ptr_ = last_ptr_; - last_ptr_ = incoming_ptr_; - incoming_ptr_ = nullptr; // This line is not really needed, but it makes things clearer. - -} + // We do not create a KF + // Advance this + last_ptr_->getFramePtr()->addCapture(incoming_ptr_); // Add incoming Capture to the tracker's last Frame + last_ptr_->remove(); + incoming_ptr_->getFramePtr()->setTimeStamp(incoming_ptr_->getTimeStamp()); + // Update pointers + advanceDerived(); + last_ptr_ = incoming_ptr_; + incoming_ptr_ = nullptr; + } + break; + } + default : + break; } - postProcess(); - //std::cout << "-----End of process():" << std::endl; + postProcess(); } -bool ProcessorTracker::keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tol_other) +void ProcessorTracker::computeProcessingStep() { - WOLF_DEBUG( "PT: KF" , _keyframe_ptr->id() , " callback received at ts= " , _keyframe_ptr->getTimeStamp().get() ); - - assert((last_ptr_ == nullptr || last_ptr_->getFramePtr() != nullptr) && "ProcessorTracker::keyFrameCallback: last_ptr_ must have a frame always"); - - Scalar time_tol = std::min(time_tolerance_, _time_tol_other); + // First determine the processing phase by checking the status of the tracker pointers + enum {FIRST_TIME, SECOND_TIME, RUNNING} step; + if (origin_ptr_ == nullptr && last_ptr_ == nullptr) + step = FIRST_TIME; + else if (origin_ptr_ == last_ptr_) + step = SECOND_TIME; + else + step = RUNNING; - // Nothing to do if: - // - there is no last - // - last frame is already a key frame - // - last frame is too far in time from keyframe - if (last_ptr_ == nullptr || last_ptr_->getFramePtr()->isKey() || std::abs(last_ptr_->getTimeStamp() - _keyframe_ptr->getTimeStamp()) > time_tol) + // Then combine with the existence (or not) of a keyframe callback pack + switch (step) { - WOLF_DEBUG( " --> nothing done" ); - return false; - } - - WOLF_DEBUG( " --> appended last capture" ); - //std::cout << "ProcessorTracker::keyFrameCallback in sensor " << getSensorPtr()->id() << std::endl; + case FIRST_TIME : - // Capture last_ is added to the new keyframe - FrameBasePtr last_old_frame = last_ptr_->getFramePtr(); - last_old_frame->unlinkCapture(last_ptr_); - last_old_frame->remove(); - _keyframe_ptr->addCapture(last_ptr_); + if (kf_pack_buffer_.selectPack(incoming_ptr_, time_tolerance_)) + processing_step_ = FIRST_TIME_WITH_PACK; + else // ! last && ! pack(incoming) + processing_step_ = FIRST_TIME_WITHOUT_PACK; + break; - // Detect new Features, initialize Landmarks, create Constraints, ... - processNew(max_new_features_); + case SECOND_TIME : - // Establish constraints between last and origin - establishConstraints(); - - // Set ready to go to 2nd case in process() - origin_ptr_ = nullptr; + if (kf_pack_buffer_.selectPack(last_ptr_, time_tolerance_)) + processing_step_ = SECOND_TIME_WITH_PACK; + else + processing_step_ = SECOND_TIME_WITHOUT_PACK; + break; - return true; + case RUNNING : + default : + if (kf_pack_buffer_.selectPack(last_ptr_, time_tolerance_)) + { + if (last_ptr_->getFramePtr()->isKey()) + { + WOLF_WARN("||*||"); + WOLF_INFO(" ... It seems you missed something!"); + WOLF_INFO("Pack's KF and last's KF have matching time stamps (i.e. below time tolerances)"); + WOLF_INFO("Check the following for correctness:"); + WOLF_INFO(" - You have all processors installed before starting receiving any data"); + WOLF_INFO(" - You issued a problem->setPrior() after all processors are installed ---> ", (getProblem()->priorIsSet() ? "OK" : "NOK")); + WOLF_INFO(" - You have configured all your processors with compatible time tolerances"); + WOLF_ERROR("Pack's KF and last's KF have matching time stamps (i.e. below time tolerances)."); + } + processing_step_ = RUNNING_WITH_PACK; + } + else + processing_step_ = RUNNING_WITHOUT_PACK; + break; + } } -void ProcessorTracker::setKeyFrame(CaptureBasePtr _capture_ptr) -{ - assert(_capture_ptr != nullptr && _capture_ptr->getFramePtr() != nullptr && "ProcessorTracker::setKeyFrame: null capture or capture without frame"); - if (!_capture_ptr->getFramePtr()->isKey()) - { - // Set key - _capture_ptr->getFramePtr()->setKey(); - // Set state to the keyframe - _capture_ptr->getFramePtr()->setState(getProblem()->getState(_capture_ptr->getTimeStamp())); - // Call the new keyframe callback in order to let the other processors to establish their constraints - getProblem()->keyFrameCallback(_capture_ptr->getFramePtr(), std::static_pointer_cast<ProcessorBase>(shared_from_this()), time_tolerance_); - } -} } // namespace wolf diff --git a/src/processor_tracker.h b/src/processor_tracker.h index fb1029d72456666131130f25a9f7665153def6e6..08304472ab9c433f89a27d064d17aeddd47c355b 100644 --- a/src/processor_tracker.h +++ b/src/processor_tracker.h @@ -67,7 +67,18 @@ struct ProcessorParamsTracker : public ProcessorParamsBase */ class ProcessorTracker : public ProcessorBase { + public: + typedef enum { + FIRST_TIME_WITH_PACK, + FIRST_TIME_WITHOUT_PACK, + SECOND_TIME_WITH_PACK, + SECOND_TIME_WITHOUT_PACK, + RUNNING_WITH_PACK, + RUNNING_WITHOUT_PACK + } ProcessingStep ; + protected: + ProcessingStep processing_step_; ///< State machine controlling the processing step CaptureBasePtr origin_ptr_; ///< Pointer to the origin of the tracker. CaptureBasePtr last_ptr_; ///< Pointer to the last tracked capture. CaptureBasePtr incoming_ptr_; ///< Pointer to the incoming capture being processed. @@ -89,7 +100,12 @@ class ProcessorTracker : public ProcessorBase void setMaxNewFeatures(const unsigned int& _max_new_features); unsigned int getMaxNewFeatures(); - virtual bool keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tol_other); +// virtual bool keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tol_other); + + bool checkTimeTolerance(const TimeStamp& _ts1, const TimeStamp& _ts2); + bool checkTimeTolerance(const CaptureBasePtr _cap, const TimeStamp& _ts); + bool checkTimeTolerance(const FrameBasePtr _frm, const TimeStamp& _ts); + bool checkTimeTolerance(const FrameBasePtr _frm, const CaptureBasePtr _cap); virtual CaptureBasePtr getOriginPtr(); virtual CaptureBasePtr getLastPtr(); @@ -159,7 +175,7 @@ class ProcessorTracker : public ProcessorBase * Call this when the tracking and keyframe policy work is done and * we need to get ready to accept a new incoming Capture. */ - virtual void advance() = 0; + virtual void advanceDerived() = 0; /**\brief Process new Features or Landmarks * @@ -171,13 +187,9 @@ class ProcessorTracker : public ProcessorBase */ virtual void establishConstraints()=0; - /**\brief set key Frame to the provided Capture's frame - */ - virtual void setKeyFrame(CaptureBasePtr _capture_ptr); - /** \brief Reset the tracker using the \b last Capture as the new \b origin. */ - virtual void reset() = 0; + virtual void resetDerived() = 0; public: @@ -185,11 +197,14 @@ class ProcessorTracker : public ProcessorBase protected: + void computeProcessingStep(); + void addNewFeatureLast(FeatureBasePtr _feature_ptr); FeatureBaseList& getNewFeaturesListIncoming(); void addNewFeatureIncoming(FeatureBasePtr _feature_ptr); + }; inline void ProcessorTracker::setMaxNewFeatures(const unsigned int& _max_new_features) @@ -217,6 +232,26 @@ inline FeatureBaseList& ProcessorTracker::getNewFeaturesListIncoming() return new_features_incoming_; } +inline bool ProcessorTracker::checkTimeTolerance(const TimeStamp& _ts1, const TimeStamp& _ts2) +{ + return (std::fabs(_ts2 - _ts2) < time_tolerance_); +} + +inline bool ProcessorTracker::checkTimeTolerance(const CaptureBasePtr _cap, const TimeStamp& _ts) +{ + return checkTimeTolerance(_cap->getTimeStamp(), _ts); +} + +inline bool ProcessorTracker::checkTimeTolerance(const FrameBasePtr _frm, const TimeStamp& _ts) +{ + return checkTimeTolerance(_frm->getTimeStamp(), _ts); +} + +inline bool ProcessorTracker::checkTimeTolerance(const FrameBasePtr _frm, const CaptureBasePtr _cap) +{ + return checkTimeTolerance(_frm->getTimeStamp(), _cap->getTimeStamp()); +} + inline void ProcessorTracker::addNewFeatureIncoming(FeatureBasePtr _feature_ptr) { new_features_incoming_.push_back(_feature_ptr); diff --git a/src/processor_tracker_feature.cpp b/src/processor_tracker_feature.cpp index c81828b0798450cdd72f57ae8f282802f86f40af..e7da3b55749c25a00a0027772f6483d659d8a9f7 100644 --- a/src/processor_tracker_feature.cpp +++ b/src/processor_tracker_feature.cpp @@ -19,11 +19,45 @@ ProcessorTrackerFeature::~ProcessorTrackerFeature() { } -unsigned int ProcessorTrackerFeature::processKnown() +unsigned int ProcessorTrackerFeature::processNew(const unsigned int& _max_new_features) { + /* Rationale: A keyFrame will be created using the last Capture. + * First, we work on the last Capture to detect new Features, + * When done, we need to track these new Features to the incoming Capture. + * At the end, all new Features are appended to the lists of known Features in + * the last and incoming Captures. + */ + + // Populate the last Capture with new Features. The result is in new_features_last_. + unsigned int n = detectNewFeatures(_max_new_features); + for (auto ftr : new_features_last_) + { + ftr->setTrackId( ftr->id() ); + WOLF_DEBUG("Det track: ", ftr->trackId(), ", last: ", ftr->id()); + } -// std::cout << "ProcessorTrackerFeature::processKnown()" << std::endl; + // Track new features from last to incoming. This will append new correspondences to matches_last_incoming + trackFeatures(new_features_last_, new_features_incoming_, matches_last_from_incoming_); + for (auto ftr : new_features_incoming_) + { + ftr->setTrackId(matches_last_from_incoming_[ftr]->feature_ptr_->trackId()); + + // Print new tracked features + WOLF_DEBUG("New track: ", ftr->trackId(), ", last: ", matches_last_from_incoming_[ftr]->feature_ptr_->id(), ", inc: ", ftr->id()); + } + // Append all new Features to the incoming Captures' list of Features + incoming_ptr_->addFeatureList(new_features_incoming_); + + // Append all new Features to the last Captures' list of Features + last_ptr_->addFeatureList(new_features_last_); + + // return the number of new features detected in \b last + return n; +} + +unsigned int ProcessorTrackerFeature::processKnown() +{ assert(incoming_ptr_->getFeatureList().size() == 0 && "In ProcessorTrackerFeature::processKnown(): incoming_ptr_ feature list must be empty before processKnown()"); assert(matches_last_from_incoming_.size() == 0 @@ -31,8 +65,8 @@ unsigned int ProcessorTrackerFeature::processKnown() // Track features from last_ptr_ to incoming_ptr_ trackFeatures(last_ptr_->getFeatureList(), known_features_incoming_, matches_last_from_incoming_); - -// std::cout << "Tracked: " << known_features_incoming_.size() << std::endl; + for (auto match : matches_last_from_incoming_) + match.first->setTrackId( match.second->feature_ptr_->trackId() ); // Check/correct incoming-origin correspondences if (origin_ptr_ != nullptr) @@ -53,16 +87,21 @@ unsigned int ProcessorTrackerFeature::processKnown() known_incoming_feature_it++; } } - // Append not destructed incoming features -> this empties known_features_incoming_ + incoming_ptr_->addFeatureList(known_features_incoming_); - std::cout << "Added to incoming features: " << incoming_ptr_->getFeatureList().size() << std::endl; + known_features_incoming_.clear(); + + // Print resulting list of matches + for (auto match : matches_last_from_incoming_) + { + WOLF_DEBUG("Known track: ", match.first->trackId(), ", last: ", match.second->feature_ptr_->id(), ", inc: ", match.first->id()); + } return matches_last_from_incoming_.size(); } -void ProcessorTrackerFeature::advance() +void ProcessorTrackerFeature::advanceDerived() { - // std::cout << "ProcessorTrackerFeature::advance()" << std::endl; // Compose correspondences to get origin_from_incoming for (auto match : matches_last_from_incoming_) { @@ -70,53 +109,32 @@ void ProcessorTrackerFeature::advance() matches_origin_from_last_[matches_last_from_incoming_[match.first]->feature_ptr_]; } matches_origin_from_last_ = std::move(matches_last_from_incoming_); - // std::cout << "advanced correspondences: " << std::endl; - // std::cout << "\tincoming 2 last: " << matches_last_from_incoming_.size() << std::endl; - // std::cout << "\tlast 2 origin: " << std::endl; - // for (auto match : matches_origin_from_last_) - // std::cout << "\t\t" << match.first->getMeasurement() << " to " << match.second.feature_ptr_->getMeasurement() << std::endl; + + // We set problem here because we could not determine Problem from incoming capture at the time of adding the features to incoming's feature list. + for (auto ftr : incoming_ptr_->getFeatureList()) + ftr->setProblem(getProblem()); + + // Print resulting list + for (auto match: matches_origin_from_last_) + { + WOLF_DEBUG("Matches advanced: track: ", match.first->trackId(), "-", match.second->feature_ptr_->trackId(), " origin: ", match.second->feature_ptr_->id(), " last: ", match.first->id()); + } } -void ProcessorTrackerFeature::reset() +void ProcessorTrackerFeature::resetDerived() { - // std::cout << "ProcessorTrackerFeature::reset()" << std::endl; // We also reset here the list of correspondences, which passes from last--incoming to origin--last. matches_origin_from_last_ = std::move(matches_last_from_incoming_); -} - -unsigned int ProcessorTrackerFeature::processNew(const unsigned int& _max_new_features) -{ - // std::cout << "ProcessorTrackerFeature::processNew()" << std::endl; - - /* Rationale: A keyFrame will be created using the last Capture. - * First, we create the constraints from the existing Features in last, - * because the ones that we want to detect later on will not be constrained by anyone yet. - * Then, we work on this last Capture to detect new Features, - * When done, we need to track these new Features to the incoming Capture. - * At the end, all new Features are appended to the lists of known Features in - * the last and incoming Captures. - */ + // Update features according to the move above. + for (auto match: matches_origin_from_last_) + match.first->setProblem(getProblem()); // Since these features were in incoming_, they had no Problem assigned. - // Populate the last Capture with new Features. The result is in new_features_last_. - unsigned int n = detectNewFeatures(_max_new_features); - - // std::cout << "detected " << n << " new features!" << std::endl; - - // Track new features from last to incoming. This will append new correspondences to matches_last_incoming - if (incoming_ptr_ != last_ptr_ && incoming_ptr_ != nullptr) // we do not do it the first time. + // Print resulting list + for (auto match: matches_origin_from_last_) { - trackFeatures(new_features_last_, new_features_incoming_, matches_last_from_incoming_); - - // Append all new Features to the incoming Captures' list of Features - incoming_ptr_->addFeatureList(new_features_incoming_); + WOLF_DEBUG("Matches reset: track: ", match.first->trackId(), "-", match.second->feature_ptr_->trackId(), " origin: ", match.second->feature_ptr_->id(), " last: ", match.first->id()); } - - // Append all new Features to the last Captures' list of Features - last_ptr_->addFeatureList(new_features_last_); - - // return the number of new features detected in \b last - return n; } void ProcessorTrackerFeature::establishConstraints() @@ -127,6 +145,12 @@ void ProcessorTrackerFeature::establishConstraints() match.first->addConstraint(ctr); match.second->feature_ptr_->addConstrainedBy(ctr); } + for (auto match : matches_origin_from_last_) + { + WOLF_DEBUG( "Constraint: track: " , match.second->feature_ptr_->trackId() , + " origin: " , match.second->feature_ptr_->id() , + " from last: " , match.first->id() ); + } } } // namespace wolf diff --git a/src/processor_tracker_feature.h b/src/processor_tracker_feature.h index 7e1d625a56a77ccb4210bed0a85bee99bfeb9d44..82253eefcd6291d9233dc9025de89ecc236a7d6b 100644 --- a/src/processor_tracker_feature.h +++ b/src/processor_tracker_feature.h @@ -128,8 +128,8 @@ class ProcessorTrackerFeature : public ProcessorTracker virtual bool voteForKeyFrame() = 0; // We overload the advance and reset functions to update the lists of matches - void advance(); - void reset(); + void advanceDerived(); + void resetDerived(); /**\brief Process new Features * @@ -137,14 +137,12 @@ class ProcessorTrackerFeature : public ProcessorTracker virtual unsigned int processNew(const unsigned int& _max_features); /** \brief Detect new Features - * \param _capture_ptr Capture for feature detection. Defaults to incoming_ptr_. - * \param _new_features_list The list of detected Features. Defaults to member new_features_list_. + * \param _max_features maximum number of features detected * \return The number of detected Features. * * This function detects Features that do not correspond to known Features/Landmarks in the system. * - * The function sets the member new_features_list_, the list of newly detected features, - * to be used for landmark initialization. + * The function sets the member new_features_last_, the list of newly detected features. */ virtual unsigned int detectNewFeatures(const unsigned int& _max_features) = 0; diff --git a/src/processor_tracker_feature_corner.cpp b/src/processor_tracker_feature_corner.cpp index 9e9ae49f8bfa7fc89b35a61dc4435f3e3e4c6f1d..33e670d69e048bf3ceae06a751656f7866c1de45 100644 --- a/src/processor_tracker_feature_corner.cpp +++ b/src/processor_tracker_feature_corner.cpp @@ -63,9 +63,9 @@ void ProcessorTrackerFeatureCorner::preProcess() t_current_prev_ = R_world_sensor_.transpose() * (t_world_sensor_prev_ - t_world_sensor_); } -void ProcessorTrackerFeatureCorner::advance() +void ProcessorTrackerFeatureCorner::advanceDerived() { - ProcessorTrackerFeature::advance(); + ProcessorTrackerFeature::advanceDerived(); corners_last_ = std::move(corners_incoming_); } diff --git a/src/processor_tracker_feature_corner.h b/src/processor_tracker_feature_corner.h index d80c6572f04e92603a2874880481ce9295a1143e..7fe63a9ef664db4b5f57f5aa8fbd0beef0d3f4d0 100644 --- a/src/processor_tracker_feature_corner.h +++ b/src/processor_tracker_feature_corner.h @@ -72,7 +72,7 @@ class ProcessorTrackerFeatureCorner : public ProcessorTrackerFeature virtual void preProcess(); - void advance(); + void advanceDerived(); /** \brief Track provided features from \b last to \b incoming * \param _feature_list_in input list of features in \b last to track diff --git a/src/processor_tracker_feature_dummy.cpp b/src/processor_tracker_feature_dummy.cpp index 4181a7814339c9effb00e8ce509c1c15196ff45a..c25ac9b4b7024828e34d0548f12c030ee2a0fcb2 100644 --- a/src/processor_tracker_feature_dummy.cpp +++ b/src/processor_tracker_feature_dummy.cpp @@ -11,26 +11,27 @@ namespace wolf { +unsigned int ProcessorTrackerFeatureDummy::count_ = 0; + unsigned int ProcessorTrackerFeatureDummy::trackFeatures(const FeatureBaseList& _feature_list_in, FeatureBaseList& _feature_list_out, FeatureMatchMap& _feature_correspondences) { - std::cout << "tracking " << _feature_list_in.size() << " features..." << std::endl; + WOLF_INFO("tracking " , _feature_list_in.size() , " features..."); - // loosing the track of the first 2 features - auto features_lost = 0; - for (auto feat_in_ptr : _feature_list_in) + for (auto feat_in : _feature_list_in) { - if (features_lost < 2) + if (++count_ % 3 == 2) // lose one every 3 tracks { - features_lost++; - std::cout << "feature " << feat_in_ptr->getMeasurement() << " lost!" << std::endl; + WOLF_INFO("track: " , feat_in->trackId() , " feature: " , feat_in->id() , " lost!"); } else { - _feature_list_out.push_back(std::make_shared<FeatureBase>("POINT IMAGE", feat_in_ptr->getMeasurement(), feat_in_ptr->getMeasurementCovariance())); - _feature_correspondences[_feature_list_out.back()] = std::make_shared<FeatureMatch>(FeatureMatch({feat_in_ptr,0})); - std::cout << "feature " << feat_in_ptr->getMeasurement() << " tracked!" << std::endl; + FeatureBasePtr ftr(std::make_shared<FeatureBase>("POINT IMAGE", feat_in->getMeasurement(), feat_in->getMeasurementCovariance())); + _feature_list_out.push_back(ftr); + _feature_correspondences[_feature_list_out.back()] = std::make_shared<FeatureMatch>(FeatureMatch({feat_in,0})); + + WOLF_INFO("track: " , feat_in->trackId() , " last: " , feat_in->id() , " inc: " , ftr->id() , " !" ); } } @@ -39,26 +40,32 @@ unsigned int ProcessorTrackerFeatureDummy::trackFeatures(const FeatureBaseList& bool ProcessorTrackerFeatureDummy::voteForKeyFrame() { - std::cout << "N features: " << incoming_ptr_->getFeatureList().size() << std::endl; + WOLF_INFO("Nbr. of active feature tracks: " , incoming_ptr_->getFeatureList().size() ); + bool vote = incoming_ptr_->getFeatureList().size() < min_feat_for_keyframe_; - std::cout << (vote ? "Vote ": "Not vote ") << "for KF" << std::endl; + + WOLF_INFO( (vote ? "Vote ": "Do not vote ") , "for KF" ); return incoming_ptr_->getFeatureList().size() < min_feat_for_keyframe_; } unsigned int ProcessorTrackerFeatureDummy::detectNewFeatures(const unsigned int& _max_features) { - std::cout << "Detecting " << _max_features << " new features..." << std::endl; + WOLF_INFO("Detecting " , _max_features , " new features..." ); // detecting new features for (unsigned int i = 1; i <= _max_features; i++) { n_feature_++; - new_features_last_.push_back( - std::make_shared<FeatureBase>("POINT IMAGE", n_feature_* Eigen::Vector1s::Ones(), Eigen::MatrixXs::Ones(1, 1))); - //std::cout << "feature " << new_features_last_.back()->getMeasurement() << " detected!" << std::endl; + FeatureBasePtr ftr(std::make_shared<FeatureBase>("POINT IMAGE", + n_feature_* Eigen::Vector1s::Ones(), + Eigen::MatrixXs::Ones(1, 1))); + new_features_last_.push_back(ftr); + + WOLF_INFO("feature " , ftr->id() , " detected!" ); } - std::cout << new_features_last_.size() << " features detected!" << std::endl; + + WOLF_INFO(new_features_last_.size() , " features detected!"); return new_features_last_.size(); } @@ -66,11 +73,11 @@ unsigned int ProcessorTrackerFeatureDummy::detectNewFeatures(const unsigned int& ConstraintBasePtr ProcessorTrackerFeatureDummy::createConstraint(FeatureBasePtr _feature_ptr, FeatureBasePtr _feature_other_ptr) { - // std::cout << "creating constraint: last feature " << _feature_ptr->getMeasurement() - // << " with origin feature " << _feature_other_ptr->getMeasurement() << std::endl; + WOLF_INFO( "creating constraint: track " , _feature_other_ptr->trackId() , " last feature " , _feature_ptr->id() + , " with origin feature " , _feature_other_ptr->id() ); + auto ctr = std::make_shared<ConstraintEpipolar>(_feature_ptr, _feature_other_ptr, shared_from_this()); - // _feature_ptr->addConstraint(ctr); - // _feature_other_ptr->addConstrainedBy(ctr); + return ctr; } diff --git a/src/processor_tracker_feature_dummy.h b/src/processor_tracker_feature_dummy.h index 1cb423f364a09b7834c171db727594db3f32444f..6fa449695f09a56fa93932dddf4d359e29000369 100644 --- a/src/processor_tracker_feature_dummy.h +++ b/src/processor_tracker_feature_dummy.h @@ -27,6 +27,7 @@ class ProcessorTrackerFeatureDummy : public ProcessorTrackerFeature protected: + static unsigned int count_; unsigned int n_feature_, min_feat_for_keyframe_; // virtual void preProcess() { } diff --git a/src/processor_tracker_landmark.cpp b/src/processor_tracker_landmark.cpp index 86fa4298b34674a4217a64ddd49cf789ecdeb27a..9c06036595520a7c30fb65fcb1b0a91f26310ba3 100644 --- a/src/processor_tracker_landmark.cpp +++ b/src/processor_tracker_landmark.cpp @@ -33,7 +33,7 @@ ProcessorTrackerLandmark::~ProcessorTrackerLandmark() // } } -void ProcessorTrackerLandmark::advance() +void ProcessorTrackerLandmark::advanceDerived() { for (auto match : matches_landmark_from_last_) { @@ -45,7 +45,7 @@ void ProcessorTrackerLandmark::advance() // std::cout << "\t" << match.first->id() << " to " << match.second->landmark_ptr_->id() << std::endl; } -void ProcessorTrackerLandmark::reset() +void ProcessorTrackerLandmark::resetDerived() { //std::cout << "ProcessorTrackerLandmark::reset" << std::endl; for (auto match : matches_landmark_from_last_) diff --git a/src/processor_tracker_landmark.h b/src/processor_tracker_landmark.h index a9fbd87a52c48699bee65320b4f15b1217ac0f95..44db01813ba1002ded7dc1309f10a3bb964164c8 100644 --- a/src/processor_tracker_landmark.h +++ b/src/processor_tracker_landmark.h @@ -120,8 +120,8 @@ class ProcessorTrackerLandmark : public ProcessorTracker virtual bool voteForKeyFrame() = 0; // We overload the advance and reset functions to update the lists of matches - void advance(); - void reset(); + void advanceDerived(); + void resetDerived(); /** \brief Process new Features * diff --git a/src/processor_tracker_landmark_corner.h b/src/processor_tracker_landmark_corner.h index 29f711137aa9ae678b2f917e11650fc9aa118815..734acc5083260b65e1933d897d7fb1214f9ae075 100644 --- a/src/processor_tracker_landmark_corner.h +++ b/src/processor_tracker_landmark_corner.h @@ -96,12 +96,12 @@ class ProcessorTrackerLandmarkCorner : public ProcessorTrackerLandmark virtual void preProcess(); // virtual void postProcess() { } - void advance() + void advanceDerived() { //std::cout << "\tProcessorTrackerLandmarkCorner::advance:" << std::endl; //std::cout << "\t\tcorners_last: " << corners_last_.size() << std::endl; //std::cout << "\t\tcorners_incoming_: " << corners_incoming_.size() << std::endl; - ProcessorTrackerLandmark::advance(); + ProcessorTrackerLandmark::advanceDerived(); while (!corners_last_.empty()) { corners_last_.front()->remove(); @@ -110,12 +110,12 @@ class ProcessorTrackerLandmarkCorner : public ProcessorTrackerLandmark corners_last_ = std::move(corners_incoming_); } - void reset() + void resetDerived() { //std::cout << "\tProcessorTrackerLandmarkCorner::reset:" << std::endl; //std::cout << "\t\tcorners_last: " << corners_last_.size() << std::endl; //std::cout << "\t\tcorners_incoming_: " << corners_incoming_.size() << std::endl; - ProcessorTrackerLandmark::reset(); + ProcessorTrackerLandmark::resetDerived(); corners_last_ = std::move(corners_incoming_); } diff --git a/src/processor_tracker_landmark_polyline.h b/src/processor_tracker_landmark_polyline.h index 11d74666ab0310ae4bfb6158a299fd7b52e1f213..0f5c58045241f922147feaa03e367e0b145546b9 100644 --- a/src/processor_tracker_landmark_polyline.h +++ b/src/processor_tracker_landmark_polyline.h @@ -126,9 +126,9 @@ class ProcessorTrackerLandmarkPolyline : public ProcessorTrackerLandmark void computeTransformations(const TimeStamp& _ts); virtual void postProcess(); - void advance(); + void advanceDerived(); - void reset(); + void resetDerived(); /** \brief Find provided landmarks in the incoming capture * \param _landmark_list_in input list of landmarks to be found in incoming @@ -219,24 +219,24 @@ inline unsigned int ProcessorTrackerLandmarkPolyline::detectNewFeatures(const un return new_features_last_.size(); } -inline void ProcessorTrackerLandmarkPolyline::advance() +inline void ProcessorTrackerLandmarkPolyline::advanceDerived() { //std::cout << "\tProcessorTrackerLandmarkPolyline::advance:" << std::endl; //std::cout << "\t\tcorners_last: " << polylines_last_.size() << std::endl; //std::cout << "\t\tcorners_incoming_: " << polylines_incoming_.size() << std::endl; - ProcessorTrackerLandmark::advance(); + ProcessorTrackerLandmark::advanceDerived(); for (auto polyline : polylines_last_) polyline->remove(); polylines_last_ = std::move(polylines_incoming_); //std::cout << "advanced" << std::endl; } -inline void ProcessorTrackerLandmarkPolyline::reset() +inline void ProcessorTrackerLandmarkPolyline::resetDerived() { //std::cout << "\tProcessorTrackerLandmarkPolyline::reset:" << std::endl; //std::cout << "\t\tcorners_last: " << corners_last_.size() << std::endl; //std::cout << "\t\tcorners_incoming_: " << polylines_incoming_.size() << std::endl; - ProcessorTrackerLandmark::reset(); + ProcessorTrackerLandmark::resetDerived(); polylines_last_ = std::move(polylines_incoming_); } diff --git a/src/processors/processor_diff_drive.cpp b/src/processors/processor_diff_drive.cpp index 83a16f77ac838af7bf943b223e4cfdaf71111677..43eb7fed018937d7eae6228e92b5bc1a4558fc6a 100644 --- a/src/processors/processor_diff_drive.cpp +++ b/src/processors/processor_diff_drive.cpp @@ -242,10 +242,10 @@ FeatureBasePtr ProcessorDiffDrive::createFeature(CaptureMotionPtr _capture_motio return key_feature_ptr; } -bool ProcessorDiffDrive::keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tol) -{ - return ProcessorMotion::keyFrameCallback(_keyframe_ptr, _time_tol); -} +//bool ProcessorDiffDrive::keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tol) +//{ +// return ProcessorMotion::keyFrameCallback(_keyframe_ptr, _time_tol); +//} ProcessorBasePtr ProcessorDiffDrive::create(const std::string& _unique_name, const ProcessorParamsBasePtr _params, diff --git a/src/processors/processor_diff_drive.h b/src/processors/processor_diff_drive.h index 064725fdfa025a7625498daac699c5c52b6bfc82..030cb9516036bfbae7fd22c2a79073c3a3400146 100644 --- a/src/processors/processor_diff_drive.h +++ b/src/processors/processor_diff_drive.h @@ -110,7 +110,7 @@ protected: virtual FeatureBasePtr createFeature(CaptureMotionPtr _capture_motion) override; - bool keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tol) override; +// bool keyFrameCallback(FrameBasePtr _keyframe_ptr, const Scalar& _time_tol) override; public: diff --git a/src/sensor_base.cpp b/src/sensor_base.cpp index 4887a088ca3b0ff55249682597f81109d5fb4bf2..83578afef1d86452eeac5473b397ae87403617b4 100644 --- a/src/sensor_base.cpp +++ b/src/sensor_base.cpp @@ -218,6 +218,23 @@ void SensorBase::setNoiseCov(const Eigen::MatrixXs& _noise_cov) { noise_cov_ = _noise_cov; } +CaptureBasePtr SensorBase::lastCapture(void) +{ + // we search for the most recent Capture of this sensor + CaptureBasePtr capture = nullptr; + FrameBaseList frame_list = getProblem()->getTrajectoryPtr()->getFrameList(); + FrameBaseRevIter frame_rev_it = frame_list.rbegin(); + while (frame_rev_it != frame_list.rend()) + { + CaptureBasePtr capture = (*frame_rev_it)->getCaptureOf(shared_from_this()); + if (capture) + // found the most recent Capture made by this sensor ! + break; + frame_rev_it++; + } + return capture; +} + CaptureBasePtr SensorBase::lastCapture(const TimeStamp& _ts) { // we search for the most recent Capture of this sensor before _ts @@ -232,9 +249,8 @@ CaptureBasePtr SensorBase::lastCapture(const TimeStamp& _ts) if (capture) // found the most recent Capture made by this sensor ! break; - - frame_rev_it++; } + frame_rev_it++; } return capture; } @@ -256,44 +272,17 @@ StateBlockPtr SensorBase::getIntrinsicPtr(const TimeStamp _ts) StateBlockPtr SensorBase::getPPtr() { - ProblemPtr P = getProblem(); - if (P) - { - FrameBasePtr KF = P->getLastKeyFramePtr(); - if (KF) - { - return getPPtr(KF->getTimeStamp()); - } - } - return state_block_vec_[0]; + return getStateBlockPtrDynamic(0); } StateBlockPtr SensorBase::getOPtr() { - ProblemPtr P = getProblem(); - if (P) - { - FrameBasePtr KF = P->getLastKeyFramePtr(); - if (KF) - { - return getOPtr(KF->getTimeStamp()); - } - } - return state_block_vec_[1]; + return getStateBlockPtrDynamic(1); } StateBlockPtr SensorBase::getIntrinsicPtr() { - ProblemPtr P = getProblem(); - if (P) - { - FrameBasePtr KF = P->getLastKeyFramePtr(); - if (KF) - { - return getIntrinsicPtr(KF->getTimeStamp()); - } - } - return state_block_vec_[2]; + return getStateBlockPtrDynamic(2); } wolf::Size SensorBase::computeCalibSize() const @@ -347,30 +336,32 @@ ProcessorBasePtr SensorBase::addProcessor(ProcessorBasePtr _proc_ptr) return _proc_ptr; } -StateBlockPtr SensorBase::getStateBlockPtrDynamic(unsigned int _i, const TimeStamp& _ts) +StateBlockPtr SensorBase::getStateBlockPtrDynamic(unsigned int _i) { - assert(_i < state_block_vec_.size() && "Requested a state block pointer out of the vector range!"); - if (((_i < 2) && extrinsicsInCaptures()) || ((_i >= 2) && intrinsicsInCaptures())) + if ((_i<2 && this->extrinsicsInCaptures()) || (_i>=2 && intrinsicsInCaptures())) { - CaptureBasePtr cap = lastCapture(_ts); - return cap->getStateBlockPtr(_i); + CaptureBasePtr cap = lastCapture(); + if (cap) + return cap->getStateBlockPtr(_i); + else + return getStateBlockPtrStatic(_i); } else - return state_block_vec_[_i]; + return getStateBlockPtrStatic(_i); } -StateBlockPtr SensorBase::getStateBlockPtrAuto(unsigned int _i) +StateBlockPtr SensorBase::getStateBlockPtrDynamic(unsigned int _i, const TimeStamp& _ts) { - ProblemPtr P = getProblem(); - if (P) + if ((_i<2 && this->extrinsicsInCaptures()) || (_i>=2 && intrinsicsInCaptures())) { - FrameBasePtr KF = P->getLastKeyFramePtr(); - if (KF) - { - return getStateBlockPtrDynamic(_i, KF->getTimeStamp()); - } + CaptureBasePtr cap = lastCapture(_ts); + if (cap) + return cap->getStateBlockPtr(_i); + else + return getStateBlockPtrStatic(_i); } - return state_block_vec_[_i]; + else + return getStateBlockPtrStatic(_i); } } // namespace wolf diff --git a/src/sensor_base.h b/src/sensor_base.h index ba16f298480705f209e9ceda483854e946e630cf..8c6b6c168d96023e12f80f819bd467aa1aa7217a 100644 --- a/src/sensor_base.h +++ b/src/sensor_base.h @@ -102,6 +102,7 @@ class SensorBase : public NodeBase, public std::enable_shared_from_this<SensorBa ProcessorBasePtr addProcessor(ProcessorBasePtr _proc_ptr); ProcessorBaseList& getProcessorList(); + CaptureBasePtr lastCapture(void); CaptureBasePtr lastCapture(const TimeStamp& _ts); bool process(const CaptureBasePtr capture_ptr); @@ -110,8 +111,8 @@ class SensorBase : public NodeBase, public std::enable_shared_from_this<SensorBa const std::vector<StateBlockPtr>& getStateBlockVec() const; std::vector<StateBlockPtr>& getStateBlockVec(); StateBlockPtr getStateBlockPtrStatic(unsigned int _i) const; + StateBlockPtr getStateBlockPtrDynamic(unsigned int _i); StateBlockPtr getStateBlockPtrDynamic(unsigned int _i, const TimeStamp& _ts); - StateBlockPtr getStateBlockPtrAuto(unsigned int _i); void setStateBlockPtrStatic(unsigned int _i, const StateBlockPtr _sb_ptr); void resizeStateBlockVec(int _size); diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 738bccd2056638606f1d1a69a94e6978f49f4756..27f02386aaa0f0a9489573f33b7b34a457882546 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -64,6 +64,10 @@ target_link_libraries(gtest_frame_base ${PROJECT_NAME}) wolf_add_gtest(gtest_imu_tools gtest_imu_tools.cpp) # target_link_libraries(gtest_imu_tools ${PROJECT_NAME}) // WOLF library not needed +# IMU tools test +wolf_add_gtest(gtest_KF_pack_buffer gtest_KF_pack_buffer.cpp) +target_link_libraries(gtest_KF_pack_buffer ${PROJECT_NAME}) + # LocalParametrizationXxx classes test wolf_add_gtest(gtest_local_param gtest_local_param.cpp) target_link_libraries(gtest_local_param ${PROJECT_NAME}) @@ -76,6 +80,10 @@ target_link_libraries(gtest_motion_buffer ${PROJECT_NAME}) wolf_add_gtest(gtest_problem gtest_problem.cpp) target_link_libraries(gtest_problem ${PROJECT_NAME}) +# ProcessorBase class test +wolf_add_gtest(gtest_processor_base gtest_processor_base.cpp) +target_link_libraries(gtest_processor_base ${PROJECT_NAME}) + # ProcessorMotion class test wolf_add_gtest(gtest_processor_motion gtest_processor_motion.cpp) target_link_libraries(gtest_processor_motion ${PROJECT_NAME}) diff --git a/src/test/gtest_IMU.cpp b/src/test/gtest_IMU.cpp index 05eb3b5b564ff51bf77f7676478e88fdd914f41f..d126a7a23f659587939472b5201f35f018375f96 100644 --- a/src/test/gtest_IMU.cpp +++ b/src/test/gtest_IMU.cpp @@ -95,6 +95,9 @@ class Process_Constraint_IMU : public testing::Test sensor_imu = static_pointer_cast<SensorIMU> (sensor); processor_imu = static_pointer_cast<ProcessorIMU>(processor); + dt = 0.01; + processor_imu->setTimeTolerance(dt/2); + // Some initializations bias_null .setZero(); x0 .resize(10); @@ -277,7 +280,7 @@ class Process_Constraint_IMU : public testing::Test DT = num_integrations * dt; // wolf objects - KF_0 = problem->setPrior(x0, P0, t0); + KF_0 = problem->setPrior(x0, P0, t0, dt/2); C_0 = processor_imu->getOriginPtr(); processor_imu->getLastPtr()->setCalibrationPreint(bias_preint); @@ -374,7 +377,14 @@ class Process_Constraint_IMU : public testing::Test FrameBasePtr KF = problem->emplaceFrame(KEY_FRAME, x1_exact, t); // ===================================== IMU CALLBACK - processor_imu->keyFrameCallback(KF, 0.01); + processor_imu->keyFrameCallback(KF, dt/2); + + + + + data = Vector6s::Zero(); + capture_imu = make_shared<CaptureIMU>(t+dt, sensor_imu, data, sensor_imu->getNoiseCov()); + processor_imu->process(capture_imu); KF_1 = problem->getLastKeyFramePtr(); C_1 = KF_1->getCaptureList().front(); // front is IMU @@ -483,6 +493,7 @@ class Process_Constraint_IMU_ODO : public Process_Constraint_IMU // Wolf objects SensorOdom3DPtr sensor_odo; ProcessorOdom3DPtr processor_odo; + CaptureOdom3DPtr capture_odo; virtual void SetUp( ) override { @@ -497,6 +508,7 @@ class Process_Constraint_IMU_ODO : public Process_Constraint_IMU ProcessorBasePtr processor = problem->installProcessor("ODOM 3D", "Odometer", "Odometer" , wolf_root + "/src/examples/processor_odom_3D.yaml"); sensor_odo = static_pointer_cast<SensorOdom3D>(sensor); processor_odo = static_pointer_cast<ProcessorOdom3D>(processor); + processor_odo->setTimeTolerance(dt/2); // prevent this processor from voting by setting high thresholds : processor_odo->setAngleTurned(2.0); @@ -530,6 +542,11 @@ class Process_Constraint_IMU_ODO : public Process_Constraint_IMU // ===================================== ODO processor_odo->keyFrameCallback(KF_1, 0.1); + + data = Vector6s::Zero(); + capture_odo = make_shared<CaptureOdom3D>(t+dt, sensor_odo, data, sensor_odo->getNoiseCov()); + processor_odo->process(capture_odo); + } }; @@ -543,7 +560,6 @@ TEST_F(Process_Constraint_IMU, MotionConstant_PQV_b__PQV_b) // F_ixed___e_stimat // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -589,7 +605,6 @@ TEST_F(Process_Constraint_IMU, test_capture) // F_ixed___e_stimated // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -638,7 +653,6 @@ TEST_F(Process_Constraint_IMU, MotionConstant_pqv_b__PQV_b) // F_ixed___e_stimat // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -685,7 +699,6 @@ TEST_F(Process_Constraint_IMU, MotionConstant_pqV_b__PQv_b) // F_ixed___e_stimat // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -732,7 +745,6 @@ TEST_F(Process_Constraint_IMU, MotionRandom_PQV_b__PQV_b) // F_ixed___e_stimated // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -779,7 +791,6 @@ TEST_F(Process_Constraint_IMU, MotionRandom_pqV_b__PQv_b) // F_ixed___e_stimated // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -825,7 +836,6 @@ TEST_F(Process_Constraint_IMU, MotionRandom_pqV_b__pQV_b) // F_ixed___e_stimated // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -871,7 +881,6 @@ TEST_F(Process_Constraint_IMU, MotionConstant_NonNullState_PQV_b__PQV_b) // F_ix // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -917,7 +926,6 @@ TEST_F(Process_Constraint_IMU_ODO, MotionConstantRotation_PQV_b__PQV_b) // F_ixe // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -963,7 +971,6 @@ TEST_F(Process_Constraint_IMU_ODO, MotionConstantRotation_PQV_b__PQv_b) // F_ixe // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -1009,7 +1016,6 @@ TEST_F(Process_Constraint_IMU_ODO, MotionConstantRotation_PQV_b__Pqv_b) // F_ixe // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -1040,7 +1046,7 @@ TEST_F(Process_Constraint_IMU_ODO, MotionConstantRotation_PQV_b__Pqv_b) // F_ixe // ===================================== RUN ALL string report = runAll(1); - // printAll(report); + // printAll(report); assertAll(); @@ -1055,7 +1061,6 @@ TEST_F(Process_Constraint_IMU_ODO, MotionConstantRotation_PQV_b__pQv_b) // F_ixe // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -1101,7 +1106,6 @@ TEST_F(Process_Constraint_IMU_ODO, MotionConstantRotation_PQV_b__pqv_b) // F_ixe // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -1147,7 +1151,6 @@ TEST_F(Process_Constraint_IMU_ODO, MotionConstant_pqv_b__pqV_b) // F_ixed___e_st // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -1193,7 +1196,6 @@ TEST_F(Process_Constraint_IMU_ODO, MotionConstant_pqV_b__pqv_b) // F_ixed___e_st // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -1239,7 +1241,6 @@ TEST_F(Process_Constraint_IMU_ODO, MotionRandom_PQV_b__pqv_b) // F_ixed___e_stim // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose @@ -1285,7 +1286,6 @@ TEST_F(Process_Constraint_IMU_ODO, MotionRandom_PqV_b__pqV_b) // F_ixed___e_stim // // ---------- time t0 = 0; - dt = 0.01; num_integrations = 50; // ---------- initial pose diff --git a/src/test/gtest_KF_pack_buffer.cpp b/src/test/gtest_KF_pack_buffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb325fd84be395d3dc5fe7cb0e926e31b71e9973 --- /dev/null +++ b/src/test/gtest_KF_pack_buffer.cpp @@ -0,0 +1,244 @@ +/* + * gtest_KF_pack_buffer.cpp + * + * Created on: Mar 5, 2018 + * Author: jsola + */ +//Wolf +#include "utils_gtest.h" + +#include "processor_odom_2D.h" +#include "sensor_odom_2D.h" + +#include "processor_tracker_feature_dummy.h" +#include "capture_void.h" + +#include "problem.h" + +// STL +#include <iterator> +#include <iostream> + +using namespace wolf; +using namespace Eigen; + +class KFPackBufferTest : public testing::Test +{ + public: + + KFPackBuffer kfpackbuffer; + FrameBasePtr f10, f20, f21, f28; + Scalar tt10, tt20, tt21, tt28; + TimeStamp timestamp; + Scalar timetolerance; + + void SetUp(void) + { + f10 = std::make_shared<FrameBase>(TimeStamp(10),nullptr,nullptr,nullptr); + f20 = std::make_shared<FrameBase>(TimeStamp(20),nullptr,nullptr,nullptr); + f21 = std::make_shared<FrameBase>(TimeStamp(21),nullptr,nullptr,nullptr); + f28 = std::make_shared<FrameBase>(TimeStamp(28),nullptr,nullptr,nullptr); + + tt10 = 1.0; + tt20 = 1.0; + tt21 = 1.0; + tt28 = 1.0; + }; +}; + +TEST_F(KFPackBufferTest, empty) +{ + ASSERT_TRUE(kfpackbuffer.empty()); +} + +TEST_F(KFPackBufferTest, add) +{ + kfpackbuffer.add(f10, tt10); + ASSERT_EQ(kfpackbuffer.size(),1); + kfpackbuffer.add(f20, tt20); + ASSERT_EQ(kfpackbuffer.size(),2); +} + +TEST_F(KFPackBufferTest, clear) +{ + kfpackbuffer.add(f10, tt10); + kfpackbuffer.add(f20, tt20); + ASSERT_EQ(kfpackbuffer.size(),2); + kfpackbuffer.clear(); + ASSERT_TRUE(kfpackbuffer.empty()); +} + +//TEST_F(KFPackBufferTest, print) +//{ +// kfpackbuffer.clear(); +// kfpackbuffer.add(f10, tt10); +// kfpackbuffer.add(f20, tt20); +// kfpackbuffer.print(); +//} + +TEST_F(KFPackBufferTest, checkTimeTolerance) +{ + kfpackbuffer.clear(); + kfpackbuffer.add(f10, tt10); + kfpackbuffer.add(f20, tt20); + // min time tolerance > diff between time stamps. It should return true + ASSERT_TRUE(kfpackbuffer.checkTimeTolerance(10, 20, 20, 20)); + // min time tolerance < diff between time stamps. It should return true + ASSERT_FALSE(kfpackbuffer.checkTimeTolerance(10, 1, 20, 20)); +} + +TEST_F(KFPackBufferTest, selectPack) +{ + // Evaluation using two packs (p1,p2) + // with different time tolerances (tp1,tp2) + // using a query pack (q) with also different time tolerances + // depending on these tolerances we will get one (p1) or the other (p2) + // packages from the buffer (res). + // This can be summarized in the table hereafter: + // + // p1 p2 q | resulting pack time stamp + // -------------------------------- + // 2 2 2 | nullptr + // 2 2 5 | nullptr + // 2 2 7 | nullptr + // 2 7 2 | nullptr + // 2 7 5 | 20 + // 2 7 7 | 20 + // 7 2 2 | nullptr + // 7 2 5 | nullptr + // 7 2 7 | 10 + // 7 7 2 | nullptr + // 7 7 5 | 20 + // 7 7 7 | 20 + + kfpackbuffer.clear(); + + // input packages + std::vector<int> p1 = {2, 7}; // Pack 1 time tolerances + std::vector<int> p2 = {2, 7}; // Pack 2 time tolerances + std::vector<int> q = {2, 5, 7}; // Query pack time tolerances + + // Solution matrix + Eigen::VectorXi res = Eigen::VectorXi::Zero(12); + res(4) = 20; + res(5) = 20; + res(8) = 10; + res(10) = 20; + res(11) = 20; + + // test + for (auto ip1=0;ip1<p1.size();++ip1) + { + for (auto ip2=0;ip2<p2.size();++ip2) + { + kfpackbuffer.add(f10, p1[ip1]); + kfpackbuffer.add(f20, p2[ip2]); + for (auto iq=0;iq<q.size();++iq) + { + KFPackPtr packQ = kfpackbuffer.selectPack(16, q[iq]); + if (packQ!=nullptr) + ASSERT_EQ(packQ->key_frame->getTimeStamp(),res(ip1*6+ip2*3+iq)); + } + kfpackbuffer.clear(); + } + } +} + +TEST_F(KFPackBufferTest, selectPackBefore) +{ + kfpackbuffer.clear(); + + kfpackbuffer.add(f10, tt10); + kfpackbuffer.add(f20, tt20); + kfpackbuffer.add(f21, tt21); + + // input time stamps + std::vector<TimeStamp> q_ts = {9.5, 9.995, 10.005, 19.5, 20.5, 21.5}; + Scalar tt = 0.01; + + // Solution matrix + // q_ts | pack + //================= + // first time + //----------------- + // 9.5 nullptr + // 9.995 10 + // 10,005 10 + // 19.5 10 + // 20.5 10 + // 21.5 10 + // second time + //----------------- + // 9.5 nullptr + // 9.995 null + // 10,005 null + // 19.5 null + // 20.5 20 + // 21.5 20 + // third time + //----------------- + // 9.5 nullptr + // 9.995 null + // 10,005 null + // 19.5 null + // 20.5 null + // 21.5 21 + + Eigen::MatrixXs truth(3,6), res(3,6); + truth << 0,10,10,10,10,10, 0,0,0,0,20,20, 0,0,0,0,0,21; + res.setZero(); + + for (int i=0; i<3; i++) + { + KFPackPtr packQ; + int j = 0; + for (auto ts : q_ts) + { + packQ = kfpackbuffer.selectPackBefore(ts, tt); + if (packQ) + res(i,j) = packQ->key_frame->getTimeStamp().get(); + + j++; + } + kfpackbuffer.removeUpTo(packQ->key_frame->getTimeStamp()); + } + + ASSERT_MATRIX_APPROX(res, truth, 1e-6); +} + +TEST_F(KFPackBufferTest, removeUpTo) +{ + // Small time tolerance for all test asserts + Scalar tt = 0.1; + kfpackbuffer.clear(); + kfpackbuffer.add(f10, tt10); + kfpackbuffer.add(f20, tt20); + kfpackbuffer.add(f21, tt21); + + // it should remove f20 and f10, thus size should be 1 after removal + // Specifically, only f21 should remain + KFPackPtr pack20 = std::make_shared<KFPack>(f20,tt20); + kfpackbuffer.removeUpTo( pack20->key_frame->getTimeStamp() ); + ASSERT_EQ(kfpackbuffer.size(),1); + ASSERT_TRUE(kfpackbuffer.selectPack(f10->getTimeStamp(),tt)==nullptr); + ASSERT_TRUE(kfpackbuffer.selectPack(f20->getTimeStamp(),tt)==nullptr); + ASSERT_TRUE(kfpackbuffer.selectPack(f21->getTimeStamp(),tt)!=nullptr); + + // Chech removal of an imprecise time stamp + // Specifically, only f28 should remain + kfpackbuffer.add(f28, tt28); + ASSERT_EQ(kfpackbuffer.size(),2); + FrameBasePtr f22 = std::make_shared<FrameBase>(TimeStamp(22),nullptr,nullptr,nullptr); + KFPackPtr pack22 = std::make_shared<KFPack>(f22,5); + kfpackbuffer.removeUpTo( pack22->key_frame->getTimeStamp() ); + ASSERT_EQ(kfpackbuffer.size(),1); + ASSERT_TRUE(kfpackbuffer.selectPack(f21->getTimeStamp(),tt)==nullptr); + ASSERT_TRUE(kfpackbuffer.selectPack(f28->getTimeStamp(),tt)!=nullptr); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/src/test/gtest_feature_imu.cpp b/src/test/gtest_feature_imu.cpp index bf0956ac15fbeb34f65fbcd227d88382637a7093..6609f97080de513b1d01ee73f749ff1685490332 100644 --- a/src/test/gtest_feature_imu.cpp +++ b/src/test/gtest_feature_imu.cpp @@ -52,12 +52,13 @@ class FeatureIMU_test : public testing::Test // Set the origin Eigen::VectorXs x0(10); x0 << 0,0,0, 0,0,0,1, 0,0,0; - origin_frame = problem->getProcessorMotionPtr()->setOrigin(x0, t); //create a keyframe at origin + MatrixXs P0; P0.setIdentity(9,9); + origin_frame = problem->setPrior(x0, P0, 0.0, 0.01); // Create one capture to store the IMU data arriving from (sensor / callback / file / etc.) // give the capture a big covariance, otherwise it will be so small that it won't pass following assertions imu_ptr = std::make_shared<CaptureIMU>(t, sensor_ptr, data_, Eigen::Matrix6s::Identity(), Eigen::Vector6s::Zero()); - imu_ptr->setFramePtr(origin_frame); //to get ptr to Frm ni processorIMU and then get biases + imu_ptr->setFramePtr(origin_frame); //to get ptr to Frm in processorIMU and then get biases //process data data_ << 2, 0, 9.8, 0, 0, 0; diff --git a/src/test/gtest_feature_motion.cpp b/src/test/gtest_feature_motion.cpp deleted file mode 100644 index 1620131a6dd4b2b8957c783e5693bab3c4e07f04..0000000000000000000000000000000000000000 --- a/src/test/gtest_feature_motion.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * gtest_feature_motion.cpp - * - * Created on: Aug 11, 2017 - * Author: jsola - */ - -#include "utils_gtest.h" - -#include "/Users/jsola/dev/wolf/src/feature_motion.h" - -namespace wolf -{ - -TEST(DummyGroup, DummyTestExample) -{ - // TODO: Automatically generated TEST stub -} - -int main(int argc, char **argv) -{ - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -} /* namespace wolf */ diff --git a/src/test/gtest_odom_2D.cpp b/src/test/gtest_odom_2D.cpp index 76bd0e6db0a116bdf304bf23fcbc5dbc8c976f9a..bd101f24074cf8fc426a8551bcce85e1bd94e97a 100644 --- a/src/test/gtest_odom_2D.cpp +++ b/src/test/gtest_odom_2D.cpp @@ -127,7 +127,7 @@ TEST(Odom2D, ConstraintFix_and_ConstraintOdom2D) CeresManager ceres_manager(Pr); // KF0 and absolute prior - FrameBasePtr F0 = Pr->setPrior(x0, P0,t0); + FrameBasePtr F0 = Pr->setPrior(x0, P0,t0, dt/2); // KF1 and motion from KF0 t += dt; @@ -210,7 +210,7 @@ TEST(Odom2D, VoteForKfAndSolve) CeresManager ceres_manager(problem); // Origin Key Frame - FrameBasePtr origin_frame = problem->setPrior(x0, P0, t0); + FrameBasePtr origin_frame = problem->setPrior(x0, P0, t0, dt/2); ceres_manager.solve(0); ceres_manager.computeCovariances(ALL_MARGINALS); @@ -322,12 +322,13 @@ TEST(Odom2D, KF_callback) Matrix3s unmeasured_cov = params->unmeasured_perturbation_std_*params->unmeasured_perturbation_std_*Matrix3s::Identity(); ProcessorBasePtr prc_base = problem->installProcessor("ODOM 2D", "odom", sensor_odom2d, params); ProcessorOdom2DPtr processor_odom2d = std::static_pointer_cast<ProcessorOdom2D>(prc_base); + processor_odom2d->setTimeTolerance(dt/2); // Ceres wrapper CeresManager ceres_manager(problem); // Origin Key Frame - FrameBasePtr keyframe_0 = problem->setPrior(x0, x0_cov, t0); + FrameBasePtr keyframe_0 = problem->setPrior(x0, x0_cov, t0, dt/2); // Check covariance values Eigen::Vector3s integrated_pose = x0; @@ -390,7 +391,11 @@ TEST(Odom2D, KF_callback) FrameBasePtr keyframe_2 = problem->emplaceFrame(KEY_FRAME, x_split, t_split); ASSERT_TRUE(problem->check(0)); - processor_odom2d->keyFrameCallback(keyframe_2, 0); + processor_odom2d->keyFrameCallback(keyframe_2, dt/2); + ASSERT_TRUE(problem->check(0)); + t += dt; + capture->setTimeStamp(t); + processor_odom2d->process(capture); ASSERT_TRUE(problem->check(0)); CaptureMotionPtr key_capture_n = std::static_pointer_cast<CaptureMotion>(keyframe_2->getCaptureList().front()); @@ -402,7 +407,7 @@ TEST(Odom2D, KF_callback) ceres_manager.computeCovariances(ALL_MARGINALS); ASSERT_POSE2D_APPROX(problem->getLastKeyFramePtr()->getState() , integrated_pose_vector[n_split], 1e-6); - ASSERT_MATRIX_APPROX(problem->getLastKeyFrameCovariance() , integrated_cov_vector [n_split], 1e-6); + ASSERT_MATRIX_APPROX(problem->getLastKeyFrameCovariance() , integrated_cov_vector [n_split], 1e-6); //////////////////////////////////////////////////////////////// // Split between keyframes, exact timestamp @@ -410,11 +415,17 @@ TEST(Odom2D, KF_callback) t_split = t0 + m_split*dt; // std::cout << "-----------------------------\nSplit between KFs; time: " << t_split - t0 << std::endl; + problem->print(4,1,1,1); + x_split = processor_odom2d->getState(t_split); FrameBasePtr keyframe_1 = problem->emplaceFrame(KEY_FRAME, x_split, t_split); ASSERT_TRUE(problem->check(0)); - processor_odom2d->keyFrameCallback(keyframe_1, 0); + processor_odom2d->keyFrameCallback(keyframe_1, dt/2); + ASSERT_TRUE(problem->check(0)); + t += dt; + capture->setTimeStamp(t); + processor_odom2d->process(capture); ASSERT_TRUE(problem->check(0)); CaptureMotionPtr key_capture_m = std::static_pointer_cast<CaptureMotion>(keyframe_1->getCaptureList().front()); @@ -427,7 +438,6 @@ TEST(Odom2D, KF_callback) keyframe_2->setState(Vector3s(3,1,2)); report = ceres_manager.solve(1); -// std::cout << report << std::endl; ceres_manager.computeCovariances(ALL_MARGINALS); // check the split KF diff --git a/src/test/gtest_problem.cpp b/src/test/gtest_problem.cpp index d2b0ef0152083a7fac41377d376e502745fd5451..0bbcf9d1872735c5bf6b41aa29405b255f7dd7eb 100644 --- a/src/test/gtest_problem.cpp +++ b/src/test/gtest_problem.cpp @@ -103,7 +103,7 @@ TEST(Problem, SetOrigin_PO_2D) Eigen::VectorXs x0(3); x0 << 1,2,3; Eigen::MatrixXs P0(3,3); P0.setIdentity(); P0 *= 0.1; // P0 is 0.1*Id - P->setPrior(x0, P0, t0); + P->setPrior(x0, P0, t0, 1.0); // check that no sensor has been added ASSERT_EQ(P->getHardwarePtr()->getSensorList().size(), 0); @@ -142,7 +142,7 @@ TEST(Problem, SetOrigin_PO_3D) Eigen::VectorXs x0(7); x0 << 1,2,3,4,5,6,7; Eigen::MatrixXs P0(6,6); P0.setIdentity(); P0 *= 0.1; // P0 is 0.1*Id - P->setPrior(x0, P0, t0); + P->setPrior(x0, P0, t0, 1.0); // check that no sensor has been added ASSERT_EQ(P->getHardwarePtr()->getSensorList().size(), 0); diff --git a/src/test/gtest_processor_base.cpp b/src/test/gtest_processor_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce31eeed39d927a660b33e249c76981c5c0bef50 --- /dev/null +++ b/src/test/gtest_processor_base.cpp @@ -0,0 +1,98 @@ +/* + * gtest_capture_base.cpp + * + * Created on: Feb 15, 2018 + * Author: asantamaria + */ + +//Wolf +#include "utils_gtest.h" + +#include "processor_odom_2D.h" +#include "sensor_odom_2D.h" + +#include "processor_tracker_feature_dummy.h" +#include "capture_void.h" + +#include "problem.h" + +// STL +#include <iterator> +#include <iostream> + +using namespace wolf; +using namespace Eigen; + + +TEST(ProcessorBase, KeyFrameCallback) +{ + + using namespace wolf; + using std::shared_ptr; + using std::make_shared; + using std::static_pointer_cast; + using Eigen::Vector2s; + + Scalar dt = 0.01; + + // Wolf problem + ProblemPtr problem = Problem::create("PO 2D"); + + // Install tracker (sensor and processor) + SensorBasePtr sens_trk = make_shared<SensorBase>("FEATURE", std::make_shared<StateBlock>(Eigen::VectorXs::Zero(2)), + std::make_shared<StateBlock>(Eigen::VectorXs::Zero(1)), + std::make_shared<StateBlock>(Eigen::VectorXs::Zero(2)), 2); + shared_ptr<ProcessorTrackerFeatureDummy> proc_trk = make_shared<ProcessorTrackerFeatureDummy>(5, 5); + proc_trk->setTimeTolerance(dt/2); + + problem->addSensor(sens_trk); + sens_trk->addProcessor(proc_trk); + + // Install odometer (sensor and processor) + SensorBasePtr sens_odo = problem->installSensor("ODOM 2D", "odometer", Vector3s(0,0,0), ""); + ProcessorParamsOdom2DPtr proc_odo_params = make_shared<ProcessorParamsOdom2D>(); + ProcessorBasePtr proc_odo = problem->installProcessor("ODOM 2D", "odometer", sens_odo, proc_odo_params); + proc_odo->setTimeTolerance(dt/2); + + std::cout << "sensor & processor created and added to wolf problem" << std::endl; + + // Sequence to test KeyFrame creations (callback calls) + + // initialize + TimeStamp t(0.0); + Vector3s x(0,0,0); + Matrix3s P = Matrix3s::Identity() * 0.1; + problem->setPrior(x, P, t, dt/2); // KF1 + + CaptureOdom2DPtr capt_odo = make_shared<CaptureOdom2D>(t, sens_odo, Vector2s(0.5,0)); + + // Track + CaptureVoidPtr capt_trk(make_shared<CaptureVoid>(t, sens_trk)); + proc_trk->process(capt_trk); + + for (size_t ii=0; ii<10; ii++ ) + { + // Move + t = t+dt; + WOLF_INFO("----------------------- ts: ", t , " --------------------------"); + + capt_odo->setTimeStamp(t); + proc_odo->process(capt_odo); + + // Track + capt_trk = make_shared<CaptureVoid>(t, sens_trk); + proc_trk->process(capt_trk); + +// problem->print(4,1,1,0); + + // Only odom creating KFs + ASSERT_TRUE( problem->getLastKeyFramePtr()->getType().compare("PO 2D")==0 ); + } +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/src/test/gtest_processor_imu.cpp b/src/test/gtest_processor_imu.cpp index e4f0e54c3e3033fab43d0f127a03408caf856e90..a3b57eb668f9285fb7ce619873a107fc0958b4c6 100644 --- a/src/test/gtest_processor_imu.cpp +++ b/src/test/gtest_processor_imu.cpp @@ -29,6 +29,7 @@ class ProcessorIMUt : public testing::Test wolf::SensorBasePtr sensor_ptr; wolf::TimeStamp t; wolf::Scalar mti_clock, tmp; + wolf::Scalar dt; Vector6s data; Matrix6s data_cov; VectorXs x0; @@ -148,7 +149,8 @@ TEST(ProcessorIMU, voteForKeyFrame) VectorXs x0(10); TimeStamp t(0); x0 << 0,0,0, 0,0,0,1, 0,0,0; - problem->getProcessorMotionPtr()->setOrigin(x0, t); //this also creates a keyframe at origin + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); //data variable and covariance matrix // since we integrate only a few times, give the capture a big covariance, otherwise it will be so small that it won't pass following assertions @@ -211,8 +213,8 @@ TEST_F(ProcessorIMUt, interpolate) t.set(0); x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); data << 2, 0, 0, 0, 0, 0; // only acc_x cap_imu_ptr->setData(data); @@ -257,8 +259,8 @@ TEST_F(ProcessorIMUt, acc_x) { t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); data << 2, 0, 9.806, 0, 0, 0; // only acc_x, but measure gravity! @@ -283,8 +285,8 @@ TEST_F(ProcessorIMUt, acc_y) t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); data << 0, 20, 9.806, 0, 0, 0; // only acc_y, but measure gravity! @@ -320,8 +322,8 @@ TEST_F(ProcessorIMUt, acc_z) { t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); data << 0, 0, 9.806 + 2.0, 0, 0, 0; // only acc_z, but measure gravity! @@ -358,8 +360,8 @@ TEST_F(ProcessorIMUt, check_Covariance) { t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); data << 2, 0, 9.806, 0, 0, 0; // only acc_x, but measure gravity! @@ -379,8 +381,8 @@ TEST_F(ProcessorIMUt, gyro_x) wolf::Scalar dt(0.001); t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); wolf::Scalar rate_of_turn = 5 * M_PI/180.0; data << 0, 0, 9.806, rate_of_turn, 0, 0; // measure gravity @@ -430,9 +432,10 @@ TEST_F(ProcessorIMUt, gyro_x_biasedAbx) Vector3s acc_bias = bias.head(3); // state x0 << 0,0,0, 0,0,0,1, 0,0,0; + MatrixXs P0(9,9); P0.setIdentity(); // init things - problem->getProcessorMotionPtr()->setOrigin(x0, t); + problem->setPrior(x0, P0, t, 0.01); std::static_pointer_cast<wolf::CaptureMotion>(problem->getProcessorMotionPtr()->getOriginPtr())->setCalibration(bias); problem->getProcessorMotionPtr()->getLastPtr()->setCalibrationPreint(bias); @@ -484,10 +487,12 @@ TEST_F(ProcessorIMUt, gyro_xy_biasedAbxy) t.set(0); // clock in 0,1 ms ticks wolf::Scalar abx(0.002), aby(0.01); x0 << 0,0,0, 0,0,0,1, 0,0,0; + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); + Vector6s bias; bias << abx,aby,0, 0,0,0; Vector3s acc_bias = bias.head(3); - problem->getProcessorMotionPtr()->setOrigin(x0, t); std::static_pointer_cast<wolf::CaptureMotion>(problem->getProcessorMotionPtr()->getOriginPtr())->setCalibration(bias); problem->getProcessorMotionPtr()->getLastPtr()->setCalibrationPreint(bias); @@ -534,8 +539,8 @@ TEST_F(ProcessorIMUt, gyro_z) wolf::Scalar dt(0.001); t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); wolf::Scalar rate_of_turn = 5 * M_PI/180.0; data << -wolf::gravity(), 0, 0, rate_of_turn; // measure gravity! @@ -572,8 +577,8 @@ TEST_F(ProcessorIMUt, gyro_xyz) { t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); Vector3s tmp_vec; //will be used to store rate of turn data Quaternions quat_comp(Quaternions::Identity()); @@ -659,8 +664,8 @@ TEST_F(ProcessorIMUt, gyro_z_ConstVelocity) wolf::Scalar dt(0.001); t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 2,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); wolf::Scalar rate_of_turn = 5 * M_PI/180.0; data << -wolf::gravity(), 0, 0, rate_of_turn; // measure gravity! @@ -698,8 +703,8 @@ TEST_F(ProcessorIMUt, gyro_x_ConstVelocity) wolf::Scalar dt(0.001); t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 2,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); wolf::Scalar rate_of_turn = 5 * M_PI/180.0; data << 0, 0, 9.806, rate_of_turn, 0, 0; // measure gravity @@ -742,8 +747,8 @@ TEST_F(ProcessorIMUt, gyro_xy_ConstVelocity) wolf::Scalar dt(0.001); t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 2,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); wolf::Scalar rate_of_turn = 5 * M_PI/180.0; data << 0, 0, 9.806, 0, rate_of_turn, 0; // measure gravity @@ -786,8 +791,8 @@ TEST_F(ProcessorIMUt, gyro_y_ConstVelocity) wolf::Scalar dt(0.001); t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 2,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); wolf::Scalar rate_of_turn = 5 * M_PI/180.0; data << 0, 0, 9.806, 0, rate_of_turn, 0; // measure gravity @@ -829,8 +834,8 @@ TEST_F(ProcessorIMUt, gyro_xyz_ConstVelocity) { t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 2,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); Vector3s tmp_vec; //will be used to store rate of turn data Quaternions quat_comp(Quaternions::Identity()); @@ -918,8 +923,8 @@ TEST_F(ProcessorIMUt, gyro_x_acc_x) wolf::Scalar dt(0.001); t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); wolf::Scalar rate_of_turn = 5 * M_PI/180.0; data << 1, 0, -wolf::gravity()(2), rate_of_turn, 0, 0; // measure gravity @@ -967,8 +972,8 @@ TEST_F(ProcessorIMUt, gyro_y_acc_y) wolf::Scalar dt(0.001); t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); wolf::Scalar rate_of_turn = 5 * M_PI/180.0; data << 0, 1, -wolf::gravity()(2), 0, rate_of_turn, 0; // measure gravity @@ -1016,8 +1021,8 @@ TEST_F(ProcessorIMUt, gyro_z_acc_z) wolf::Scalar dt(0.001); t.set(0); // clock in 0,1 ms ticks x0 << 0,0,0, 0,0,0,1, 0,0,0; - - problem->getProcessorMotionPtr()->setOrigin(x0, t); + MatrixXs P0(9,9); P0.setIdentity(); + problem->setPrior(x0, P0, t, 0.01); wolf::Scalar rate_of_turn = 5 * M_PI/180.0; data << 0, 0, -wolf::gravity()(2) + 1, 0, 0, rate_of_turn; // measure gravity diff --git a/src/test/gtest_processor_motion.cpp b/src/test/gtest_processor_motion.cpp index 228570f147419c5a08f1a52429d053beb9f82807..6cd5e06450c0a99ab691c27081db20cd28f92cbd 100644 --- a/src/test/gtest_processor_motion.cpp +++ b/src/test/gtest_processor_motion.cpp @@ -44,7 +44,8 @@ class ProcessorMotion_test : public ProcessorOdom2D, public testing::Test{ capture = std::make_shared<CaptureMotion>(0.0, sensor, data, data_cov, 3, 3, nullptr); Vector3s x0; x0 << 0, 0, 0; - processor->setOrigin(x0, 0.0); + Matrix3s P0; P0.setIdentity(); + problem->setPrior(x0, P0, 0.0, 0.01); } virtual void TearDown(){}