poseslam_alg_node.cpp
Go to the documentation of this file.
00001 #include "poseslam_alg_node.h"
00002 
00003 PoseslamAlgNode::PoseslamAlgNode(void) :
00004   algorithm_base::IriBaseAlgorithm<PoseslamAlgorithm>()
00005 {
00006   //init class attributes if necessary
00007   this->loop_rate_ = alg_.config_.loop_rate; //in [Hz]
00008 
00009   // [init publishers]
00010   this->trajectory_publisher_ = this->public_node_handle_.advertise<iri_poseslam::Trajectory>("trajectory", 10);
00011   if (alg_.config_.also_no_loops)
00012     this->no_loops_trajectory_publisher_ = this->public_node_handle_.advertise<iri_poseslam::Trajectory>("no_loops_trajectory", 10);
00013   
00014   // [init subscribers]
00015   
00016   // [init services]
00017   
00018   // [init clients]
00019   get_link_client_ = this->public_node_handle_.serviceClient<iri_poseslam::GetLink>("get_link");
00020   
00021   // [init action servers]
00022   
00023   // [init action clients]
00024   
00025   // INIT
00026   step_ = 0;
00027   ended = 0;
00028 }
00029 
00030 PoseslamAlgNode::~PoseslamAlgNode(void)
00031 {
00032   // [free dynamic memory]
00033 }
00034 
00035 void PoseslamAlgNode::mainNodeThread(void)
00036 {
00037   bool LoopClosure = false;
00038   while (step_ == 0)
00039   {
00040     //ROS_INFO("POSE SLAM: Asking for the first Laser Scan header... step_ = %u", step_);
00041     // First Laser Scan Header
00042     get_link_srv_.request.current_step = 0;
00043     get_link_srv_.request.with_step = 0;
00044     if (get_link_client_.call(get_link_srv_))
00045     {
00046       if (get_link_srv_.response.success)
00047       {
00048         augment_trajectories(get_link_srv_.response.odom.header);
00049         update_trajectories(false);
00050         
00051         this->trajectory_publisher_.publish(this->Trajectory_msg_);
00052         if (alg_.config_.also_no_loops)
00053           this->no_loops_trajectory_publisher_.publish(this->Trajectory_msg_no_loops_);
00054         
00055         step_++;
00056         
00057         ROS_INFO("POSE SLAM: First laser scan header obtained");
00058       }
00059     }
00060     //else
00061       //ROS_WARN("POSE SLAM: Coudn't get first laser scan header");
00062   }
00063   
00064   // [fill msg structures]
00065   
00066   // [fill srv structure and make request to the server]
00067   
00068   // [fill action structure and make request to the action server]
00069 
00070   // [publish messages]
00071   
00072   // ---------- POSE SLAM ROUTINE -----------
00073   //if (ended < 5)
00074   //{
00075     // Odometry reception
00076     get_link_srv_.request.current_step = step_ - 1;
00077     get_link_srv_.request.with_step = step_;
00078     
00079     alg_.tSens = ros::Time::now().toSec();
00080     //ROS_INFO("POSE SLAM: New pose odometry requested! step_ = %i - previous step_ = %i", step_, step_ - 1);
00081     if (get_link_client_.call(get_link_srv_))
00082     {
00083       if (get_link_srv_.response.success && !get_link_srv_.response.end)// && step_ <= 800) 
00084       {
00085         // TIME VARIABLES
00086         if (alg_.timePub.capacity() == alg_.timePub.size())
00087         {
00088           alg_.timePub.reserve(alg_.timePub.size() + size_t(100));
00089           alg_.timeSensOpen.reserve(alg_.timeSensOpen.size() + size_t(100));
00090           alg_.timeSensClose.reserve(alg_.timeSensClose.size() + size_t(100));
00091         }
00092         alg_.timePub.push_back(0.0);
00093         alg_.timeSensOpen.push_back(0.0);
00094         alg_.timeSensClose.push_back(0.0);
00095             
00096         alg_.timeSensOpen.back() = alg_.timeSensOpen.back() + ros::Time::now().toSec() - alg_.tSens;
00097         
00098         // State Augmentation
00099         alg_.augmentation(step_, get_link_srv_.response.odom);
00100         
00101         // Augment trajectory
00102         augment_trajectories(get_link_srv_.response.odom.header);
00103 
00104         // Create list of link candidates
00105         alg_.create_candidates_list(true);
00106         
00107         // Process all link candidates for loop closure
00108         while (alg_.any_candidate() && !alg_.is_redundant())
00109         {
00110           // Select the most information gain link candidate
00111           alg_.select_best_candidate();
00112           //ROS_INFO("CANDIDATE: %i with step_ %i", step_, alg_.get_candidate_step());
00113           
00114           // Check if the present pose is redundant
00115           alg_.redundant_evaluation();
00116 
00117           // Check if we can try loop closure
00118           if (alg_.loop_closure_requeriments())
00119           {
00120             get_link_srv_.request.current_step = step_;
00121             get_link_srv_.request.with_step = alg_.get_candidate_step();
00122             get_link_srv_.request.prior_d = alg_.get_candidate_d();
00123             
00124             ROS_DEBUG("POSE SLAM: trying to close a loop: actual step_: %i with step_: %i", int(get_link_srv_.request.current_step), int(get_link_srv_.request.with_step));
00125             
00126             alg_.tSens = ros::Time::now().toSec();
00127             if (get_link_client_.call(get_link_srv_))
00128               LoopClosure = get_link_srv_.response.success;
00129             else
00130               ROS_ERROR("POSE SLAM: Communication with sensors_2_link failed");
00131             alg_.timeSensClose.back() = alg_.timeSensClose.back() + ros::Time::now().toSec() - alg_.tSens;
00132         
00133             if (LoopClosure) //If the sensor(s) confirms the loop closure..
00134               LoopClosure = alg_.try_loop_closure(get_link_srv_.response.odom);
00135             
00136             if (LoopClosure)
00137             {
00138               ROS_INFO("POSE SLAM: LOOP CLOSED! current step_: %i with step_: %i", step_, alg_.get_candidate_step());
00139               loops_.push_back(alg_.get_candidate_step());
00140               loops_.push_back(step_);
00141             }
00142           }
00143           alg_.update_candidates_list(LoopClosure, true);
00144         }
00145         
00146         if (!alg_.is_redundant()) 
00147           ROS_DEBUG("POSE SLAM: NEW STATE - step_: %i - IG: %f", step_, alg_.get_candidate_ig());
00148         
00149         // Trajectories publishing messages
00150         alg_.tPub = ros::Time::now().toSec();
00151         update_trajectories(LoopClosure);
00152         //ROS_INFO("Trajectories updated");
00153         
00154         this->trajectory_publisher_.publish(this->Trajectory_msg_);
00155         if (alg_.config_.also_no_loops)
00156           this->no_loops_trajectory_publisher_.publish(this->Trajectory_msg_no_loops_);
00157         alg_.timePub.back() = alg_.timePub.back() + ros::Time::now().toSec() - alg_.tPub;
00158                 
00159         step_++;
00160         ended = 0;
00161       }
00162       else if (step_ != 1 && get_link_srv_.response.end) //no more odometries and not before starting simulation
00163         ended++;
00164       //else if (step_ == 1 && get_link_srv_.response.end)
00165         //ROS_INFO("POSE SLAM: Waiting for first odometry");
00166       //else
00167         //ROS_WARN("POSE SLAM: Something went wrong: step_ = %u", step_);
00168     }
00169     else 
00170       ROS_ERROR("POSE SLAM: Failed to Call Server (service get_link) in next odom");
00171     
00172   //}
00173   
00174   if (ended == 5) //5 consecutive steps without new odometries --> END SIMULATION 
00175   {
00176     ROS_INFO("POSE SLAM: SIMULATION ENDED");
00177     
00178     print_results();
00179     ended ++;
00180   }
00181 }
00182 
00183 /*  [subscriber callbacks] */
00184 
00185 /*  [service callbacks] */
00186 
00187 /*  [action callbacks] */
00188 
00189 /*  [action requests] */
00190 
00191 void PoseslamAlgNode::node_config_update(Config &config, uint32_t level)
00192 {
00193   this->alg_.lock();
00194     loop_rate_ = config.loop_rate; //in [Hz]
00195     dz_footprint_2_base_ = config.dz_footprint_2_base;
00196   this->alg_.unlock();
00197 }
00198 
00199 void PoseslamAlgNode::addNodeDiagnostics(void)
00200 {
00201 }
00202 
00203 /* main function */
00204 int main(int argc,char *argv[])
00205 {
00206   return algorithm_base::main<PoseslamAlgNode>(argc, argv, "poseslam_alg_node");
00207 }
00208 
00209 void PoseslamAlgNode::augment_trajectories(const std_msgs::Header& header)
00210 {  
00211   //ROS_INFO("POSE SLAM: Augment trajectories");
00212   
00213   // HEADER
00214   Trajectory_msg_.header.seq = step_;
00215   Trajectory_msg_.header.stamp = ros::Time::now();
00216   Trajectory_msg_.header.frame_id = "/world";
00217   
00218   if (alg_.config_.also_no_loops)
00219   {
00220     Trajectory_msg_no_loops_.header.seq = step_;
00221     Trajectory_msg_no_loops_.header.stamp = ros::Time::now();
00222     Trajectory_msg_no_loops_.header.frame_id = "/world";
00223   }
00224     
00225   // STEPS AND STATES suposed redundant
00226   Trajectory_msg_.steps_2_states.push_back(-1);
00227   if (alg_.config_.also_no_loops)
00228     Trajectory_msg_no_loops_.steps_2_states.push_back(-1);
00229 
00230   // LAST POSE
00231   Trajectory_msg_.poses.push_back(create_PoseWithCovarianceStamped(header, alg_.get_last_pose(), alg_.get_last_covariance()));
00232   Trajectory_poses_.push_back(alg_.get_last_pose());
00233   
00234   if (alg_.config_.also_no_loops)
00235     Trajectory_msg_no_loops_.poses.push_back(create_PoseWithCovarianceStamped(header, alg_.get_last_pose_no_loops(), alg_.get_last_covariance_no_loops()));
00236 }
00237 
00238 void PoseslamAlgNode::update_trajectories(const bool& LoopClosed)
00239 {  
00240   //ROS_INFO("POSE SLAM: Update trajectories");
00241   
00242   // STEPS AND STATES CORRECTION
00243   if (!alg_.is_redundant())
00244   {
00245     Trajectory_msg_.states_2_steps.push_back(step_);
00246     Trajectory_msg_.steps_2_states.back() = Trajectory_msg_.states_2_steps.size() - 1;
00247     if (alg_.config_.also_no_loops)
00248     {
00249       Trajectory_msg_no_loops_.states_2_steps.push_back(step_);
00250       Trajectory_msg_no_loops_.steps_2_states.back() = Trajectory_msg_no_loops_.states_2_steps.size() - 1;
00251     }
00252     ROS_DEBUG("POSE SLAM: Update traj: STATE %u - step_ %u", uint(Trajectory_msg_.states_2_steps.size() - 1), step_);
00253   }
00254 
00255   // LOOP CLOSURE
00256   if (LoopClosed)
00257     recompute_trajectory();
00258 }
00259 
00260 void PoseslamAlgNode::print_results() const
00261 {
00262   // Printing results in a Matlab File
00263   std::fstream file;
00264   file.open("/home/jvallve/poseSLAM_results.m",std::ios::out);
00265   if (file.is_open())
00266   {
00267     // Computational time
00268     this->alg_.print_time_file(file);
00269     
00270     file << "time_publishing";
00271     this->alg_.print_vector_in_file(this->alg_.timePub, file);
00272     file << "time_sensing_open";
00273     this->alg_.print_vector_in_file(this->alg_.timeSensOpen, file);
00274     file << "time_sensing_close";
00275     this->alg_.print_vector_in_file(this->alg_.timeSensClose, file);
00276     file << "states_2_steps";
00277     this->alg_.print_vector_in_file(alg_.get_trajectory_steps(), file);
00278     file << "loops";
00279     if (loops_.size() > 0)
00280       this->alg_.print_vector_in_file(loops_, file);
00281     else
00282       file << " = []";
00283     for (uint i=0; i<alg_.Q_aug_.size(); i++)
00284     {
00285       file << "Q_aug{" << i+1 << "}";
00286       this->alg_.print_matrix_in_file(alg_.Q_aug_.at(i), file);
00287     }
00288     for (uint i=0; i<alg_.Q_loop_.size(); i++)
00289     {
00290       file << "Q_loop{" << i+1 << "}";
00291       this->alg_.print_matrix_in_file(alg_.Q_loop_.at(i), file);
00292     }
00293     for (uint i=0; i<alg_.d_aug_.size(); i++)
00294     {
00295       file << "d_aug{" << i+1 << "}";
00296       this->alg_.print_matrix_in_file(alg_.d_aug_.at(i), file);
00297     }
00298     for (uint i=0; i<alg_.d_loop_.size(); i++)
00299     {
00300       file << "d_loop{" << i+1 << "}";
00301       this->alg_.print_matrix_in_file(alg_.d_loop_.at(i), file);
00302     }
00303     for (uint i=0; i<alg_.d_loop_.size(); i++)
00304     {
00305       file << "success_loop{" << i+1 << "}";
00306       if (alg_.success_loop_.at(i))
00307         file << "= 1;\n";
00308       else
00309         file << "= 0;\n";
00310     }
00311   }
00312 }
00313 
00314 void PoseslamAlgNode::recompute_trajectory()
00315 {
00316   //ROS_INFO("POSE SLAM: Loop Closed --> Update trajectory...");
00317 
00318   // Get trajectory data
00319   std::vector<VectorXd> non_redundant_trajectory_poses = alg_.get_trajectory();
00320   std::vector<std::vector<double> > non_redundant_trajectory_cov = alg_.get_trajectory_covariance();
00321 
00322   std::vector<double> empty_cov (9,0);
00323   
00324   // Update new trajectory poses
00325   //ROS_INFO("POSE SLAM: non_redundant_trajectory_poses.size() = %i Trajectory_msg_.states_2_steps.size() = %i", non_redundant_trajectory_poses.size(), Trajectory_msg_.states_2_steps.size());
00326   for (uint i = 0; i < Trajectory_msg_.states_2_steps.size() - 1; i++)
00327   {
00328     uint initial_step = Trajectory_msg_.states_2_steps.at(i);
00329     uint last_step = Trajectory_msg_.states_2_steps.at(i + 1);
00330     
00331     // Recompute segment between non redundant poses
00332     std::vector<VectorXd> new_segment = recompute_segment(non_redundant_trajectory_poses.at(i), non_redundant_trajectory_poses.at(i + 1), initial_step, last_step);
00333     //ROS_INFO("POSE SLAM: Recomputed segment between %i and %i: %f, %f, %f and %f, %f, %f", i, i+1, non_redundant_trajectory_poses.at(i)(0),non_redundant_trajectory_poses.at(i)(1),non_redundant_trajectory_poses.at(i)(2), non_redundant_trajectory_poses.at(i + 1)(0), non_redundant_trajectory_poses.at(i + 1)(1), non_redundant_trajectory_poses.at(i + 1)(2));
00334   
00335 
00336     // Update the state i
00337     Trajectory_msg_.poses.at(initial_step).pose = create_PoseWithCovariance(non_redundant_trajectory_poses.at(i), non_redundant_trajectory_cov.at(i));
00338     //ROS_INFO("POSE SLAM: recomputed non-redundant step_: %i", initial_step);
00339     
00340     // Update the segment intermediate poses
00341     for (uint j = 0; j < new_segment.size(); j++)
00342     {
00343       //ROS_INFO("POSE SLAM: recomputed redundant step_: %i", initial_step + j + 1);
00344       Trajectory_msg_.poses.at(initial_step + j + 1).pose = create_PoseWithCovariance(new_segment.at(j), empty_cov);
00345       Trajectory_poses_.at(initial_step + j + 1) = new_segment.at(j);
00346     }
00347   }
00348 
00349   // Update last state
00350   Trajectory_msg_.poses.back().pose = create_PoseWithCovariance(non_redundant_trajectory_poses.back(), non_redundant_trajectory_cov.back());
00351   //ROS_INFO("POSE SLAM: Recomputed step_ %i: %f, %f, %f", Trajectory_msg_.poses.size() - 1, non_redundant_trajectory_poses.back()(0), non_redundant_trajectory_poses.back()(1),non_redundant_trajectory_poses.back()(2));
00352   
00353   //ROS_INFO("POSE SLAM: recomputed non-redundant step_: %i", Trajectory_msg_.poses.size() - 1);
00354     
00355   // Update loops indexs
00356   for (uint i = Trajectory_msg_.loops.size(); i < loops_.size(); i++)
00357     Trajectory_msg_.loops.push_back(loops_.at(i));
00358   
00359   // Store the trajectory non-redundant poses
00360   for (uint i = 0; i < Trajectory_msg_.states_2_steps.size(); i++)
00361     Trajectory_poses_.at(Trajectory_msg_.states_2_steps.at(i)) = non_redundant_trajectory_poses.at(i);
00362     
00363   }
00364 
00365 std::vector<VectorXd> PoseslamAlgNode::recompute_segment(const VectorXd& new_initial_pose, const VectorXd& new_final_pose, const int& initial_step, const int& final_step)
00366 {
00367   std::vector<VectorXd> segment_poses;
00368 
00369   // Old values
00370   std::vector<VectorXd> old_segment_poses;
00371   old_segment_poses.assign(Trajectory_poses_.begin() + initial_step + 1, Trajectory_poses_.begin() + final_step);
00372 
00373   VectorXd old_initial_pose = Trajectory_poses_.at(initial_step);
00374   VectorXd old_final_pose = Trajectory_poses_.at(final_step);
00375   
00376   VectorXd old_d = old_final_pose - old_initial_pose;
00377   Vector2d old_dxy = old_d.head(2);
00378   double old_dist = sqrt(old_dxy.dot(old_dxy));
00379   
00380   // New values
00381   VectorXd new_d = new_final_pose - new_initial_pose;
00382   Vector2d new_dxy = new_d.head(2);
00383   double new_dist = sqrt(new_dxy.dot(new_dxy));
00384   
00385   // Transformation
00386   double xy_scale = new_dist / old_dist;
00387   double th_scale = pi_2_pi(new_d(2)) / pi_2_pi(old_d(2));
00388 
00389   double rotation = angle_between_2D_vectors(old_dxy, new_dxy);
00390   MatrixXd R = rotation_matrix(rotation);
00391 
00392   for (uint i = 0; i < old_segment_poses.size(); i++)
00393   {
00394     // vector from initial pose
00395     VectorXd d_i = old_segment_poses.at(i) - old_initial_pose;
00396     
00397     // scale
00398     d_i.head(2) = xy_scale * d_i.head(2);
00399     d_i(2) = th_scale * pi_2_pi(d_i(2));
00400     
00401     // xy rotation
00402     d_i = R * d_i;
00403     
00404     // intermediate pose
00405     VectorXd pose_i = new_initial_pose + d_i;
00406     
00407     // store intermediate pose
00408     segment_poses.push_back(pose_i);
00409   }
00410 
00411   return segment_poses;
00412 }
00413 
00414 geometry_msgs::PoseWithCovarianceStamped PoseslamAlgNode::create_PoseWithCovarianceStamped(const std_msgs::Header& header, const VectorXd& last_pose, const std::vector<double>& last_cov)
00415 {
00416   geometry_msgs::PoseWithCovarianceStamped new_pose;
00417 
00418   new_pose.header = header;
00419   new_pose.header.frame_id = "/world";
00420   new_pose.pose = create_PoseWithCovariance(last_pose, last_cov);
00421 
00422   return new_pose;
00423 }
00424 
00425 geometry_msgs::PoseWithCovariance PoseslamAlgNode::create_PoseWithCovariance(const VectorXd& last_pose, const std::vector<double>& last_cov)
00426 {
00427   geometry_msgs::PoseWithCovariance new_pose;
00428 
00429   new_pose.pose.position.x = last_pose(0);
00430   new_pose.pose.position.y = last_pose(1);
00431   new_pose.pose.position.z = dz_footprint_2_base_;
00432   new_pose.pose.orientation = tf::createQuaternionMsgFromYaw(last_pose(2));
00433   
00434   for (uint j = 0; j < 9; j++)
00435     new_pose.covariance.at(j) = last_cov.at(j); 
00436 
00437   return new_pose;
00438 }
00439 
00440 MatrixXd PoseslamAlgNode::rotation_matrix(const double &alpha) const
00441 {
00442   MatrixXd rot = MatrixXd::Identity(3,3);
00443   
00444   rot(0,0) = cos(alpha);
00445   rot(0,1) = -sin(alpha);
00446   rot(1,0) = sin(alpha);
00447   rot(1,1) = cos(alpha);
00448 
00449   return rot;
00450 }
00451 
00452 double PoseslamAlgNode::angle_between_2D_vectors(const Vector2d& v, const Vector2d& w) const
00453 {
00454   Vector3d v3D = MatrixXd::Zero(3,1);
00455   Vector3d w3D = MatrixXd::Zero(3,1);
00456 
00457   v3D.head(2) = v;
00458   w3D.head(2) = w;
00459 
00460   Vector3d cross_prod = v3D.cross(w3D);
00461 
00462   double v_norm = sqrt(v.dot(v));
00463   double w_norm = sqrt(w.dot(w));
00464   double cross_norm = sqrt(cross_prod.dot(cross_prod));
00465   double sign = 1;
00466   if (cross_prod(2) < 0)
00467     sign = -1;
00468 
00469   return pi_2_pi(asin(sign * cross_norm / (v_norm * w_norm)));
00470 }
00471 
00472 double PoseslamAlgNode::pi_2_pi(const double& angle) const
00473 {
00474   return angle - 2 * M_PI * floor((angle + M_PI)/(2 * M_PI));
00475 }


iri_poseslam
Author(s): Joan Vallvé
autogenerated on Fri Dec 6 2013 21:21:14