graph.cpp
Go to the documentation of this file.
00001 #include "common/graph.h"
00002 #include "common/vertex.h"
00003 
00007 slam::Graph::Graph()
00008 {
00009   init();
00010 }
00011 
00015 bool slam::Graph::init()
00016 {
00017   // Initialize the g2o graph optimizer
00018     if (params_.g2o_algorithm == 0)
00019     {
00020       // Slam linear solver with gauss-newton
00021       SlamLinearSolver* linear_solver_ptr = new SlamLinearSolver();
00022       linear_solver_ptr->setBlockOrdering(false);
00023       SlamBlockSolver* block_solver_ptr = new SlamBlockSolver(linear_solver_ptr);
00024       g2o::OptimizationAlgorithmGaussNewton* solver_gauss_ptr =
00025         new g2o::OptimizationAlgorithmGaussNewton(block_solver_ptr);
00026       graph_optimizer_.setAlgorithm(solver_gauss_ptr);
00027     }
00028     else if (params_.g2o_algorithm == 1)
00029     {
00030       // Linear solver with Levenberg
00031       g2o::BlockSolverX::LinearSolverType * linear_solver_ptr;
00032       linear_solver_ptr = new g2o::LinearSolverCholmod<g2o::BlockSolverX::PoseMatrixType>();
00033       g2o::BlockSolverX * solver_ptr = new g2o::BlockSolverX(linear_solver_ptr);
00034       g2o::OptimizationAlgorithmLevenberg * solver =
00035         new g2o::OptimizationAlgorithmLevenberg(solver_ptr);
00036       graph_optimizer_.setAlgorithm(solver);
00037     }
00038     else
00039     {
00040       ROS_ERROR("[StereoSlam:] g2o_algorithm parameter must be 0 or 1.");
00041       return false;
00042     }
00043 }
00044 
00051 void slam::Graph::getLastPoses(tf::Transform current_odom,
00052                                tf::Transform &last_graph_pose,
00053                                tf::Transform &last_graph_odom)
00054 {
00055   // Init
00056   last_graph_pose = current_odom;
00057   last_graph_odom = current_odom;
00058 
00059   // Get last
00060   int last_idx = graph_optimizer_.vertices().size() - 1;
00061   if (odom_history_.size() > 0 && last_idx >= 0)
00062   {
00063     // Get the last optimized pose
00064     slam::Vertex* last_vertex =  dynamic_cast<slam::Vertex*>
00065           (graph_optimizer_.vertices()[last_idx]);
00066     last_graph_pose = Tools::getVertexPose(last_vertex);
00067 
00068     // Original odometry
00069     last_graph_odom = odom_history_.at(last_idx).first;
00070   }
00071 
00072   return;
00073 }
00074 
00081 void slam::Graph::findClosestNodes(int discart_first_n, int best_n, vector<int> &neighbors)
00082 {
00083   // Init
00084   neighbors.clear();
00085 
00086   // Get the pose of last graph node
00087   int last_idx = graph_optimizer_.vertices().size() - 1;
00088   if (last_idx < 0) return;
00089   slam::Vertex* last_vertex =  dynamic_cast<slam::Vertex*>
00090         (graph_optimizer_.vertices()[last_idx]);
00091   tf::Transform last_graph_pose = Tools::getVertexPose(last_vertex);
00092 
00093   // Loop thought all the other nodes
00094   vector< pair< int,double > > neighbor_distances;
00095   for (int i=last_idx-discart_first_n-1; i>=0; i--)
00096   {
00097     // Get the node pose
00098     slam::Vertex* cur_vertex =  dynamic_cast<slam::Vertex*>
00099             (graph_optimizer_.vertices()[i]);
00100     tf::Transform cur_pose = Tools::getVertexPose(cur_vertex);
00101     double dist = Tools::poseDiff(cur_pose, last_graph_pose);
00102     neighbor_distances.push_back(make_pair(i, dist));
00103   }
00104 
00105   // Exit if no neighbors
00106   if (neighbor_distances.size() == 0) return;
00107 
00108   // Sort the neighbors
00109   sort(neighbor_distances.begin(), neighbor_distances.end(), Tools::sortByDistance);
00110 
00111   // First
00112   neighbors.push_back(neighbor_distances[0].first);
00113 
00114   // Min number
00115   if (neighbor_distances.size() < best_n)
00116     best_n = neighbor_distances.size();
00117 
00118   // Get the best non-consecutive n nodes
00119   for (uint i=1; i<neighbor_distances.size(); i++)
00120   {
00121     if (abs(neighbor_distances[i-1].first - neighbor_distances[i].first) > 3)
00122       neighbors.push_back(neighbor_distances[i].first);
00123     if (neighbors.size() == best_n)
00124       break;
00125   }
00126 }
00127 
00134 int slam::Graph::addVertice(tf::Transform pose)
00135 {
00136   // Convert pose for graph
00137   Eigen::Isometry3d vertice_pose = Tools::tfToIsometry(pose);
00138 
00139   // Set node id equal to graph size
00140   int id = graph_optimizer_.vertices().size();
00141 
00142   // Build the vertex
00143   slam::Vertex* cur_vertex = new slam::Vertex();
00144   cur_vertex->setId(id);
00145   cur_vertex->setEstimate(vertice_pose);
00146   if (id == 0)
00147   {
00148     // First time, no edges.
00149     cur_vertex->setFixed(true);
00150     graph_optimizer_.addVertex(cur_vertex);
00151   }
00152   else
00153   {
00154     // When graph has been initialized get the transform between current and previous vertices
00155     // and save it as an edge
00156 
00157     // Get last vertex
00158     slam::Vertex* prev_vertex = dynamic_cast<slam::Vertex*>(
00159       graph_optimizer_.vertices()[id - 1]);
00160     graph_optimizer_.addVertex(cur_vertex);
00161 
00162     // Odometry edges
00163     g2o::EdgeSE3* e = new g2o::EdgeSE3();
00164     Eigen::Isometry3d t = prev_vertex->estimate().inverse() * cur_vertex->estimate();
00165     e->setVertex(0, prev_vertex);
00166     e->setVertex(1, cur_vertex);
00167     e->setMeasurement(t);
00168     graph_optimizer_.addEdge(e);
00169   }
00170 
00171   return id;
00172 }
00173 
00180 int slam::Graph::addVertice(tf::Transform pose,
00181                             tf::Transform pose_corrected,
00182                             double timestamp)
00183 {
00184   // Save the original odometry for this new node
00185   odom_history_.push_back(make_pair(pose, timestamp));
00186 
00187   // Add the node
00188   return addVertice(pose_corrected);
00189 }
00190 
00197 void slam::Graph::addEdge(int i, int j, tf::Transform edge)
00198 {
00199   // TODO: Check size of graph
00200 
00201   // Get the vertices
00202   slam::Vertex* v_i = dynamic_cast<slam::Vertex*>(graph_optimizer_.vertices()[i]);
00203   slam::Vertex* v_j = dynamic_cast<slam::Vertex*>(graph_optimizer_.vertices()[j]);
00204 
00205   // Add the new edge to graph
00206   g2o::EdgeSE3* e = new g2o::EdgeSE3();
00207   Eigen::Isometry3d t = Tools::tfToIsometry(edge);
00208   e->setVertex(0, v_j);
00209   e->setVertex(1, v_i);
00210   e->setMeasurement(t);
00211   graph_optimizer_.addEdge(e);
00212 }
00213 
00219 void slam::Graph::setVerticeEstimate(int vertice_id, tf::Transform pose)
00220 {
00221   dynamic_cast<slam::Vertex*>(graph_optimizer_.vertices()[vertice_id])->setEstimate(Tools::tfToIsometry(pose));
00222 }
00223 
00226 void slam::Graph::update()
00227 {
00228     graph_optimizer_.initializeOptimization();
00229     graph_optimizer_.optimize(params_.go2_opt_max_iter);
00230     ROS_INFO_STREAM("[StereoSlam:] Optimization done in graph with " << graph_optimizer_.vertices().size() << " vertices.");
00231 }
00232 
00236 bool slam::Graph::saveGraphToFile()
00237 {
00238   string block_file, vertices_file, edges_file;
00239   vertices_file = params_.save_dir + "graph_vertices.txt";
00240   edges_file = params_.save_dir + "graph_edges.txt";
00241   block_file = params_.save_dir + ".graph.block";
00242 
00243   // Create a blocking element
00244   fstream f_block(block_file.c_str(), ios::out | ios::trunc);
00245 
00246   // Open to append
00247   fstream f_vertices(vertices_file.c_str(), ios::out | ios::trunc);
00248   fstream f_edges(edges_file.c_str(), ios::out | ios::trunc);
00249 
00250   // Output the vertices file
00251   for (unsigned int i=0; i<graph_optimizer_.vertices().size(); i++)
00252   {
00253     // Get timestamp
00254     double timestamp = odom_history_.at(i).second;
00255 
00256     slam::Vertex* v = dynamic_cast<slam::Vertex*>(graph_optimizer_.vertices()[i]);
00257     tf::Transform pose = Tools::getVertexPose(v);
00258     f_vertices << fixed << setprecision(9) <<
00259           timestamp  << "," <<
00260           i << "," <<
00261           timestamp << "," <<
00262           params_.pose_frame_id << "," <<
00263           params_.pose_child_frame_id << "," <<
00264           setprecision(6) <<
00265           pose.getOrigin().x() << "," <<
00266           pose.getOrigin().y() << "," <<
00267           pose.getOrigin().z() << "," <<
00268           pose.getRotation().x() << "," <<
00269           pose.getRotation().y() << "," <<
00270           pose.getRotation().z() << "," <<
00271           pose.getRotation().w() <<  endl;
00272   }
00273   f_vertices.close();
00274 
00275   // Output the edges file
00276   int counter = 0;
00277   for ( g2o::OptimizableGraph::EdgeSet::iterator it=graph_optimizer_.edges().begin();
00278         it!=graph_optimizer_.edges().end(); it++)
00279   {
00280     g2o::EdgeSE3* e = dynamic_cast<g2o::EdgeSE3*> (*it);
00281     if (e)
00282     {
00283       // Only take into account non-directed edges
00284       if (abs(e->vertices()[0]->id() - e->vertices()[1]->id()) > 1 )
00285       {
00286         slam::Vertex* v_0 = dynamic_cast<slam::Vertex*>(graph_optimizer_.vertices()[e->vertices()[0]->id()]);
00287         slam::Vertex* v_1 = dynamic_cast<slam::Vertex*>(graph_optimizer_.vertices()[e->vertices()[1]->id()]);
00288         tf::Transform pose_0 = Tools::getVertexPose(v_0);
00289         tf::Transform pose_1 = Tools::getVertexPose(v_1);
00290 
00291         f_edges <<
00292               e->vertices()[0]->id() << "," <<
00293               e->vertices()[1]->id() << "," <<
00294               setprecision(6) <<
00295               pose_0.getOrigin().x() << "," <<
00296               pose_0.getOrigin().y() << "," <<
00297               pose_0.getOrigin().z() << "," <<
00298               pose_0.getRotation().x() << "," <<
00299               pose_0.getRotation().y() << "," <<
00300               pose_0.getRotation().z() << "," <<
00301               pose_0.getRotation().w() << "," <<
00302               pose_1.getOrigin().x() << "," <<
00303               pose_1.getOrigin().y() << "," <<
00304               pose_1.getOrigin().z() << "," <<
00305               pose_1.getRotation().x() << "," <<
00306               pose_1.getRotation().y() << "," <<
00307               pose_1.getRotation().z() << "," <<
00308               pose_1.getRotation().w() << endl;
00309         counter++;
00310       }
00311     }
00312   }
00313   f_edges.close();
00314 
00315   // Un-block
00316   f_block.close();
00317   int ret_code = remove(block_file.c_str());
00318   if (ret_code != 0)
00319   {
00320     ROS_ERROR("[StereoSlam:] Error deleting the blocking file.");
00321     return false;
00322   }
00323 
00324   return true;
00325 }
00326 


stereo_slam
Author(s): Pep Lluis Negre
autogenerated on Thu Aug 27 2015 15:24:22