63 virtual bool read(std::istream&) {
return false; }
64 virtual bool write(std::ostream&)
const {
return false; }
68 :
public BaseBinaryEdge<3, OdomAndLaserMotion, VertexSE2, VertexBaseline> {
86 calibratedVelocityMeasurement, odomParams->
estimate());
90 SE2 laserMotionInRobotFrame = laserOffset->
estimate() *
93 SE2 delta = Ku_ij.
inverse() * laserMotionInRobotFrame;
97 virtual bool read(std::istream&) {
return false; }
98 virtual bool write(std::ostream&)
const {
return false; }
101int main(
int argc,
char** argv) {
105 string inputFilename;
106 string outputfilename;
108 string odomTestFilename;
109 string dumpGraphFilename;
112 commandLineArguments.
param(
"i", maxIterations, 10,
"perform n iterations");
113 commandLineArguments.
param(
"v", verbose,
false,
114 "verbose output of the optimization process");
115 commandLineArguments.
param(
"o", outputfilename,
"",
116 "output final version of the graph");
117 commandLineArguments.
param(
"test", odomTestFilename,
"",
118 "apply odometry calibration to some test data");
119 commandLineArguments.
param(
"dump", dumpGraphFilename,
"",
120 "write the graph to the disk");
121 commandLineArguments.
param(
"fixLaser", fixLaser,
false,
122 "keep the laser offset fixed during optimization");
123 commandLineArguments.
paramLeftOver(
"gm2dl-input", inputFilename,
"",
124 "gm2dl file which will be processed");
125 commandLineArguments.
paramLeftOver(
"raw-log", rawFilename,
"",
126 "raw log file containing the odometry");
128 commandLineArguments.
parseArgs(argc, argv);
138 if (numLaserOdom == 0) {
139 cerr <<
"No raw information read" << endl;
142 cerr <<
"Read " << numLaserOdom <<
" laser readings from file" << endl;
144 Eigen::Vector3d odomCalib(1., 1., 1.);
145 SE2 initialLaserPose;
148 if (numRobotLaser == 0) {
149 cerr <<
"No robot laser read" << endl;
155 cerr << PVAR(initialLaserPose.
toVector().transpose()) << endl;
159 vector<MotionInformation> motions;
161 std::map<double, RobotData*>::const_iterator it =
162 robotLaserQueue.
buffer().begin();
163 std::map<double, RobotData*>::const_iterator prevIt = it++;
164 for (; it != robotLaserQueue.
buffer().end(); ++it) {
177 motions.push_back(mi);
189 odomParamsVertex->
setEstimate(Eigen::Vector3d(1., 1., 1.));
191 for (
size_t i = 0; i < motions.size(); ++i) {
192 const SE2& odomMotion = motions[i].odomMotion;
193 const SE2& laserMotion = motions[i].laserMotion;
194 const double& timeInterval = motions[i].timeInterval;
198 odomMotion.
rotation().angle(), timeInterval);
204 calibEdge->
setVertex(1, odomParamsVertex);
207 if (!optimizer.
addEdge(calibEdge)) {
208 cerr <<
"Error adding calib edge" << endl;
214 cerr <<
"Fix position of the laser offset" << endl;
218 cerr <<
"\nPerforming full non-linear estimation" << endl;
222 cerr <<
"Calibrated laser offset (x, y, theta):"
224 odomCalib = odomParamsVertex->
estimate();
225 cerr <<
"Odometry parameters (scaling factors (v_l, v_r, b)): "
226 << odomParamsVertex->
estimate().transpose() << endl;
232 Eigen::MatrixXd A(motions.size(), 2);
233 Eigen::VectorXd x(motions.size());
234 for (
size_t i = 0; i < motions.size(); ++i) {
235 const SE2& odomMotion = motions[i].odomMotion;
236 const SE2& laserMotion = motions[i].laserMotion;
237 const double& timeInterval = motions[i].timeInterval;
240 odomMotion.
rotation().angle(), timeInterval);
242 A(i, 0) = velMeas.
vl() * timeInterval;
243 A(i, 1) = velMeas.
vr() * timeInterval;
244 x(i) = laserMotion.
rotation().angle();
260 for (
size_t i = 0; i < motions.size(); ++i) {
261 const SE2& odomMotion = motions[i].odomMotion;
262 const SE2& laserMotion = motions[i].laserMotion;
263 const double& timeInterval = motions[i].timeInterval;
267 odomMotion.
rotation().angle(), timeInterval);
273 calibEdge->
setVertex(1, odomParamsVertex);
276 if (!optimizer.
addEdge(calibEdge)) {
277 cerr <<
"Error adding calib edge" << endl;
283 cerr <<
"Fix position of the laser offset" << endl;
287 cerr <<
"\nPerforming partial non-linear estimation" << endl;
291 cerr <<
"Calibrated laser offset (x, y, theta):"
295 odomCalib(2) = odomParamsVertex->
estimate();
296 cerr <<
"Odometry parameters (scaling factors (v_l, v_r, b)): "
297 << odomCalib.transpose() << endl;
301 Eigen::Vector3d closedFormOdom;
303 cerr <<
"\nObtaining closed form solution" << endl;
304 cerr <<
"Calibrated laser offset (x, y, theta):"
305 << closedFormLaser.
toVector().transpose() << endl;
306 cerr <<
"Odometry parameters (scaling factors (v_l, v_r, b)): "
307 << closedFormOdom.transpose() << endl;
310 if (dumpGraphFilename.size() > 0) {
311 cerr <<
"Writing " << dumpGraphFilename <<
" ... ";
312 optimizer.
save(dumpGraphFilename.c_str());
313 cerr <<
"done." << endl;
317 if (odomTestFilename.size() > 0) {
321 if (numTestOdom == 0) {
322 cerr <<
"Unable to read test data" << endl;
324 ofstream rawStream(
"odometry_raw.txt");
325 ofstream calibratedStream(
"odometry_calibrated.txt");
327 testRobotLaserQueue.
buffer().begin()->second);
330 for (DataQueue::Buffer::const_iterator it =
331 testRobotLaserQueue.
buffer().begin();
332 it != testRobotLaserQueue.
buffer().end(); ++it) {
348 calibratedVelocityMeasurement.
setVl(odomCalib(0) *
349 calibratedVelocityMeasurement.
vl());
350 calibratedVelocityMeasurement.
setVr(odomCalib(1) *
351 calibratedVelocityMeasurement.
vr());
353 calibratedVelocityMeasurement, odomCalib(2));
358 SE2 calOdomPose = prevCalibratedPose * remappedOdom;
364 calibratedStream << calOdomPose.
translation().x() <<
" "
366 << calOdomPose.
rotation().angle() << endl;
368 prevCalibratedPose = calOdomPose;
virtual bool write(std::ostream &) const
write the vertex to a stream
virtual bool read(std::istream &)
read the vertex from a stream, i.e., the internal state of the vertex
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
virtual void setToOriginImpl()
sets the node to the origin (used in the multilevel stuff)
virtual bool write(std::ostream &) const
write the vertex to a stream
virtual bool read(std::istream &)
read the vertex from a stream, i.e., the internal state of the vertex
virtual void oplusImpl(const double *update)
EIGEN_STRONG_INLINE const Measurement & measurement() const
accessor functions for the measurement represented by the edge
virtual void setMeasurement(const Measurement &m)
void setInformation(const InformationType &information)
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 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
RobotData * findClosestData(double timestamp) const
calibrate odometry and laser based on a set of measurements
static const int ID_LASERPOSE
static const int ID_ODOMCALIB
static int readRobotLaser(const std::string &filename, DataQueue &queue)
void setVertex(size_t i, Vertex *v)
VertexContainer _vertices
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)
virtual void setId(int id)
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 setVerbose(bool verbose)
virtual bool initializeOptimization(HyperGraph::EdgeSet &eset)
velocity measurement of a differential robot
2D pose Vertex, (x,y,theta)
void allocateSolverForSclam(SparseOptimizer &optimizer, bool levenberg)
static Eigen::Vector2d linearSolution
VelocityMeasurement velocityMeasurement
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.
virtual bool addVertex(HyperGraph::Vertex *v, Data *userData)
utility functions for handling time related stuff