graph_mgr_odom.cpp
Go to the documentation of this file.
00001 #include "graph_manager.h"
00002 #include "scoped_timer.h"
00003 #include "misc.h"
00004 #include "g2o/core/robust_kernel_factory.h"
00005 #include <tf/transform_listener.h>
00006 #include "g2o/types/slam3d/edge_se3.h"
00007 
00008 
00009 //specifies the information matrix for the odometry edge
00010 //tf::Transform odomTf is in the camera coordinate system
00011 void createOdometryEdge(int id1, int id2, tf::Transform& odomTf, LoadedEdge3D& edge)
00012 {
00013   double infoCoeff = ParameterServer::instance()->get<double>("odometry_information_factor");
00014   edge.id1 = id1;
00015   edge.id2 = id2;
00016 
00017   tf::Vector3 origin = odomTf.getOrigin();
00018   if(std::fabs(origin[0])<1e-5) origin[0] =0;
00019   if(std::fabs(origin[1])<1e-5) origin[1] =0;
00020   if(std::fabs(origin[2])<1e-5) origin[2] =0;
00021   odomTf.setOrigin(origin);
00022   if(std::fabs(tf::getYaw(odomTf.getRotation())) <1e-7) odomTf.setRotation(tf::createIdentityQuaternion());
00023 
00024 //comment in when parameters are calibrated correctly
00025 //make sure that the final information matrix is given in the camera coordinate system
00026 //-> for this the information matrix needs to be transformed into the camera coordinate system
00027 //1. calibrate odometry -> extract noise parameters
00028 //2. construct information matrix according to traveled distance and the noise parameters#
00029 //3. transform information matrix to camera coordinate frame
00030 /* 
00031   //parameters of Gaussian probabilistic motion model
00032   //http://www.mrpt.org/tutorials/programming/odometry-and-motion-models/probabilistic_motion_models/
00033   double alpha1 = 0.59;
00034   double alpha2 = 0.0014;
00035   double alpha3 = 0.02;
00036   double alpha4 = 0.00001;
00037 
00038   //hack as we know the transformation
00039   double var_dist_min = 0.001;
00040   double var_theta_min = 0.01;
00041   double var_dist = alpha3 * std::fabs(odomTf.getOrigin()[2]); //this is the translation
00042   var_dist = std::max(var_dist,var_dist_min);
00043   var_dist = var_dist_min + var_dist*var_dist;
00044   double var_theta = alpha1 * std::fabs(tf::getYaw(odomTf.getRotation())); //this is the translation
00045   var_theta = var_theta_min + var_theta*var_theta;
00046   var_theta = std::max(var_theta,var_theta_min);
00047 */  
00048  
00049  edge.transform = tf2G2O(odomTf);
00050   edge.informationMatrix = Eigen::Matrix<double, 6, 6>::Ones(); //Do not influence optimization
00051   edge.informationMatrix = edge.informationMatrix*0.001*infoCoeff;
00052 
00053 //  edge.informationMatrix = Eigen::Matrix<double, 6, 6>::Zero(); //Do not influence optimization
00054 //  edge.informationMatrix(0,0) = infoCoeff*(1./var_dist); //0.1m accuracy in the floor plane
00055 //  edge.informationMatrix(1,1) = 10000000; //
00056 //  edge.informationMatrix(2,2) = infoCoeff*(1./var_dist);//1./(0.001+var_dist);//0.01m information on rotation w.r. to floor
00057 //  edge.informationMatrix(4,4) = infoCoeff*(1./var_theta);//0.02rad information on rotation w.r. to floor
00058 //  edge.informationMatrix(3,3) = 10000000;//0.02rad information on rotation w.r. to floor
00059 //  edge.informationMatrix(5,5) = 10000000;//1/var_angle; //rotation about vertical
00060 }
00061 
00062 void GraphManager::addOdometry(ros::Time timestamp,
00063          tf::TransformListener* listener) 
00064 {
00065   //return if graph is empty
00066   if (graph_.size() < 2) return;
00067 
00068   //Variables Used in loop
00069   //look through graph to find nodes that do not have odom edges
00070   std::map<int, Node*>::reverse_iterator rit = graph_.rbegin();
00071   std::map<int, Node*>::reverse_iterator prev_rit = graph_.rbegin();
00072   prev_rit++;
00073 
00074   std::string odom_fixed_frame = ParameterServer::instance()->get<std::string>("odom_frame_name");
00075   std::string odom_target_frame = ParameterServer::instance()->get<std::string>("odom_target_frame_name");
00076   std::string odom_target_frame1;//for start's frame in loop
00077   std::string odom_target_frame2;//for end's frame in loop
00078   tf::StampedTransform deltaTransform;
00079   std::string error_msg;
00080   bool ok = false;
00081   
00082   for (; prev_rit != graph_.rend(); ++prev_rit, ++rit) {
00083     Node *earlier_node = prev_rit->second;
00084     Node *later_node = rit->second;
00085     //if we have already received the odometry for the node which we would like to point to
00086     //we know we can interpolate instead of extrapolate the odometry and insert an edge as well as the odometry to the node
00087     if (!earlier_node->has_odometry_edge_) {
00088         ROS_INFO("Processing odometry between %d and %d.", earlier_node->id_, later_node->id_); 
00089         //Get Frames
00090         if(odom_target_frame.empty()){//Use data frame
00091           odom_target_frame1 = earlier_node->pc_col->header.frame_id;
00092           odom_target_frame2 = later_node->pc_col->header.frame_id;
00093         } else{//Use value from parameter
00094           odom_target_frame1 = odom_target_frame;
00095           odom_target_frame2 = odom_target_frame;
00096         }
00097 
00098         ROS_WARN_STREAM("ODOM Target Frame " << odom_target_frame1 << " " << odom_target_frame2 << " " << odom_fixed_frame); 
00099  
00100         ok = listener->canTransform(odom_target_frame1, earlier_node->timestamp_, //frame and time of earlier node
00101                                     odom_target_frame2, later_node->timestamp_,   //frame and time of newer node
00102                                     odom_fixed_frame, &error_msg);
00103         if(ok){
00104           //from http://wiki.ros.org/tf/Tutorials/Time%20travel%20with%20tf%20%28C%2B%2B%29
00105           //listener.lookupTransform("/turtle2", now, "/turtle1", past, "/world", transform);
00106           listener->lookupTransform(odom_target_frame1, earlier_node->timestamp_, //frame and time of earlier node
00107                                     odom_target_frame2, later_node->timestamp_,   //frame and time of newer node
00108                                     odom_fixed_frame, deltaTransform);
00109 
00110           printTransform("Odometry Delta", deltaTransform);
00111           //ADD edge here
00112           LoadedEdge3D edge;
00113           createOdometryEdge(earlier_node->id_, later_node->id_, deltaTransform, edge);
00114           QMatrix4x4 motion_estimate =eigenTF2QMatrix(edge.transform);//not used
00115           addOdometryEdgeToG2O(edge, earlier_node, later_node, motion_estimate);
00116           earlier_node->has_odometry_edge_=true;
00117     //      }
00118         } else {//couldn't transform
00119           ROS_ERROR("Cannot transform between node %d (time %d.%09d) and %d (time %d.%09d). Stated reason: %s", 
00120                     earlier_node->id_, earlier_node->timestamp_.sec, earlier_node->timestamp_.nsec, later_node->id_, later_node->timestamp_.sec, later_node->timestamp_.nsec, error_msg.c_str());
00121           ROS_ERROR_STREAM(listener->allFramesAsString());
00122         }
00123     } else {// Encountered node with odometry edge = true
00124         //ROS_DEBUG("Node already has odometry: %d", earlier_node->id_); 
00125       //break; //One could save the latest node before which all nodes have odometry, but running through the nodes is quick
00126     }
00127 
00128   }
00129   //Hack: Update display after adding edge
00130   Q_EMIT updateTransforms(getAllPosesAsMatrixList());
00131 }
00132 
00133 bool GraphManager::addOdometryEdgeToG2O(const LoadedEdge3D& edge,
00134                                         Node* n1, Node* n2,  
00135                                         QMatrix4x4& motion_estimate) //Pure output
00136 {
00137     ScopedTimer s(__FUNCTION__);
00138     assert(n1);
00139     assert(n2);
00140     assert(n1->id_ == edge.id1);
00141     assert(n2->id_ == edge.id2);
00142 
00143     QMutexLocker locker(&optimizer_mutex_);
00144     g2o::VertexSE3* v1 = dynamic_cast<g2o::VertexSE3*>(optimizer_->vertex(n1->vertex_id_));
00145     g2o::VertexSE3* v2 = dynamic_cast<g2o::VertexSE3*>(optimizer_->vertex(n2->vertex_id_));
00146 
00147     if(!v1 && !v2){
00148       ROS_ERROR("Missing both vertices: %i, %i, cannot create edge", edge.id1, edge.id2);
00149       return false;
00150     } else if (!v1 && v2) {
00151       ROS_ERROR("Missing previous id. This is unexpected by the programmer");
00152       return false;
00153     } else if (!v2 && v1) {
00154       ROS_ERROR("Creating new id for odometry. This is unexpected by the programmer");
00155       return false;
00156     }
00157     else
00158     { 
00159       g2o::EdgeSE3* g2o_edge = new g2o::EdgeSE3;
00160       g2o_edge->vertices()[0] = v1;
00161       g2o_edge->vertices()[1] = v2;
00162       Eigen::Isometry3d meancopy(edge.transform); 
00163       g2o_edge->setMeasurement(meancopy);
00164       g2o_edge->setInformation(edge.informationMatrix);
00165       optimizer_->addEdge(g2o_edge);
00166       ROS_INFO_STREAM("Added Edge ("<< edge.id1 << "-" << edge.id2 << ") to Optimizer:\n" << edge.transform.matrix() << "\nInformation Matrix:\n" << edge.informationMatrix);
00167       cam_cam_edges_.insert(g2o_edge);
00168       odometry_edges_.insert(g2o_edge);
00169       current_match_edges_.insert(g2o_edge); //Used if all previous vertices are fixed ("pose_relative_to" == "all")
00170     } 
00171     if (ParameterServer::instance()->get<std::string>("pose_relative_to") == "inaffected") {
00172       v1->setFixed(false);
00173       v2->setFixed(false);
00174     }
00175     else if(ParameterServer::instance()->get<std::string>("pose_relative_to") == "largest_loop") {
00176       earliest_loop_closure_node_ = std::min(earliest_loop_closure_node_, edge.id1);
00177       earliest_loop_closure_node_ = std::min(earliest_loop_closure_node_, edge.id2);
00178     }
00179     ROS_INFO("Added odometry edge between %d and %d.", n1->id_, n2->id_);
00180     return true;
00181 }
00182 


rgbdslam_v2
Author(s): Felix Endres, Juergen Hess, Nikolas Engelhard
autogenerated on Thu Jun 6 2019 21:49:45