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
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
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
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
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
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
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
00089
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
00100 NodePoseMap optimizeGraph (const PoseGraph& g)
00101 {
00102
00103
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
00111
00112
00113 const size_t num_nodes = res.spa->nodes.size();
00114 const size_t num_constraints = res.spa->p2cons.size();
00115
00116
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
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 }