diff --git a/include/laser/processor/processor_odom_icp_3d.h b/include/laser/processor/processor_odom_icp_3d.h
index bf4ac864099113e28d72e088437b0581a8c195e5..b9b77f457de2aa0188943218b66e5b35aeb7606e 100644
--- a/include/laser/processor/processor_odom_icp_3d.h
+++ b/include/laser/processor/processor_odom_icp_3d.h
@@ -29,6 +29,7 @@
 
 #include "laser/capture/capture_laser_3d.h"
 #include "laser/sensor/sensor_laser_3d.h"
+#include "laser/utils/laser3d_tools.h"
 
 #include "core/common/wolf.h"
 #include "core/processor/processor_tracker.h"
@@ -40,6 +41,7 @@
 #include <pcl/point_types.h>
 #include <pcl/point_cloud.h>
 #include <pcl/registration/icp_nl.h>
+#include <pcl/registration/registration.h>
 
 namespace wolf
 {
@@ -101,7 +103,9 @@ class ProcessorOdomIcp3d : public ProcessorTracker, public MotionProvider
 
     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_;
+    RegistrationPtr registration_solver_;
+
+    // std::shared_ptr<pcl::IterativeClosestPointNonLinear<pcl::PointXYZ, pcl::PointXYZ>> registration_solver_;
 
     Eigen::Matrix6d transform_cov_;
 
diff --git a/include/laser/utils/laser3d_tools.h b/include/laser/utils/laser3d_tools.h
index 9040dd50f124b207e049506803cf8a0a11ceb3e8..47f2cec9be81ed440abff579904bb677d2040bd0 100644
--- a/include/laser/utils/laser3d_tools.h
+++ b/include/laser/utils/laser3d_tools.h
@@ -38,16 +38,22 @@
 // typedef boost::shared_ptr<PointCloud>       PointCloudBoostPtr;
 // typedef boost::shared_ptr<const PointCloud> PointCloudBoostConstPtr;
 
+// typedef std::shared_ptr<pcl::Registration<pcl::PointXYZ, pcl::PointXYZ>> RegistrationPtr;
+
+typedef pcl::Registration<pcl::PointXYZ, pcl::PointXYZ>::Ptr RegistrationPtr;
+
+
 namespace wolf
 {
 // _cloud_ref: first PointCloud
 // _cloud_other: second PointCloud
-inline void pairAlign(const pcl::PointCloud<pcl::PointXYZ>::Ptr                          _cloud_ref,
-                      const pcl::PointCloud<pcl::PointXYZ>::Ptr                          _cloud_other,
-                      const Eigen::Isometry3d                                           &_transform_guess,
-                      Eigen::Isometry3d                                                 &_transform_final,
-                      pcl::IterativeClosestPointNonLinear<pcl::PointXYZ, pcl::PointXYZ> &_registration_solver,
-                      bool                                                               _downsample = false)
+inline void pairAlign(const pcl::PointCloud<pcl::PointXYZ>::Ptr _cloud_ref,
+                      const pcl::PointCloud<pcl::PointXYZ>::Ptr _cloud_other,
+                      const Eigen::Isometry3d                  &_transform_guess,
+                      Eigen::Isometry3d                        &_transform_final,
+                      RegistrationPtr                          &_registration_solver,
+                      bool                                      _downsample = false,
+                      double                                    _voxel_size = 0.05)
 {
     // Internal PointCloud pointers (boost::shared_ptr)
     pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ref   = pcl::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
@@ -73,8 +79,8 @@ inline void pairAlign(const pcl::PointCloud<pcl::PointXYZ>::Ptr
     }
 
     // Set input clouds
-    _registration_solver.setInputSource(cloud_ref);
-    _registration_solver.setInputTarget(cloud_other);
+    _registration_solver->setInputSource(cloud_ref);
+    _registration_solver->setInputTarget(cloud_other);
 
     // Declare variables
     Eigen::Matrix4f transform_pcl;
@@ -83,8 +89,8 @@ inline void pairAlign(const pcl::PointCloud<pcl::PointXYZ>::Ptr
     Eigen::Matrix4f transform_guess = _transform_guess.matrix().cast<float>();
 
     // Alignment
-    _registration_solver.align(*cloud_ref, transform_guess);
-    transform_pcl = _registration_solver.getFinalTransformation();
+    _registration_solver->align(*cloud_ref, transform_guess);
+    transform_pcl = _registration_solver->getFinalTransformation();
 
     // Output the transformation as Isometry of double(s)
     _transform_final = Eigen::Isometry3d(transform_pcl.cast<double>());
diff --git a/src/processor/processor_odom_icp_3d.cpp b/src/processor/processor_odom_icp_3d.cpp
index 7624be9d7463e7fe6a4e03a295cf5e1c49731823..b9b7982597622547c255a15a88f93a10376b2dba 100644
--- a/src/processor/processor_odom_icp_3d.cpp
+++ b/src/processor/processor_odom_icp_3d.cpp
@@ -19,9 +19,19 @@
 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 //
 //--------LICENSE_END--------
+
+// wolf laser
 #include "laser/processor/processor_odom_icp_3d.h"
 #include "laser/utils/laser3d_tools.h"
+
+// wolf core
 #include "core/factor/factor_relative_pose_3d_with_extrinsics.h"
+#include "core/utils/logging.h"
+
+// pcl
+#include <pcl/registration/icp.h>
+#include <pcl/registration/gicp.h>
+#include <pcl/registration/icp_nl.h>
 
 namespace wolf
 {
@@ -35,10 +45,30 @@ ProcessorOdomIcp3d::ProcessorOdomIcp3d(ParamsProcessorOdomIcp3dPtr _params)
     T_robot_sensor_.setIdentity();
     T_sensor_robot_.setIdentity();
 
-    registration_solver_.setMaximumIterations(_params->icp_max_iterations);
-    registration_solver_.setTransformationRotationEpsilon(_params->icp_transformation_rotation_epsilon);
-    registration_solver_.setTransformationEpsilon(_params->icp_transformation_translation_epsilon);
-    registration_solver_.setMaxCorrespondenceDistance(_params->icp_max_correspondence_distance);
+    if (std::strcmp(_params->icp_algorithm.c_str(), "icp_nl") == 0)
+    {
+        WOLF_INFO("ProcessorOdomIcp3d: Using icp_nl");
+        registration_solver_ = std::make_shared<pcl::IterativeClosestPointNonLinear<pcl::PointXYZ, pcl::PointXYZ>>();
+    }
+    else if (std::strcmp(_params->icp_algorithm.c_str(), "icp") == 0)
+    {
+        WOLF_INFO("ProcessorOdomIcp3d: Using icp");
+        registration_solver_ = std::make_shared<pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ>>();
+    }
+    else if (std::strcmp(_params->icp_algorithm.c_str(), "gicp") == 0)
+    {
+        WOLF_INFO("ProcessorOdomIcp3d: Using gicp");
+        registration_solver_ = std::make_shared<pcl::GeneralizedIterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ>>();
+    }
+    else
+    {
+        WOLF_ERROR("ProcessorOdomIcp3d: Unrecognized ICP algorithm \"", _params->icp_algorithm, "\". Valid options are \"icp\", \"icp_nl\" and \"gicp\" only.");
+        throw("ICP algorithm not recognized");
+    }
+    registration_solver_->setMaximumIterations(_params->icp_max_iterations);
+    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();
diff --git a/test/gtest_laser3d_tools.cpp b/test/gtest_laser3d_tools.cpp
index 8c5541d5f51b220ebb2c56f1a702932fe629bd8b..c8be82381b387e40be45446b503da317d9f6c77b 100644
--- a/test/gtest_laser3d_tools.cpp
+++ b/test/gtest_laser3d_tools.cpp
@@ -76,22 +76,23 @@ TEST(pairAlign, identity)
     Isometry3d transformation_final;
 
     // Solver configuration
-    pcl::IterativeClosestPointNonLinear<pcl::PointXYZ, pcl::PointXYZ> registration_solver;
-    registration_solver.setTransformationEpsilon(1e-6);
+    RegistrationPtr registration_solver =
+        std::make_shared<pcl::IterativeClosestPointNonLinear<pcl::PointXYZ, pcl::PointXYZ>>();
+    registration_solver->setTransformationEpsilon(1e-6);
     // Set the maximum distance between two correspondences (src<->tgt) to 10cm
     // Note: adjust this based on the size of your datasets
-    registration_solver.setMaxCorrespondenceDistance(0.5);  // visaub: changed to 100 cm
+    registration_solver->setMaxCorrespondenceDistance(0.5);  // visaub: changed to 100 cm
     // Set the point representation
     // reg.setPointRepresentation(pcl::make_shared<const MyPointRepresentation>(point_representation));
-    registration_solver.setMaximumIterations(200);
+    registration_solver->setMaximumIterations(200);
 
     // Alignment
     wolf::pairAlign(pcl_ref,
-                           pcl_other,
-                           transformation_guess,
-                           transformation_final,
-                           registration_solver,
-                           true);  // false);
+                    pcl_other,
+                    transformation_guess,
+                    transformation_final,
+                    registration_solver,
+                    true);  // false);
 
     WOLF_INFO("Final transform: \n", transformation_final.matrix());
 
@@ -121,33 +122,34 @@ TEST(pairAlign, known_transformation)
     WOLF_INFO("Applied transformation: \n", transformation_known.matrix());
 
     // Solver configuration
-    pcl::IterativeClosestPointNonLinear<pcl::PointXYZ, pcl::PointXYZ> registration_solver;
+    RegistrationPtr registration_solver =
+        std::make_shared<pcl::IterativeClosestPointNonLinear<pcl::PointXYZ, pcl::PointXYZ>>();
     // pcl::GeneralizedIterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> registration_solver;
 
     double max_trans_epsilon_meters = 0.001;
     double max_rot_epsilon_degrees  = 0.1;
     double trf_rotation_epsilon     = cos(toRad(max_rot_epsilon_degrees));
 
-    registration_solver.setTransformationEpsilon(max_trans_epsilon_meters * max_trans_epsilon_meters);
-    registration_solver.setTransformationRotationEpsilon(trf_rotation_epsilon);
+    registration_solver->setTransformationEpsilon(max_trans_epsilon_meters * max_trans_epsilon_meters);
+    registration_solver->setTransformationRotationEpsilon(trf_rotation_epsilon);
     // Set the maximum distance between two correspondences (src<->tgt) to 10cm
     // Note: adjust this based on the size of your datasets
-    registration_solver.setMaxCorrespondenceDistance(0.5);  // visaub: changed to 100 cm
-    registration_solver.setMaximumIterations(100);
+    registration_solver->setMaxCorrespondenceDistance(0.5);  // visaub: changed to 100 cm
+    registration_solver->setMaximumIterations(100);
 
     // Alignment
     wolf::pairAlign(pcl_ref,
-                           pcl_other,
-                           transformation_guess,
-                           transformation_final,
-                           registration_solver,
-                           true);  // false);
+                    pcl_other,
+                    transformation_guess,
+                    transformation_final,
+                    registration_solver,
+                    true);  // false);
 
     WOLF_INFO("Final transform: \n", transformation_final.matrix());
 
-    auto convcrit = registration_solver.getConvergeCriteria();
+    // auto convcrit = registration_solver->getConvergeCriteria();
 
-    WOLF_INFO("convergence criteria: ", registration_solver.getConvergeCriteria()->getConvergenceState());
+    // WOLF_INFO("convergence criteria: ", registration_solver->getConvergeCriteria()->getConvergenceState());
 
     ASSERT_MATRIX_APPROX(transformation_final.matrix(), transformation_known.matrix(), 1e-2);
 }