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
00018 if (params_.g2o_algorithm == 0)
00019 {
00020
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
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
00056 last_graph_pose = current_odom;
00057 last_graph_odom = current_odom;
00058
00059
00060 int last_idx = graph_optimizer_.vertices().size() - 1;
00061 if (odom_history_.size() > 0 && last_idx >= 0)
00062 {
00063
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
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
00084 neighbors.clear();
00085
00086
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
00094 vector< pair< int,double > > neighbor_distances;
00095 for (int i=last_idx-discart_first_n-1; i>=0; i--)
00096 {
00097
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
00106 if (neighbor_distances.size() == 0) return;
00107
00108
00109 sort(neighbor_distances.begin(), neighbor_distances.end(), Tools::sortByDistance);
00110
00111
00112 neighbors.push_back(neighbor_distances[0].first);
00113
00114
00115 if (neighbor_distances.size() < best_n)
00116 best_n = neighbor_distances.size();
00117
00118
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
00137 Eigen::Isometry3d vertice_pose = Tools::tfToIsometry(pose);
00138
00139
00140 int id = graph_optimizer_.vertices().size();
00141
00142
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
00149 cur_vertex->setFixed(true);
00150 graph_optimizer_.addVertex(cur_vertex);
00151 }
00152 else
00153 {
00154
00155
00156
00157
00158 slam::Vertex* prev_vertex = dynamic_cast<slam::Vertex*>(
00159 graph_optimizer_.vertices()[id - 1]);
00160 graph_optimizer_.addVertex(cur_vertex);
00161
00162
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
00185 odom_history_.push_back(make_pair(pose, timestamp));
00186
00187
00188 return addVertice(pose_corrected);
00189 }
00190
00197 void slam::Graph::addEdge(int i, int j, tf::Transform edge)
00198 {
00199
00200
00201
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
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
00244 fstream f_block(block_file.c_str(), ios::out | ios::trunc);
00245
00246
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
00251 for (unsigned int i=0; i<graph_optimizer_.vertices().size(); i++)
00252 {
00253
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
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
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
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