g2o
simulator_3d_plane.cpp
Go to the documentation of this file.
1 #include <fstream>
9 #include "g2o/stuff/macros.h"
10 #include "g2o/stuff/command_args.h"
11 
12 #include <iostream>
13 
14 using namespace g2o;
15 using namespace std;
16 using namespace Eigen;
17 
19 
20 //typedef Eigen::Matrix<double, 6,6> Matrix6d; //Avoid ambiguous symbol
21 
22 double uniform_rand(double lowerBndr, double upperBndr)
23 {
24  return lowerBndr + ((double) std::rand() / (RAND_MAX + 1.0)) * (upperBndr - lowerBndr);
25 }
26 
27 double gauss_rand(double sigma)
28 {
29  double x, y, r2;
30  do {
31  x = -1.0 + 2.0 * uniform_rand(0.0, 1.0);
32  y = -1.0 + 2.0 * uniform_rand(0.0, 1.0);
33  r2 = x * x + y * y;
34  } while (r2 > 1.0 || r2 == 0.0);
35  return sigma * y * std::sqrt(-2.0 * log(r2) / r2);
36 }
37 
38 Eigen::Isometry3d sample_noise_from_se3(const Vector6d& cov ){
39  double nx=gauss_rand(cov(0));
40  double ny=gauss_rand(cov(1));
41  double nz=gauss_rand(cov(2));
42 
43  double nroll=gauss_rand(cov(3));
44  double npitch=gauss_rand(cov(4));
45  double nyaw=gauss_rand(cov(5));
46 
47  AngleAxisd aa(AngleAxisd(nyaw, Vector3d::UnitZ())*
48  AngleAxisd(nroll, Vector3d::UnitX())*
49  AngleAxisd(npitch, Vector3d::UnitY()));
50 
51  Eigen::Isometry3d retval=Isometry3d::Identity();
52  retval.matrix().block<3,3>(0,0)= aa.toRotationMatrix();
53  retval.translation()=Vector3d(nx,ny,nz);
54  return retval;
55 }
56 
57 Vector3d sample_noise_from_plane(const Vector3d& cov ){
58  return Vector3d(gauss_rand(cov(0)), gauss_rand(cov(1)), gauss_rand(cov(2)));
59 }
60 
61 struct SimulatorItem {
62  SimulatorItem(OptimizableGraph* graph_): _graph(graph_){}
63  OptimizableGraph* graph() {return _graph;}
64  virtual ~SimulatorItem(){}
65  protected:
67 };
68 
69 struct WorldItem: public SimulatorItem {
71  SimulatorItem(graph_),_vertex(vertex_) {}
72  OptimizableGraph::Vertex* vertex() {return _vertex;}
73  void setVertex(OptimizableGraph::Vertex* vertex_) {_vertex = vertex_;}
74 protected:
76 };
77 
78 typedef std::set<WorldItem*> WorldItemSet;
79 
80 struct Robot;
81 
82 struct Sensor {
83  Sensor(Robot* robot_) : _robot(robot_){}
84  Robot* robot() {return _robot;}
85  virtual bool isVisible(const WorldItem* ) const {return false;}
86  virtual bool sense(WorldItem* , const Isometry3d& ) {return false;}
87  virtual ~Sensor(){};
88 protected:
89  Robot* _robot;
90 };
91 
92 typedef std::vector<Sensor*> SensorVector;
93 
94 struct Robot: public WorldItem {
95 
96  Robot(OptimizableGraph* graph_): WorldItem(graph_) {
97  _planarMotion=false;
98  _position = Isometry3d::Identity();
99  }
100 
101 
102  void move(const Isometry3d& newPosition, int& id) {
103  Isometry3d delta = _position.inverse()*newPosition;
104  _position = newPosition;
105  VertexSE3* v=new VertexSE3();
106  v->setId(id);
107  id++;
108  graph()->addVertex(v);
109  if (_planarMotion){
110  // add a singleton constraint that locks the position of the robot on the plane
111  EdgeSE3Prior* planeConstraint=new EdgeSE3Prior();
112  Matrix6d pinfo = Matrix6d::Zero();
113  pinfo(2,2)=1e9;
114  planeConstraint->setInformation(pinfo);
115  planeConstraint->setMeasurement(Isometry3d::Identity());
116  planeConstraint->vertices()[0]=v;
117  planeConstraint->setParameterId(0,0);
118  graph()->addEdge(planeConstraint);
119  }
120  if (vertex()){
121  VertexSE3* oldV=dynamic_cast<VertexSE3*>(vertex());
122  EdgeSE3* e=new EdgeSE3();
123  Isometry3d noise=sample_noise_from_se3(_nmovecov);
124  e->setMeasurement(delta*noise);
125  Matrix6d m=Matrix6d::Identity();
126  for (int i=0; i<6; i++){
127  m(i,i)=1./(_nmovecov(i));
128  }
129  e->setInformation(m);
130  e->vertices()[0]=vertex();
131  e->vertices()[1]=v;
132  graph()->addEdge(e);
133  v->setEstimate(oldV->estimate()*e->measurement());
134  } else {
135  v->setEstimate(_position);
136  }
137  setVertex(v);
138  }
139 
140  void relativeMove(const Isometry3d& delta, int& id){
141  Isometry3d newPosition = _position*delta;
142  move(newPosition, id);
143  }
144 
145  void sense(WorldItem* wi=0){
146  for (size_t i=0; i<_sensors.size(); i++){
147  Sensor* s=_sensors[i];
148  s->sense(wi, _position);
149  }
150  }
151 
152  Isometry3d _position;
156 };
157 
158 typedef std::vector<Robot*> RobotVector;
159 
160 struct Simulator: public SimulatorItem {
161  Simulator(OptimizableGraph* graph_): SimulatorItem(graph_), _lastVertexId(0){}
162  void sense(int robotIndex){
163  Robot* r=_robots[robotIndex];
164  for (WorldItemSet::iterator it=_world.begin(); it!=_world.end(); it++){
165  WorldItem* item=*it;
166  r->sense(item);
167  }
168  }
169 
170  void move(int robotIndex, const Isometry3d& newRobotPose){
171  Robot* r=_robots[robotIndex];
172  r->move(newRobotPose, _lastVertexId);
173  }
174 
175  void relativeMove(int robotIndex, const Isometry3d& delta){
176  Robot* r=_robots[robotIndex];
177  r->relativeMove(delta, _lastVertexId);
178  }
179 
183 };
184 
185 struct PlaneItem: public WorldItem{
186  PlaneItem(OptimizableGraph* graph_, int id) : WorldItem(graph_){
187  VertexPlane* p=new VertexPlane();
188  p->setId(id);
189  graph()->addVertex(p);
190  setVertex(p);
191  }
192 };
193 
194 struct PlaneSensor: public Sensor{
195  PlaneSensor(Robot* r, int offsetId, const Isometry3d& offset_): Sensor(r){
196  _offsetVertex = new VertexSE3();
197  _offsetVertex->setId(offsetId);
198  _offsetVertex->setEstimate(offset_);
199  robot()->graph()->addVertex(_offsetVertex);
200  };
201 
202  virtual bool isVisible(const WorldItem* wi) const {
203  if (! wi)
204  return false;
205  const PlaneItem* pi=dynamic_cast<const PlaneItem*>(wi);
206  if (! pi)
207  return false;
208  return true;
209  }
210 
211  virtual bool sense(WorldItem* wi, const Isometry3d& position){
212  if (! wi)
213  return false;
214  PlaneItem* pi=dynamic_cast<PlaneItem*>(wi);
215  if (! pi)
216  return false;
217  OptimizableGraph::Vertex* rv = robot()->vertex();
218  if (! rv) {
219  return false;
220  }
221  VertexSE3* robotVertex = dynamic_cast<VertexSE3*>(rv);
222  if (! robotVertex){
223  return false;
224  }
225  const Isometry3d& robotPose=position;
226  Isometry3d sensorPose=robotPose*_offsetVertex->estimate();
227  VertexPlane* planeVertex=dynamic_cast<VertexPlane*>(pi->vertex());
228  Plane3D worldPlane=planeVertex->estimate();
229 
230  Plane3D measuredPlane=sensorPose.inverse()*worldPlane;
231 
233  e->vertices()[0]=robotVertex;
234  e->vertices()[1]=planeVertex;
235  e->vertices()[2]=_offsetVertex;
236  Vector3d noise = sample_noise_from_plane(_nplane);
237  measuredPlane.oplus(noise);
238  e->setMeasurement(measuredPlane);
239  Matrix3d m=Matrix3d::Zero();
240  m(0,0)=1./(_nplane(0));
241  m(1,1)=1./(_nplane(1));
242  m(2,2)=1./(_nplane(2));
243  e->setInformation(m);
244  robot()->graph()->addEdge(e);
245  return true;
246  }
247 
249  Vector3d _nplane;
250 };
251 
252 int main (int argc , char ** argv){
253  int maxIterations;
254  bool verbose;
255  bool robustKernel;
256  double lambdaInit;
257  CommandArgs arg;
258  bool fixSensor;
259  bool fixPlanes;
260  bool fixFirstPose;
261  bool fixTrajectory;
262  bool planarMotion;
263  bool listSolvers;
264  string strSolver;
265  cerr << "graph" << endl;
266  arg.param("i", maxIterations, 5, "perform n iterations");
267  arg.param("v", verbose, false, "verbose output of the optimization process");
268  arg.param("solver", strSolver, "lm_var", "select one specific solver");
269  arg.param("lambdaInit", lambdaInit, 0, "user specified lambda init for levenberg");
270  arg.param("robustKernel", robustKernel, false, "use robust error functions");
271  arg.param("fixSensor", fixSensor, false, "fix the sensor position on the robot");
272  arg.param("fixTrajectory", fixTrajectory, false, "fix the trajectory");
273  arg.param("fixFirstPose", fixFirstPose, false, "fix the first robot pose");
274  arg.param("fixPlanes", fixPlanes, false, "fix the planes (do localization only)");
275  arg.param("planarMotion", planarMotion, false, "robot moves on a plane");
276  arg.param("listSolvers", listSolvers, false, "list the solvers");
277  arg.parseArgs(argc, argv);
278 
279 
280 
282  ParameterSE3Offset* odomOffset=new ParameterSE3Offset();
283  odomOffset->setId(0);
284  g->addParameter(odomOffset);
285 
287  OptimizationAlgorithmProperty solverProperty;
288  OptimizationAlgorithm* solver = solverFactory->construct(strSolver, solverProperty);
289  g->setAlgorithm(solver);
290  if (listSolvers){
291  solverFactory->listSolvers(cerr);
292  return 0;
293  }
294 
295  if (! g->solver()){
296  cerr << "Error allocating solver. Allocating \"" << strSolver << "\" failed!" << endl;
297  cerr << "available solvers: " << endl;
298  solverFactory->listSolvers(cerr);
299  cerr << "--------------" << endl;
300  return 0;
301  }
302 
303  cerr << "sim" << endl;
304  Simulator* sim = new Simulator(g);
305 
306  cerr << "robot" << endl;
307  Robot* r=new Robot(g);
308 
309 
310  cerr << "planeSensor" << endl;
311  Matrix3d R=Matrix3d::Identity();
312  R <<
313  0, 0, 1,
314  -1, 0, 0,
315  0, -1, 0;
316 
317  Isometry3d sensorPose=Isometry3d::Identity();
318  sensorPose.matrix().block<3,3>(0,0) = R;
319  sensorPose.translation()= Vector3d(.3 , 0.5 , 1.2);
320  PlaneSensor* ps = new PlaneSensor(r, 0, sensorPose);
321  ps->_nplane << 0.03, 0.03, 0.005;
322  r->_sensors.push_back(ps);
323  sim->_robots.push_back(r);
324 
325  cerr << "p1" << endl;
326  Plane3D plane;
327  PlaneItem* pi =new PlaneItem(g,1);
328  plane.fromVector(Eigen::Vector4d(0.,0.,1.,5.));
329  static_cast<VertexPlane*>(pi->vertex())->setEstimate(plane);
330  pi->vertex()->setFixed(fixPlanes);
331  sim->_world.insert(pi);
332 
333  plane.fromVector(Eigen::Vector4d(1.,0.,0.,5.));
334  pi =new PlaneItem(g,2);
335  static_cast<VertexPlane*>(pi->vertex())->setEstimate(plane);
336  pi->vertex()->setFixed(fixPlanes);
337  sim->_world.insert(pi);
338 
339  cerr << "p2" << endl;
340  pi =new PlaneItem(g,3);
341  plane.fromVector(Eigen::Vector4d(0.,1.,0.,5.));
342  static_cast<VertexPlane*>(pi->vertex())->setEstimate(plane);
343  pi->vertex()->setFixed(fixPlanes);
344  sim->_world.insert(pi);
345 
346 
347  Quaterniond q, iq;
348  if (planarMotion) {
349  r->_planarMotion = true;
350  r->_nmovecov << 0.01, 0.0025, 1e-9, 0.001, 0.001, 0.025;
351  q = Quaterniond(AngleAxisd(0.2, Vector3d::UnitZ()).toRotationMatrix());
352  iq = Quaterniond(AngleAxisd(-0.2, Vector3d::UnitZ()).toRotationMatrix());
353  } else {
354  r->_planarMotion = false;
355  //r->_nmovecov << 0.1, 0.005, 1e-9, 0.05, 0.001, 0.001;
356  r->_nmovecov << 0.1, 0.005, 1e-9, 0.001, 0.001, 0.05;
357  q = Quaterniond((AngleAxisd(M_PI/10, Vector3d::UnitZ()) * AngleAxisd(0.1, Vector3d::UnitY())).toRotationMatrix());
358  iq = Quaterniond((AngleAxisd(-M_PI/10, Vector3d::UnitZ()) * AngleAxisd(0.1, Vector3d::UnitY())).toRotationMatrix());
359  }
360 
361  Isometry3d delta=Isometry3d::Identity();
362  sim->_lastVertexId=4;
363 
364  Isometry3d startPose=Isometry3d::Identity();
365  startPose.matrix().block<3,3>(0,0) = AngleAxisd(-0.75*M_PI, Vector3d::UnitZ()).toRotationMatrix();
366  sim->move(0,startPose);
367 
368  int k =20;
369  int l = 2;
370  double delta_t = 0.2;
371  for (int j=0; j<l; j++) {
372  Vector3d tr(1.,0.,0.);
373  delta.matrix().block<3,3>(0,0) = q.toRotationMatrix();
374  if (j==(l-1)){
375  delta.matrix().block<3,3>(0,0) = Matrix3d::Identity();
376  }
377  delta.translation()=tr*(delta_t*j);
378  Isometry3d iDelta = delta.inverse();
379  for (int a=0; a<2; a++){
380  for (int i=0; i<k; i++){
381  cerr << "m";
382  if (a==0)
383  sim->relativeMove(0,delta);
384  else
385  sim->relativeMove(0,iDelta);
386  cerr << "s";
387  sim->sense(0);
388  }
389  }
390  }
391 
392  for (int j=0; j<l; j++) {
393  Vector3d tr(1.,0.,0.);
394  delta.matrix().block<3,3>(0,0) = iq.toRotationMatrix();
395  if (j==l-1){
396  delta.matrix().block<3,3>(0,0) = Matrix3d::Identity();
397  }
398  delta.translation()=tr*(delta_t*j);
399  Isometry3d iDelta = delta.inverse();
400  for (int a=0; a<2; a++){
401  for (int i=0; i<k; i++){
402  cerr << "m";
403  if (a==0)
404  sim->relativeMove(0,delta);
405  else
406  sim->relativeMove(0,iDelta);
407  cerr << "s";
408  sim->sense(0);
409  }
410  }
411  }
412 
413  ofstream os("test_gt.g2o");
414  g->save(os);
415 
416  if (fixSensor) {
417  ps->_offsetVertex->setFixed(true);
418  } else {
419  Vector6d noffcov;
420  noffcov << 0.1,0.1,0.1,0.5, 0.5, 0.5;
422  ps->_offsetVertex->setFixed(false);
423  }
424 
425  if (fixFirstPose){
426  OptimizableGraph::Vertex* gauge = g->vertex(4);
427  if (gauge)
428  gauge->setFixed(true);
429  } // else {
430  // // multiply all vertices of the robot by this standard quantity
431  // Quaterniond q(AngleAxisd(1, Vector3d::UnitZ()).toRotationMatrix());
432  // Vector3d tr(1,0,0);
433  // Isometry3d delta;
434  // delta.matrix().block<3,3>(0,0)=q.toRotationMatrix();
435  // delta.translation()=tr;
436  // for (size_t i=0; i< g->vertices().size(); i++){
437  // VertexSE3 *v = dynamic_cast<VertexSE3 *>(g->vertex(i));
438  // if (v && v->id()>0){
439  // v->setEstimate (v->estimate()*delta);
440  // }
441  // }
442  // }
443 
444  ofstream osp("test_preopt.g2o");
445  g->save(osp);
446  //g->setMethod(SparseOptimizer::LevenbergMarquardt);
448  g->setVerbose(verbose);
449  g->optimize(maxIterations);
450  if (! fixSensor ){
452  std::pair<int, int> indexParams;
453  indexParams.first = ps->_offsetVertex->hessianIndex();
454  indexParams.second = ps->_offsetVertex->hessianIndex();
455  std::vector<std::pair <int, int> > blockIndices;
456  blockIndices.push_back(indexParams);
457  if (!g->computeMarginals(spinv, blockIndices)){
458  cerr << "error in computing the covariance" << endl;
459  } else {
460 
461  MatrixXd m = *spinv.block(ps->_offsetVertex->hessianIndex(), ps->_offsetVertex->hessianIndex());
462 
463  cerr << "Param covariance" << endl;
464  cerr << m << endl;
465  cerr << "OffsetVertex: " << endl;
466  ps->_offsetVertex->write(cerr);
467  cerr << endl;
468  cerr << "rotationDeterminant: " << m.block<3,3>(0,0).determinant() << endl;
469  cerr << "translationDeterminant: " << m.block<3,3>(3,3).determinant() << endl;
470  cerr << endl;
471  }
472  }
473  ofstream os1("test_postOpt.g2o");
474  g->save(os1);
475 
476 }
void oplus(const Eigen::Vector3d &v)
Definition: plane3d.h:87
Robot * robot()
virtual ~Sensor()
Command line parsing of argc and argv.
Definition: command_args.h:46
OptimizableGraph::Vertex * _vertex
Vector6d _nmovecov
void setVertex(OptimizableGraph::Vertex *vertex_)
VertexSE3 * _offsetVertex
describe the properties of a solver
PlaneItem(OptimizableGraph *graph_, int id)
int optimize(int iterations, bool online=false)
SparseMatrixBlock * block(int r, int c, bool alloc=false)
returns the block at location r,c. if alloc=true he block is created if it does not exist ...
SensorVector _sensors
virtual void sense()
Definition: simulator.cpp:61
OptimizationAlgorithm * solver()
Isometry3d _position
void move(int robotIndex, const Isometry3d &newRobotPose)
int hessianIndex() const
temporary index of this node in the parameter vector obtained from linearization
create solvers based on their short name
void setId(int id_)
Definition: parameter.cpp:35
double uniform_rand(double lowerBndr, double upperBndr)
Vertex * vertex(int id)
returns the vertex number id appropriately casted
Edge between two 3D pose vertices.
Definition: edge_se3.h:18
virtual bool sense(WorldItem *, const Isometry3d &)
virtual bool write(std::ostream &os) const
write the vertex to a stream
Definition: vertex_se3.cpp:58
virtual void setId(int id)
sets the id of the node in the graph be sure that the graph keeps consistent after changing the id ...
std::set< BaseSensor * > _sensors
Definition: simulator.h:90
Eigen::Matrix< double, 6, 6 > Matrix6d
WorldItemSet _world
Sensor(Robot *robot_)
bool setParameterId(int argNum, int paramId)
const VertexContainer & vertices() const
Definition: hyper_graph.h:178
bool parseArgs(int argc, char **argv, bool exitOnError=true)
virtual bool save(std::ostream &os, int level=0) const
save the graph to a stream. Again uses the Factory system.
virtual bool isVisible(const WorldItem *wi) const
void setVerbose(bool verbose)
void sense(WorldItem *wi=0)
class G2O_CORE_API SparseOptimizer
virtual void setMeasurement(const Isometry3D &m)
Definition: edge_se3.h:27
virtual ~SimulatorItem()
void setAlgorithm(OptimizationAlgorithm *algorithm)
EIGEN_STRONG_INLINE void setInformation(const InformationType &information)
Definition: base_edge.h:69
void relativeMove(const Isometry3d &delta, int &id)
plane measurement that also calibrates an offset for the sensor
Robot(OptimizableGraph *graph_)
SimulatorItem(OptimizableGraph *graph_)
void param(const std::string &name, bool &p, bool defValue, const std::string &desc)
void fromVector(const Eigen::Vector4d &coeffs_)
Definition: plane3d.h:59
G2O_USE_OPTIMIZATION_LIBRARY(cholmod)
bool addParameter(Parameter *p)
void relativeMove(int robotIndex, const Isometry3d &delta)
PlaneSensor(Robot *r, int offsetId, const Isometry3d &offset_)
void setEstimate(const EstimateType &et)
set the estimate for the vertex also calls updateCache()
Definition: base_vertex.h:101
void listSolvers(std::ostream &os) const
list the known solvers into a stream
Simulator(OptimizableGraph *graph_)
A general case Vertex for optimization.
std::vector< Robot * > RobotVector
virtual void relativeMove(const PoseType &movement_)
Definition: simulator.h:104
static OptimizationAlgorithmFactory * instance()
return the instance
void setMeasurement(const Plane3D &m)
void sense(int robotIndex)
void move(const Isometry3d &newPosition, int &id)
Vector3d sample_noise_from_plane(const Vector3d &cov)
const EstimateType & estimate() const
return the current estimate of the vertex
Definition: base_vertex.h:99
Eigen::Matrix< double, 6, 1 > Vector6d
Eigen::Isometry3d sample_noise_from_se3(const Vector6d &cov)
3D pose Vertex, represented as an Isometry3D
Definition: vertex_se3.h:50
void setFixed(bool fixed)
true => this node should be considered fixed during the optimization
virtual bool sense(WorldItem *wi, const Isometry3d &position)
virtual bool initializeOptimization(HyperGraph::EdgeSet &eset)
virtual void setMeasurement(const Isometry3D &m)
Generic interface for a non-linear solver operating on a graph.
OptimizableGraph::Vertex * vertex()
std::vector< Sensor * > SensorVector
bool computeMarginals(SparseBlockMatrix< MatrixXD > &spinv, const std::vector< std::pair< int, int > > &blockIndices)
virtual bool isVisible(const WorldItem *) const
OptimizableGraph * _graph
virtual void move(const PoseType &pose_)
Definition: simulator.h:109
std::set< WorldItem * > WorldItemSet
#define M_PI
Definition: misc.h:34
Sparse matrix which uses blocks.
OptimizationAlgorithm * construct(const std::string &tag, OptimizationAlgorithmProperty &solverProperty) const
prior for an SE3 element
WorldItem(OptimizableGraph *graph_, OptimizableGraph::Vertex *vertex_=0)
double gauss_rand(double sigma)
Protocol The SLAM executable accepts such as solving the and retrieving or vertices in the graph
Definition: protocol.txt:7
EIGEN_STRONG_INLINE const Measurement & measurement() const
accessor functions for the measurement represented by the edge
Definition: base_edge.h:75
RobotVector _robots
int main(int argc, char **argv)
OptimizableGraph * graph()