g2o
Loading...
Searching...
No Matches
simulator.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 "simulator.h"
28
29#include <cmath>
30#include <iostream>
31#include <map>
32
33#include "g2o/stuff/sampler.h"
34using namespace std;
35
36namespace g2o {
37namespace tutorial {
38
39using namespace Eigen;
40
41#ifdef _MSC_VER
42inline double round(double number) {
43 return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5);
44}
45#endif
46
47typedef std::map<int, std::map<int, Simulator::LandmarkPtrVector> >
49
51 time_t seed = time(0);
52 Sampler::seedRand(static_cast<unsigned int>(seed));
53}
54
56
57void Simulator::simulate(int numNodes, const SE2& sensorOffset) {
58 // simulate a robot observing landmarks while travelling on a grid
59 int steps = 5;
60 double stepLen = 1.0;
61 int boundArea = 50;
62
63 double maxSensorRangeLandmarks = 2.5 * stepLen;
64
65 int landMarksPerSquareMeter = 1;
66 double observationProb = 0.8;
67
68 int landmarksRange = 2;
69
70 Vector2d transNoise(0.05, 0.01);
71 double rotNoise = DEG2RAD(2.);
72 Vector2d landmarkNoise(0.05, 0.05);
73
74 Vector2d bound(boundArea, boundArea);
75
76 VectorXd probLimits;
77 probLimits.resize(MO_NUM_ELEMS);
78 for (int i = 0; i < probLimits.size(); ++i)
79 probLimits[i] = (i + 1) / (double)MO_NUM_ELEMS;
80
81 Matrix3d covariance;
82 covariance.fill(0.);
83 covariance(0, 0) = transNoise[0] * transNoise[0];
84 covariance(1, 1) = transNoise[1] * transNoise[1];
85 covariance(2, 2) = rotNoise * rotNoise;
86 Matrix3d information = covariance.inverse();
87
88 SE2 maxStepTransf(stepLen * steps, 0, 0);
90 poses.clear();
92 landmarks.clear();
93 Simulator::GridPose firstPose;
94 firstPose.id = 0;
95 firstPose.truePose = SE2(0, 0, 0);
96 firstPose.simulatorPose = SE2(0, 0, 0);
97 poses.push_back(firstPose);
98 cerr << "Simulator: sampling nodes ...";
99 while ((int)poses.size() < numNodes) {
100 // add straight motions
101 for (int i = 1; i < steps && (int)poses.size() < numNodes; ++i) {
103 poses.back(), SE2(stepLen, 0, 0), transNoise, rotNoise);
104 poses.push_back(nextGridPose);
105 }
106 if ((int)poses.size() == numNodes) break;
107
108 // sample a new motion direction
109 double sampleMove = Sampler::uniformRand(0., 1.);
110 int motionDirection = 0;
111 while (probLimits[motionDirection] < sampleMove &&
112 motionDirection + 1 < MO_NUM_ELEMS) {
113 motionDirection++;
114 }
115
116 SE2 nextMotionStep = getMotion(motionDirection, stepLen);
117 Simulator::GridPose nextGridPose =
118 generateNewPose(poses.back(), nextMotionStep, transNoise, rotNoise);
119
120 // check whether we will walk outside the boundaries in the next iteration
121 SE2 nextStepFinalPose = nextGridPose.truePose * maxStepTransf;
122 if (fabs(nextStepFinalPose.translation().x()) >= bound[0] ||
123 fabs(nextStepFinalPose.translation().y()) >= bound[1]) {
124 // cerr << "b";
125 // will be outside boundaries using this
126 for (int i = 0; i < MO_NUM_ELEMS; ++i) {
127 nextMotionStep = getMotion(i, stepLen);
128 nextGridPose =
129 generateNewPose(poses.back(), nextMotionStep, transNoise, rotNoise);
130 nextStepFinalPose = nextGridPose.truePose * maxStepTransf;
131 if (fabs(nextStepFinalPose.translation().x()) < bound[0] &&
132 fabs(nextStepFinalPose.translation().y()) < bound[1])
133 break;
134 }
135 }
136
137 poses.push_back(nextGridPose);
138 }
139 cerr << "done." << endl;
140
141 // creating landmarks along the trajectory
142 cerr << "Simulator: Creating landmarks ... ";
143 LandmarkGrid grid;
144 for (PosesVector::const_iterator it = poses.begin(); it != poses.end();
145 ++it) {
146 int ccx = (int)round(it->truePose.translation().x());
147 int ccy = (int)round(it->truePose.translation().y());
148 for (int a = -landmarksRange; a <= landmarksRange; a++)
149 for (int b = -landmarksRange; b <= landmarksRange; b++) {
150 int cx = ccx + a;
151 int cy = ccy + b;
152 LandmarkPtrVector& landmarksForCell = grid[cx][cy];
153 if (landmarksForCell.size() == 0) {
154 for (int i = 0; i < landMarksPerSquareMeter; ++i) {
155 Landmark* l = new Landmark();
156 double offx, offy;
157 do {
158 offx = Sampler::uniformRand(-0.5 * stepLen, 0.5 * stepLen);
159 offy = Sampler::uniformRand(-0.5 * stepLen, 0.5 * stepLen);
160 } while (hypot_sqr(offx, offy) < 0.25 * 0.25);
161 l->truePose[0] = cx + offx;
162 l->truePose[1] = cy + offy;
163 landmarksForCell.push_back(l);
164 }
165 }
166 }
167 }
168 cerr << "done." << endl;
169
170 cerr << "Simulator: Simulating landmark observations for the poses ... ";
171 double maxSensorSqr = maxSensorRangeLandmarks * maxSensorRangeLandmarks;
172 int globalId = 0;
173 for (PosesVector::iterator it = poses.begin(); it != poses.end(); ++it) {
174 Simulator::GridPose& pv = *it;
175 int cx = (int)round(it->truePose.translation().x());
176 int cy = (int)round(it->truePose.translation().y());
177 int numGridCells = (int)(maxSensorRangeLandmarks) + 1;
178
179 pv.id = globalId++;
180 SE2 trueInv = pv.truePose.inverse();
181
182 for (int xx = cx - numGridCells; xx <= cx + numGridCells; ++xx)
183 for (int yy = cy - numGridCells; yy <= cy + numGridCells; ++yy) {
184 LandmarkPtrVector& landmarksForCell = grid[xx][yy];
185 if (landmarksForCell.size() == 0) continue;
186 for (size_t i = 0; i < landmarksForCell.size(); ++i) {
187 Landmark* l = landmarksForCell[i];
188 double dSqr =
189 hypot_sqr(pv.truePose.translation().x() - l->truePose.x(),
190 pv.truePose.translation().y() - l->truePose.y());
191 if (dSqr > maxSensorSqr) continue;
192 double obs = Sampler::uniformRand(0.0, 1.0);
193 if (obs > observationProb) // we do not see this one...
194 continue;
195 if (l->id < 0) l->id = globalId++;
196 if (l->seenBy.size() == 0) {
197 Vector2d trueObservation = trueInv * l->truePose;
198 Vector2d observation = trueObservation;
199 observation[0] += Sampler::gaussRand(0., landmarkNoise[0]);
200 observation[1] += Sampler::gaussRand(0., landmarkNoise[1]);
201 l->simulatedPose = pv.simulatorPose * observation;
202 }
203 l->seenBy.push_back(pv.id);
204 pv.landmarks.push_back(l);
205 }
206 }
207 }
208 cerr << "done." << endl;
209
210 // add the odometry measurements
211 _odometry.clear();
212 cerr << "Simulator: Adding odometry measurements ... ";
213 for (size_t i = 1; i < poses.size(); ++i) {
214 const GridPose& prev = poses[i - 1];
215 const GridPose& p = poses[i];
216
217 _odometry.push_back(GridEdge());
218 GridEdge& edge = _odometry.back();
219
220 edge.from = prev.id;
221 edge.to = p.id;
222 edge.trueTransf = prev.truePose.inverse() * p.truePose;
224 edge.information = information;
225 }
226 cerr << "done." << endl;
227
228 _landmarks.clear();
229 _landmarkObservations.clear();
230 // add the landmark observations
231 {
232 cerr << "Simulator: add landmark observations ... ";
233 Matrix2d covariance;
234 covariance.fill(0.);
235 covariance(0, 0) = landmarkNoise[0] * landmarkNoise[0];
236 covariance(1, 1) = landmarkNoise[1] * landmarkNoise[1];
237 Matrix2d information = covariance.inverse();
238
239 for (size_t i = 0; i < poses.size(); ++i) {
240 const GridPose& p = poses[i];
241 for (size_t j = 0; j < p.landmarks.size(); ++j) {
242 Landmark* l = p.landmarks[j];
243 if (l->seenBy.size() > 0 && l->seenBy[0] == p.id) {
244 landmarks.push_back(*l);
245 }
246 }
247 }
248
249 for (size_t i = 0; i < poses.size(); ++i) {
250 const GridPose& p = poses[i];
251 SE2 trueInv = (p.truePose * sensorOffset).inverse();
252 for (size_t j = 0; j < p.landmarks.size(); ++j) {
253 Landmark* l = p.landmarks[j];
254 Vector2d observation;
255 Vector2d trueObservation = trueInv * l->truePose;
256 observation = trueObservation;
257 if (l->seenBy.size() > 0 &&
258 l->seenBy[0] ==
259 p.id) { // write the initial position of the landmark
260 observation =
261 (p.simulatorPose * sensorOffset).inverse() * l->simulatedPose;
262 } else {
263 // create observation for the LANDMARK using the true positions
264 observation[0] += Sampler::gaussRand(0., landmarkNoise[0]);
265 observation[1] += Sampler::gaussRand(0., landmarkNoise[1]);
266 }
267
270
271 le.from = p.id;
272 le.to = l->id;
273 le.trueMeas = trueObservation;
274 le.simulatorMeas = observation;
275 le.information = information;
276 }
277 }
278 cerr << "done." << endl;
279 }
280
281 // cleaning up
282 for (LandmarkGrid::iterator it = grid.begin(); it != grid.end(); ++it) {
283 for (std::map<int, Simulator::LandmarkPtrVector>::iterator itt =
284 it->second.begin();
285 itt != it->second.end(); ++itt) {
287 for (size_t i = 0; i < landmarks.size(); ++i) delete landmarks[i];
288 }
289 }
290}
291
293 const Simulator::GridPose& prev, const SE2& trueMotion,
294 const Eigen::Vector2d& transNoise, double rotNoise) {
295 Simulator::GridPose nextPose;
296 nextPose.id = prev.id + 1;
297 nextPose.truePose = prev.truePose * trueMotion;
298 SE2 noiseMotion = sampleTransformation(trueMotion, transNoise, rotNoise);
299 nextPose.simulatorPose = prev.simulatorPose * noiseMotion;
300 return nextPose;
301}
302
303SE2 Simulator::getMotion(int motionDirection, double stepLen) {
304 switch (motionDirection) {
305 case MO_LEFT:
306 return SE2(stepLen, 0, 0.5 * M_PI);
307 case MO_RIGHT:
308 return SE2(stepLen, 0, -0.5 * M_PI);
309 default:
310 cerr << "Unknown motion direction" << endl;
311 return SE2(stepLen, 0, -0.5 * M_PI);
312 }
313}
314
316 const Eigen::Vector2d& transNoise,
317 double rotNoise) {
318 Vector3d trueMotion = trueMotion_.toVector();
319 SE2 noiseMotion(trueMotion[0] + Sampler::gaussRand(0.0, transNoise[0]),
320 trueMotion[1] + Sampler::gaussRand(0.0, transNoise[1]),
321 trueMotion[2] + Sampler::gaussRand(0.0, rotNoise));
322 return noiseMotion;
323}
324
325} // namespace tutorial
326} // namespace g2o
static void seedRand()
Definition sampler.h:109
static double gaussRand(double mean, double sigma)
Definition sampler.h:89
static double uniformRand(double lowerBndr, double upperBndr)
Definition sampler.h:102
const Eigen::Vector2d & translation() const
Definition se2.h:49
SE2 inverse() const
Definition se2.h:76
Eigen::Vector3d toVector() const
Definition se2.h:98
SE2 sampleTransformation(const SE2 &trueMotion_, const Eigen::Vector2d &transNoise, double rotNoise)
const PosesVector & poses() const
Definition simulator.h:98
GridPose generateNewPose(const GridPose &prev, const SE2 &trueMotion, const Eigen::Vector2d &transNoise, double rotNoise)
std::vector< Landmark * > LandmarkPtrVector
Definition simulator.h:55
void simulate(int numPoses, const SE2 &sensorOffset=SE2())
Definition simulator.cpp:57
std::vector< GridPose > PosesVector
Definition simulator.h:67
LandmarkVector _landmarks
Definition simulator.h:107
LandmarkEdgeVector _landmarkObservations
Definition simulator.h:109
const LandmarkVector & landmarks() const
Definition simulator.h:99
std::vector< Landmark > LandmarkVector
Definition simulator.h:54
SE2 getMotion(int motionDirection, double stepLen)
GridEdgeVector _odometry
Definition simulator.h:108
MO_LEFT
Definition simulator.h:41
MO_RIGHT
Definition simulator.h:41
#define DEG2RAD(x)
Definition macros.h:31
Definition jet.h:938
Jet< T, N > floor(const Jet< T, N > &f)
Definition jet.h:516
Jet< T, N > ceil(const Jet< T, N > &f)
Definition jet.h:525
std::map< int, std::map< int, Simulator::LandmarkPtrVector > > LandmarkGrid
Definition simulator.cpp:48
T hypot_sqr(T x, T y)
Definition misc.h:84
Definition jet.h:876
LandmarkPtrVector landmarks
the landmarks observed by this node
Definition simulator.h:65