mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 17:40:23 +08:00
0.19.2: Refactored SensorData interface. DBReader: Fixed GPS not published. #345: both g2o and gtsam working with GPS. g2o: added gravity edges.
This commit is contained in:
@@ -60,6 +60,8 @@ typedef Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor> Matr
|
||||
#include "g2o/types/slam2d/types_slam2d.h"
|
||||
#include "g2o/types/slam3d/types_slam3d.h"
|
||||
#include "g2o/edge_se3_xyzprior.h"
|
||||
#include "g2o/edge_se3_gravity.h"
|
||||
#include "g2o/edge_sbacam_gravity.h"
|
||||
#ifdef G2O_HAVE_CSPARSE
|
||||
#include "g2o/solvers/csparse/linear_solver_csparse.h"
|
||||
#endif
|
||||
@@ -306,7 +308,7 @@ std::map<int, Transform> OptimizerG2O::optimize(
|
||||
{
|
||||
for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
|
||||
{
|
||||
if(iter->second.from() == iter->second.to())
|
||||
if(iter->second.from() == iter->second.to() && iter->second.type() == Link::kPosePrior)
|
||||
{
|
||||
rootId = 0;
|
||||
break;
|
||||
@@ -494,6 +496,7 @@ std::map<int, Transform> OptimizerG2O::optimize(
|
||||
1 / static_cast<double>(iter->second.infMatrix().at<double>(4,4)) >= 9999.0 ||
|
||||
1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) >= 9999.0)
|
||||
{
|
||||
//GPS XYZ case
|
||||
EdgeSE3XYZPrior * priorEdge = new EdgeSE3XYZPrior();
|
||||
g2o::VertexSE3* v1 = (g2o::VertexSE3*)optimizer.vertex(id1);
|
||||
priorEdge->setVertex(0, v1);
|
||||
@@ -517,6 +520,7 @@ std::map<int, Transform> OptimizerG2O::optimize(
|
||||
}
|
||||
else
|
||||
{
|
||||
// XYZ+RPY case
|
||||
g2o::EdgeSE3Prior * priorEdge = new g2o::EdgeSE3Prior();
|
||||
g2o::VertexSE3* v1 = (g2o::VertexSE3*)optimizer.vertex(id1);
|
||||
priorEdge->setVertex(0, v1);
|
||||
@@ -536,6 +540,25 @@ std::map<int, Transform> OptimizerG2O::optimize(
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!isSlam2d() && gravitySigma() > 0 && iter->second.type() == Link::kPoseOdom && poses.find(iter->first) != poses.end())
|
||||
{
|
||||
Eigen::Matrix<double, 6, 1> m;
|
||||
// Up vector in robot frame
|
||||
m.head<3>() = Eigen::Vector3d::UnitZ();
|
||||
// Observed Gravity vector in world frame
|
||||
float roll, pitch, yaw;
|
||||
iter->second.transform().getEulerAngles(roll, pitch, yaw);
|
||||
m.tail<3>() = Transform(0,0,0,roll,pitch,0).toEigen3d() * -Eigen::Vector3d::UnitZ();
|
||||
|
||||
Eigen::MatrixXd information = Eigen::MatrixXd::Identity(3, 3) * 1.0/(gravitySigma()*gravitySigma());
|
||||
|
||||
g2o::VertexSE3* v1 = (g2o::VertexSE3*)optimizer.vertex(id1);
|
||||
EdgeSE3Gravity* priorEdge(new EdgeSE3Gravity());
|
||||
priorEdge->setMeasurement(m);
|
||||
priorEdge->setInformation(information);
|
||||
priorEdge->vertices()[0] = v1;
|
||||
edge = priorEdge;
|
||||
}
|
||||
}
|
||||
else if(id1<0 || id2 < 0)
|
||||
{
|
||||
@@ -1386,7 +1409,38 @@ std::map<int, Transform> OptimizerG2O::optimizeBA(
|
||||
int id1 = iter->second.from();
|
||||
int id2 = iter->second.to();
|
||||
|
||||
if(id1 != id2) // not supporting prior
|
||||
if(id1 == id2)
|
||||
{
|
||||
#ifndef RTABMAP_ORB_SLAM2
|
||||
g2o::HyperGraph::Edge * edge = 0;
|
||||
if(gravitySigma() > 0 && iter->second.type() == Link::kPoseOdom && poses.find(iter->first) != poses.end())
|
||||
{
|
||||
Eigen::Matrix<double, 6, 1> m;
|
||||
// Up vector in robot frame
|
||||
m.head<3>() = Eigen::Vector3d::UnitZ();
|
||||
// Observed Gravity vector in world frame
|
||||
float roll, pitch, yaw;
|
||||
iter->second.transform().getEulerAngles(roll, pitch, yaw);
|
||||
m.tail<3>() = Transform(0,0,0,roll,pitch,0).toEigen3d() * -Eigen::Vector3d::UnitZ();
|
||||
|
||||
Eigen::MatrixXd information = Eigen::MatrixXd::Identity(3, 3) * 1.0/(gravitySigma()*gravitySigma());
|
||||
|
||||
g2o::VertexCam* v1 = (g2o::VertexCam*)optimizer.vertex(id1);
|
||||
EdgeSBACamGravity* priorEdge(new EdgeSBACamGravity());
|
||||
priorEdge->setMeasurement(m);
|
||||
priorEdge->setInformation(information);
|
||||
priorEdge->vertices()[0] = v1;
|
||||
edge = priorEdge;
|
||||
}
|
||||
if (edge && !optimizer.addEdge(edge))
|
||||
{
|
||||
delete edge;
|
||||
UERROR("Map: Failed adding constraint between %d and %d, skipping", id1, id2);
|
||||
return optimizedPoses;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(id1>0 && id2>0) // not supporting landmarks
|
||||
{
|
||||
UASSERT(!iter->second.transform().isNull());
|
||||
|
||||
|
||||
@@ -50,7 +50,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <gtsam/nonlinear/NonlinearOptimizer.h>
|
||||
#include <gtsam/nonlinear/Marginals.h>
|
||||
#include <gtsam/nonlinear/Values.h>
|
||||
#include "optimizer/gtsam/GravityFactor.h"
|
||||
#include "gtsam/GravityFactor.h"
|
||||
#include "gtsam/GPSPose2XYFactor.h"
|
||||
#include "gtsam/GPSPose3XYZFactor.h"
|
||||
|
||||
#ifdef RTABMAP_VERTIGO
|
||||
#include "vertigo/gtsam/betweenFactorMaxMix.h"
|
||||
@@ -104,14 +106,27 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
|
||||
gtsam::NonlinearFactorGraph graph;
|
||||
|
||||
// detect if there is a global pose prior set, if so remove rootId
|
||||
bool gpsPriorOnly = false;
|
||||
if(!priorsIgnored())
|
||||
{
|
||||
for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
|
||||
{
|
||||
if(iter->second.from() == iter->second.to())
|
||||
if(iter->second.from() == iter->second.to() && iter->second.type() == Link::kPosePrior)
|
||||
{
|
||||
rootId = 0;
|
||||
break;
|
||||
if ((isSlam2d() && 1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) < 9999) ||
|
||||
(1 / static_cast<double>(iter->second.infMatrix().at<double>(3,3)) < 9999.0 &&
|
||||
1 / static_cast<double>(iter->second.infMatrix().at<double>(4,4)) < 9999.0 &&
|
||||
1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) < 9999.0))
|
||||
{
|
||||
// orientation is set, don't set root prior
|
||||
gpsPriorOnly = false;
|
||||
rootId = 0;
|
||||
break;
|
||||
}
|
||||
else if(gravitySigma()<=0)
|
||||
{
|
||||
gpsPriorOnly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +143,11 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
|
||||
}
|
||||
else
|
||||
{
|
||||
gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances((gtsam::Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished());
|
||||
gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(
|
||||
(gtsam::Vector(6) <<
|
||||
(gpsPriorOnly?2:1e-2), gpsPriorOnly?2:1e-2, gpsPriorOnly?2:1e-2,
|
||||
1e-2, 1e-2, 1e-2
|
||||
).finished());
|
||||
graph.add(gtsam::PriorFactor<gtsam::Pose3>(rootId, gtsam::Pose3(initialPose.toEigen4d()), priorNoise));
|
||||
}
|
||||
}
|
||||
@@ -207,42 +226,65 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
|
||||
{
|
||||
if(isSlam2d())
|
||||
{
|
||||
Eigen::Matrix<double, 3, 3> information = Eigen::Matrix<double, 3, 3>::Identity();
|
||||
if(!isCovarianceIgnored())
|
||||
if (1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) >= 9999.0)
|
||||
{
|
||||
information(0,0) = iter->second.infMatrix().at<double>(0,0); // x-x
|
||||
information(0,1) = iter->second.infMatrix().at<double>(0,1); // x-y
|
||||
information(0,2) = iter->second.infMatrix().at<double>(0,5); // x-theta
|
||||
information(1,0) = iter->second.infMatrix().at<double>(1,0); // y-x
|
||||
information(1,1) = iter->second.infMatrix().at<double>(1,1); // y-y
|
||||
information(1,2) = iter->second.infMatrix().at<double>(1,5); // y-theta
|
||||
information(2,0) = iter->second.infMatrix().at<double>(5,0); // theta-x
|
||||
information(2,1) = iter->second.infMatrix().at<double>(5,1); // theta-y
|
||||
information(2,2) = iter->second.infMatrix().at<double>(5,5); // theta-theta
|
||||
noiseModel::Diagonal::shared_ptr model = noiseModel::Diagonal::Variances(Vector2(
|
||||
1/iter->second.infMatrix().at<double>(0,0),
|
||||
1/iter->second.infMatrix().at<double>(1,1)));
|
||||
graph.add(GPSPose2XYFactor(id1, gtsam::Point2(iter->second.transform().x(), iter->second.transform().y()), model));
|
||||
}
|
||||
else
|
||||
{
|
||||
Eigen::Matrix<double, 3, 3> information = Eigen::Matrix<double, 3, 3>::Identity();
|
||||
if(!isCovarianceIgnored())
|
||||
{
|
||||
information(0,0) = iter->second.infMatrix().at<double>(0,0); // x-x
|
||||
information(0,1) = iter->second.infMatrix().at<double>(0,1); // x-y
|
||||
information(0,2) = iter->second.infMatrix().at<double>(0,5); // x-theta
|
||||
information(1,0) = iter->second.infMatrix().at<double>(1,0); // y-x
|
||||
information(1,1) = iter->second.infMatrix().at<double>(1,1); // y-y
|
||||
information(1,2) = iter->second.infMatrix().at<double>(1,5); // y-theta
|
||||
information(2,0) = iter->second.infMatrix().at<double>(5,0); // theta-x
|
||||
information(2,1) = iter->second.infMatrix().at<double>(5,1); // theta-y
|
||||
information(2,2) = iter->second.infMatrix().at<double>(5,5); // theta-theta
|
||||
}
|
||||
|
||||
gtsam::noiseModel::Gaussian::shared_ptr model = gtsam::noiseModel::Gaussian::Information(information);
|
||||
graph.add(gtsam::PriorFactor<gtsam::Pose2>(id1, gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model));
|
||||
gtsam::noiseModel::Gaussian::shared_ptr model = gtsam::noiseModel::Gaussian::Information(information);
|
||||
graph.add(gtsam::PriorFactor<gtsam::Pose2>(id1, gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity();
|
||||
if(!isCovarianceIgnored())
|
||||
if (1 / static_cast<double>(iter->second.infMatrix().at<double>(3,3)) >= 9999.0 ||
|
||||
1 / static_cast<double>(iter->second.infMatrix().at<double>(4,4)) >= 9999.0 ||
|
||||
1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) >= 9999.0)
|
||||
{
|
||||
memcpy(information.data(), iter->second.infMatrix().data, iter->second.infMatrix().total()*sizeof(double));
|
||||
noiseModel::Diagonal::shared_ptr model = noiseModel::Diagonal::Precisions(Vector3(
|
||||
iter->second.infMatrix().at<double>(0,0),
|
||||
iter->second.infMatrix().at<double>(1,1),
|
||||
iter->second.infMatrix().at<double>(2,2)));
|
||||
graph.add(GPSPose3XYZFactor(id1, gtsam::Point3(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().z()), model));
|
||||
}
|
||||
else
|
||||
{
|
||||
Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity();
|
||||
if(!isCovarianceIgnored())
|
||||
{
|
||||
memcpy(information.data(), iter->second.infMatrix().data, iter->second.infMatrix().total()*sizeof(double));
|
||||
}
|
||||
|
||||
Eigen::Matrix<double, 6, 6> mgtsam = Eigen::Matrix<double, 6, 6>::Identity();
|
||||
mgtsam.block(0,0,3,3) = information.block(3,3,3,3); // cov rotation
|
||||
mgtsam.block(3,3,3,3) = information.block(0,0,3,3); // cov translation
|
||||
mgtsam.block(0,3,3,3) = information.block(0,3,3,3); // off diagonal
|
||||
mgtsam.block(3,0,3,3) = information.block(3,0,3,3); // off diagonal
|
||||
gtsam::SharedNoiseModel model = gtsam::noiseModel::Gaussian::Information(mgtsam);
|
||||
Eigen::Matrix<double, 6, 6> mgtsam = Eigen::Matrix<double, 6, 6>::Identity();
|
||||
mgtsam.block(0,0,3,3) = information.block(3,3,3,3); // cov rotation
|
||||
mgtsam.block(3,3,3,3) = information.block(0,0,3,3); // cov translation
|
||||
mgtsam.block(0,3,3,3) = information.block(0,3,3,3); // off diagonal
|
||||
mgtsam.block(3,0,3,3) = information.block(3,0,3,3); // off diagonal
|
||||
gtsam::SharedNoiseModel model = gtsam::noiseModel::Gaussian::Information(mgtsam);
|
||||
|
||||
graph.add(gtsam::PriorFactor<gtsam::Pose3>(id1, gtsam::Pose3(iter->second.transform().toEigen4d()), model));
|
||||
graph.add(gtsam::PriorFactor<gtsam::Pose3>(id1, gtsam::Pose3(iter->second.transform().toEigen4d()), model));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(gravitySigma() > 0 && iter->second.type() == Link::kPoseOdom && poses.find(iter->first) != poses.end())
|
||||
else if(!isSlam2d() && gravitySigma() > 0 && iter->second.type() == Link::kPoseOdom && poses.find(iter->first) != poses.end())
|
||||
{
|
||||
Vector3 r = gtsam::Pose3(iter->second.transform().toEigen4d()).rotation().xyz();
|
||||
gtsam::Unit3 nG = gtsam::Rot3::RzRyRx(r.x(), r.y(), 0).rotate(gtsam::Unit3(0,0,-1));
|
||||
|
||||
88
corelib/src/optimizer/g2o/edge_sbacam_gravity.h
Normal file
88
corelib/src/optimizer/g2o/edge_sbacam_gravity.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Universite de Sherbrooke nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adapted from EdgeSE3Gravity
|
||||
*/
|
||||
|
||||
#ifndef RTAB_G2O_EDGE_SBACAM_GRAVITY_H_
|
||||
#define RTAB_G2O_EDGE_SBACAM_GRAVITY_H_
|
||||
|
||||
#include "g2o/types/sba/types_sba.h"
|
||||
#include "g2o/core/base_unary_edge.h"
|
||||
namespace rtabmap {
|
||||
/**
|
||||
* \brief EdgeSBACamGravity
|
||||
* \brief g2o edge with gravity constraint
|
||||
*/
|
||||
class EdgeSBACamGravity : public g2o::BaseUnaryEdge<3, Eigen::Matrix<double, 6, 1>, g2o::VertexCam> {
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
EdgeSBACamGravity(){
|
||||
information().setIdentity();
|
||||
}
|
||||
virtual bool read(std::istream& is) {return false;} // not implemented
|
||||
virtual bool write(std::ostream& os) const {return false;} // not implemented
|
||||
|
||||
// return the error estimate as a 3-vector
|
||||
void computeError(){
|
||||
const g2o::VertexCam* v1 = static_cast<const g2o::VertexCam*>(_vertices[0]);
|
||||
|
||||
Eigen::Vector3d direction = _measurement.head<3>();
|
||||
Eigen::Vector3d measurement = _measurement.tail<3>();
|
||||
|
||||
Eigen::Vector3d ea;
|
||||
|
||||
Eigen::Matrix3d t = v1->estimate().rotation().toRotationMatrix();
|
||||
ea[0] = atan2(t (2, 1), t (2, 2));
|
||||
ea[1] = asin(-t (2, 0));
|
||||
ea[2] = atan2(t (1, 0), t (0, 0));
|
||||
|
||||
Eigen::Matrix3d rot =
|
||||
(Eigen::AngleAxisd(ea[1], Eigen::Vector3d::UnitY()) *
|
||||
Eigen::AngleAxisd(ea[0], Eigen::Vector3d::UnitX())).toRotationMatrix();
|
||||
|
||||
Eigen::Vector3d estimate = rot * -direction;
|
||||
_error = estimate - measurement;
|
||||
|
||||
//printf("%d : measured=%f %f %f est=%f %f %f error=%f %f %f\n", v1->id(),
|
||||
// measurement[0], measurement[1], measurement[2],
|
||||
// estimate[0], estimate[1], estimate[2],
|
||||
// _error[0], _error[1], _error[2]);
|
||||
}
|
||||
|
||||
// 6 values:
|
||||
// [0:2] Up vector in robot frame
|
||||
// [3:5] Observed gravity vector in world frame
|
||||
virtual void setMeasurement(const Eigen::Matrix<double, 6, 1>& m){
|
||||
_measurement.head<3>() = m.head<3>().normalized();
|
||||
_measurement.tail<3>() = m.tail<3>().normalized();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
89
corelib/src/optimizer/g2o/edge_se3_gravity.h
Normal file
89
corelib/src/optimizer/g2o/edge_se3_gravity.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Universite de Sherbrooke nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adapted code from HDL graph slam:
|
||||
* https://github.com/koide3/hdl_graph_slam/blob/master/include/g2o/edge_se3_priorvec.hpp
|
||||
*/
|
||||
|
||||
#ifndef RTAB_G2O_EDGE_SE3_GRAVITY_H_
|
||||
#define RTAB_G2O_EDGE_SE3_GRAVITY_H_
|
||||
|
||||
#include "g2o/core/base_unary_edge.h"
|
||||
#include "g2o/types/slam3d/vertex_se3.h"
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
/*! \class EdgeSE3Gravity
|
||||
* \brief g2o edge with gravity constraint
|
||||
*/
|
||||
class EdgeSE3Gravity : public g2o::BaseUnaryEdge<3, Eigen::Matrix<double, 6, 1>, g2o::VertexSE3> {
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
EdgeSE3Gravity(){
|
||||
information().setIdentity();
|
||||
}
|
||||
virtual bool read(std::istream& is) {return false;} // not implemented
|
||||
virtual bool write(std::ostream& os) const {return false;} // not implemented
|
||||
|
||||
// return the error estimate as a 3-vector
|
||||
void computeError(){
|
||||
const g2o::VertexSE3* v1 = static_cast<const g2o::VertexSE3*>(_vertices[0]);
|
||||
|
||||
Eigen::Vector3d direction = _measurement.head<3>();
|
||||
Eigen::Vector3d measurement = _measurement.tail<3>();
|
||||
|
||||
Eigen::Vector3d ea;
|
||||
|
||||
Eigen::Matrix3d t = v1->estimate().linear();
|
||||
ea[0] = atan2(t (2, 1), t (2, 2));
|
||||
ea[1] = asin(-t (2, 0));
|
||||
ea[2] = atan2(t (1, 0), t (0, 0));
|
||||
|
||||
Eigen::Matrix3d rot =
|
||||
(Eigen::AngleAxisd(ea[1], Eigen::Vector3d::UnitY()) *
|
||||
Eigen::AngleAxisd(ea[0], Eigen::Vector3d::UnitX())).toRotationMatrix();
|
||||
|
||||
Eigen::Vector3d estimate = rot * -direction;
|
||||
_error = estimate - measurement;
|
||||
|
||||
//printf("%d : measured=%f %f %f est=%f %f %f error=%f %f %f\n", v1->id(),
|
||||
// measurement[0], measurement[1], measurement[2],
|
||||
// estimate[0], estimate[1], estimate[2],
|
||||
// _error[0], _error[1], _error[2]);
|
||||
}
|
||||
|
||||
// 6 values:
|
||||
// [0:2] Up vector in robot frame
|
||||
// [3:5] Observed gravity vector in world frame
|
||||
virtual void setMeasurement(const Eigen::Matrix<double, 6, 1>& m){
|
||||
_measurement.head<3>() = m.head<3>().normalized();
|
||||
_measurement.tail<3>() = m.tail<3>().normalized();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -87,10 +87,6 @@ void EdgeSE3XYZPrior::computeError() {
|
||||
_error = v->estimate().translation() - _measurement;
|
||||
}
|
||||
|
||||
void EdgeSE3XYZPrior::linearizeOplus() {
|
||||
_jacobianOplusXi << Eigen::Matrix3d::Identity();
|
||||
}
|
||||
|
||||
bool EdgeSE3XYZPrior::setMeasurementFromState() {
|
||||
const g2o::VertexSE3* v = static_cast<const g2o::VertexSE3*>(_vertices[0]);
|
||||
_measurement = v->estimate().translation();
|
||||
|
||||
@@ -63,7 +63,6 @@ public:
|
||||
virtual bool read(std::istream& is);
|
||||
virtual bool write(std::ostream& os) const;
|
||||
virtual void computeError();
|
||||
virtual void linearizeOplus();
|
||||
virtual bool setMeasurementFromState();
|
||||
|
||||
virtual double initialEstimatePossible(const g2o::OptimizableGraph::VertexSet& /*from*/, g2o::OptimizableGraph::Vertex* /*to*/) {return 1.;}
|
||||
|
||||
57
corelib/src/optimizer/gtsam/GPSPose2XYFactor.h
Normal file
57
corelib/src/optimizer/gtsam/GPSPose2XYFactor.h
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
/**
|
||||
* Author: Mathieu Labbe
|
||||
* This file is a copy of GPSPose2Factor.h of gtsam examples
|
||||
*/
|
||||
|
||||
/**
|
||||
* A simple 2D 'GPS' like factor
|
||||
* The factor contains a X-Y position measurement (mx, my) for a Pose, but no rotation information
|
||||
* The error vector will be [x-mx, y-my]'
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/nonlinear/NonlinearFactor.h>
|
||||
#include <gtsam/base/Matrix.h>
|
||||
#include <gtsam/base/Vector.h>
|
||||
#include <gtsam/geometry/Pose2.h>
|
||||
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class GPSPose2XYFactor: public gtsam::NoiseModelFactor1<gtsam::Pose2> {
|
||||
|
||||
private:
|
||||
// measurement information
|
||||
double mx_, my_;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param poseKey associated pose varible key
|
||||
* @param model noise model for GPS snesor, in X-Y
|
||||
* @param m Point2 measurement
|
||||
*/
|
||||
GPSPose2XYFactor(gtsam::Key poseKey, const gtsam::Point2 m, gtsam::SharedNoiseModel model) :
|
||||
gtsam::NoiseModelFactor1<gtsam::Pose2>(model, poseKey), mx_(m.x()), my_(m.y()) {}
|
||||
|
||||
// error function
|
||||
// @param p the pose in Pose2
|
||||
// @param H the optional Jacobian matrix, which use boost optional and has default null pointer
|
||||
gtsam::Vector evaluateError(const gtsam::Pose2& p, boost::optional<gtsam::Matrix&> H = boost::none) const {
|
||||
|
||||
// note that use boost optional like a pointer
|
||||
// only calculate jacobian matrix when non-null pointer exists
|
||||
if (H) *H = (gtsam::Matrix23() << 1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0).finished();
|
||||
|
||||
// return error vector
|
||||
return (gtsam::Vector2() << p.x() - mx_, p.y() - my_).finished();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace gtsamexamples
|
||||
|
||||
53
corelib/src/optimizer/gtsam/GPSPose3XYZFactor.h
Normal file
53
corelib/src/optimizer/gtsam/GPSPose3XYZFactor.h
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
/**
|
||||
* Author: Mathieu Labbe
|
||||
* This file is a copy of GPSPose2Factor.h of gtsam examples for Pose3
|
||||
*/
|
||||
|
||||
/**
|
||||
* A simple 3D 'GPS' like factor
|
||||
* The factor contains a X-Y-Z position measurement (mx, my, mz) for a Pose, but no rotation information
|
||||
* The error vector will be [x-mx, y-my, z-mz]'
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/nonlinear/NonlinearFactor.h>
|
||||
#include <gtsam/base/Matrix.h>
|
||||
#include <gtsam/base/Vector.h>
|
||||
#include <gtsam/geometry/Pose3.h>
|
||||
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class GPSPose3XYZFactor: public gtsam::NoiseModelFactor1<gtsam::Pose3> {
|
||||
|
||||
private:
|
||||
// measurement information
|
||||
double mx_, my_, mz_;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param poseKey associated pose variable key
|
||||
* @param model noise model for GPS sensor, in X-Y
|
||||
* @param m Point2 measurement
|
||||
*/
|
||||
GPSPose3XYZFactor(gtsam::Key poseKey, const gtsam::Point3 m, gtsam::SharedNoiseModel model) :
|
||||
gtsam::NoiseModelFactor1<gtsam::Pose3>(model, poseKey), mx_(m.x()), my_(m.y()), mz_(m.z()) {}
|
||||
|
||||
// error function
|
||||
// @param p the pose in Pose
|
||||
// @param H the optional Jacobian matrix, which use boost optional and has default null pointer
|
||||
gtsam::Vector evaluateError(const gtsam::Pose3& p, boost::optional<gtsam::Matrix&> H = boost::none) const {
|
||||
if(H)
|
||||
{
|
||||
p.translation(H);
|
||||
}
|
||||
return (gtsam::Vector3() << p.x() - mx_, p.y() - my_, p.z() - mz_).finished();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gtsamexamples
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Author: Mathieu Labbe
|
||||
* This file is a copy of AttitudeFactor.cpp of gtsam library but
|
||||
* with attitudeError() function overridden to ignore yaw errors.
|
||||
* For the noise model, use Sigmas(Vector2(0.1, 10)) (with second sigma high!)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file GravityFactor.cpp
|
||||
* @author Frank Dellaert
|
||||
|
||||
Reference in New Issue
Block a user