diff --git a/include/laser_scan_utils/icp.h b/include/laser_scan_utils/icp.h
index 6cfbdb6cbada3619c6347473c7f4786e389606c5..be8676cd2f4bf25d3b11a1b39a4eab7c3535b2f9 100644
--- a/include/laser_scan_utils/icp.h
+++ b/include/laser_scan_utils/icp.h
@@ -34,7 +34,8 @@ namespace laserscanutils
 
     struct icpOutput
     {
-        bool valid;                 // If the result is valid
+        bool valid;                 // If the result is valid (converged & mean_error < max_mean_error & points_ratio > min_points_ratio)
+        bool converged;             // If the algorithm found a solution
         Eigen::Vector3s res_transf; // Transformation found
         Eigen::Matrix3s res_covar;  // Covariance of the transformation
         int nvalid;                 // Number of valid correspondences in the match
@@ -129,6 +130,10 @@ namespace laserscanutils
         unsigned int icp_attempts;        // number of icp attempts if result fails (not valid or error > restart_threshold_mean_error)
         double perturbation_new_attempts; // perturbation noise amplitude applied to initial guess in new attempts
 
+        // Validation ----------------------------------------------------------------
+        double max_mean_error;   // mean_error threshold to consider the solution not valid
+        double min_points_ratio; // points ratio threshold to consider the solution valid
+
         void print() const
         {
             std::cout << "verbose: " << std::to_string(verbose) << std::endl;
@@ -162,6 +167,10 @@ namespace laserscanutils
             std::cout << "do_compute_covariance: " << std::to_string(do_compute_covariance) << std::endl;
             std::cout << "cov_factor: " << std::to_string(cov_factor) << std::endl;
             std::cout << "cov_max_eigv_factor: " << std::to_string(cov_max_eigv_factor) << std::endl;
+            std::cout << "icp_attempts: " << std::to_string(icp_attempts) << std::endl;
+            std::cout << "perturbation_new_attempts: " << std::to_string(perturbation_new_attempts) << std::endl;
+            std::cout << "max_mean_error: " << std::to_string(max_mean_error) << std::endl;
+            std::cout << "min_points_ratio: " << std::to_string(min_points_ratio) << std::endl;
         }
     };
 
@@ -198,7 +207,9 @@ namespace laserscanutils
         5,     // double cov_factor
         2,     // double cov_max_eigv_factor
         1,     // unsigned int attempts
-        1e-1   // double perturbation_new_attempts
+        1e-1,  // double perturbation_new_attempts
+        1e-2,  // max_mean_error
+        0.75   // min_points_ratio
     };
 
     class ICP
diff --git a/src/icp.cpp b/src/icp.cpp
index cb23c4fd2eb028e59a69d8a06e0ed64761f12699..c627cdf13b79c2c9fc8dc773024ce5467d432cdc 100644
--- a/src/icp.cpp
+++ b/src/icp.cpp
@@ -166,68 +166,91 @@ icpOutput ICP::align(const LaserScan &_current_ls,
         try
         {
             sm_icp(&csm_input, &csm_output);
-            result.valid = csm_output.valid == 1;
-        }
-        catch (...)
-        {
-            result.valid = false;
-        }
+            result.converged = csm_output.valid == 1;
+            result.valid = result.converged;
 
-        // VALID --> copy output (and modify covariance)
-        if (result.valid == 1)
-        {
-            result.nvalid = csm_output.nvalid;
-            result.error = csm_output.error;
-            result.mean_error = csm_output.error / csm_output.nvalid;
-            result.points_ratio = ((double)csm_output.nvalid) / ((double)num_rays);
-            result.res_transf(0) = csm_output.x[0];
-            result.res_transf(1) = csm_output.x[1];
-            result.res_transf(2) = csm_output.x[2];
-
-            if (csm_input.do_compute_covariance)
+            // Further validation
+            if (result.converged)
             {
-                for (int i = 0; i < 3; ++i)
-                    for (int j = 0; j < 3; ++j)
-                        result.res_covar(i, j) = _icp_params.cov_factor *
-                                                 csm_output.cov_x_m->data[i * csm_output.cov_x_m->tda + j];
+                result.nvalid = csm_output.nvalid;
+                result.error = csm_output.error;
+                result.mean_error = csm_output.error / csm_output.nvalid;
+                result.points_ratio = ((double)csm_output.nvalid) / ((double)num_rays);
 
-                // Grow covariance in the biggest eigenvalue direction
-                if (_icp_params.cov_max_eigv_factor - 1 > 1e-6)
+                if (result.mean_error > _icp_params.max_mean_error or
+                    result.points_ratio < _icp_params.min_points_ratio)
                 {
-                    Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eigensolver(result.res_covar.topLeftCorner<2, 2>());
-
-                    if (eigensolver.info() == Eigen::Success)
-                    {
-                        Eigen::Vector2d eigvs = eigensolver.eigenvalues();
-                        Eigen::Index maxRow, maxCol;
-                        float max_eigv = eigvs.maxCoeff(&maxRow, &maxCol);
-
-                        eigvs(maxRow) = _icp_params.cov_max_eigv_factor * max_eigv;
-                        result.res_covar.topLeftCorner<2, 2>() = eigensolver.eigenvectors() *
-                                                                 eigvs.asDiagonal() *
-                                                                 eigensolver.eigenvectors().transpose();
-                    }
+                    result.valid = false;
+                    if (_icp_params.verbose)
+                        std::cout << "Validation NOT passed! mean_error: "
+                                  << result.mean_error
+                                  << " (should be < "
+                                  << _icp_params.max_mean_error
+                                  << "). points_ratio: "
+                                  << result.points_ratio
+                                  << " (should be > "
+                                  << _icp_params.min_points_ratio
+                                  << ")." << std::endl;
                 }
             }
         }
-        else
+        catch (...)
         {
-            // std::cout << "ICP NOT VALID, providing first guess transformation and identity covariance\n";
-            result.res_transf = _initial_guess;
-            result.res_covar = Eigen::Matrix3s::Identity();
+            if (_icp_params.verbose)
+                std::cout << "ICP failed (catch)" << std::endl;
+
+            result.converged = false;
+            result.valid = false;
         }
-        if (_icp_params.verbose and not result.valid and result.attempts < _icp_params.icp_attempts)
+
+        if (_icp_params.verbose and not result.valid)
         {
             std::cout << "Invalid result, trying again!" << std::endl;
         }
-        if (_icp_params.verbose and result.mean_error > _icp_params.restart_threshold_mean_error and result.attempts < _icp_params.icp_attempts)
+
+    } while (not result.valid and result.attempts < _icp_params.icp_attempts);
+
+    // if valid, copy values and grow covariance
+    if (result.valid)
+    {
+        result.res_transf(0) = csm_output.x[0];
+        result.res_transf(1) = csm_output.x[1];
+        result.res_transf(2) = csm_output.x[2];
+
+        if (csm_input.do_compute_covariance)
         {
-            std::cout << "Error too big: " << result.mean_error
-                      << " ( should be < "
-                      << _icp_params.restart_threshold_mean_error << "). Trying again!" << std::endl;
+            for (int i = 0; i < 3; ++i)
+                for (int j = 0; j < 3; ++j)
+                    result.res_covar(i, j) = _icp_params.cov_factor *
+                                             csm_output.cov_x_m->data[i * csm_output.cov_x_m->tda + j];
+
+            // Grow covariance in the biggest eigenvalue direction
+            if (_icp_params.cov_max_eigv_factor - 1 > 1e-6)
+            {
+                Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eigensolver(result.res_covar.topLeftCorner<2, 2>());
+
+                if (eigensolver.info() == Eigen::Success)
+                {
+                    Eigen::Vector2d eigvs = eigensolver.eigenvalues();
+                    Eigen::Index maxRow, maxCol;
+                    float max_eigv = eigvs.maxCoeff(&maxRow, &maxCol);
+
+                    eigvs(maxRow) = _icp_params.cov_max_eigv_factor * max_eigv;
+                    result.res_covar.topLeftCorner<2, 2>() = eigensolver.eigenvectors() *
+                                                             eigvs.asDiagonal() *
+                                                             eigensolver.eigenvectors().transpose();
+                }
+            }
         }
-    } while ((not result.valid or result.mean_error > _icp_params.restart_threshold_mean_error) and
-             result.attempts < _icp_params.icp_attempts);
+    }
+    else
+    {
+        if (_icp_params.verbose)
+            std::cout << "ICP NOT VALID, providing first guess transformation and identity covariance\n";
+
+        result.res_transf = _initial_guess;
+        result.res_covar = Eigen::Matrix3s::Identity();
+    }
 
     return result;
 }
diff --git a/test/gtest_icp.cpp b/test/gtest_icp.cpp
index 991ffe0dafc10e53337296c09f97a61f9e66a895..e6d39686f4a0cebde5e0ac1f49e9b75c927b808f 100644
--- a/test/gtest_icp.cpp
+++ b/test/gtest_icp.cpp
@@ -280,9 +280,11 @@ TEST(TestIcp, TestIcpSame1)
                                  icp_params,
                                  Eigen::Vector3d::Zero());
 
-    std::cout << "  icp_output:   " << icp_output.res_transf.transpose() << std::endl;
-    std::cout << "  icp error:    " << icp_output.error << std::endl;
-    std::cout << "  icp valid:    " << icp_output.valid << std::endl;
+    std::cout << "  output:       " << icp_output.res_transf.transpose() << std::endl;
+    std::cout << "  mean error:   " << icp_output.mean_error << std::endl;
+    std::cout << "  points_ratio: " << icp_output.points_ratio << std::endl;
+    std::cout << "  valid:        " << icp_output.valid << std::endl;
+    std::cout << "  attempts:     " << icp_output.attempts << std::endl;
 
     ASSERT_TRUE(icp_output.valid);
     EXPECT_MATRIX_APPROX(icp_output.res_transf, Eigen::Vector3d::Zero(), 1e-1);
@@ -297,10 +299,11 @@ TEST(TestIcp, TestIcpSame1)
                             initial_guess);
 
     std::cout << "  initial_guess: " << initial_guess.transpose() << std::endl;
-    std::cout << "  icp_output:    " << icp_output.res_transf.transpose() << std::endl;
-    std::cout << "  icp error:     " << icp_output.error << std::endl;
-    std::cout << "  icp valid:     " << icp_output.valid << std::endl;
-    std::cout << "  icp attempts:  " << icp_output.attempts << std::endl;
+    std::cout << "  output:        " << icp_output.res_transf.transpose() << std::endl;
+    std::cout << "  mean error:    " << icp_output.mean_error << std::endl;
+    std::cout << "  points_ratio:  " << icp_output.points_ratio << std::endl;
+    std::cout << "  valid:         " << icp_output.valid << std::endl;
+    std::cout << "  attempts:      " << icp_output.attempts << std::endl;
 
     ASSERT_TRUE(icp_output.valid);
     EXPECT_MATRIX_APPROX(icp_output.res_transf, Eigen::Vector3d::Zero(), 1e-1);
@@ -331,9 +334,11 @@ TEST(TestIcp, TestIcpSame2)
                                  icp_params,
                                  Eigen::Vector3d::Zero());
 
-    std::cout << "  icp_output:   " << icp_output.res_transf.transpose() << std::endl;
-    std::cout << "  icp error:    " << icp_output.error << std::endl;
-    std::cout << "  icp valid:    " << icp_output.valid << std::endl;
+    std::cout << "  output:       " << icp_output.res_transf.transpose() << std::endl;
+    std::cout << "  mean error:   " << icp_output.mean_error << std::endl;
+    std::cout << "  points_ratio: " << icp_output.points_ratio << std::endl;
+    std::cout << "  valid:        " << icp_output.valid << std::endl;
+    std::cout << "  attempts:     " << icp_output.attempts << std::endl;
 
     ASSERT_TRUE(icp_output.valid);
     EXPECT_MATRIX_APPROX(icp_output.res_transf, Eigen::Vector3d::Zero(), 1e-1);
@@ -348,10 +353,11 @@ TEST(TestIcp, TestIcpSame2)
                             initial_guess);
 
     std::cout << "  initial_guess: " << initial_guess.transpose() << std::endl;
-    std::cout << "  icp_output:    " << icp_output.res_transf.transpose() << std::endl;
-    std::cout << "  icp error:     " << icp_output.error << std::endl;
-    std::cout << "  icp valid:     " << icp_output.valid << std::endl;
-    std::cout << "  icp attempts:  " << icp_output.attempts << std::endl;
+    std::cout << "  output:        " << icp_output.res_transf.transpose() << std::endl;
+    std::cout << "  mean error:    " << icp_output.mean_error << std::endl;
+    std::cout << "  points_ratio:  " << icp_output.points_ratio << std::endl;
+    std::cout << "  valid:         " << icp_output.valid << std::endl;
+    std::cout << "  attempts:      " << icp_output.attempts << std::endl;
 
     ASSERT_TRUE(icp_output.valid);
     EXPECT_MATRIX_APPROX(icp_output.res_transf, Eigen::Vector3d::Zero(), 1e-1);
@@ -370,9 +376,9 @@ TEST(TestIcp, TestIcp1)
 
   auto icp_params = icp_params_default;
   icp_params.icp_attempts = n_attempts;
-  
+
   double pert = 0.0;
-  
+
   for (auto i = 0; i < N; i++)
   {
     // Random problem
@@ -392,10 +398,11 @@ TEST(TestIcp, TestIcp1)
     std::cout << "  pose_tar:       " << pose_tar.transpose() << std::endl;
     std::cout << "  groundtruth:    " << pose_d.transpose() << std::endl;
     std::cout << "  initial_guess:  " << initial_guess.transpose() << std::endl;
-    std::cout << "  icp_output:     " << icp_output.res_transf.transpose() << std::endl;
-    std::cout << "  icp error:      " << icp_output.error << std::endl;
-    std::cout << "  icp valid:      " << icp_output.valid << std::endl;
-    std::cout << "  icp attempts:   " << icp_output.attempts << std::endl;
+    std::cout << "  output:         " << icp_output.res_transf.transpose() << std::endl;
+    std::cout << "  mean error:     " << icp_output.mean_error << std::endl;
+    std::cout << "  points ratio:   " << icp_output.points_ratio << std::endl;
+    std::cout << "  valid:          " << icp_output.valid << std::endl;
+    std::cout << "  attempts:       " << icp_output.attempts << std::endl;
     std::cout << "  d error:        " << (pose_d - icp_output.res_transf).transpose() << std::endl;
 
     ASSERT_TRUE(icp_output.valid);
@@ -437,10 +444,11 @@ TEST(TestIcp, TestIcp10)
     std::cout << "  pose_tar:       " << pose_tar.transpose() << std::endl;
     std::cout << "  groundtruth:    " << pose_d.transpose() << std::endl;
     std::cout << "  initial_guess:  " << initial_guess.transpose() << std::endl;
-    std::cout << "  icp_output:     " << icp_output.res_transf.transpose() << std::endl;
-    std::cout << "  icp error:      " << icp_output.error << std::endl;
-    std::cout << "  icp valid:      " << icp_output.valid << std::endl;
-    std::cout << "  icp attempts:   " << icp_output.attempts << std::endl;
+    std::cout << "  output:         " << icp_output.res_transf.transpose() << std::endl;
+    std::cout << "  mean error:     " << icp_output.mean_error << std::endl;
+    std::cout << "  points ratio:   " << icp_output.points_ratio << std::endl;
+    std::cout << "  valid:          " << icp_output.valid << std::endl;
+    std::cout << "  attempts:       " << icp_output.attempts << std::endl;
     std::cout << "  d error:        " << (pose_d - icp_output.res_transf).transpose() << std::endl;
 
     ASSERT_TRUE(icp_output.valid);