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