g2o
Loading...
Searching...
No Matches
simulator_3d_line.cpp
Go to the documentation of this file.
1#include <fstream>
2#include <iostream>
3
9#include "g2o/stuff/macros.h"
10#include "g2o/stuff/sampler.h"
13
14using namespace g2o;
15using namespace std;
16using namespace Eigen;
17
19
20Eigen::Isometry3d sample_noise_from_se3(const Vector6& cov) {
21 double nx = Sampler::gaussRand(0., cov(0));
22 double ny = Sampler::gaussRand(0., cov(1));
23 double nz = Sampler::gaussRand(0., cov(2));
24
25 double nroll = Sampler::gaussRand(0., cov(3));
26 double npitch = Sampler::gaussRand(0., cov(4));
27 double nyaw = Sampler::gaussRand(0., cov(5));
28
29 AngleAxisd aa(AngleAxisd(nyaw, Vector3d::UnitZ()) *
30 AngleAxisd(nroll, Vector3d::UnitX()) *
31 AngleAxisd(npitch, Vector3d::UnitY()));
32
33 Eigen::Isometry3d retval = Isometry3d::Identity();
34 retval.matrix().block<3, 3>(0, 0) = aa.toRotationMatrix();
35 retval.translation() = Vector3d(nx, ny, nz);
36 return retval;
37}
38
39Vector4d sample_noise_from_line(const Vector4d& cov) {
40 return Vector4d(
41 Sampler::gaussRand(0., cov(0)), Sampler::gaussRand(0., cov(1)),
42 Sampler::gaussRand(0., cov(2)), Sampler::gaussRand(0., cov(3)));
43}
44
48 virtual ~SimulatorItem() {}
49
50 protected:
52};
53
54struct WorldItem : public SimulatorItem {
56 : SimulatorItem(graph_), _vertex(vertex_) {}
58 void setVertex(OptimizableGraph::Vertex* vertex_) { _vertex = vertex_; }
59
60 protected:
62};
63
64typedef std::set<WorldItem*> WorldItemSet;
65
66struct Robot;
67
68struct Sensor {
69 Sensor(Robot* robot_) : _robot(robot_) {}
70 Robot* robot() { return _robot; }
71 virtual bool isVisible(const WorldItem*) const { return false; }
72 virtual bool sense(WorldItem*, const Isometry3d&) { return false; }
73 virtual ~Sensor(){};
74
75 protected:
77};
78
79typedef std::vector<Sensor*> SensorVector;
80
81struct Robot : public WorldItem {
83
84 Robot(OptimizableGraph* graph_) : WorldItem(graph_) {
85 _planarMotion = false;
86 _position = Isometry3d::Identity();
87 }
88
89 void move(const Isometry3d& newPosition, int& id) {
90 Isometry3d delta = _position.inverse() * newPosition;
91 _position = newPosition;
92 VertexSE3* v = new VertexSE3();
93 v->setId(id);
94 id++;
95 graph()->addVertex(v);
96 if (_planarMotion) {
97 // add a singleton constraint that locks the position of the robot on the
98 // plane
99 EdgeSE3Prior* planeConstraint = new EdgeSE3Prior();
100 Matrix6 pinfo = Matrix6::Zero();
101 pinfo(2, 2) = 1e9;
102 planeConstraint->setInformation(pinfo);
103 planeConstraint->setMeasurement(Isometry3d::Identity());
104 planeConstraint->vertices()[0] = v;
105 planeConstraint->setParameterId(0, 0);
106 graph()->addEdge(planeConstraint);
107 }
108 if (vertex()) {
109 VertexSE3* oldV = dynamic_cast<VertexSE3*>(vertex());
110 EdgeSE3* e = new EdgeSE3();
111 Isometry3d noise = sample_noise_from_se3(_nmovecov);
112 e->setMeasurement(delta * noise);
113 Matrix6 m = Matrix6::Identity();
114 for (int i = 0; i < 6; ++i) {
115 m(i, i) = 1.0 / (_nmovecov(i));
116 }
117 e->setInformation(m);
118 e->vertices()[0] = vertex();
119 e->vertices()[1] = v;
120 graph()->addEdge(e);
121 v->setEstimate(oldV->estimate() * e->measurement());
122 } else {
124 }
125 setVertex(v);
126 }
127
128 void relativeMove(const Isometry3d& delta, int& id) {
129 Isometry3d newPosition = _position * delta;
130 move(newPosition, id);
131 }
132
133 void sense(WorldItem* wi = 0) {
134 for (size_t i = 0; i < _sensors.size(); ++i) {
135 Sensor* s = _sensors[i];
136 s->sense(wi, _position);
137 }
138 }
139
140 Isometry3d _position;
144};
145
146typedef std::vector<Robot*> RobotVector;
147
148struct Simulator : public SimulatorItem {
151 void sense(int robotIndex) {
152 Robot* r = _robots[robotIndex];
153 for (WorldItemSet::iterator it = _world.begin(); it != _world.end(); ++it) {
154 WorldItem* item = *it;
155 r->sense(item);
156 }
157 }
158
159 void move(int robotIndex, const Isometry3d& newRobotPose) {
160 Robot* r = _robots[robotIndex];
161 r->move(newRobotPose, _lastVertexId);
162 }
163
164 void relativeMove(int robotIndex, const Isometry3d& delta) {
165 Robot* r = _robots[robotIndex];
166 r->relativeMove(delta, _lastVertexId);
167 }
168
172};
173
174struct LineItem : public WorldItem {
175 LineItem(OptimizableGraph* graph_, int id) : WorldItem(graph_) {
176 VertexLine3D* l = new VertexLine3D();
177 l->setId(id);
178 graph()->addVertex(l);
179 setVertex(l);
180 }
181};
182
183struct LineSensor : public Sensor {
185
186 LineSensor(Robot* r, int offsetId, const Isometry3d& offset_) : Sensor(r) {
187 _offsetVertex = new VertexSE3();
188 _offsetVertex->setId(offsetId);
189 _offsetVertex->setEstimate(offset_);
191 };
192
193 virtual bool isVisible(const WorldItem* wi) const {
194 if (!wi) {
195 return false;
196 }
197 const LineItem* li = dynamic_cast<const LineItem*>(wi);
198 if (!li) {
199 return false;
200 }
201 return true;
202 }
203
204 virtual bool sense(WorldItem* wi, const Isometry3d& position) {
205 if (!wi) {
206 return false;
207 }
208 LineItem* li = dynamic_cast<LineItem*>(wi);
209 if (!li) {
210 return false;
211 }
212 OptimizableGraph::Vertex* rv = robot()->vertex();
213 if (!rv) {
214 return false;
215 }
216 VertexSE3* robotVertex = dynamic_cast<VertexSE3*>(rv);
217 if (!robotVertex) {
218 return false;
219 }
220 const Isometry3d& robotPose = position;
221 Isometry3d sensorPose = robotPose * _offsetVertex->estimate();
222 VertexLine3D* lineVertex = dynamic_cast<VertexLine3D*>(li->vertex());
223 Line3D worldLine = lineVertex->estimate();
224
225 Line3D measuredLine = sensorPose.inverse() * worldLine;
226
227 EdgeSE3Line3D* e = new EdgeSE3Line3D();
228 e->vertices()[0] = robotVertex;
229 e->vertices()[1] = lineVertex;
230 Vector4d noise = sample_noise_from_line(_nline);
231 measuredLine.oplus(noise);
232 e->setMeasurement(measuredLine);
233 Matrix4d m = Matrix4d::Zero();
234 m(0, 0) = 1.0 / (_nline(0));
235 m(1, 1) = 1.0 / (_nline(1));
236 m(2, 2) = 1.0 / (_nline(2));
237 m(3, 3) = 1.0 / (_nline(3));
238 e->setInformation(m);
239 e->setParameterId(0, 0);
240 robot()->graph()->addEdge(e);
241 return true;
242 }
243
245 Vector4d _nline;
246};
247
248int main(int argc, char** argv) {
249 bool verbose, robustKernel, fixLines, planarMotion, listSolvers;
250 int maxIterations;
251 double lambdaInit;
252 string strSolver;
253 CommandArgs arg;
254 arg.param("i", maxIterations, 10, "perform n iterations");
255 arg.param("v", verbose, false, "verbose output of the optimization process");
256 arg.param("solver", strSolver, "lm_var", "select one specific solver");
257 arg.param("lambdaInit", lambdaInit, 0,
258 "user specified lambda init for levenberg");
259 arg.param("robustKernel", robustKernel, false, "use robust error functions");
260 arg.param("fixLines", fixLines, false,
261 "fix the lines (do localization only)");
262 arg.param("planarMotion", planarMotion, false, "robot moves on a plane");
263 arg.param("listSolvers", listSolvers, false, "list the solvers");
264 arg.parseArgs(argc, argv);
265
267 ParameterSE3Offset* odomOffset = new ParameterSE3Offset();
268 odomOffset->setId(0);
269 g->addParameter(odomOffset);
270
271 OptimizationAlgorithmFactory* solverFactory =
273 OptimizationAlgorithmProperty solverProperty;
274 OptimizationAlgorithm* solver =
275 solverFactory->construct(strSolver, solverProperty);
276 g->setAlgorithm(solver);
277 if (listSolvers) {
278 solverFactory->listSolvers(std::cout);
279 return 0;
280 }
281
282 if (!g->solver()) {
283 std::cout << "Error allocating solver. Allocating \"" << strSolver
284 << "\" failed!" << std::endl;
285 std::cout << "Available solvers: " << std::endl;
286 solverFactory->listSolvers(std::cout);
287 std::cout << "--------------" << std::endl;
288 return 0;
289 }
290
291 std::cout << "Creating simulator" << std::endl;
292 Simulator* sim = new Simulator(g);
293
294 std::cout << "Creating robot" << std::endl;
295 Robot* r = new Robot(g);
296
297 std::cout << "Creating line sensor" << std::endl;
298 Isometry3d sensorPose = Isometry3d::Identity();
299 LineSensor* ls = new LineSensor(r, 0, sensorPose);
300 ls->_nline << 0.001, 0.001, 0.001, 0.0001;
301 // ls->_nline << 1e-9, 1e-9, 1e-9, 1e-9;
302 r->_sensors.push_back(ls);
303 sim->_robots.push_back(r);
304
305 Line3D line;
306 std::cout << "Creating landmark line 1" << std::endl;
307 LineItem* li = new LineItem(g, 1);
308 Vector6 liv;
309 liv << 0.0, 0.0, 5.0, 0.0, 1.0, 0.0;
310 line = Line3D::fromCartesian(liv);
311 static_cast<VertexLine3D*>(li->vertex())->setEstimate(line);
312 li->vertex()->setFixed(fixLines);
313 sim->_world.insert(li);
314
315 std::cout << "Creating landmark line 2" << std::endl;
316 liv << 5.0, 0.0, 0.0, 0.0, 0.0, 1.0;
317 line = Line3D::fromCartesian(liv);
318 li = new LineItem(g, 2);
319 static_cast<VertexLine3D*>(li->vertex())->setEstimate(line);
320 li->vertex()->setFixed(fixLines);
321 sim->_world.insert(li);
322
323 std::cout << "Creating landmark line 3" << std::endl;
324 liv << 0.0, 5.0, 0.0, 1.0, 0.0, 0.0;
325 line = Line3D::fromCartesian(liv);
326 li = new LineItem(g, 3);
327 static_cast<VertexLine3D*>(li->vertex())->setEstimate(line);
328 li->vertex()->setFixed(fixLines);
329 sim->_world.insert(li);
330
331 Quaterniond q, iq;
332 if (planarMotion) {
333 r->_planarMotion = true;
334 r->_nmovecov << 0.01, 0.0025, 1e-9, 0.001, 0.001, 0.025;
335 q = Quaterniond(AngleAxisd(0.2, Vector3d::UnitZ()).toRotationMatrix());
336 iq = Quaterniond(AngleAxisd(-0.2, Vector3d::UnitZ()).toRotationMatrix());
337 } else {
338 r->_planarMotion = false;
339 r->_nmovecov << 0.1, 0.005, 1e-9, 0.001, 0.001, 0.05;
340 q = Quaterniond((AngleAxisd(M_PI / 10, Vector3d::UnitZ()) *
341 AngleAxisd(0.1, Vector3d::UnitY()))
342 .toRotationMatrix());
343 iq = Quaterniond((AngleAxisd(-M_PI / 10, Vector3d::UnitZ()) *
344 AngleAxisd(0.1, Vector3d::UnitY()))
345 .toRotationMatrix());
346 }
347
348 Isometry3d delta = Isometry3d::Identity();
349 sim->_lastVertexId = 4;
350
351 Isometry3d startPose = Isometry3d::Identity();
352 startPose.matrix().block<3, 3>(0, 0) =
353 AngleAxisd(-0.75 * M_PI, Vector3d::UnitZ()).toRotationMatrix();
354 sim->move(0, startPose);
355
356 int k = 20;
357 int l = 2;
358 double delta_t = 0.2;
359 for (int j = 0; j < l; ++j) {
360 Vector3d tr(1.0, 0.0, 0.0);
361 delta.matrix().block<3, 3>(0, 0) = q.toRotationMatrix();
362 if (j == l - 1) {
363 delta.matrix().block<3, 3>(0, 0) = Matrix3d::Identity();
364 }
365 delta.translation() = tr * (delta_t * j);
366 Isometry3d iDelta = delta.inverse();
367 for (int a = 0; a < 2; ++a) {
368 for (int i = 0; i < k; ++i) {
369 std::cout << "m";
370 if (a == 0) {
371 sim->relativeMove(0, delta);
372 } else {
373 sim->relativeMove(0, iDelta);
374 }
375 std::cout << "s";
376 sim->sense(0);
377 }
378 }
379 }
380 for (int j = 0; j < l; ++j) {
381 Vector3d tr(1.0, 0.0, 0.0);
382 delta.matrix().block<3, 3>(0, 0) = iq.toRotationMatrix();
383 if (j == l - 1) {
384 delta.matrix().block<3, 3>(0, 0) = Matrix3d::Identity();
385 }
386 delta.translation() = tr * (delta_t * j);
387 Isometry3d iDelta = delta.inverse();
388 for (int a = 0; a < 2; ++a) {
389 for (int i = 0; i < k; ++i) {
390 std::cout << "m";
391 if (a == 0) {
392 sim->relativeMove(0, delta);
393 } else {
394 sim->relativeMove(0, iDelta);
395 }
396 std::cout << "s";
397 sim->sense(0);
398 }
399 }
400 }
401 std::cout << std::endl;
402
403 ls->_offsetVertex->setFixed(true);
404 OptimizableGraph::Vertex* gauge = g->vertex(4);
405 if (gauge) {
406 gauge->setFixed(true);
407 }
408
409 ofstream osp("line3d.g2o");
410 g->save(osp);
411 std::cout << "Saved graph on file line3d.g2o, use g2o_viewer to work with it."
412 << std::endl;
413
414 return 0;
415}
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)
virtual void setMeasurement(const Vector6 &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
static G2O_TYPES_SLAM3D_ADDONS_API Line3D fromCartesian(const Vector6 &cart)
Definition line3d.h:80
G2O_TYPES_SLAM3D_ADDONS_API void oplus(const Vector4 &v)
Definition line3d.h:142
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
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
void setAlgorithm(OptimizationAlgorithm *algorithm)
OptimizationAlgorithm * solver()
3D pose Vertex, represented as an Isometry3
Definition vertex_se3.h:50
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
Vector4d sample_noise_from_line(const Vector4d &cov)
std::vector< Robot * > RobotVector
std::set< WorldItem * > WorldItemSet
Eigen::Isometry3d sample_noise_from_se3(const Vector6 &cov)
std::vector< Sensor * > SensorVector
std::vector< Robot * > RobotVector
std::set< WorldItem * > WorldItemSet
LineItem(OptimizableGraph *graph_, int id)
LineSensor(Robot *r, int offsetId, const Isometry3d &offset_)
virtual bool sense(WorldItem *wi, const Isometry3d &position)
VertexSE3 * _offsetVertex
virtual bool isVisible(const WorldItem *wi) const
void move(const Isometry3d &newPosition, int &id)
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
void relativeMove(const Isometry3d &delta, int &id)
Vector6 _nmovecov
SensorVector _sensors
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