spa_conversion.cpp
Go to the documentation of this file.
00001 #include <pose_graph/spa_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::Node;
00016 using sba::SysSPA;
00017 using sba::ConP2;
00018 using geometry_msgs::Pose;
00019 
00020 // Make a spa node given an initial pose estimate
00021 Node makeNode (const Pose& initial_pose)
00022 {
00023   Node n;
00024   n.trans = translationToVector4d(initial_pose.position);
00025   n.qrot = quaternionMsgToVector4d(initial_pose.orientation);
00026   n.normRot();
00027   n.setTransform();
00028   n.setDr();
00029   return n;
00030 }
00031 
00032 
00033 // Turn a PoseConstraint into a ConP2
00034 ConP2 makeSpaConstraint (const PoseConstraint& constraint)
00035 {
00036   ConP2 spa;
00037   spa.tmean = constraint.translation;
00038   spa.qpmean = constraint.rotation.inverse();
00039 
00040   spa.prec = constraint.precision;
00041 
00042   return spa;
00043 }
00044 
00045 
00046 // Turn a pose graph into a SysSpa
00047 SpaConversionResult poseGraphToSpa (const PoseGraph& pose_graph)
00048 {
00049   SpaPtr spa(new SysSPA());
00050   map<NodeId, unsigned> node_indices;
00051   unsigned next_index=0;
00052 
00053   // 1. Add the nodes
00054   BOOST_FOREACH (const NodeId n, pose_graph.allNodes()) {
00055     spa->nodes.push_back(makeNode(pose_graph.getInitialPoseEstimate(n)));
00056     node_indices[n] = next_index++;
00057   }
00058 
00059   // 2. Add the edge constraints
00060   BOOST_FOREACH (const EdgeId e, pose_graph.allEdges()) {
00061     
00062     std::pair<NodeId, NodeId> ids = pose_graph.incidentNodes(e);
00063     const pose_graph::PoseConstraint constraint = pose_graph.getConstraint(e);
00064     ConP2 spa_constraint = makeSpaConstraint(constraint);
00065 
00066     spa_constraint.ndr = node_indices[ids.first];
00067     spa_constraint.nd1 = node_indices[ids.second];
00068     spa->p2cons.push_back(spa_constraint);
00069     ROS_DEBUG_STREAM_NAMED ("pose_graph_spa", "Adding constraint with tmean " << spa_constraint.tmean << 
00070                             ", qpmean " << spa_constraint.qpmean.coeffs() << " and precision "
00071                             << spa_constraint.prec << " from " << 
00072                             spa_constraint.ndr << " to " << spa_constraint.nd1);
00073   }
00074 
00075   return SpaConversionResult(spa, node_indices);
00076 }
00077 
00078 
00079 // Return the Pose corresponding to a spa node
00080 Pose getNodePose (const sba::Node& n)
00081 {
00082   Pose pose;
00083 
00084   pose.position.x = n.trans(0);
00085   pose.position.y = n.trans(1);
00086   pose.position.z = n.trans(2);
00087 
00088   // Per documentation, qrot is in xyzw order
00089   // Since Eigen uses wxyz, n.qrot(w) is not the same as n.qrot[3]
00090   pose.orientation.x = n.qrot.x();
00091   pose.orientation.y = n.qrot.y();
00092   pose.orientation.z = n.qrot.z();
00093   pose.orientation.w = n.qrot.w();
00094 
00095   return pose;
00096 }
00097 
00098 
00099 // Convert and optimize a graph
00100 NodePoseMap optimizeGraph (const PoseGraph& g)
00101 {
00102   /******************************
00103    * 1. Convert graph to SPA
00104    ******************************/
00105 
00106   ROS_DEBUG_NAMED ("pose_graph_spa", "Converting graph with %zu nodes to spa", g.allNodes().size());
00107   SpaConversionResult res=poseGraphToSpa(g);
00108 
00109   /******************************
00110    * 2. Optimize
00111    ******************************/
00112 
00113   const size_t num_nodes = res.spa->nodes.size();
00114   const size_t num_constraints = res.spa->p2cons.size();
00115 
00116   // Shouldn't need this check, but spa dies otherwise
00117   if (num_nodes>=2 && num_constraints>=1) { 
00118     ROS_DEBUG_NAMED ("pose_graph_spa", "Performing spa with %zu nodes and %zu constraints",
00119                      num_nodes, num_constraints);
00120     int num_iters = res.spa->doSPA(10, 1.0e-4, true);
00121     ROS_DEBUG_NAMED ("pose_graph_spa", "Graph optimization complete; took %d iterations", num_iters);
00122   }
00123   else 
00124     ROS_DEBUG_NAMED ("pose_graph_spa", "Not optimizing graph with %zu nodes and %zu constraints",
00125                      num_nodes, num_constraints);
00126   
00127   /******************************
00128    * 3. Return optimized poses
00129    ******************************/
00130 
00131   NodePoseMap optimized_poses;
00132   BOOST_FOREACH (const NodeIndexMap::value_type entry, res.node_index_map) {
00133     optimized_poses[entry.first] = getNodePose(res.spa->nodes[entry.second]);
00134     ROS_DEBUG_STREAM_NAMED ("spa_result", "  Node " << entry.first <<
00135                             "; pose " << optimized_poses[entry.first]);
00136   }
00137   return optimized_poses;
00138 }
00139 
00140 
00141 
00142 
00143 
00144 } // namespace


pose_graph
Author(s): Bhaskara Marthi
autogenerated on Tue Jan 7 2014 11:17:15