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
00010
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
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 edge.transform = tf2G2O(odomTf);
00050 edge.informationMatrix = Eigen::Matrix<double, 6, 6>::Ones();
00051 edge.informationMatrix = edge.informationMatrix*0.001*infoCoeff;
00052
00053
00054
00055
00056
00057
00058
00059
00060 }
00061
00062 void GraphManager::addOdometry(ros::Time timestamp,
00063 tf::TransformListener* listener)
00064 {
00065
00066 if (graph_.size() < 2) return;
00067
00068
00069
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;
00077 std::string odom_target_frame2;
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
00086
00087 if (!earlier_node->has_odometry_edge_) {
00088 ROS_INFO("Processing odometry between %d and %d.", earlier_node->id_, later_node->id_);
00089
00090 if(odom_target_frame.empty()){
00091 odom_target_frame1 = earlier_node->pc_col->header.frame_id;
00092 odom_target_frame2 = later_node->pc_col->header.frame_id;
00093 } else{
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_,
00101 odom_target_frame2, later_node->timestamp_,
00102 odom_fixed_frame, &error_msg);
00103 if(ok){
00104
00105
00106 listener->lookupTransform(odom_target_frame1, earlier_node->timestamp_,
00107 odom_target_frame2, later_node->timestamp_,
00108 odom_fixed_frame, deltaTransform);
00109
00110 printTransform("Odometry Delta", deltaTransform);
00111
00112 LoadedEdge3D edge;
00113 createOdometryEdge(earlier_node->id_, later_node->id_, deltaTransform, edge);
00114 QMatrix4x4 motion_estimate =eigenTF2QMatrix(edge.transform);
00115 addOdometryEdgeToG2O(edge, earlier_node, later_node, motion_estimate);
00116 earlier_node->has_odometry_edge_=true;
00117
00118 } else {
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 {
00124
00125
00126 }
00127
00128 }
00129
00130 Q_EMIT updateTransforms(getAllPosesAsMatrixList());
00131 }
00132
00133 bool GraphManager::addOdometryEdgeToG2O(const LoadedEdge3D& edge,
00134 Node* n1, Node* n2,
00135 QMatrix4x4& motion_estimate)
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);
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