diff --git a/cfg/AdcLandmarksSlamSolver.cfg b/cfg/AdcLandmarksSlamSolver.cfg
index e5ed1827febea5a1eb51199efb090dbe613a9c92..20b60450736048b5411c7c7cbcdb47ff57d97546 100755
--- a/cfg/AdcLandmarksSlamSolver.cfg
+++ b/cfg/AdcLandmarksSlamSolver.cfg
@@ -48,6 +48,7 @@ gen.add("global_frame",                       str_t,        0,           "Global
 gen.add("odom_frame",                         str_t,        0,           "Odom frame",                                                                "odom")
 gen.add("base_link_frame",                    str_t,        0,           "Robot base_link frame",                                                     "base_link")
 gen.add("tf_timeout",                         double_t,     0,           "Timeout to find a transform",                                               0.2, 0.1, 2.0)
+gen.add("old_feature_timeout",                double_t,     0,           "Timeout to set a features source as old",                                   0.5, 0.1, 2.0)
 gen.add("amcl_pose_estimated_sigma",          double_t,     0,           "AMCL pose sigma when using AMCL localization",                              1, 0.1, 10)
 gen.add("publish_pose_rate",                  double_t,     0,           "Rate to publish the robot pose",                                            1.0,   0.00001, 10)
 gen.add("publish_pose_distance",              double_t,     0,           "Distance from last robot state to publish the robot pose",                  1.0,   0.1, 100000)
diff --git a/include/adc_landmarks_slam_solver_alg_node.h b/include/adc_landmarks_slam_solver_alg_node.h
index 61c7bf43b30d39fe41a8acf95d3ac76c542fedf9..b724d8fb92499b7700ccd1b8405e9ea60375ee0b 100644
--- a/include/adc_landmarks_slam_solver_alg_node.h
+++ b/include/adc_landmarks_slam_solver_alg_node.h
@@ -73,6 +73,7 @@ typedef struct {
   double th; ///< Angle at detection.
   double landmark_key; ///< The landmark id detected. -1 if no landmark detected.
   int type; ///< Feature type.
+  std::string frame; ///< features origin frame.
 }FeatureInfo;
 
 /**
@@ -89,9 +90,18 @@ class AdcLandmarksSlamSolverAlgNode : public algorithm_base::IriBaseAlgorithm<Ad
     double covariance_m_[3 * 3]; ///< Last robot pose covariance.
 
     bool new_features_data_; ///< Bool to know that new features has been received.
-    std::string features_frame_; ///< Features origin frame.
-    ros::Time features_stamp_; ///< Time stamp from the features.
-    std::vector<FeatureInfo> features_; ///< Feature data vector.
+    ros::Time features_stamp_; ///< Time stamp from the last features.
+    std::vector<FeatureInfo> features_; ///< Both features data vector.
+
+    bool new_front_features_data_; ///< Bool to know that new front_features has been received.
+    std::string front_features_frame_; ///< front_features origin frame.
+    ros::Time front_features_stamp_; ///< Time stamp from the front_features.
+    std::vector<FeatureInfo> front_features_; ///< Feature data vector.
+
+    bool new_rear_features_data_; ///< Bool to know that new rear_features has been received.
+    std::string rear_features_frame_; ///< rear_features origin frame.
+    ros::Time rear_features_stamp_; ///< Time stamp from the rear_features.
+    std::vector<FeatureInfo> rear_features_; ///< Feature data vector.
 
     std::list<LandmarkCandidate> landmarks_candidates_; ///< Landmark candidates.
 
@@ -111,7 +121,7 @@ class AdcLandmarksSlamSolverAlgNode : public algorithm_base::IriBaseAlgorithm<Ad
     Eigen::Vector3d estimated_sigma_; ///< Estimated main sigmas.
     bool reset_estimated_pose_; ///< Boolena to set new_estimated_pose to false.
 
-    bool last_frame_min_detections_; ///< Flag to know that last frame was because a lot of features seen.
+    bool last_frame_min_detections_; ///< Flag to know that last frame was because a lot of front_features seen.
 
     // [publisher attributes]
     ros::Publisher frame_data_publisher_;
@@ -144,11 +154,17 @@ class AdcLandmarksSlamSolverAlgNode : public algorithm_base::IriBaseAlgorithm<Ad
 
     tf2_ros::TransformListener tf2_listener;
 
-    ros::Subscriber features_subscriber_;
-    void features_callback(const iri_adc_msgs::feature_array::ConstPtr& msg);
-    pthread_mutex_t features_mutex_;
-    void features_mutex_enter(void);
-    void features_mutex_exit(void);
+    ros::Subscriber front_features_subscriber_;
+    void front_features_callback(const iri_adc_msgs::feature_array::ConstPtr& msg);
+    pthread_mutex_t front_features_mutex_;
+    void front_features_mutex_enter(void);
+    void front_features_mutex_exit(void);
+
+    ros::Subscriber rear_features_subscriber_;
+    void rear_features_callback(const iri_adc_msgs::feature_array::ConstPtr& msg);
+    pthread_mutex_t rear_features_mutex_;
+    void rear_features_mutex_enter(void);
+    void rear_features_mutex_exit(void);
 
 
     // [service attributes]
@@ -168,8 +184,10 @@ class AdcLandmarksSlamSolverAlgNode : public algorithm_base::IriBaseAlgorithm<Ad
 
     /**
      * \brief Function to remove landmark candidates not detected and reinit its variables.
+     * 
+     * \param _front Flag to select front or rear features.
      */
-    void prepare_landmark_candidates(void);
+    void prepare_landmark_candidates(bool _front);
 
     /**
      * \brief Function to analyze the feature information.
@@ -178,10 +196,12 @@ class AdcLandmarksSlamSolverAlgNode : public algorithm_base::IriBaseAlgorithm<Ad
      * If enabled, it searchs for new landmarks.
      *
      * \param _update_landmarks Flag to know if it must search for new landmarks.
+     * 
+     * \param _front Flag to select front or rear features.
      *
      * \return True on success.
      */
-    bool check_landmarks(bool _update_landmarks);
+    bool check_landmarks(bool _update_landmarks, bool _front);
 
     /**
      * \brief Function to check if the feature is an existing landmark candidate and to update landmark candidates info.
@@ -191,10 +211,12 @@ class AdcLandmarksSlamSolverAlgNode : public algorithm_base::IriBaseAlgorithm<Ad
      * If the feature isn't an existing landmark candidate, a new landmark candidate is added with its information.
      *
      * \param _feature The feature to check.
+     * 
+     * \param _front Flag to select front or rear features.
      *
      * \return If is a landmark candidate have been seen enough times (is a landmark).
      */
-    bool is_a_new_landmark(FeatureInfo &_feature);
+    bool is_a_new_landmark(FeatureInfo &_feature, bool _front);
 
     /**
      * \brief Function to update the frame data with the detected landmarks' information.
@@ -202,10 +224,12 @@ class AdcLandmarksSlamSolverAlgNode : public algorithm_base::IriBaseAlgorithm<Ad
      * It transform The sensor information to base_link frame.
      *
      * \param _frame_data The frame data.
+     * 
+     * \param _front Flag to select front or rear features.
      *
      * \return If succeded.
      */
-    bool update_landmarks_frame_data(FrameData& _frame_data);
+    bool update_landmarks_frame_data(FrameData& _frame_data, bool _front);
 
     /**
      * \brief Function to update tf from map to odom at a requested time stamp.
@@ -238,6 +262,13 @@ class AdcLandmarksSlamSolverAlgNode : public algorithm_base::IriBaseAlgorithm<Ad
      */
     bool get_tf_map_odom(ros::Time _t, Eigen::Vector3d& _tf_map_odom);
 
+    /**
+     * \brief Function to merge features received.
+     * 
+     * It only add features when they are not too old.
+     */
+    void merge_features();
+
     /**
      * \brief Function to publish landmarks markers.
      */
diff --git a/launch/node.launch b/launch/node.launch
index b333afe78b6d379e0f3d84519de3a4c8a8cb8ef0..336600572dd4854dba192f093306d402cd96fd4f 100644
--- a/launch/node.launch
+++ b/launch/node.launch
@@ -14,7 +14,8 @@
   <!-- <arg name="topic_name"  default="new_topic_name"/> -->
   <arg name="estimated_pose_topic_name" default="~/estimated_pose"/>
   <arg name="initialpose_topic_name" default="~/initialpose"/>
-  <arg name="features_topic_name" default="~/features"/>
+  <arg name="front_features_topic_name" default="~/front_features"/>
+  <arg name="rear_features_topic_name" default="~/rear_features"/>
 
 
   <node name="$(arg node_name)"
@@ -30,7 +31,8 @@
     <!--<remap from="~/topic" to="$(arg topic_name)"/>-->
     <remap from="~/estimated_pose" to="$(arg estimated_pose_topic_name)"/>
     <remap from="~/initialpose" to="$(arg initialpose_topic_name)"/>
-    <remap from="~/features" to="$(arg features_topic_name)"/>
+    <remap from="~/front_features" to="$(arg front_features_topic_name)"/>
+    <remap from="~/rear_features" to="$(arg rear_features_topic_name)"/>
   </node>
 
 </launch>
diff --git a/src/adc_landmarks_slam_solver_alg_node.cpp b/src/adc_landmarks_slam_solver_alg_node.cpp
index f7da6129cb18ad43d779027e5e8d6ffb19b2f47f..473b0030ee79bcb5dd2494670f356022b1e3a3c0 100644
--- a/src/adc_landmarks_slam_solver_alg_node.cpp
+++ b/src/adc_landmarks_slam_solver_alg_node.cpp
@@ -129,11 +129,16 @@ AdcLandmarksSlamSolverAlgNode::AdcLandmarksSlamSolverAlgNode(void) :
   this->estimated_pose_subscriber_ = this->private_node_handle_.subscribe("estimated_pose", 1, &AdcLandmarksSlamSolverAlgNode::estimated_pose_callback, this);
   pthread_mutex_init(&this->estimated_pose_mutex_,NULL);
 
-  this->features_subscriber_ = this->private_node_handle_.subscribe("features", 1, &AdcLandmarksSlamSolverAlgNode::features_callback, this);
-  pthread_mutex_init(&this->features_mutex_,NULL);
+  this->front_features_subscriber_ = this->private_node_handle_.subscribe("front_features", 1, &AdcLandmarksSlamSolverAlgNode::front_features_callback, this);
+  pthread_mutex_init(&this->front_features_mutex_,NULL);
+
+  this->rear_features_subscriber_ = this->private_node_handle_.subscribe("rear_features", 1, &AdcLandmarksSlamSolverAlgNode::rear_features_callback, this);
+  pthread_mutex_init(&this->rear_features_mutex_,NULL);
 
   //Init class atributes
   this->tf_odom_base_ << 0.0, 0.0, 0.0;
+  this->new_front_features_data_ = false;
+  this->new_rear_features_data_ = false;
   this->new_features_data_ = false;
   this->new_estimated_pose_ = false;
   this->reset_estimated_pose_ = false;
@@ -147,6 +152,8 @@ AdcLandmarksSlamSolverAlgNode::AdcLandmarksSlamSolverAlgNode(void) :
   this->publish_pose_ = false;
 
   this->new_estimated_pose_t_ = ros::Time::now();
+  this->front_features_stamp_ = ros::Time::now();
+  this->rear_features_stamp_ = ros::Time::now();
   this->features_stamp_ = ros::Time::now();
   this->tf_map_odom_ << 0.0, 0.0, 0.0;
 
@@ -166,6 +173,8 @@ AdcLandmarksSlamSolverAlgNode::AdcLandmarksSlamSolverAlgNode(void) :
   this->covariance_m_[7] = 0.0;
   this->covariance_m_[8] = 0.0;
 
+  std::vector<FeatureInfo>().swap(this->front_features_);
+  std::vector<FeatureInfo>().swap(this->rear_features_);
   std::vector<FeatureInfo>().swap(this->features_);
   std::list<LandmarkCandidate>().swap(this->landmarks_candidates_);
 
@@ -183,7 +192,10 @@ AdcLandmarksSlamSolverAlgNode::~AdcLandmarksSlamSolverAlgNode(void)
   // [free dynamic memory]
   pthread_mutex_destroy(&this->initialpose_mutex_);
   pthread_mutex_destroy(&this->estimated_pose_mutex_);
-  pthread_mutex_destroy(&this->features_mutex_);
+  pthread_mutex_destroy(&this->front_features_mutex_);
+  pthread_mutex_destroy(&this->rear_features_mutex_);
+  std::vector<FeatureInfo>().swap(this->front_features_);
+  std::vector<FeatureInfo>().swap(this->rear_features_);
   std::vector<FeatureInfo>().swap(this->features_);
   std::list<LandmarkCandidate>().swap(this->landmarks_candidates_);
 }
@@ -192,7 +204,7 @@ void AdcLandmarksSlamSolverAlgNode::mainNodeThread(void)
 {
   //lock access to algorithm if necessary
   // this->alg_.lock();
-  this->features_mutex_enter();
+  this->front_features_mutex_enter();
   this->estimated_pose_mutex_enter();
   // ROS_DEBUG("AdcLandmarksSlamSolverAlgNode::mainNodeThread");
 
@@ -258,7 +270,7 @@ void AdcLandmarksSlamSolverAlgNode::mainNodeThread(void)
         }
         // this->new_estimated_pose_ = false;
         this->estimated_pose_mutex_exit();
-        this->features_mutex_exit();
+        this->front_features_mutex_exit();
         return;
       }
       tf_odom_base_msg = this->tf2_buffer.lookupTransform(this->config_.odom_frame, this->config_.base_link_frame, this->new_estimated_pose_t_);
@@ -297,8 +309,15 @@ void AdcLandmarksSlamSolverAlgNode::mainNodeThread(void)
 
     if (this->new_features_data_)
     {
+      merge_features();
       // Check landmarks
-      bool land_success = check_landmarks(this->config_.search_for_new_landmarks);
+      bool front_land_success = false;
+      if (this->new_front_features_data_)
+        front_land_success = check_landmarks(this->config_.search_for_new_landmarks, true);
+      bool rear_land_success = false;
+      if (this->new_rear_features_data_)
+        rear_land_success = check_landmarks(this->config_.search_for_new_landmarks, false);
+
       if (this->config_.publish_visualization)
         publish_landmarks_markers();
 
@@ -308,8 +327,11 @@ void AdcLandmarksSlamSolverAlgNode::mainNodeThread(void)
       dist(1) = this->tf_odom_base_(1) - this->last_update_odom_base_(1);
       inc_ang = std::fabs(this->tf_odom_base_(2) - this->last_update_odom_base_(2));
 
-      if (((this->features_stamp_ - this->last_update_t_) > ros::Duration(1/this->config_.update_problem_rate)) || (dist.norm() > this->config_.update_problem_distance) ||
-         (inc_ang > this->config_.update_problem_angle) || this->new_estimated_pose_ || (!this->last_frame_min_detections_ && (this->features_.size() >= this->config_.update_problem_features_detected)))
+      if (((this->features_stamp_ - this->last_update_t_) > ros::Duration(1/this->config_.update_problem_rate))
+         || (dist.norm() > this->config_.update_problem_distance)
+         || (inc_ang > this->config_.update_problem_angle)
+         || this->new_estimated_pose_ 
+         || (!this->last_frame_min_detections_ && (this->features_.size() >= this->config_.update_problem_features_detected)))
       {
         this->last_frame_min_detections_ = !this->last_frame_min_detections_;
         if (!this->waiting_for_feature_)
@@ -323,9 +345,9 @@ void AdcLandmarksSlamSolverAlgNode::mainNodeThread(void)
           frame_data.current_odom = this->tf_odom_base_;
           if (!get_tf_map_odom(this->features_stamp_, frame_data.tf_map_odom))
           {
-            // this->new_features_data_ = false;
+            // this->new_front_features_data_ = false;
             this->estimated_pose_mutex_exit();
-            this->features_mutex_exit();
+            this->front_features_mutex_exit();
             return;
           }
           //Get global robot_state
@@ -335,21 +357,28 @@ void AdcLandmarksSlamSolverAlgNode::mainNodeThread(void)
           {
             if (!calculate_robot_state(frame_data.ts, frame_data.robot_state))
             {
-              // this->new_features_data_ = false;
+              // this->new_front_features_data_ = false;
               this->estimated_pose_mutex_exit();
-              this->features_mutex_exit();
+              this->front_features_mutex_exit();
               return;
             }
           }
 
           // Update frame information and Ceres problem
-          if (this->alg_.get_frames_data_size() != 0 && land_success)
+          if (this->alg_.get_frames_data_size() != 0 && (front_land_success || rear_land_success))
           {
-            if (!update_landmarks_frame_data(frame_data))
+            front_land_success = true;
+            rear_land_success = true;
+            if (this->new_front_features_data_)
+              front_land_success = update_landmarks_frame_data(frame_data, true);
+            if (this->new_rear_features_data_)
+              rear_land_success = update_landmarks_frame_data(frame_data, false);
+
+            if (!front_land_success || !rear_land_success)
             {
-              // this->new_features_data_ = false;
+              // this->new_front_features_data_ = false;
               this->estimated_pose_mutex_exit();
-              this->features_mutex_exit();
+              this->front_features_mutex_exit();
               return;
             }
           }
@@ -424,7 +453,7 @@ void AdcLandmarksSlamSolverAlgNode::mainNodeThread(void)
             this->reset_estimated_pose_ = false;
           }
           this->estimated_pose_mutex_exit();
-          this->features_mutex_exit();
+          this->front_features_mutex_exit();
           return;
         }
         tf_robot = this->tf2_buffer.lookupTransform(this->config_.global_frame, this->config_.base_link_frame, t);
@@ -506,32 +535,32 @@ void AdcLandmarksSlamSolverAlgNode::mainNodeThread(void)
 
   // this->alg_.unlock();
   this->estimated_pose_mutex_exit();
-  this->features_mutex_exit();
+  this->front_features_mutex_exit();
 }
 
-bool AdcLandmarksSlamSolverAlgNode::check_landmarks(bool _update_landmarks)
+bool AdcLandmarksSlamSolverAlgNode::check_landmarks(bool _update_landmarks, bool _front)
 {
-  ///Transform local features to global
+  ///Transform local front_features to global
   //get transform from fixed_frame to sensor frame
   geometry_msgs::TransformStamped tf_map_sensor_msg;
   geometry_msgs::PoseStamped local_feature, global_feature;
 
-  if (this->features_frame_ == "")
+  if ((_front && this->front_features_frame_ == "") || (!_front && this->rear_features_frame_ == ""))
   {
-    ROS_WARN("AdcLandmarksSlamSolverAlgNode::check_landmarks -> Features frame id empty; AR tag filter not initialized.");
+    ROS_WARN_STREAM("AdcLandmarksSlamSolverAlgNode::check_landmarks -> " << (_front? "front ": "rear ") << "features frame id empty; AR tag filter not initialized.");
     return false;
   }
 
   //Prepare landmarks status
   if (_update_landmarks)
-    prepare_landmark_candidates();
-  this->alg_.reset_landmarks_detected(this->features_frame_);
+    prepare_landmark_candidates(_front);
+  this->alg_.reset_landmarks_detected((_front? this->front_features_frame_: this->rear_features_frame_));
   
+  tf_map_sensor_msg.header.frame_id = this->config_.global_frame;
+  tf_map_sensor_msg.header.stamp = this->features_stamp_;//front/rear
+  tf_map_sensor_msg.child_frame_id = (_front? this->front_features_frame_: this->rear_features_frame_);
   if(!this->config_.amcl_localization)
   {
-    tf_map_sensor_msg.header.frame_id = this->config_.global_frame;
-    tf_map_sensor_msg.header.stamp = this->features_stamp_;
-    tf_map_sensor_msg.child_frame_id = this->features_frame_;
 
     tf2::Transform tf_map_odom;
     tf2::Quaternion q;
@@ -540,12 +569,12 @@ bool AdcLandmarksSlamSolverAlgNode::check_landmarks(bool _update_landmarks)
     tf_map_odom.setRotation(q);
 
     geometry_msgs::TransformStamped tf_odom_sensor_msg;
-    if (!this->tf2_buffer.canTransform(this->config_.odom_frame, this->features_frame_, this->features_stamp_, ros::Duration(this->config_.tf_timeout)))
+    if (!this->tf2_buffer.canTransform(this->config_.odom_frame, tf_map_sensor_msg.child_frame_id, tf_map_sensor_msg.header.stamp, ros::Duration(this->config_.tf_timeout)))
     {
-      ROS_WARN_STREAM("LandmarksTrackerAlgNode:check_landmarks -> Can't transform from " << this->config_.odom_frame << " to " << this->features_frame_ << " at " << this->features_stamp_);
+      ROS_WARN_STREAM("LandmarksTrackerAlgNode:check_landmarks -> Can't transform from " << this->config_.odom_frame << " to " << tf_map_sensor_msg.child_frame_id << " at " << tf_map_sensor_msg.header.stamp);
       return false;
     }
-    tf_odom_sensor_msg = this->tf2_buffer.lookupTransform(this->config_.odom_frame, this->features_frame_, this->features_stamp_);
+    tf_odom_sensor_msg = this->tf2_buffer.lookupTransform(this->config_.odom_frame, tf_map_sensor_msg.child_frame_id, tf_map_sensor_msg.header.stamp);
     tf2::Transform tf_odom_sensor;
     // tf2::transformMsgToTF2(tf_odom_sensor_msg.transform, tf_odom_sensor);
     tf_odom_sensor = tf2::Transform(tf2::Quaternion(tf_odom_sensor_msg.transform.rotation.x, tf_odom_sensor_msg.transform.rotation.y, tf_odom_sensor_msg.transform.rotation.z, tf_odom_sensor_msg.transform.rotation.w), tf2::Vector3(tf_odom_sensor_msg.transform.translation.x, tf_odom_sensor_msg.transform.translation.y, tf_odom_sensor_msg.transform.translation.z));
@@ -563,20 +592,20 @@ bool AdcLandmarksSlamSolverAlgNode::check_landmarks(bool _update_landmarks)
   }
   else
   {
-    if (!this->tf2_buffer.canTransform(this->config_.global_frame, this->features_frame_, this->features_stamp_, ros::Duration(this->config_.tf_timeout)))
+    if (!this->tf2_buffer.canTransform(this->config_.global_frame, tf_map_sensor_msg.child_frame_id, tf_map_sensor_msg.header.stamp, ros::Duration(this->config_.tf_timeout)))
     {
-      ROS_WARN_STREAM("AdcLandmarksSlamSolverAlgNode:check_landmarks -> Can't transform from " << this->config_.global_frame << " to " << this->features_frame_ << " at " << this->features_stamp_);
+      ROS_WARN_STREAM("AdcLandmarksSlamSolverAlgNode:check_landmarks -> Can't transform from " << this->config_.global_frame << " to " << tf_map_sensor_msg.child_frame_id << " at " << tf_map_sensor_msg.header.stamp);
       return false;
     }
-    tf_map_sensor_msg = this->tf2_buffer.lookupTransform(this->config_.global_frame, this->features_frame_, this->features_stamp_);
+    tf_map_sensor_msg = this->tf2_buffer.lookupTransform(this->config_.global_frame, tf_map_sensor_msg.child_frame_id, tf_map_sensor_msg.header.stamp);
   }
 
-  local_feature.header.stamp = this->features_stamp_;
-  local_feature.header.frame_id = this->features_frame_;
-  for (unsigned int i = 0; i < this->features_.size(); i++)
+  local_feature.header.stamp = this->features_stamp_;//front/rear
+  local_feature.header.frame_id = (_front? this->front_features_frame_: this->rear_features_frame_);
+  for (unsigned int i = 0; i < (_front? this->front_features_.size(): this->rear_features_.size()); i++)
   {
     //Get global feature
-    local_feature.pose = this->features_[i].msg_pose;
+    local_feature.pose = (_front? this->front_features_: this->rear_features_)[i].msg_pose;
     tf2::doTransform(local_feature, global_feature, tf_map_sensor_msg);
 
     //Check if is a mapped landmark
@@ -585,39 +614,39 @@ bool AdcLandmarksSlamSolverAlgNode::check_landmarks(bool _update_landmarks)
     tf2::Matrix3x3(q).getEulerYPR(yaw, pitch, roll);
     Eigen::Vector3d feature_pose;
     feature_pose << global_feature.pose.position.x, global_feature.pose.position.y, yaw;
-    this->features_[i].landmark_key = this->alg_.is_a_mapped_landmark(feature_pose, this->features_[i].r, this->features_[i].th, this->features_[i].type, this->features_frame_);
+    (_front? this->front_features_: this->rear_features_)[i].landmark_key = this->alg_.is_a_mapped_landmark(feature_pose, (_front? this->front_features_: this->rear_features_)[i].r, (_front? this->front_features_: this->rear_features_)[i].th, (_front? this->front_features_: this->rear_features_)[i].type, (_front? this->front_features_frame_: this->rear_features_frame_));
 
     //if it isn't a mapped landmark, update them if enabled
-    if (_update_landmarks && (this->features_[i].landmark_key < 0.0))
+    if (_update_landmarks && ((_front? this->front_features_: this->rear_features_)[i].landmark_key < 0.0))
     {
-      this->features_[i].pose(0) = global_feature.pose.position.x;
-      this->features_[i].pose(1) = global_feature.pose.position.y;
-      this->features_[i].pose(2) = yaw;
-      if (is_a_new_landmark(this->features_[i]))
+      (_front? this->front_features_: this->rear_features_)[i].pose(0) = global_feature.pose.position.x;
+      (_front? this->front_features_: this->rear_features_)[i].pose(1) = global_feature.pose.position.y;
+      (_front? this->front_features_: this->rear_features_)[i].pose(2) = yaw;
+      if (is_a_new_landmark((_front? this->front_features_: this->rear_features_)[i], _front))
       {
         LandmarkInfo landmark;
-        landmark.pose = this->features_[i].pose;
+        landmark.pose = (_front? this->front_features_: this->rear_features_)[i].pose;
         landmark.detected = true;
-        landmark.source_frame_id = this->features_frame_;
-        landmark.type = this->features_[i].type;
-        double landmark_key = std::fmod(this->features_stamp_.toSec(), L_KEY_DIV)*100+i;
-        this->features_[i].landmark_key = landmark_key;
+        landmark.source_frame_id = (_front? this->front_features_frame_: this->rear_features_frame_);
+        landmark.type = (_front? this->front_features_: this->rear_features_)[i].type;
+        double landmark_key = std::fmod(this->front_features_stamp_.toSec(), L_KEY_DIV)*100+i;
+        (_front? this->front_features_: this->rear_features_)[i].landmark_key = landmark_key;
         this->alg_.add_landmark(landmark_key, landmark);
-        ROS_DEBUG_STREAM("New landmark " << landmark_key << " at " << this->features_[i].pose(0) << ", " << this->features_[i].pose(1) << "; yaw " << this->features_[i].pose(2));
+        ROS_DEBUG_STREAM("New landmark " << landmark_key << " at " << (_front? this->front_features_: this->rear_features_)[i].pose(0) << ", " << (_front? this->front_features_: this->rear_features_)[i].pose(1) << "; yaw " << (_front? this->front_features_: this->rear_features_)[i].pose(2));
       }
     }
   }
   return true;
 }
 
-void AdcLandmarksSlamSolverAlgNode::prepare_landmark_candidates(void)
+void AdcLandmarksSlamSolverAlgNode::prepare_landmark_candidates(bool _front)
 {
   //Remove not detected candidates
   if (!this->config_.landmarks_candidates_filter_en)
     return;
   for (auto it = this->landmarks_candidates_.begin(); it != this->landmarks_candidates_.end(); ++it)
   {
-    if (it->source_frame_id.compare(this->features_frame_) == 0)//equal
+    if (it->source_frame_id == (_front ? this->front_features_frame_: this->rear_features_frame_))
     {
       if (it->detected)
         it->detected = false;
@@ -631,7 +660,7 @@ void AdcLandmarksSlamSolverAlgNode::prepare_landmark_candidates(void)
   }
 }
 
-bool AdcLandmarksSlamSolverAlgNode::is_a_new_landmark(FeatureInfo &_feature)
+bool AdcLandmarksSlamSolverAlgNode::is_a_new_landmark(FeatureInfo &_feature, bool _front)
 {
   //Check if a landmark candidate has been seen enough times
   if (!this->config_.landmarks_candidates_filter_en)
@@ -660,7 +689,7 @@ bool AdcLandmarksSlamSolverAlgNode::is_a_new_landmark(FeatureInfo &_feature)
   if (min_dist_land != this->landmarks_candidates_.end())
   {
     min_dist_land->detected = true;
-    min_dist_land->source_frame_id = this->features_frame_;
+    min_dist_land->source_frame_id = (_front? this->front_features_frame_: this->rear_features_frame_);
     min_dist_land->count++;
     if (min_dist_land->count >= this->config_.landmarks_min_detections)
     {
@@ -673,32 +702,32 @@ bool AdcLandmarksSlamSolverAlgNode::is_a_new_landmark(FeatureInfo &_feature)
   cand.pose = _feature.pose;
   cand.count = 1;
   cand.detected = true;
-  cand.source_frame_id = this->features_frame_;
+  cand.source_frame_id = (_front? this->front_features_frame_: this->rear_features_frame_);
   cand.type = _feature.type;
   this->landmarks_candidates_.push_back(cand);
   return false;
 }
 
-bool AdcLandmarksSlamSolverAlgNode::update_landmarks_frame_data(FrameData& _frame_data)
+bool AdcLandmarksSlamSolverAlgNode::update_landmarks_frame_data(FrameData& _frame_data, bool _front)
 {
   //calculate tf from base_link to sensor
   geometry_msgs::TransformStamped tf;
   geometry_msgs::PoseStamped from_sensor, from_base_link;
-  if (!this->tf2_buffer.canTransform(this->config_.base_link_frame, this->features_frame_, this->features_stamp_, ros::Duration(this->config_.tf_timeout)))
+  if (!this->tf2_buffer.canTransform(this->config_.base_link_frame, (_front? this->front_features_frame_: this->rear_features_frame_), this->features_stamp_, ros::Duration(this->config_.tf_timeout)))
   {
-    ROS_WARN_STREAM("AdcLandmarksSlamSolverAlgNode:update_landmarks_frame_data -> Can't transform from " << this->config_.base_link_frame << " to " << this->features_frame_ << " at " << this->features_stamp_);
+    ROS_WARN_STREAM("AdcLandmarksSlamSolverAlgNode:update_landmarks_frame_data -> Can't transform from " << this->config_.base_link_frame << " to " << (_front? this->front_features_frame_: this->rear_features_frame_) << " at " << this->features_stamp_);
     return false;
   }
-  tf = this->tf2_buffer.lookupTransform(this->config_.base_link_frame, this->features_frame_, this->features_stamp_);
-  from_sensor.header.stamp = this->features_stamp_;
-  from_sensor.header.frame_id = this->features_frame_;
-  for (unsigned int i = 0; i < this->features_.size(); i++)
+  tf = this->tf2_buffer.lookupTransform(this->config_.base_link_frame, (_front? this->front_features_frame_: this->rear_features_frame_), this->features_stamp_);
+  from_sensor.header.stamp = this->features_stamp_;//front/rear
+  from_sensor.header.frame_id = (_front? this->front_features_frame_: this->rear_features_frame_);
+  for (unsigned int i = 0; i < (_front? this->front_features_: this->rear_features_).size(); i++)
   {
-    if(this->features_[i].landmark_key > 0.0)
+    if(this->front_features_[i].landmark_key > 0.0)
     {
       LandmarkResidualData land_res_data;
       // Transform sensor info to base_link frame
-      from_sensor.pose = this->features_[i].msg_pose;
+      from_sensor.pose = (_front? this->front_features_: this->rear_features_)[i].msg_pose;
       tf2::doTransform(from_sensor, from_base_link, tf);
       Eigen::Vector2d feature;
       feature << from_base_link.pose.position.x, from_base_link.pose.position.y;
@@ -709,7 +738,7 @@ bool AdcLandmarksSlamSolverAlgNode::update_landmarks_frame_data(FrameData& _fram
       while (th < -M_PI)
         th += 2*M_PI;
       land_res_data.theta = th;
-      land_res_data.landmark_key = this->features_[i].landmark_key;
+      land_res_data.landmark_key = (_front? this->front_features_: this->rear_features_)[i].landmark_key;
       _frame_data.landmark_residuals_data.push_back(land_res_data);
     }
   }
@@ -796,6 +825,36 @@ void AdcLandmarksSlamSolverAlgNode::load_landmarks(void)
     ROS_ERROR_STREAM("AdcLandmarksSlamSolverAlgNode::load_landmarks -> File" << this->config_.landmarks_map_file << " can't be opened");
 }
 
+void AdcLandmarksSlamSolverAlgNode::merge_features()
+{
+  std::vector<FeatureInfo>().swap(this->features_);
+  if (this->new_rear_features_data_ && (this->features_stamp_ - this->rear_features_stamp_) < ros::Duration(this->config_.old_feature_timeout))
+  {
+    this->features_.resize(this->rear_features_.size());
+    for (unsigned int i=0; i<this->rear_features_.size(); i++)
+      this->features_[i] = this->rear_features_[i];
+  }
+  else
+  {
+    if (this->new_rear_features_data_)
+      ROS_WARN_STREAM("AdcLandmarksSlamSolverAlgNode::merge_features -> rear features too old: last stamp " << this->rear_features_stamp_);
+    this->new_rear_features_data_ = false;
+  }
+  if (this->new_front_features_data_ && (this->features_stamp_ - this->front_features_stamp_) < ros::Duration(this->config_.old_feature_timeout))
+  {
+    unsigned int old_size = this->features_.size();
+    this->features_.resize(this->features_.size() + this->front_features_.size());
+    for (unsigned int i=0; i<this->front_features_.size(); i++)
+      this->features_[old_size + i] = this->front_features_[i];
+  }
+  else
+  {
+    if (this->new_front_features_data_)
+      ROS_WARN_STREAM("AdcLandmarksSlamSolverAlgNode::merge_features -> front features too old: last stamp " << this->front_features_stamp_);
+    this->new_front_features_data_ = false;
+  }
+}
+
 void AdcLandmarksSlamSolverAlgNode::publish_landmarks_markers()
 {
   this->landmarks_MarkerArray_msg_.markers.resize(this->alg_.get_landmarks_size());
@@ -803,7 +862,7 @@ void AdcLandmarksSlamSolverAlgNode::publish_landmarks_markers()
   for (unsigned int i = 0; i < this->landmarks_MarkerArray_msg_.markers.size() && it != this->alg_.get_landmarks_end(); i++, ++it)
   {
     this->landmarks_MarkerArray_msg_.markers[i].header.frame_id = this->config_.global_frame;
-    this->landmarks_MarkerArray_msg_.markers[i].header.stamp = this->features_stamp_;
+    this->landmarks_MarkerArray_msg_.markers[i].header.stamp = this->front_features_stamp_;
     this->landmarks_MarkerArray_msg_.markers[i].id = i;
     this->landmarks_MarkerArray_msg_.markers[i].ns = "landmarks";
     // this->landmarks_MarkerArray_msg_.markers[i].type = visualization_msgs::Marker::TEXT_VIEW_FACING;
@@ -1028,17 +1087,19 @@ void AdcLandmarksSlamSolverAlgNode::estimated_pose_mutex_exit(void)
   pthread_mutex_unlock(&this->estimated_pose_mutex_);
 }
 
-void AdcLandmarksSlamSolverAlgNode::features_callback(const iri_adc_msgs::feature_array::ConstPtr& msg)
+void AdcLandmarksSlamSolverAlgNode::front_features_callback(const iri_adc_msgs::feature_array::ConstPtr& msg)
 {
   ROS_DEBUG("AdcLandmarksSlamSolverAlgNode::landmarks_callback: New Message Received");
 
   //use appropiate mutex to shared variables if necessary
   //this->alg_.lock();
-  this->features_mutex_enter();
-  this->features_frame_ = msg->header.frame_id;
+  this->front_features_mutex_enter();
+  this->front_features_frame_ = msg->header.frame_id;
+  this->front_features_stamp_ = msg->header.stamp;
   this->features_stamp_ = msg->header.stamp;
+  this->new_front_features_data_ = true;
   this->new_features_data_ = true;
-  this->features_.resize(msg->features.size());
+  this->front_features_.resize(msg->features.size());
   for (unsigned int i = 0; i < msg->features.size(); i++)
   {
     FeatureInfo feature;
@@ -1049,25 +1110,69 @@ void AdcLandmarksSlamSolverAlgNode::features_callback(const iri_adc_msgs::featur
     dist << msg->features[i].pose.position.x, msg->features[i].pose.position.y, msg->features[i].pose.position.z;
     feature.r = dist.norm();
     feature.th = std::atan2(msg->features[i].pose.position.x, msg->features[i].pose.position.z);
-    this->features_[i] = feature;
+    feature.frame = msg->header.frame_id;
+    this->front_features_[i] = feature;
   }
 
   //std::cout << msg->data << std::endl;
   //unlock previously blocked shared variables
   //this->alg_.unlock();
-  this->features_mutex_exit();
+  this->front_features_mutex_exit();
 }
 
-void AdcLandmarksSlamSolverAlgNode::features_mutex_enter(void)
+void AdcLandmarksSlamSolverAlgNode::front_features_mutex_enter(void)
+{
+  pthread_mutex_lock(&this->front_features_mutex_);
+}
+
+void AdcLandmarksSlamSolverAlgNode::front_features_mutex_exit(void)
+{
+  pthread_mutex_unlock(&this->front_features_mutex_);
+}
+
+
+void AdcLandmarksSlamSolverAlgNode::rear_features_callback(const iri_adc_msgs::feature_array::ConstPtr& msg)
 {
-  pthread_mutex_lock(&this->features_mutex_);
+  ROS_DEBUG("AdcLandmarksSlamSolverAlgNode::landmarks_callback: New Message Received");
+
+  //use appropiate mutex to shared variables if necessary
+  //this->alg_.lock();
+  this->front_features_mutex_enter();
+  this->rear_features_frame_ = msg->header.frame_id;
+  this->rear_features_stamp_ = msg->header.stamp;
+  this->features_stamp_ = msg->header.stamp;
+  this->new_rear_features_data_ = true;
+  this->new_features_data_ = true;
+  this->rear_features_.resize(msg->features.size());
+  for (unsigned int i = 0; i < msg->features.size(); i++)
+  {
+    FeatureInfo feature;
+    feature.msg_pose = msg->features[i].pose;
+    feature.landmark_key = -1.0;
+    feature.type = msg->features[i].type;
+    Eigen::Vector3d dist;
+    dist << msg->features[i].pose.position.x, msg->features[i].pose.position.y, msg->features[i].pose.position.z;
+    feature.r = dist.norm();
+    feature.th = std::atan2(msg->features[i].pose.position.x, msg->features[i].pose.position.z);
+    feature.frame = msg->header.frame_id;
+    this->rear_features_[i] = feature;
+  }
+
+  //std::cout << msg->data << std::endl;
+  //unlock previously blocked shared variables
+  //this->alg_.unlock();
+  this->front_features_mutex_exit();
 }
 
-void AdcLandmarksSlamSolverAlgNode::features_mutex_exit(void)
+void AdcLandmarksSlamSolverAlgNode::rear_features_mutex_enter(void)
 {
-  pthread_mutex_unlock(&this->features_mutex_);
+  pthread_mutex_lock(&this->rear_features_mutex_);
 }
 
+void AdcLandmarksSlamSolverAlgNode::rear_features_mutex_exit(void)
+{
+  pthread_mutex_unlock(&this->rear_features_mutex_);
+}
 
 /*  [service callbacks] */
 
@@ -1078,7 +1183,7 @@ void AdcLandmarksSlamSolverAlgNode::features_mutex_exit(void)
 void AdcLandmarksSlamSolverAlgNode::node_config_update(Config &config, uint32_t level)
 {
   this->alg_.lock();
-  this->features_mutex_enter();
+  this->front_features_mutex_enter();
   if (config.load_landmarks && !this->config_.load_landmarks)
     load_landmarks();
   if (!config.load_landmarks && this->config_.load_landmarks)
@@ -1098,7 +1203,7 @@ void AdcLandmarksSlamSolverAlgNode::node_config_update(Config &config, uint32_t
     }
   }
   this->config_=config;
-  this->features_mutex_exit();
+  this->front_features_mutex_exit();
   this->alg_.unlock();
 }