diff --git a/include/laser/processor/params_icp.h b/include/laser/processor/params_icp.h
index b93bfb469f45db6e98b419395d55200db82fc6fd..3e0d9ef405eaffe9eeee5f6bc26b140c15ac3c02 100644
--- a/include/laser/processor/params_icp.h
+++ b/include/laser/processor/params_icp.h
@@ -3,7 +3,6 @@
 
 #include "core/common/wolf.h"
 #include "laser_scan_utils/icp.h"
-#undef max
 
 namespace wolf {
 
diff --git a/include/laser/processor/processor_loop_closure_icp.h b/include/laser/processor/processor_loop_closure_icp.h
index b1ac1868cfe669ede330bb20b7c2579e7a106f23..8d95796f4c6795b9bbdae8e1b0b7ff88c6c12261 100644
--- a/include/laser/processor/processor_loop_closure_icp.h
+++ b/include/laser/processor/processor_loop_closure_icp.h
@@ -46,29 +46,41 @@ WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorLoopClosureIcp);
 
 struct ParamsProcessorLoopClosureIcp : public ParamsProcessorLoopClosure, public ParamsIcp
 {
-    int recent_frames_ignored, frames_ignored_after_loop;
-    double max_error_threshold;
-    double min_points_percent;
+    int recent_frames_ignored;          // recent frames not considered candidates
+    int frames_ignored_after_loop;      // wait frames after closing a loop
+    int max_attempts;                   // max number of ICP attempts for stopping creating candidates
+    int max_candidates;                 // max number of candidats (ICP success) for stopping creating candidates
+
+    std::string candidate_generation;   // order of selection of frames: "deterministic" or "random"
+
+    double max_error_threshold;         // maximum error for accepting ICP
+    double min_points_percent;          // minimum correspondence % for accepting ICP
 
     ParamsProcessorLoopClosureIcp() = default;
     ParamsProcessorLoopClosureIcp(std::string _unique_name, const ParamsServer& _server) :
         ParamsProcessorLoopClosure(_unique_name, _server),
         ParamsIcp(prefix + _unique_name, _server)
     {
-        recent_frames_ignored     = _server.getParam<int>    (prefix + _unique_name + "/recent_frames_ignored");
-        frames_ignored_after_loop = _server.getParam<int>    (prefix + _unique_name + "/frames_ignored_after_loop");
-        max_error_threshold       = _server.getParam<double> (prefix + _unique_name + "/max_error_threshold");
-        min_points_percent        = _server.getParam<double> (prefix + _unique_name + "/min_points_percent");
+        recent_frames_ignored     = _server.getParam<int>           (prefix + _unique_name + "/recent_frames_ignored");
+        frames_ignored_after_loop = _server.getParam<int>           (prefix + _unique_name + "/frames_ignored_after_loop");
+        max_attempts              = _server.getParam<int>           (prefix + _unique_name + "/max_attempts");
+        max_candidates            = _server.getParam<int>           (prefix + _unique_name + "/max_candidates");
+        candidate_generation      = _server.getParam<std::string>   (prefix + _unique_name + "/candidate_generation");
+        max_error_threshold       = _server.getParam<double>        (prefix + _unique_name + "/max_error_threshold");
+        min_points_percent        = _server.getParam<double>        (prefix + _unique_name + "/min_points_percent");
     }
 
     std::string print() const override
     {
         return "\n" + ParamsProcessorLoopClosure::print()
             + ParamsIcp::print() + "\n"
-            + "recent_frames_ignored: " + std::to_string(recent_frames_ignored) + "\n"
+            + "recent_frames_ignored: "     + std::to_string(recent_frames_ignored)     + "\n"
             + "frames_ignored_after_loop: " + std::to_string(frames_ignored_after_loop) + "\n"
-            + "max_error_threshold: " + std::to_string(max_error_threshold) + "\n"
-            + "min_points_percent: " + std::to_string(min_points_percent) + "\n";
+            + "max_attempts: "              + std::to_string(max_attempts)              + "\n"
+            + "max_candidates: "            + std::to_string(max_candidates)            + "\n"
+            + "candidate_generation: "      + candidate_generation                      + "\n"
+            + "max_error_threshold: "       + std::to_string(max_error_threshold)       + "\n"
+            + "min_points_percent: "        + std::to_string(min_points_percent)        + "\n";
     }
 };
 
@@ -134,6 +146,10 @@ class ProcessorLoopClosureIcp : public ProcessorLoopClosure
         /** \brief emplaces the factor(s) corresponding to a Loop Closure between two captures
          */
         void emplaceFactors(MatchLoopClosurePtr) override;
+
+        /** \brief returns a list containing the loop closure frame candidates list
+         */
+        FrameBasePtrList generateSearchList(CaptureBasePtr) const;
 };
 
 }
diff --git a/src/processor/processor_loop_closure_icp.cpp b/src/processor/processor_loop_closure_icp.cpp
index b7f4b651a20c28f6f067b9647851d67e0fb83f34..a609404ec3ce49042b23b7f668a4a5b7473e06e4 100644
--- a/src/processor/processor_loop_closure_icp.cpp
+++ b/src/processor/processor_loop_closure_icp.cpp
@@ -22,6 +22,7 @@
 #include "laser/processor/processor_loop_closure_icp.h"
 #include "laser/sensor/sensor_laser_2d.h"
 #include "core/math/covariance.h"
+#include <random>
 
 using namespace laserscanutils;
 using namespace Eigen;
@@ -75,42 +76,38 @@ std::map<double,MatchLoopClosurePtr> ProcessorLoopClosureIcp::findLoopClosures(C
     auto cap_laser = std::dynamic_pointer_cast<CaptureLaser2d>(_capture);
     assert(cap_laser != nullptr);
 
-    // Ignore the most recent 'recent_frames_ignored' frames
-    const auto &trajectory = getProblem()->getTrajectory();
-    int n_ignored = 0;
-    for(auto frm_it  = trajectory->rbegin();
-             frm_it != trajectory->rend();
-             frm_it++)
-    {
-        if (frm_it->second == _capture->getFrame())
-            continue;
-
-        if (n_ignored < params_loop_closure_icp_->recent_frames_ignored)
-        {
-            n_ignored++;
-            continue;
-        }
+    // generate search list
+    auto frames_search_list = generateSearchList(_capture);
 
-        auto cap_ref_list = frm_it->second->getCapturesOfType<CaptureLaser2d>();
-        for (auto cap_ref : cap_ref_list)
+    // Iterate search list looking for loop closure candidates
+    for (auto frm : frames_search_list)
+    {
+        // Frame can have more than one laser capture
+        for (auto cap_ref : frm->getCapturesOfType<CaptureLaser2d>())
         {
             auto cap_ref_laser = std::dynamic_pointer_cast<CaptureLaser2d>(cap_ref);
-            if (cap_ref_laser != nullptr)
+            assert(cap_ref_laser != nullptr);
+
+            // Match Scans
+            auto match = matchScans(cap_ref_laser, cap_laser);
+
+            // IT'S A MATCH!
+            if (match != nullptr)
             {
-                // Match Scans
-                auto match = matchScans(cap_ref_laser, cap_laser);
+                // avoid duplicated scores (std::map)
+                while (match_lc_map.count(match->normalized_score))
+                    match->normalized_score -= 1e-9;
 
-                // IT'S A MATCH!
-                if (match != nullptr)
-                {
-                    // avoid duplicated scores (std::map)
-                    while (match_lc_map.count(match->normalized_score))
-                        match->normalized_score -= 1e-9;
+                match_lc_map.emplace(match->normalized_score, match);
 
-                    match_lc_map.emplace(match->normalized_score, match);
-                }
+                // one factor to each frame (in case of more than one laser capture..)
+                break;
             }
         }
+
+        // stop if enough candidates
+        if (match_lc_map.size() == params_loop_closure_icp_->max_candidates)
+            return match_lc_map;
     }
 
     return match_lc_map;
@@ -225,6 +222,105 @@ void ProcessorLoopClosureIcp::emplaceFactors(MatchLoopClosurePtr match)
     last_loop_closure_ = match;
 }
 
+FrameBasePtrList ProcessorLoopClosureIcp::generateSearchList(CaptureBasePtr _cap) const
+{
+    assert(_cap->getFrame() and _cap->getFrame()->getTrajectory());
+
+    int N = getProblem()->getTrajectory()->getFrameMap().size() - 1 - params_loop_closure_icp_->recent_frames_ignored;
+
+    auto map_begin = getProblem()->getTrajectory()->getFrameMap().begin();
+
+    //std::vector<int> idxs;
+    std::vector<bool> done(N, false);
+    FrameBasePtrList frame_list;
+
+    if (params_loop_closure_icp_->candidate_generation == "tree" or
+        params_loop_closure_icp_->candidate_generation == "TREE" or
+        params_loop_closure_icp_->candidate_generation == "Tree")
+    {
+        // generates the series:
+        // 0, 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8,...
+
+        double frac = N;
+        int checked = 1;
+
+        // initialize with first: 0
+        done.at(0) = true;
+        if (not map_begin->second->getCapturesOfType<CaptureLaser2d>().empty())
+        {
+            //idxs.push_back(0);
+            frame_list.push_back(map_begin->second);
+        }
+
+        // continue with tree
+        while (checked < N and
+               frame_list.size() < params_loop_closure_icp_->max_attempts)
+        {
+            frac *= 0.5;
+            for (auto i = 1; ; i+=2)
+            {
+                int idx = (int)round(i*frac);
+                if (idx >= N)
+                    break;
+
+                if (not done.at(idx))
+                {
+                    done.at(idx) = true;
+                    checked++;
+                    auto frame_idx = std::next(map_begin, idx)->second;
+                    assert(frame_idx);
+                    assert(frame_idx != _cap->getFrame());
+                    if (not frame_idx->getCapturesOfType<CaptureLaser2d>().empty())
+                    {
+                        //idxs.push_back(idx);
+                        frame_list.push_back(frame_idx);
+                    }
+                }
+            }
+        }
+    }
+    else if (params_loop_closure_icp_->candidate_generation == "random" or
+            params_loop_closure_icp_->candidate_generation == "RANDOM" or
+            params_loop_closure_icp_->candidate_generation == "Random")
+    {
+        int checked = 1;
+        while (checked < N and
+               frame_list.size() < params_loop_closure_icp_->max_attempts)
+        {
+            std::random_device rd; // obtain a random number from hardware
+            std::mt19937 gen(rd()); // seed the generator
+            std::uniform_int_distribution<> distr(0, N-1); // define the range
+
+            int idx = distr(gen); // generate random number
+
+            // already added to list
+            if (done.at(idx))
+                continue;
+
+            // mark as done
+            done.at(idx) = true;
+            checked++;
+
+            // consider adding
+            auto frame_idx = std::next(map_begin, idx)->second;
+            assert(frame_idx);
+            assert(frame_idx != _cap->getFrame());
+            if (not frame_idx->getCapturesOfType<CaptureLaser2d>().empty())
+            {
+                //idxs.push_back(idx);
+                frame_list.push_back(frame_idx);
+            }
+        }
+    }
+    else
+    {
+        std::cout << params_loop_closure_icp_->print() << std::endl;
+        throw std::runtime_error("ParamsProcessorLoopClosureIcp::candidate_generation only accepts 'tree' or 'random'");
+    }
+
+    return frame_list;
+}
+
 }
 // Register in the FactorySensor
 #include "core/processor/factory_processor.h"
diff --git a/test/gtest_processor_loop_closure_icp.cpp b/test/gtest_processor_loop_closure_icp.cpp
index 998bc2e77021e116347ac20be0f34577082a47d8..12f33d6c9568a12d52233393fc21d7ded7c6063b 100644
--- a/test/gtest_processor_loop_closure_icp.cpp
+++ b/test/gtest_processor_loop_closure_icp.cpp
@@ -52,6 +52,9 @@ class ProcessorLoopClosureIcp_Test : public testing::Test
             params->frames_ignored_after_loop               = 0;
             params->max_error_threshold                     = 0.1;
             params->min_points_percent                      = 50;
+            params->max_candidates                          = 50;
+            params->max_attempts                            = 50;
+            params->candidate_generation                    = "random";
 
             params->icp_params.use_point_to_line_distance   = 1;
             params->icp_params.max_correspondence_dist      = 1e9;
diff --git a/test/yaml/processor_loop_closure_icp.yaml b/test/yaml/processor_loop_closure_icp.yaml
index a553959b916989ffb66b1a70f9afe900f3a21c77..c5125820901c97e44dc0066bdbe662bbec732eb7 100644
--- a/test/yaml/processor_loop_closure_icp.yaml
+++ b/test/yaml/processor_loop_closure_icp.yaml
@@ -6,7 +6,10 @@ voting_active               : true
 min_features_for_keyframe   : 0
 max_new_features            : 0
 
-# from processor odom ICP
+# from processor loop closure ICP
+candidate_generation        : random
+max_candidates              : 2
+max_attempts                : 10
 cov_factor                  : 1
 use_point_to_line_distance  : true
 max_correspondence_dist     : 2
@@ -17,10 +20,4 @@ outliers_adaptive_order     : 6
 outliers_adaptive_mult      : 7
 max_reading                 : 100
 min_reading                 : 0
-do_compute_covariance       : true
-vfk_min_dist                : 0
-vfk_min_angle               : 0
-vfk_min_time                : 0
-vfk_min_error               : 0
-vfk_max_points              : 0
-initial_guess               : "zero"
+do_compute_covariance       : true
\ No newline at end of file