diff --git a/include/laser/processor/processor_odom_icp_3d.h b/include/laser/processor/processor_odom_icp_3d.h index 06da63839a3d7deb90a4d3b5ce50808f3c50b360..655b72090286104dbd03dfa6337fcb555830a1cf 100644 --- a/include/laser/processor/processor_odom_icp_3d.h +++ b/include/laser/processor/processor_odom_icp_3d.h @@ -5,10 +5,9 @@ /************************** * WOLF includes * **************************/ -// #include "laser/processor/params_icp.h" //vsainz: parameters not specified yet -#include "laser/sensor/sensor_laser_3d.h" + #include "laser/capture/capture_laser_3d.h" -#include "laser/utils/laser3d_tools.h" +#include "laser/sensor/sensor_laser_3d.h" #include "core/common/wolf.h" #include "core/processor/processor_tracker.h" @@ -19,11 +18,7 @@ **************************/ #include <pcl/point_types.h> #include <pcl/point_cloud.h> -// #include <pcl/io/pcd_io.h> -// #include <pcl/filters/voxel_grid.h> -// #include <pcl/registration/icp.h> -// #include <pcl/registration/icp_nl.h> -// #include <pcl/registration/transforms.h> +#include <pcl/registration/icp_nl.h> namespace wolf { @@ -38,6 +33,8 @@ struct ParamsProcessorOdomIcp3d : public ParamsProcessorTracker, public ParamsMo { bool pcl_downsample; + int vote_elapsed_time; + int icp_max_iterations; double icp_transformation_translation_epsilon; double icp_transformation_rotation_epsilon; @@ -55,6 +52,8 @@ struct ParamsProcessorOdomIcp3d : public ParamsProcessorTracker, public ParamsMo pcl_downsample = _server.getParam<bool>(prefix + _unique_name + "/pcl_downsample"); + vote_elapsed_time = _server.getParam<int>(prefix + _unique_name + "/vote_elapsed_time"); + icp_max_iterations = _server.getParam<int>(prefix + _unique_name + "/icp_max_iterations"); icp_transformation_translation_epsilon = _server.getParam<double>(prefix + _unique_name + "/icp_transformation_translation_epsilon"); icp_transformation_rotation_epsilon = _server.getParam<double>(prefix + _unique_name + "/icp_transformation_rotation_epsilon"); @@ -87,9 +86,11 @@ class ProcessorOdomIcp3d : public ProcessorTracker, public MotionProvider CaptureLaser3dPtr origin_laser_, last_laser_, incoming_laser_; Eigen::Isometry3d T_origin_last_, T_last_incoming_, T_origin_incoming_, T_robot_sensor_, T_sensor_robot_; - pcl::IterativeClosestPointNonLinear<pcl::PointXYZ, pcl::PointXYZ> registration_solver_; + Eigen::Matrix6d transform_cov_; + + public: ParamsProcessorOdomIcp3dPtr params_odom_icp_; @@ -104,7 +105,6 @@ class ProcessorOdomIcp3d : public ProcessorTracker, public MotionProvider VectorComposite getState(const StateStructure& _structure = "") const override; TimeStamp getTimeStamp() const override; VectorComposite getState(const TimeStamp& _ts, const StateStructure& _structure = "") const override; - void setProblem(ProblemPtr _problem_ptr) override; protected: // API required by ProcessorTracker diff --git a/include/laser/sensor/sensor_laser_3d.h b/include/laser/sensor/sensor_laser_3d.h index 1a16c56076731001e0e410b8887a52c3cec3d795..9f047946ee5ddaa52d40f61ca4d2e620e8c55411 100644 --- a/include/laser/sensor/sensor_laser_3d.h +++ b/include/laser/sensor/sensor_laser_3d.h @@ -19,17 +19,20 @@ struct ParamsSensorLaser3d : public ParamsSensorBase { } ~ParamsSensorLaser3d() override = default; +}; - WOLF_PTR_TYPEDEFS(SensorLaser3d); +WOLF_PTR_TYPEDEFS(SensorLaser3d); - class SensorLaser3d : public SensorBase - { - public: - SensorLaser3d(StateBlockPtr p_ptr, StateBlockPtr _o_ptr); - ~SensorLaser3d(); - }; - - WOLF_SENSOR_CREATE(SensorLaser3d, ParamsSensorLaser3d, 0); +class SensorLaser3d : public SensorBase +{ + public: + SensorLaser3d(StateBlockPtr _p_ptr, StateBlockPtr _o_ptr); + SensorLaser3d(const Eigen::VectorXd& _extrinsics, const std::shared_ptr<ParamsSensorLaser3d> _params); + ~SensorLaser3d(); + ParamsSensorLaser3dPtr params_laser3d_; +}; + +WOLF_SENSOR_CREATE(SensorLaser3d, ParamsSensorLaser3d, 7); } // namespace laser } // namespace wolf diff --git a/include/laser/utils/laser3d_tools.h b/include/laser/utils/laser3d_tools.h index 5c82a908f0b51c75a31ca297f04187ab5172a8dc..c98305ea8c372850babf878c9ffe8f43afcdaa8c 100644 --- a/include/laser/utils/laser3d_tools.h +++ b/include/laser/utils/laser3d_tools.h @@ -1,5 +1,3 @@ - - #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/common/transforms.h> @@ -11,7 +9,6 @@ #include <pcl/registration/icp_nl.h> #include <pcl/registration/transforms.h> - using PointCloud = pcl::PointCloud<pcl::PointXYZ>; typedef boost::shared_ptr<PointCloud> PointCloudBoostPtr; typedef boost::shared_ptr<const PointCloud> PointCloudBoostConstPtr; @@ -20,9 +17,6 @@ namespace wolf { namespace laser { - -// convenient typedefs - // _cloud_ref: first PointCloud // _cloud_otherref: first PointCloud inline void pairAlign(const PointCloudBoostConstPtr _cloud_ref, diff --git a/src/processor/processor_odom_icp_3d.cpp b/src/processor/processor_odom_icp_3d.cpp index d2372ed77d0eb34bdebce23915bdb566df61f4e2..641ecc9cacca8f8f646970096a4d4a3117beb451 100644 --- a/src/processor/processor_odom_icp_3d.cpp +++ b/src/processor/processor_odom_icp_3d.cpp @@ -1,4 +1,6 @@ #include "laser/processor/processor_odom_icp_3d.h" +#include "laser/utils/laser3d_tools.h" +#include "core/factor/factor_relative_pose_3d_with_extrinsics.h" namespace wolf { @@ -17,7 +19,12 @@ ProcessorOdomIcp3d::ProcessorOdomIcp3d(ParamsProcessorOdomIcp3dPtr _params) registration_solver_.setTransformationRotationEpsilon(_params->icp_transformation_rotation_epsilon); registration_solver_.setTransformationEpsilon(_params->icp_transformation_translation_epsilon); registration_solver_.setMaxCorrespondenceDistance(_params->icp_max_correspondence_distance); -} + + params_odom_icp_ = _params; + transform_cov_.setIdentity(); + } + +ProcessorOdomIcp3d::~ProcessorOdomIcp3d() {} void ProcessorOdomIcp3d::configure(SensorBasePtr _sensor) { @@ -34,5 +41,128 @@ void ProcessorOdomIcp3d::preProcess() incoming_laser_ = std::static_pointer_cast<CaptureLaser3d>(incoming_ptr_); } +/** \brief Tracker function + * \return The number of successful tracks. + * + * This is the tracker function to be implemented in derived classes. + * It operates on the \b incoming capture pointed by incoming_ptr_. + * + * This should do one of the following, depending on the design of the tracker -- see use_landmarks_: + * - Track Features against other Features in the \b origin Capture. Tips: + * - An intermediary step of matching against Features in the \b last Capture makes tracking easier. + * - Once tracked against last, then the link to Features in \b origin is provided by the Features' Factors in \b + * last. + * - If required, correct the drift by re-comparing against the Features in origin. + * - The Factors in \b last need to be transferred to \b incoming (moved, not copied). + * - Track Features against Landmarks in the Map. Tips: + * - The links to the Landmarks are in the Features' Factors in last. + * - The Factors in \b last need to be transferred to \b incoming (moved, not copied). + * + * The function must generate the necessary Features in the \b incoming Capture, + * of the correct type, derived from FeatureBase. + * + * It must also generate the factors, of the correct type, derived from FactorBase + * (through FactorAnalytic or FactorSparse). + */ +unsigned int ProcessorOdomIcp3d::processKnown() +{ + pairAlign(origin_laser_->getPointCloud(), + incoming_laser_->getPointCloud(), + T_origin_last_, + T_origin_incoming_, + registration_solver_); + return 0; +}; + +/**\brief Process new Features or Landmarks + * + */ +unsigned int ProcessorOdomIcp3d::processNew(const int& _max_features) +{ + pairAlign(last_laser_->getPointCloud(), + incoming_laser_->getPointCloud(), + Eigen::Isometry3d::Identity(), + T_last_incoming_, + registration_solver_); + return 0; +}; + +/** \brief Vote for KeyFrame generation + * + * If a KeyFrame criterion is validated, this function returns true, + * meaning that it wants to create a KeyFrame at the \b last Capture. + * + * WARNING! This function only votes! It does not create KeyFrames! + */ +bool ProcessorOdomIcp3d::voteForKeyFrame() const +{ + if (incoming_laser_->getTimeStamp() - origin_laser_->getTimeStamp() > params_odom_icp_->vote_elapsed_time) + { + return true; + } + return false; +}; + +/** \brief Advance the incoming Capture to become the last. + * + * Call this when the tracking and keyframe policy work is done and + * we need to get ready to accept a new incoming Capture. + */ +void ProcessorOdomIcp3d::advanceDerived(){ + T_origin_last_ = T_origin_incoming_; + last_laser_ = incoming_laser_; + incoming_laser_ = nullptr; +}; + +/** \brief Reset the tracker using the \b last Capture as the new \b origin. + */ +void ProcessorOdomIcp3d::resetDerived(){ + T_origin_last_ = T_last_incoming_; + origin_laser_ = last_laser_; + last_laser_ = incoming_laser_; + incoming_laser_ = nullptr; +}; + +// Queries to the processor: +TimeStamp ProcessorOdomIcp3d::getTimeStamp() const +{ + return last_laser_->getTimeStamp(); +} + +VectorComposite ProcessorOdomIcp3d::getState(const StateStructure& _structure) const +{ + VectorComposite state_origin = origin_laser_->getFrame()->getState("PO"); + Eigen::Isometry3d T_world_origin_robot = Eigen::Translation3d(state_origin.at('P')) * Eigen::Quaterniond(state_origin.at('O').data()); + Eigen::Isometry3d T_world_last_robot = T_world_origin_robot * T_robot_sensor_ * T_origin_last_ * T_sensor_robot_; + VectorComposite state_last; + state_last.at('P') = T_world_last_robot.translation(); + state_last.at('O') = Eigen::Quaterniond(T_world_last_robot.rotation()).coeffs(); + return state_last; +} + +VectorComposite ProcessorOdomIcp3d::getState(const TimeStamp& _ts, const StateStructure& _structure) const +{ + // TODO get the appropriate capture + return getState(_structure); +} + +/**\brief Creates and adds factors from last_ to origin_ + * + */ +void ProcessorOdomIcp3d::establishFactors() +{ +// emplace a feature of type FeatureMotion undet the capture last_ptr_ or last_laser_ + Eigen::Vector7d measurement_of_motion ; + measurement_of_motion.head(3) = T_origin_last_.translation(); + measurement_of_motion.tail(4) = Eigen::Quaterniond( T_origin_last_.rotation() ).coeffs(); + auto feature = FeatureBase::emplace<FeatureBase>(last_laser_, "FeatureBase", measurement_of_motion, transform_cov_ ); + + auto factor = FactorBase::emplace<FactorRelativePose3dWithExtrinsics>(feature, feature, origin_laser_->getFrame(), shared_from_this(), false , TOP_MOTION); + +// emplace a factor of type FactorRelativePose3dWithExtrinsics under the feature above +// TODO + +}; + } // namespace laser } // namespace wolf \ No newline at end of file diff --git a/src/sensor/sensor_laser_3d.cpp b/src/sensor/sensor_laser_3d.cpp index e70bcd0b4785d421c9b9b4677a3ff6c25ce255bb..dd71f5a18531710e1ee210d8bd8bada7ffba6919 100644 --- a/src/sensor/sensor_laser_3d.cpp +++ b/src/sensor/sensor_laser_3d.cpp @@ -5,9 +5,21 @@ namespace wolf namespace laser { -SensorLaser3d::SensorLaser3d(StateBlockPtr _p_ptr, StateBlockPtr _o_ptr) : -SensorBase("SensorLaser3d", _p_ptr, _o_ptr, nullptr, 0) {} -// vsainz: Parameters should be set somewhere, not yet!! +SensorLaser3d::SensorLaser3d(StateBlockPtr _p_ptr, StateBlockPtr _o_ptr) + : SensorBase("SensorLaser3d", _p_ptr, _o_ptr, nullptr, 0) +{ +} + +SensorLaser3d::SensorLaser3d(const Eigen::VectorXd& _extrinsics, const std::shared_ptr<ParamsSensorLaser3d> _params); +SensorBase("SensorLaser3d", + std::make_shared<StatePoint3d>(_extrinsics.head(3), true), + std::make_shared<StateQuaternion>(_extrinsics.tail(4), true), + nullptr, + 0), + params_laser3d_(_params) +{ + // +} SensorLaser3d::~SensorLaser3d() {}