g2o
solver_slam2d_linear.cpp
Go to the documentation of this file.
1 // g2o - General Graph Optimization
2 // Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #include "solver_slam2d_linear.h"
28 
29 #include <Eigen/Core>
30 
34 
36 
37 #include "g2o/stuff/misc.h"
39 
41 
42 using namespace std;
43 
44 namespace g2o {
45 
50  {
51  public:
52  ThetaTreeAction(double* theta) : HyperDijkstra::TreeAction(), _thetaGuess(theta) {}
54  {
55  if (! vParent)
56  return 0.;
57  EdgeSE2* odom = static_cast<EdgeSE2*>(e);
58  VertexSE2* from = static_cast<VertexSE2*>(vParent);
59  VertexSE2* to = static_cast<VertexSE2*>(v);
60  assert(to->hessianIndex() >= 0);
61  double fromTheta = from->hessianIndex() < 0 ? 0. : _thetaGuess[from->hessianIndex()];
62  bool direct = odom->vertices()[0] == from;
63  if (direct)
64  _thetaGuess[to->hessianIndex()] = fromTheta + odom->measurement().rotation().angle();
65  else
66  _thetaGuess[to->hessianIndex()] = fromTheta - odom->measurement().rotation().angle();
67  return 1.;
68  }
69  protected:
70  double* _thetaGuess;
71  };
72 
73  SolverSLAM2DLinear::SolverSLAM2DLinear(Solver* solver) :
75  {
76  }
77 
79  {
80  }
81 
82  OptimizationAlgorithm::SolverResult SolverSLAM2DLinear::solve(int iteration, bool online)
83  {
84  if (iteration == 0) {
85  bool status = solveOrientation();
86  if (! status)
87  return OptimizationAlgorithm::Fail;
88  }
89 
90  return OptimizationAlgorithmGaussNewton::solve(iteration, online);
91  }
92 
94  {
95  assert(_optimizer->indexMapping().size() + 1 == _optimizer->vertices().size() && "Needs to operate on full graph");
96  assert(_optimizer->vertex(0)->fixed() && "Graph is not fixed by vertex 0");
97  VectorXD b, x; // will be used for theta and x/y update
98  b.setZero(_optimizer->indexMapping().size());
99  x.setZero(_optimizer->indexMapping().size());
100 
101  typedef Eigen::Matrix<double, 1, 1, Eigen::ColMajor> ScalarMatrix;
102 
103  ScopedArray<int> blockIndeces(new int[_optimizer->indexMapping().size()]);
104  for (size_t i = 0; i < _optimizer->indexMapping().size(); ++i)
105  blockIndeces[i] = i+1;
106 
107  SparseBlockMatrix<ScalarMatrix> H(blockIndeces.get(), blockIndeces.get(), _optimizer->indexMapping().size(), _optimizer->indexMapping().size());
108 
109  // building the structure, diagonal for each active vertex
110  for (size_t i = 0; i < _optimizer->indexMapping().size(); ++i) {
112  int poseIdx = v->hessianIndex();
113  ScalarMatrix* m = H.block(poseIdx, poseIdx, true);
114  m->setZero();
115  }
116 
117  HyperGraph::VertexSet fixedSet;
118 
119  // off diagonal for each edge
120  for (SparseOptimizer::EdgeContainer::const_iterator it = _optimizer->activeEdges().begin(); it != _optimizer->activeEdges().end(); ++it) {
121 # ifndef NDEBUG
122  EdgeSE2* e = dynamic_cast<EdgeSE2*>(*it);
123  assert(e && "Active edges contain non-odometry edge"); //
124 # else
125  EdgeSE2* e = static_cast<EdgeSE2*>(*it);
126 # endif
127  OptimizableGraph::Vertex* from = static_cast<OptimizableGraph::Vertex*>(e->vertices()[0]);
128  OptimizableGraph::Vertex* to = static_cast<OptimizableGraph::Vertex*>(e->vertices()[1]);
129 
130  int ind1 = from->hessianIndex();
131  int ind2 = to->hessianIndex();
132  if (ind1 == -1 || ind2 == -1) {
133  if (ind1 == -1) fixedSet.insert(from); // collect the fixed vertices
134  if (ind2 == -1) fixedSet.insert(to);
135  continue;
136  }
137 
138  bool transposedBlock = ind1 > ind2;
139  if (transposedBlock){ // make sure, we allocate the upper triangle block
140  std::swap(ind1, ind2);
141  }
142 
143  ScalarMatrix* m = H.block(ind1, ind2, true);
144  m->setZero();
145  }
146 
147  // walk along the Minimal Spanning Tree to compute the guess for the robot orientation
148  assert(fixedSet.size() == 1);
149  VertexSE2* root = static_cast<VertexSE2*>(*fixedSet.begin());
150  VectorXD thetaGuess;
151  thetaGuess.setZero(_optimizer->indexMapping().size());
152  UniformCostFunction uniformCost;
153  HyperDijkstra hyperDijkstra(_optimizer);
154  hyperDijkstra.shortestPaths(root, &uniformCost);
155 
156  HyperDijkstra::computeTree(hyperDijkstra.adjacencyMap());
157  ThetaTreeAction thetaTreeAction(thetaGuess.data());
158  HyperDijkstra::visitAdjacencyMap(hyperDijkstra.adjacencyMap(), &thetaTreeAction);
159 
160  // construct for the orientation
161  for (SparseOptimizer::EdgeContainer::const_iterator it = _optimizer->activeEdges().begin(); it != _optimizer->activeEdges().end(); ++it) {
162  EdgeSE2* e = static_cast<EdgeSE2*>(*it);
163  VertexSE2* from = static_cast<VertexSE2*>(e->vertices()[0]);
164  VertexSE2* to = static_cast<VertexSE2*>(e->vertices()[1]);
165 
166  double omega = e->information()(2,2);
167 
168  double fromThetaGuess = from->hessianIndex() < 0 ? 0. : thetaGuess[from->hessianIndex()];
169  double toThetaGuess = to->hessianIndex() < 0 ? 0. : thetaGuess[to->hessianIndex()];
170  double error = normalize_theta(-e->measurement().rotation().angle() + toThetaGuess - fromThetaGuess);
171 
172  bool fromNotFixed = !(from->fixed());
173  bool toNotFixed = !(to->fixed());
174 
175  if (fromNotFixed || toNotFixed) {
176  double omega_r = - omega * error;
177  if (fromNotFixed) {
178  b(from->hessianIndex()) -= omega_r;
179  (*H.block(from->hessianIndex(), from->hessianIndex()))(0,0) += omega;
180  if (toNotFixed) {
181  if (from->hessianIndex() > to->hessianIndex())
182  (*H.block(to->hessianIndex(), from->hessianIndex()))(0,0) -= omega;
183  else
184  (*H.block(from->hessianIndex(), to->hessianIndex()))(0,0) -= omega;
185  }
186  }
187  if (toNotFixed ) {
188  b(to->hessianIndex()) += omega_r;
189  (*H.block(to->hessianIndex(), to->hessianIndex()))(0,0) += omega;
190  }
191  }
192  }
193 
194  // solve orientation
195  typedef LinearSolverCSparse<ScalarMatrix> SystemSolver;
196  SystemSolver linearSystemSolver;
197  linearSystemSolver.init();
198  bool ok = linearSystemSolver.solve(H, x.data(), b.data());
199  if (!ok) {
200  cerr << __PRETTY_FUNCTION__ << "Failure while solving linear system" << endl;
201  return false;
202  }
203 
204  // update the orientation of the 2D poses and set translation to 0, GN shall solve that
205  root->setToOrigin();
206  for (size_t i = 0; i < _optimizer->indexMapping().size(); ++i) {
207  VertexSE2* v = static_cast<VertexSE2*>(_optimizer->indexMapping()[i]);
208  int poseIdx = v->hessianIndex();
209  SE2 poseUpdate(0, 0, normalize_theta(thetaGuess(poseIdx) + x(poseIdx)));
210  v->setEstimate(poseUpdate);
211  }
212 
213  return true;
214  }
215 
216 } // end namespace
#define __PRETTY_FUNCTION__
Definition: macros.h:89
some general case utility functions
2D edge between two Vertex2
Definition: edge_se2.h:40
static void computeTree(AdjacencyMap &amap)
std::set< Vertex * > VertexSet
Definition: hyper_graph.h:136
virtual double perform(HyperGraph::Vertex *v, HyperGraph::Vertex *vParent, HyperGraph::Edge *e)
represent SE2
Definition: se2.h:40
const EdgeContainer & activeEdges() const
the edges active in the current optimization
int hessianIndex() const
temporary index of this node in the parameter vector obtained from linearization
2D pose Vertex, (x,y,theta)
Definition: vertex_se2.h:41
const VertexIDMap & vertices() const
Definition: hyper_graph.h:225
Implementation of the Gauss Newton Algorithm.
Vertex * vertex(int id)
returns the vertex number id appropriately casted
static void visitAdjacencyMap(AdjacencyMap &amap, TreeAction *action, bool useDistance=false)
const VertexContainer & vertices() const
Definition: hyper_graph.h:178
const Eigen::Rotation2Dd & rotation() const
rotational component
Definition: se2.h:58
void shortestPaths(HyperGraph::Vertex *v, HyperDijkstra::CostFunction *cost, double maxDistance=std::numeric_limits< double >::max(), double comparisonConditioner=1e-3, bool directed=false, double maxEdgeCost=std::numeric_limits< double >::max())
linear solver which uses CSparse
Generic interface for a sparse solver operating on a graph which solves one iteration of the lineariz...
Definition: solver.h:44
SparseOptimizer * _optimizer
the optimizer the solver is working on
const VertexContainer & indexMapping() const
the index mapping of the vertices
double normalize_theta(double theta)
Definition: misc.h:94
void setEstimate(const EstimateType &et)
set the estimate for the vertex also calls updateCache()
Definition: base_vertex.h:101
A general case Vertex for optimization.
compute the initial guess of theta while travelling along the MST
abstract Vertex, your types must derive from that one
Definition: hyper_graph.h:142
Eigen::Matrix< double, Eigen::Dynamic, 1, Eigen::ColMajor > VectorXD
Definition: eigen_types.h:48
EIGEN_STRONG_INLINE const InformationType & information() const
information matrix of the constraint
Definition: base_edge.h:67
virtual OptimizationAlgorithm::SolverResult solve(int iteration, bool online=false)
AdjacencyMap & adjacencyMap()
virtual SolverResult solve(int iteration, bool online=false)
bool fixed() const
true => this node is fixed during the optimization
a scoped pointer for an array, i.e., array will be deleted on leaving the scope
Sparse matrix which uses blocks.
EIGEN_STRONG_INLINE const Measurement & measurement() const
accessor functions for the measurement represented by the edge
Definition: base_edge.h:75