60 cerr <<
" forcing exit" << endl;
66int main(
int argc,
char** argv) {
71 string outputfilename;
73 string odomTestFilename;
74 string dumpGraphFilename;
77 commandLineArguments.
param(
"i", maxIterations, 10,
"perform n iterations");
78 commandLineArguments.
param(
"v", verbose,
false,
79 "verbose output of the optimization process");
80 commandLineArguments.
param(
"o", outputfilename,
"",
81 "output final version of the graph");
82 commandLineArguments.
param(
"test", odomTestFilename,
"",
83 "apply odometry calibration to some test data");
84 commandLineArguments.
param(
"dump", dumpGraphFilename,
"",
85 "write the graph to the disk");
86 commandLineArguments.
param(
"fixLaser", fixLaser,
false,
87 "keep the laser offset fixed during optimization");
88 commandLineArguments.
paramLeftOver(
"gm2dl-input", inputFilename,
"",
89 "gm2dl file which will be processed");
90 commandLineArguments.
paramLeftOver(
"raw-log", rawFilename,
"",
91 "raw log file containing the odometry");
93 commandLineArguments.
parseArgs(argc, argv);
103 cerr <<
"Error while loading gm2dl file" << endl;
107 if (numLaserOdom == 0) {
108 cerr <<
"No raw information read" << endl;
111 cerr <<
"Read " << numLaserOdom <<
" laser readings from file" << endl;
118 cerr <<
"# cannot find a vertex to fix in this thing" << endl;
121 cerr <<
"# graph is fixed by node " << gauge->
id() << endl;
125 cerr <<
"# graph is fixed by priors" << endl;
137 cerr <<
CL_RED(
"Warning: d.visited().size() != optimizer.vertices().size()")
139 cerr <<
"visited: " << d.
visited().size() << endl;
140 cerr <<
"vertices: " << optimizer.
vertices().size() << endl;
142 for (SparseOptimizer::VertexIDMap::const_iterator it =
144 it != optimizer.
vertices().end(); ++it) {
147 if (d.
visited().count(v) == 0) {
148 cerr <<
"\t unvisited vertex " << it->first <<
" "
149 <<
static_cast<void*
>(v) << endl;
155 for (SparseOptimizer::VertexIDMap::const_iterator it =
157 it != optimizer.
vertices().end(); ++it) {
161 cerr <<
"\t fixed vertex " << it->first << endl;
172 cerr <<
"Fix position of the laser offset" << endl;
177 cerr <<
"Doing full estimation" << endl;
180 cerr <<
"Initial chi2 = " << FIXED(optimizer.
chi2()) << endl;
182 int i = optimizer.
optimize(maxIterations);
183 if (maxIterations > 0 && !i) {
184 cerr <<
"optimize failed, result might be invalid" << endl;
188 cerr <<
"Calibrated laser offset (x, y, theta):"
192 if (odomParamsVertex) {
193 cerr <<
"Odometry parameters (scaling factors (v_l, v_r, b)): "
194 << odomParamsVertex->
estimate().transpose() << endl;
197 cerr <<
"vertices: " << optimizer.
vertices().size() << endl;
198 cerr <<
"edges: " << optimizer.
edges().size() << endl;
200 if (dumpGraphFilename.size() > 0) {
201 cerr <<
"Writing " << dumpGraphFilename <<
" ... ";
202 optimizer.
save(dumpGraphFilename.c_str());
203 cerr <<
"done." << endl;
207 if (odomTestFilename.size() > 0) {
211 if (numTestOdom == 0) {
212 cerr <<
"Unable to read test data" << endl;
214 ofstream rawStream(
"odometry_raw.txt");
215 ofstream calibratedStream(
"odometry_calibrated.txt");
216 const Vector3d& odomCalib =
217 odomParamsVertex ? odomParamsVertex->
estimate() : Vector3d::Ones();
219 testRobotLaserQueue.
buffer().begin()->second);
222 for (DataQueue::Buffer::const_iterator it =
223 testRobotLaserQueue.
buffer().begin();
224 it != testRobotLaserQueue.
buffer().end(); ++it) {
240 calibratedVelocityMeasurement.
setVl(odomCalib(0) *
241 calibratedVelocityMeasurement.
vl());
242 calibratedVelocityMeasurement.
setVr(odomCalib(1) *
243 calibratedVelocityMeasurement.
vr());
245 calibratedVelocityMeasurement, odomCalib(2));
250 SE2 calOdomPose = prevCalibratedPose * remappedOdom;
256 calibratedStream << calOdomPose.
translation().x() <<
" "
258 << calOdomPose.
rotation().angle() << endl;
260 prevCalibratedPose = calOdomPose;
266 if (outputfilename.size() > 0) {
268 cerr <<
"Writing " << outputfilename <<
" ... ";
270 cerr << (writeStatus ?
"done." :
"failed") << endl;
const EstimateType & estimate() const
return the current estimate of the vertex
Command line parsing of argc and argv.
bool parseArgs(int argc, char **argv, bool exitOnError=true)
void paramLeftOver(const std::string &name, std::string &p, const std::string &defValue, const std::string &desc, bool optional=false)
void param(const std::string &name, bool &p, bool defValue, const std::string &desc)
a simple queue to store data and retrieve based on a timestamp
const Buffer & buffer() const
static bool readGm2dl(const std::string &filename, SparseOptimizer &optimizer, bool overrideCovariances=false)
static const int ID_LASERPOSE
static const int ID_ODOMCALIB
static int readRobotLaser(const std::string &filename, DataQueue &queue)
static bool updateLaserData(SparseOptimizer &optimizer)
static bool writeGm2dl(const std::string &filename, const SparseOptimizer &optimizer)
int id() const
returns the id
const EdgeSet & edges() const
const VertexIDMap & vertices() const
A 2D odometry measurement expressed as a transformation.
const Vector3 & measurement() const
static VelocityMeasurement convertToVelocity(const MotionMeasurement &m)
static MotionMeasurement convertToMotion(const VelocityMeasurement &vi, double l=1.0)
A general case Vertex for optimization.
bool fixed() const
true => this node is fixed during the optimization
void setFixed(bool fixed)
true => this node should be considered fixed during the optimization
laser measurement obtained by a robot
const SE2 & odomPose() const
const Vector2 & translation() const
translational component
Vector3 toVector() const
convert to a 3D vector (x, y, theta)
SE2 inverse() const
invert :-)
void fromVector(const Vector3 &v)
assign from a 3D vector (x, y, theta)
const Rotation2D & rotation() const
rotational component
void computeActiveErrors()
int optimize(int iterations, bool online=false)
void setForceStopFlag(bool *flag)
void setVerbose(bool verbose)
virtual bool initializeOptimization(HyperGraph::EdgeSet &eset)
virtual Vertex * findGauge()
finds a gauge in the graph to remove the undefined dof.
velocity measurement of a differential robot
2D pose Vertex, (x,y,theta)
void addOdometryCalibLinksDifferential(SparseOptimizer &optimizer, const DataQueue &odomData)
void allocateSolverForSclam(SparseOptimizer &optimizer, bool levenberg)
void sigquit_handler(int sig)
HyperGraph::VertexSet & visited()
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())
virtual bool save(std::ostream &os, int level=0) const
save the graph to a stream. Again uses the Factory system.
double chi2() const
returns the chi2 of the current configuration
Vertex * vertex(int id)
returns the vertex number id appropriately casted
utility functions for handling time related stuff