UrbanGraph class and testUrbanGraph TODOs
parent
68de3ae715
commit
d61d92c0e7
|
@ -127,9 +127,11 @@ headers += SQPOptimizer.h SQPOptimizer-inl.h
|
|||
headers += NonlinearConstraint.h NonlinearConstraint-inl.h
|
||||
headers += NonlinearEquality.h
|
||||
headers += Pose2Config.h Pose2Factor.h
|
||||
headers += UrbanGraph.h
|
||||
sources += NonlinearFactor.cpp
|
||||
sources += Pose2Graph.cpp
|
||||
check_PROGRAMS += testNonlinearFactor testNonlinearFactorGraph testNonlinearOptimizer testNonlinearEquality testSQP testNonlinearConstraint testSQPOptimizer testPose2Factor testPose2Graph
|
||||
sources += UrbanConfig.cpp UrbanMeasurement.cpp
|
||||
check_PROGRAMS += testNonlinearFactor testNonlinearFactorGraph testNonlinearOptimizer testNonlinearEquality testSQP testNonlinearConstraint testSQPOptimizer testPose2Factor testPose2Graph testUrbanGraph
|
||||
testNonlinearFactor_SOURCES = $(example) testNonlinearFactor.cpp
|
||||
testNonlinearFactor_LDADD = libgtsam.la
|
||||
testNonlinearConstraint_SOURCES = $(example) testNonlinearConstraint.cpp
|
||||
|
@ -148,6 +150,8 @@ testPose2Factor_SOURCES = $(example) testPose2Factor.cpp
|
|||
testPose2Factor_LDADD = libgtsam.la
|
||||
testPose2Graph_SOURCES = $(example) testPose2Graph.cpp
|
||||
testPose2Graph_LDADD = libgtsam.la
|
||||
testUrbanGraph_SOURCES = $(example) testUrbanGraph.cpp
|
||||
testUrbanGraph_LDADD = libgtsam.la
|
||||
|
||||
# geometry
|
||||
sources += Point2.cpp Rot2.cpp Pose2.cpp Point3.cpp Rot3.cpp Pose3.cpp Cal3_S2.cpp
|
||||
|
|
|
@ -101,25 +101,44 @@ Vector hPose (const Vector& x) {
|
|||
*/
|
||||
/* ************************************************************************* */
|
||||
Matrix DhPose(const Vector& x) {
|
||||
Matrix H = eye(6,6);
|
||||
return H;
|
||||
Matrix H = eye(6,6);
|
||||
return H;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Pose3 Pose3::inverse() const
|
||||
{
|
||||
Rot3 Rt = R_.inverse();
|
||||
return Pose3(Rt,-(Rt*t_));
|
||||
}
|
||||
{
|
||||
Rot3 Rt = R_.inverse();
|
||||
return Pose3(Rt,-(Rt*t_));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Pose3 Pose3::transformPose_to(const Pose3& pose) const
|
||||
{
|
||||
Rot3 cRv = R_ * Rot3(pose.R_.inverse());
|
||||
Point3 t = transform_to(pose, t_);
|
||||
|
||||
return Pose3(cRv, t);
|
||||
}
|
||||
{
|
||||
Rot3 cRv = R_ * Rot3(pose.R_.inverse());
|
||||
Point3 t = transform_to(pose, t_);
|
||||
|
||||
return Pose3(cRv, t);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
||||
|
||||
Pose3 between(const Pose3& p1, const Pose3& p2){
|
||||
Pose3 p;
|
||||
return p;
|
||||
// TODO: implement
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
Matrix Dbetween1(const Pose3& p1, const Pose3& p2){
|
||||
Matrix m;
|
||||
return m;
|
||||
// TODO: implement
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
Matrix Dbetween2(const Pose3& p1, const Pose3& p2){
|
||||
Matrix m;
|
||||
return m;
|
||||
// TODO: implement
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
} // namespace gtsam
|
||||
|
|
20
cpp/Pose3.h
20
cpp/Pose3.h
|
@ -77,6 +77,19 @@ namespace gtsam {
|
|||
/** inverse transformation */
|
||||
Pose3 inverse() const;
|
||||
|
||||
// operators
|
||||
Pose3 operator+(const Pose3& p3) const{
|
||||
// TODO implement the operators "+"
|
||||
Pose3 p;
|
||||
return p;
|
||||
};
|
||||
|
||||
Pose3 operator-(const Pose3& p3) const{
|
||||
// TODO implement the operators "-"
|
||||
Pose3 p;
|
||||
return p;
|
||||
};
|
||||
|
||||
/** composition */
|
||||
inline Pose3 operator*(const Pose3& B) const {
|
||||
return Pose3(R_*B.R_, t_ + R_*B.t_);
|
||||
|
@ -123,6 +136,13 @@ namespace gtsam {
|
|||
Matrix Dtransform_to1(const Pose3& pose, const Point3& p);
|
||||
Matrix Dtransform_to2(const Pose3& pose); // does not depend on p !
|
||||
|
||||
/**
|
||||
* Return relative pose between p1 and p2, in p1 coordinate frame
|
||||
*/
|
||||
Pose3 between(const Pose3& p1, const Pose3& p2);
|
||||
Matrix Dbetween1(const Pose3& p1, const Pose3& p2);
|
||||
Matrix Dbetween2(const Pose3& p1, const Pose3& p2);
|
||||
|
||||
/** direct measurement of a pose */
|
||||
Vector hPose(const Vector& x);
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* @file UrbanOdometryFactor.cpp
|
||||
* @brief A non-linear factor specialized to the Visual SLAM problem
|
||||
* @author Frank Dellaert
|
||||
* @author Viorela Ila
|
||||
*/
|
||||
|
||||
#include "UrbanConfig.h"
|
||||
#include "Pose3Factor.h"
|
||||
#include "Pose3.h"
|
||||
#include "SimpleCamera.h"
|
||||
|
||||
using namespace std;
|
||||
namespace gtsam{
|
||||
|
||||
/* ************************************************************************* */
|
||||
Pose3Factor::Pose3Factor() {
|
||||
/// Arbitrary values
|
||||
robotPoseNumber_ = 1;
|
||||
robotPoseName_ = symbol('x',robotPoseNumber_);
|
||||
keys_.push_back(robotPoseName_);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
Pose3Factor::Pose3Factor(const Point2& z, double sigma, int cn, int ln)
|
||||
: NonlinearFactor<Pose3Config>(z.vector(), sigma)
|
||||
{
|
||||
robotPoseNumber_ = cn;
|
||||
landmarkNumber_ = ln;
|
||||
robotPoseName_ = symbol('x',robotPoseNumber_);
|
||||
landmarkName_ = symbol('l',landmarkNumber_);
|
||||
keys_.push_back(robotPoseName_);
|
||||
keys_.push_back(landmarkName_);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void Pose3Factor::print(const std::string& s) const {
|
||||
printf("%s %s %s\n", s.c_str(), robotPoseName_.c_str(), landmarkName_.c_str());
|
||||
gtsam::print(this->z_, s+".z");
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool Pose3Factor::equals(const Pose3Factor& p, double tol) const {
|
||||
if (&p == NULL) return false;
|
||||
if (robotPoseNumber_ != p.robotPoseNumber_ || landmarkNumber_ != p.landmarkNumber_) return false;
|
||||
if (!equal_with_abs_tol(this->z_,p.z_,tol)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO Implement transformPoint2_from
|
||||
// the difference here that we have a 2d point in a 3D coordinate
|
||||
Vector Pose3Factor::predict(const Pose3Config& c) const {
|
||||
Pose3 pose = c.cameraPose(robotPoseNumber_);
|
||||
Point2 landmark = c.landmarkPoint(landmarkNumber_);
|
||||
return transformPoint2_from(SimpleCamera(*K_,pose), landmark).vector();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Vector Pose3Factor::error_vector(const Pose3Config& c) const {
|
||||
// Right-hand-side b = (z - h(x))/sigma
|
||||
Point2 h = predict(c);
|
||||
return (this->z_ - h);
|
||||
}
|
||||
|
||||
GaussianFactor::shared_ptr Pose3Factor::linearize(const Pose3Config& c) const
|
||||
{
|
||||
// get arguments from config
|
||||
Pose3 pose = c.cameraPose(robotPoseNumber_);
|
||||
Point3 landmark = c.landmarkPoint(landmarkNumber_);
|
||||
|
||||
SimpleCamera camera(*K_,pose);
|
||||
|
||||
// Jacobians
|
||||
Matrix Dh1 = Dproject_pose(camera, landmark);
|
||||
Matrix Dh2 = Dproject_point(camera, landmark);
|
||||
|
||||
// Right-hand-side b = (z - h(x))
|
||||
Vector h = project(camera, landmark).vector();
|
||||
Vector b = this->z_ - h;
|
||||
|
||||
// Make new linearfactor, divide by sigma
|
||||
GaussianFactor::shared_ptr
|
||||
p(new GaussianFactor(robotPoseName_, Dh1, landmarkName_, Dh2, b, this->sigma_));
|
||||
return p;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
} // namespace gtsam
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* @file Pose3Factor.h
|
||||
* @brief A Nonlinear Factor, specialized for Urban application
|
||||
* @author Frank Dellaert
|
||||
* @author Viorela Ila
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "NonlinearFactor.h"
|
||||
#include "GaussianFactor.h"
|
||||
#include "VectorConfig.h"
|
||||
#include "Pose3.h"
|
||||
#include "Matrix.h"
|
||||
#include "ostream"
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
template <class Config>
|
||||
class Pose3Factor : public NonlinearFactor<Config> {
|
||||
private:
|
||||
std::string key1_, key2_; /** The keys of the two poses, order matters */
|
||||
Pose3 measured_;
|
||||
Matrix square_root_inverse_covariance_; /** sqrt(inv(measurement_covariance)) */
|
||||
|
||||
public:
|
||||
|
||||
typedef boost::shared_ptr<Pose3Factor> shared_ptr; // shorthand for a smart pointer to a factor
|
||||
|
||||
Pose3Factor(const std::string& key1, const std::string& key2,
|
||||
const Pose3& measured, const Matrix& measurement_covariance): key1_(key1),key2_(key2),measured_(measured) {
|
||||
square_root_inverse_covariance_ = inverse_square_root(measurement_covariance);
|
||||
}
|
||||
|
||||
/** implement functions needed for Testable */
|
||||
void print(const std::string& name) const {
|
||||
std::cout << name << std::endl;
|
||||
std::cout << "Factor "<< std::endl;
|
||||
std::cout << "key1 "<< key1_<<std::endl;
|
||||
std::cout << "key2 "<< key2_<<std::endl;
|
||||
measured_.print("measured ");
|
||||
gtsam::print(square_root_inverse_covariance_,"MeasurementCovariance");
|
||||
}
|
||||
bool equals(const NonlinearFactor<Config>& expected, double tol) const {return false;}
|
||||
|
||||
/** implement functions needed to derive from Factor */
|
||||
Vector error_vector(const Config& config) const {
|
||||
//z-h
|
||||
Pose3 p1 = config.get(key1_), p2 = config.get(key2_);
|
||||
return (measured_ - between(p1,p2)).vector();
|
||||
}
|
||||
|
||||
std::list<std::string> keys() const { std::list<std::string> l; return l; }
|
||||
std::size_t size() const { return 2;}
|
||||
|
||||
/** linearize */
|
||||
boost::shared_ptr<GaussianFactor> linearize(const Config& config) const {
|
||||
Pose3 p1 = config.get(key1_), p2 = config.get(key2_);
|
||||
Vector b = (measured_ - between(p1,p2)).vector();
|
||||
Matrix H1 = Dbetween1(p1,p2);
|
||||
Matrix H2 = Dbetween2(p1,p2);
|
||||
boost::shared_ptr<GaussianFactor> linearized(new GaussianFactor(
|
||||
key1_, square_root_inverse_covariance_ * H1,
|
||||
key2_, square_root_inverse_covariance_ * H2,
|
||||
b, 1.0));
|
||||
return linearized;
|
||||
}
|
||||
};
|
||||
} /// namespace gtsam
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
* @file UrbanConfig.cpp
|
||||
* @brief The Config for Urban example
|
||||
* @author Frank Dellaert
|
||||
* @author Viorela Ila
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include "UrbanConfig.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// trick from some reading group
|
||||
#define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL)
|
||||
|
||||
#define SIGMA 1.0
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
// Exponential map
|
||||
UrbanConfig UrbanConfig::exmap(const VectorConfig & delta) const {
|
||||
|
||||
UrbanConfig newConfig;
|
||||
|
||||
for (map<string, Vector>::const_iterator it = delta.begin(); it
|
||||
!= delta.end(); it++) {
|
||||
string key = it->first;
|
||||
if (key[0] == 'x') {
|
||||
int robotNumber = atoi(key.substr(1, key.size() - 1).c_str());
|
||||
if (robotPoseExists(robotNumber)) {
|
||||
Pose3 basePose = robotPose(robotNumber);
|
||||
newConfig.addRobotPose(robotNumber, basePose.exmap(it->second));
|
||||
}
|
||||
}
|
||||
if (key[0] == 'l') {
|
||||
int landmarkNumber = atoi(key.substr(1, key.size() - 1).c_str());
|
||||
if (landmarkPointExists(landmarkNumber)) {
|
||||
Point2 basePoint = landmarkPoint(landmarkNumber);
|
||||
newConfig.addLandmark(landmarkNumber, basePoint.exmap(it->second));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void UrbanConfig::print(const std::string& s) const
|
||||
{
|
||||
printf("%s:\n", s.c_str());
|
||||
printf("robot Poses:\n");
|
||||
for(PoseMap::const_iterator it = robotIteratorBegin(); it != robotIteratorEnd(); it++)
|
||||
{
|
||||
printf("x%d:\n", it->first);
|
||||
it->second.print();
|
||||
}
|
||||
printf("Landmark Points:\n");
|
||||
for(PointMap::const_iterator it = landmarkIteratorBegin(); it != landmarkIteratorEnd(); it++)
|
||||
{
|
||||
printf("l%d:\n", (*it).first);
|
||||
(*it).second.print();
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool UrbanConfig::equals(const UrbanConfig& c, double tol) const {
|
||||
for (PoseMap::const_iterator it = robotIteratorBegin(); it
|
||||
!= robotIteratorEnd(); it++) {
|
||||
if (!c.robotPoseExists(it->first)) return false;
|
||||
if (!it->second.equals(c.robotPose(it->first), tol)) return false;
|
||||
}
|
||||
|
||||
for (PointMap::const_iterator it = landmarkIteratorBegin(); it
|
||||
!= landmarkIteratorEnd(); it++) {
|
||||
if (!c.landmarkPointExists(it->first)) return false;
|
||||
if (!it->second.equals(c.landmarkPoint(it->first), tol)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void UrbanConfig::addRobotPose(const int i, Pose3 cp)
|
||||
{
|
||||
pair<int, Pose3> robot;
|
||||
robot.first = i;
|
||||
robot.second = cp;
|
||||
robotPoses_.insert(robot);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void UrbanConfig::addLandmark(const int i, Point2 lp)
|
||||
{
|
||||
pair<int, Point2> landmark;
|
||||
landmark.first = i;
|
||||
landmark.second = lp;
|
||||
landmarkPoints_.insert(landmark);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void UrbanConfig::removeRobotPose(const int i)
|
||||
{
|
||||
if(robotPoseExists(i))
|
||||
robotPoses_.erase(i);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void UrbanConfig::removeLandmark(const int i)
|
||||
{
|
||||
if(landmarkPointExists(i))
|
||||
landmarkPoints_.erase(i);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
* @file UrbanConfig.h
|
||||
* @brief Config for Urban application
|
||||
* @author Frank Dellaert
|
||||
* @author Viorela Ila
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include "VectorConfig.h"
|
||||
#include "Pose3.h"
|
||||
#include "Point2.h"
|
||||
#include "Testable.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace gtsam{
|
||||
|
||||
/**
|
||||
* Config that knows about points and poses
|
||||
*/
|
||||
class UrbanConfig : Testable<UrbanConfig> {
|
||||
|
||||
private:
|
||||
typedef std::map<int, Pose3> PoseMap;
|
||||
typedef std::map<int, Point2> PointMap;
|
||||
PointMap landmarkPoints_;
|
||||
PoseMap robotPoses_;
|
||||
|
||||
public:
|
||||
typedef std::map<std::string, Vector>::const_iterator const_iterator;
|
||||
typedef PoseMap::const_iterator const_Pose_iterator;
|
||||
typedef PointMap::const_iterator const_Point_iterator;
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
UrbanConfig() {}
|
||||
|
||||
/*
|
||||
* copy constructor
|
||||
*/
|
||||
UrbanConfig(const UrbanConfig& original):
|
||||
robotPoses_(original.robotPoses_), landmarkPoints_(original.landmarkPoints_){}
|
||||
|
||||
/**
|
||||
* Exponential map: takes 6D vectors in VectorConfig
|
||||
* and applies them to the poses in the UrbanConfig.
|
||||
* Needed for use in nonlinear optimization
|
||||
*/
|
||||
UrbanConfig exmap(const VectorConfig & delta) const;
|
||||
|
||||
PoseMap::const_iterator robotIteratorBegin() const { return robotPoses_.begin();}
|
||||
PoseMap::const_iterator robotIteratorEnd() const { return robotPoses_.end();}
|
||||
PointMap::const_iterator landmarkIteratorBegin() const { return landmarkPoints_.begin();}
|
||||
PointMap::const_iterator landmarkIteratorEnd() const { return landmarkPoints_.end();}
|
||||
|
||||
/**
|
||||
* print
|
||||
*/
|
||||
void print(const std::string& s = "") const;
|
||||
|
||||
/**
|
||||
* Retrieve robot pose
|
||||
*/
|
||||
bool robotPoseExists(int i) const
|
||||
{
|
||||
PoseMap::const_iterator it = robotPoses_.find(i);
|
||||
if (it==robotPoses_.end())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Pose3 robotPose(int i) const {
|
||||
PoseMap::const_iterator it = robotPoses_.find(i);
|
||||
if (it==robotPoses_.end())
|
||||
throw(std::invalid_argument("robotPose: invalid key"));
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a landmark point exists
|
||||
*/
|
||||
bool landmarkPointExists(int i) const
|
||||
{
|
||||
PointMap::const_iterator it = landmarkPoints_.find(i);
|
||||
if (it==landmarkPoints_.end())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve landmark point
|
||||
*/
|
||||
Point2 landmarkPoint(int i) const {
|
||||
PointMap::const_iterator it = landmarkPoints_.find(i);
|
||||
if (it==landmarkPoints_.end())
|
||||
throw(std::invalid_argument("markerPose: invalid key"));
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether two configs are equal
|
||||
*/
|
||||
bool equals(const UrbanConfig& c, double tol=1e-6) const;
|
||||
void addRobotPose(const int i, Pose3 cp);
|
||||
void addLandmark(const int i, Point2 lp);
|
||||
|
||||
void removeRobotPose(const int i);
|
||||
void removeLandmark(const int i);
|
||||
|
||||
void clear() {landmarkPoints_.clear(); robotPoses_.clear();}
|
||||
|
||||
inline size_t size(){
|
||||
return landmarkPoints_.size() + robotPoses_.size();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* @file UrbanGraph.h
|
||||
* @brief A factor graph for the Urban problem
|
||||
* @author Frank Dellaert
|
||||
* @author Viorela Ila
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <fstream>
|
||||
|
||||
#include "NonlinearFactorGraph.h"
|
||||
#include "FactorGraph-inl.h"
|
||||
#include "UrbanMeasurement.h"
|
||||
#include "Pose3Factor.h"
|
||||
#include "UrbanConfig.h"
|
||||
#include "Testable.h"
|
||||
|
||||
namespace gtsam{
|
||||
|
||||
/**
|
||||
* Non-linear factor graph for visual SLAM
|
||||
*/
|
||||
class UrbanGraph : public gtsam::NonlinearFactorGraph<UrbanConfig>{
|
||||
|
||||
public:
|
||||
|
||||
/** default constructor is empty graph */
|
||||
UrbanGraph() {}
|
||||
|
||||
/**
|
||||
* print out graph
|
||||
*/
|
||||
void print(const std::string& s = "") const {
|
||||
gtsam::NonlinearFactorGraph<UrbanConfig>::print(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* equals
|
||||
*/
|
||||
bool equals(const UrbanGraph& p, double tol=1e-9) const {
|
||||
return gtsam::NonlinearFactorGraph<UrbanConfig>::equals(p, tol);
|
||||
}
|
||||
// TODO implement addMeasurenment, addOdometry and addOriginalConstraint (out of the class)
|
||||
/**
|
||||
* Add a landmark constraint
|
||||
*/
|
||||
void addMeasurement(double x, double y, double sigma, int p1, int p2) {};
|
||||
|
||||
/**
|
||||
* Add an odometry constraint
|
||||
*/
|
||||
void addOdometry(double dx, double yaw, double sigmadx, double sigmayaw, int p ) {};
|
||||
|
||||
/**
|
||||
* Add an initial constraint on the first pose
|
||||
*/
|
||||
void addOriginConstraint(int p){};
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int version) {}
|
||||
};
|
||||
|
||||
} // namespace gtsam
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* @file UrbanMeasurement.cpp
|
||||
* @brief A non-linear factor specialized to the Visual SLAM problem
|
||||
* @author Frank Dellaert
|
||||
* @author Viorela Ila
|
||||
*/
|
||||
|
||||
#include "UrbanConfig.h"
|
||||
#include "UrbanMeasurement.h"
|
||||
#include "Pose3.h"
|
||||
#include "SimpleCamera.h"
|
||||
|
||||
using namespace std;
|
||||
namespace gtsam{
|
||||
/** receives the 2D point in world coordinates and transforms it to Pose coordinates */
|
||||
Point3 transformPoint2_to(const Pose3& pose, const Point2& p);
|
||||
Matrix DtransformPoint2_to1(const Pose3& pose, const Point2& p);
|
||||
Matrix DtransformPoint2_to2(const Pose3& pose); // does not depend on p !
|
||||
/* ************************************************************************* */
|
||||
UrbanMeasurement::UrbanMeasurement() {
|
||||
/// Arbitrary values
|
||||
robotPoseNumber_ = 111;
|
||||
landmarkNumber_ = 222;
|
||||
robotPoseName_ = symbol('x',robotPoseNumber_);
|
||||
landmarkName_ = symbol('l',landmarkNumber_);
|
||||
keys_.push_back(robotPoseName_);
|
||||
keys_.push_back(landmarkName_);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
UrbanMeasurement::UrbanMeasurement(const Point2& z, double sigma, int cn, int ln)
|
||||
: NonlinearFactor<UrbanConfig>(z.vector(), sigma)
|
||||
{
|
||||
robotPoseNumber_ = cn;
|
||||
landmarkNumber_ = ln;
|
||||
robotPoseName_ = symbol('x',robotPoseNumber_);
|
||||
landmarkName_ = symbol('l',landmarkNumber_);
|
||||
keys_.push_back(robotPoseName_);
|
||||
keys_.push_back(landmarkName_);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void UrbanMeasurement::print(const std::string& s) const {
|
||||
printf("%s %s %s\n", s.c_str(), robotPoseName_.c_str(), landmarkName_.c_str());
|
||||
gtsam::print(this->z_, s+".z");
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool UrbanMeasurement::equals(const UrbanMeasurement& p, double tol) const {
|
||||
if (&p == NULL) return false;
|
||||
if (robotPoseNumber_ != p.robotPoseNumber_ || landmarkNumber_ != p.landmarkNumber_) return false;
|
||||
if (!equal_with_abs_tol(this->z_,p.z_,tol)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// the difference here that we have a 2d point in a 3D coordinate
|
||||
Vector UrbanMeasurement::predict(const UrbanConfig& c) const {
|
||||
Pose3 pose = c.robotPose(robotPoseNumber_);
|
||||
Point2 landmark = c.landmarkPoint(landmarkNumber_);
|
||||
// TODO Implement predict function
|
||||
Vector v;
|
||||
return v;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Vector UrbanMeasurement::error_vector(const UrbanConfig& c) const {
|
||||
// Right-hand-side b = (z - h(x))/sigma
|
||||
Point2 h = predict(c);
|
||||
// TODO Return z-h(x)
|
||||
Vector v;
|
||||
return v;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
} // namespace gtsam
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* @file UrbanMeasurement.h
|
||||
* @brief A Nonlinear Factor, specialized for Urban application
|
||||
* @author Frank Dellaert
|
||||
* @author Viorela Ila
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NonlinearFactor.h"
|
||||
#include "GaussianFactor.h"
|
||||
#include "Testable.h"
|
||||
#include "Point2.h"
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
class UrbanConfig;
|
||||
|
||||
/**
|
||||
* Non-linear factor for a constraint derived from a 2D measurement,
|
||||
*/
|
||||
class UrbanMeasurement : public NonlinearFactor<UrbanConfig>, Testable<UrbanMeasurement>
|
||||
{
|
||||
private:
|
||||
|
||||
int robotPoseNumber_, landmarkNumber_;
|
||||
std::string robotPoseName_, landmarkName_;
|
||||
//boost::shared_ptr<Cal3_S2> K_; // Calibration stored in each factor. FD: need to think about this.
|
||||
typedef NonlinearFactor<UrbanConfig> ConvenientFactor;
|
||||
|
||||
public:
|
||||
|
||||
typedef boost::shared_ptr<UrbanMeasurement> shared_ptr; // shorthand for a smart pointer to a factor
|
||||
//typedef boost::shared_ptr<Cal3_S2> shared_ptrK;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
UrbanMeasurement();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param z is the 2 dimensional location of landmark respect to the robot (the measurement)
|
||||
* @param sigma is the standard deviation
|
||||
* @param robotPoseNumber is basically the pose number
|
||||
* @param landmarkNumber is the index of the landmark
|
||||
*
|
||||
*
|
||||
*/
|
||||
UrbanMeasurement(const Point2& z, double sigma, int robotPoseNumber, int landmarkNumber);
|
||||
|
||||
|
||||
/**
|
||||
* print
|
||||
* @param s optional string naming the factor
|
||||
*/
|
||||
void print(const std::string& s="UrbanMeasurement") const;
|
||||
|
||||
/**
|
||||
* equals
|
||||
*/
|
||||
bool equals(const UrbanMeasurement&, double tol=1e-9) const;
|
||||
|
||||
/**
|
||||
* predict the measurement (is that update ??)
|
||||
*/
|
||||
Vector predict(const UrbanConfig&) const;
|
||||
|
||||
/**
|
||||
* calculate the error of the factor
|
||||
*/
|
||||
Vector error_vector(const UrbanConfig&) const;
|
||||
|
||||
/**
|
||||
* linerarization
|
||||
*/
|
||||
|
||||
GaussianFactor::shared_ptr linearize(const UrbanConfig&) const {
|
||||
//TODO implement linearize
|
||||
|
||||
};
|
||||
|
||||
int getrobotPoseNumber() const { return robotPoseNumber_; }
|
||||
int getLandmarkNumber() const { return landmarkNumber_; }
|
||||
|
||||
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_NVP(robotPoseNumber_);
|
||||
ar & BOOST_SERIALIZATION_NVP(landmarkNumber_);
|
||||
ar & BOOST_SERIALIZATION_NVP(robotPoseName_);
|
||||
ar & BOOST_SERIALIZATION_NVP(landmarkName_);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
#! /bin/sh
|
||||
|
||||
# testUrbanGraph - temporary wrapper script for .libs/testUrbanGraph
|
||||
# Generated by ltmain.sh - GNU libtool 1.5.22 (1.1220.2.365 2005/12/18 22:14:06)
|
||||
#
|
||||
# The testUrbanGraph program cannot be directly executed until all the libtool
|
||||
# libraries that it depends on are installed.
|
||||
#
|
||||
# This wrapper script should never be moved out of the build directory.
|
||||
# If it is, it will not operate correctly.
|
||||
|
||||
# Sed substitution that helps us do robust quoting. It backslashifies
|
||||
# metacharacters that are still active within double-quoted strings.
|
||||
Xsed='/usr/bin/sed -e 1s/^X//'
|
||||
sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
|
||||
|
||||
# The HP-UX ksh and POSIX shell print the target directory to stdout
|
||||
# if CDPATH is set.
|
||||
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
|
||||
|
||||
relink_command=""
|
||||
|
||||
# This environment variable determines our operation mode.
|
||||
if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
|
||||
# install mode needs the following variable:
|
||||
notinst_deplibs=' libgtsam.la'
|
||||
else
|
||||
# When we are sourced in execute mode, $file and $echo are already set.
|
||||
if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
|
||||
echo="/bin/echo"
|
||||
file="$0"
|
||||
# Make sure echo works.
|
||||
if test "X$1" = X--no-reexec; then
|
||||
# Discard the --no-reexec flag, and continue.
|
||||
shift
|
||||
elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
|
||||
# Yippee, $echo works!
|
||||
:
|
||||
else
|
||||
# Restart under the correct shell, and then maybe $echo will work.
|
||||
exec /bin/sh "$0" --no-reexec ${1+"$@"}
|
||||
fi
|
||||
fi
|
||||
|
||||
# Find the directory that this script lives in.
|
||||
thisdir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
|
||||
test "x$thisdir" = "x$file" && thisdir=.
|
||||
|
||||
# Follow symbolic links until we get to the real thisdir.
|
||||
file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'`
|
||||
while test -n "$file"; do
|
||||
destdir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
|
||||
|
||||
# If there was a directory component, then change thisdir.
|
||||
if test "x$destdir" != "x$file"; then
|
||||
case "$destdir" in
|
||||
[\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
|
||||
*) thisdir="$thisdir/$destdir" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
file=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
|
||||
file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'`
|
||||
done
|
||||
|
||||
# Try to get the absolute directory name.
|
||||
absdir=`cd "$thisdir" && pwd`
|
||||
test -n "$absdir" && thisdir="$absdir"
|
||||
|
||||
program='testUrbanGraph'
|
||||
progdir="$thisdir/.libs"
|
||||
|
||||
|
||||
if test -f "$progdir/$program"; then
|
||||
# Add our own library path to DYLD_LIBRARY_PATH
|
||||
DYLD_LIBRARY_PATH="/Users/vila/borg/gtsam/cpp/.libs:$DYLD_LIBRARY_PATH"
|
||||
|
||||
# Some systems cannot cope with colon-terminated DYLD_LIBRARY_PATH
|
||||
# The second colon is a workaround for a bug in BeOS R4 sed
|
||||
DYLD_LIBRARY_PATH=`$echo "X$DYLD_LIBRARY_PATH" | $Xsed -e 's/::*$//'`
|
||||
|
||||
export DYLD_LIBRARY_PATH
|
||||
|
||||
if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
|
||||
# Run the actual program with our arguments.
|
||||
|
||||
exec "$progdir/$program" ${1+"$@"}
|
||||
|
||||
$echo "$0: cannot exec $program ${1+"$@"}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# The program doesn't exist.
|
||||
$echo "$0: error: \`$progdir/$program' does not exist" 1>&2
|
||||
$echo "This script is just a wrapper for $program." 1>&2
|
||||
/bin/echo "See the libtool documentation for more information." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* @file testUrbanGraph.cpp
|
||||
* @brief Unit test for two robot poses and four landmarks
|
||||
* @author Frank Dellaert
|
||||
* @author Viorela Ila
|
||||
*/
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include "UrbanGraph.h"
|
||||
#include "NonlinearFactorGraph-inl.h"
|
||||
#include "NonlinearOptimizer-inl.h"
|
||||
#include "Pose3.h"
|
||||
#include "Point2.h"
|
||||
#include "Ordering.h"
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
typedef NonlinearOptimizer<UrbanGraph,UrbanConfig> Optimizer;
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
Point2 landmark1( 2, 5);
|
||||
Point2 landmark2( 2, 10);
|
||||
Point2 landmark3( -2, 5);
|
||||
Point2 landmark4( -2,-10);
|
||||
|
||||
/* Robot is at (0,0,0) looking in global "y" direction.
|
||||
* For the local frame we used Navlab convention,
|
||||
* x-looks forward, y-looks right, z- down*/
|
||||
Pose3 robotPose1(Matrix_(3,3,
|
||||
0., 1., 0.,
|
||||
1., 0., 0.,
|
||||
0., 0.,-1.
|
||||
),
|
||||
Point3(0,0,0));
|
||||
|
||||
/* move at a speed 10 m/s (36 km/h or 22 mph), 10 Hz update, we move 1m.*/
|
||||
Pose3 robotPose2(Matrix_(3,3,
|
||||
0., 1., 0.,
|
||||
1., 0., 0.,
|
||||
0., 0.,-1.
|
||||
),
|
||||
Point3(0,1,0));
|
||||
|
||||
/* ************************************************************************* */
|
||||
/* the measurements are relative to the robot pose so
|
||||
* they are in robot coordinate frame different from the global (above)*/
|
||||
UrbanGraph testGraph() {
|
||||
|
||||
double sigma = 0.2;// 20 cm
|
||||
double sigmadx = 0.01; // 1 cm
|
||||
double sigmayaw = M_PI/180.0;// 1 degree
|
||||
|
||||
UrbanGraph g;
|
||||
g.addOriginConstraint(1); // pose1 is the origin
|
||||
g.addMeasurement( 5, 2, sigma, 1, 1); // z11
|
||||
g.addMeasurement(10, 2, sigma, 1, 2); // z12
|
||||
g.addMeasurement( 5, -2, sigma, 1, 3); // z13
|
||||
g.addMeasurement(10, -2, sigma, 1, 4); // z14
|
||||
g.addOdometry(1, 0, sigmadx,sigmayaw, 1); // 1m forward, 0 yaw
|
||||
g.addMeasurement( 4, 2, sigma, 2, 1); // z21
|
||||
g.addMeasurement( 9, 2, sigma, 2, 2); // z22
|
||||
g.addMeasurement( 4, -2, sigma, 2, 3); // z23
|
||||
g.addMeasurement( 9, -2, sigma, 2, 4); // z24
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( UrbanGraph, optimizeLM)
|
||||
{
|
||||
// build a graph
|
||||
UrbanGraph graph = testGraph();
|
||||
|
||||
// Create an initial configuration corresponding to the ground truth
|
||||
boost::shared_ptr<UrbanConfig> initialEstimate(new UrbanConfig);
|
||||
initialEstimate->addRobotPose(1, robotPose1);
|
||||
initialEstimate->addRobotPose(2, robotPose2);
|
||||
initialEstimate->addLandmark(1, landmark1);
|
||||
initialEstimate->addLandmark(2, landmark2);
|
||||
initialEstimate->addLandmark(3, landmark3);
|
||||
initialEstimate->addLandmark(4, landmark4);
|
||||
|
||||
// Create an ordering of the variables
|
||||
Ordering ordering;
|
||||
ordering += "l1","l2","l3","l4","x1","x2"; // boost assign syntax
|
||||
|
||||
// Create an optimizer and check its error
|
||||
// We expect the initial to be zero because config is the ground truth
|
||||
//Optimizer optimizer(graph, ordering, initialEstimate, 1e-5);
|
||||
//DOUBLES_EQUAL(0, optimizer.error(), 1e-9);
|
||||
|
||||
// Iterate once, and the config should not have changed because we started
|
||||
// with the ground truth
|
||||
|
||||
// Optimizer afterOneIteration = optimizer.iterate();
|
||||
// DOUBLES_EQUAL(0, optimizer.error(), 1e-9);
|
||||
|
||||
// check if correct
|
||||
// CHECK(assert_equal(*initialEstimate,*(afterOneIteration.config())));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; TestRegistry::runAllTests(tr); return 0;}
|
||||
/* ************************************************************************* */
|
Loading…
Reference in New Issue