00001 #include <pose_graph/spa_2d_conversion.h>
00002 #include <pose_graph/transforms.h>
00003 #include <pose_graph/exception.h>
00004 #include <pose_graph/utils.h>
00005 #include <tf/transform_datatypes.h>
00006 #include <boost/foreach.hpp>
00007 #include <boost/tuple/tuple.hpp>
00008 #include <set>
00009
00010 namespace pose_graph
00011 {
00012
00013 using std::set;
00014 using boost::tie;
00015 using sba::Node2d;
00016 using sba::SysSPA2d;
00017 using sba::Con2dP2;
00018 using geometry_msgs::Pose;
00019
00020
00021 typedef std::pair<NodeId, NodeId> NodePair;
00022
00023
00024 Node2d makeNode (const double x, const double y, const double theta)
00025 {
00026 Node2d n;
00027 n.trans(0) = x;
00028 n.trans(1) = y;
00029 n.trans(2) = 1.0;
00030 n.arot = theta;
00031 n.setTransform();
00032 n.setDr();
00033 return n;
00034 }
00035
00036
00037
00038 double getYaw (const Quaterniond& q)
00039 {
00040 const tf::Quaternion qt(q.x(), q.y(), q.z(), q.w());
00041 return tf::getYaw(qt);
00042 }
00043
00044 Con2dP2 makeSpa2DConstraint (const PoseConstraint& constraint)
00045 {
00046 Con2dP2 spa;
00047 spa.tmean[0] = constraint.translation[0];
00048 spa.tmean[1] = constraint.translation[1];
00049 spa.amean = getYaw(constraint.rotation);
00050
00051 spa.prec = Matrix3d::Zero();
00052 spa.prec(0,0) = constraint.precision(0,0);
00053 spa.prec(1,1) = constraint.precision(1,1);
00054
00055 spa.prec(2,2) = constraint.precision(5,5)*4;
00056
00057 return spa;
00058 }
00059
00060
00061
00062 Spa2DConversionResult poseGraphToSpa2D (const PoseGraph& pose_graph)
00063 {
00064 Spa2DPtr spa(new SysSPA2d());
00065 map<NodeId, unsigned> node_indices;
00066 unsigned next_index=0;
00067
00068
00069 BOOST_FOREACH (const NodeId n, pose_graph.allNodes()) {
00070 const Pose p = pose_graph.getInitialPoseEstimate(n);
00071 Eigen3::Vector3d pos(p.position.x, p.position.y, tf::getYaw(p.orientation));
00072 spa->addNode(pos, next_index);
00073 ROS_DEBUG_STREAM_NAMED ("pose_graph_spa", "Adding node " << next_index << " with mean " << pos);
00074 node_indices[n] = next_index++;
00075 }
00076
00077
00078 BOOST_FOREACH (const EdgeId e, pose_graph.allEdges()) {
00079
00080 NodePair ids = pose_graph.incidentNodes(e);
00081 const pose_graph::PoseConstraint constraint = pose_graph.getConstraint(e);
00082 Eigen3::Vector3d mean(constraint.translation[0], constraint.translation[1], getYaw(constraint.rotation));
00083 Eigen3::Matrix3d prec = Eigen3::Matrix3d::Zero();
00084
00085
00086
00087
00088 prec(2, 2) = constraint.precision(5, 5)*4;
00089 prec(0, 0) = constraint.precision(0, 0);
00090 prec(1, 1) = constraint.precision(1, 1);
00091
00092 const unsigned ind1 = node_indices[ids.first];
00093 const unsigned ind2 = node_indices[ids.second];
00094 spa->addConstraint(ind1, ind2, mean, prec);
00095 ROS_DEBUG_STREAM_NAMED ("pose_graph_spa", "Adding constraint from " << ind1 << " to " << ind2 <<
00096 " with mean " << mean << " and precision " << prec);
00097 }
00098
00099
00100 return Spa2DConversionResult(spa, node_indices);
00101 }
00102
00103
00104
00105 Pose getNodePose (const sba::Node2d& n)
00106 {
00107 Pose pose;
00108
00109 pose.position.x = n.trans(0);
00110 pose.position.y = n.trans(1);
00111 pose.position.z = 0.0;
00112
00113 pose.orientation = tf::createQuaternionMsgFromYaw(n.arot);
00114
00115 return pose;
00116 }
00117
00118
00119
00120 NodePoseMap optimizeGraph2D (const PoseGraph& g)
00121 {
00122
00123
00124
00125
00126 ROS_DEBUG_NAMED ("pose_graph_spa", "Converting graph with %zu nodes to spa", g.allNodes().size());
00127 Spa2DConversionResult res=poseGraphToSpa2D(g);
00128
00129
00130
00131
00132
00133 const size_t num_nodes = res.spa->nodes.size();
00134 const size_t num_constraints = res.spa->p2cons.size();
00135
00136
00137 if (num_nodes>=2 && num_constraints>=1) {
00138 ROS_DEBUG_NAMED ("pose_graph_spa", "Performing spa with %zu nodes and %zu constraints",
00139 num_nodes, num_constraints);
00140 res.spa->doSPA(10, 1.0e-4, SBA_BLOCK_JACOBIAN_PCG);
00141 ROS_DEBUG_NAMED ("pose_graph_spa", "Graph optimization complete");
00142 }
00143 else
00144 ROS_DEBUG_NAMED ("pose_graph_spa", "Not optimizing graph with %zu nodes and %zu constraints",
00145 num_nodes, num_constraints);
00146
00147
00148
00149
00150
00151 NodePoseMap optimized_poses;
00152 BOOST_FOREACH (const NodeIndexMap::value_type entry, res.node_index_map) {
00153 optimized_poses[entry.first] = getNodePose(res.spa->nodes[entry.second]);
00154 ROS_DEBUG_STREAM_NAMED ("spa_result", " Node " << entry.first <<
00155 "; pose " << optimized_poses[entry.first]);
00156 }
00157 return optimized_poses;
00158 }
00159
00160
00161
00162
00163
00164
00165 }