Skip to content

Commit

Permalink
[Lie] SystemModel + Numerical Differentiation
Browse files Browse the repository at this point in the history
  • Loading branch information
arntanguy committed Mar 20, 2017
0 parents commit 0869e54
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
BasedOnStyle: Google
BreakBeforeBraces: Allman
ColumnLimit: 0
IndentWidth: 4
...
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "include/kalman"]
path = include/kalman
url = https://github.com/mherb/kalman.git
[submodule "include/Sophus"]
path = include/Sophus
url = https://github.com/strasdat/Sophus.git
26 changes: 26 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 2.8)
project(KalmanLie CXX)

# TODO: Use VERSION argument to project command after raising the minimum
set(PROJECT_VERSION_MAJOR 0)
set(PROJECT_VERSION_MINOR 1)
set(PROJECT_VERSION_PATCH 0)
set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})


set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/include/kalman/cmake")
find_package(Eigen3 REQUIRED)

include_directories(
"include"
"include/kalman/include"
"include/Sophus"
${Eigen3_INCLUDE_DIR}
)

set(KALMAN_CXX_FLAGS "-std=c++11")
# Flags
set(CMAKE_CXX_FLAGS "${KALMAN_CXX_FLAGS}") # -Wall -pedantic -g")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DEIGEN_NO_DEBUG")

add_executable(example_lie "examples/Lie/main.cpp")
192 changes: 192 additions & 0 deletions examples/Lie/SystemModel.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
#pragma once

#include <kalman/LinearizedSystemModel.hpp>
#include <sophus/se3.hpp>
#include <unsupported/Eigen/AutoDiff>
#include <kalman_lie/NumericalDiff.hpp>

// Lie Type Definition
#define LIE_KALMAN_VECTOR(NAME, T) \
typedef typename Sophus::SE3<T>::Tangent Base; \
typedef typename Sophus::SE3<T> Group; \
using typename Base::Scalar; \
using Base::RowsAtCompileTime; \
using Base::ColsAtCompileTime; \
using Base::SizeAtCompileTime; \
NAME(void) : Base() {} \
template <typename OtherDerived> \
NAME(const Eigen::MatrixBase<OtherDerived>& other) : Base(other) \
{ \
} \
\
template <typename OtherDerived> \
NAME& operator=(const Eigen::MatrixBase<OtherDerived>& other) \
{ \
this->Base::operator=(other); \
return *this; \
}

namespace KalmanExamples
{
namespace Lie
{
/**
* @brief System state vector-type for a 6DOF Pose
*
* This is a system state for a 6D Pose expressed in Lie algebra,
* with a constant velocity model
*
* @param T
*/
template <typename T>
class State : public Sophus::SE3<T>::Tangent
{
public:
LIE_KALMAN_VECTOR(State, T)

// //! X-position
// static constexpr size_t X = 0;
// //! Y-Position
// static constexpr size_t Y = 1;
// //! Orientation
// static constexpr size_t THETA = 2;

// T x() const { return (*this)[ X ]; }
// T y() const { return (*this)[ Y ]; }
// T theta() const { return (*this)[ THETA ]; }

// T& x() { return (*this)[ X ]; }
// T& y() { return (*this)[ Y ]; }
// T& theta() { return (*this)[ THETA ]; }
};

/**
* @brief System control-input in se3
*
* @param T Numeric scalar type
*/
template <typename T>
class Control : public Sophus::SE3<T>::Tangent
{
public:
LIE_KALMAN_VECTOR(Control, T)

// //! Velocity
// static constexpr size_t V = 0;
// //! Angular Rate (Orientation-change)
// static constexpr size_t DTHETA = 1;

// T v() const { return (*this)[ V ]; }
// T dtheta() const { return (*this)[ DTHETA ]; }

// T& v() { return (*this)[ V ]; }
// T& dtheta() { return (*this)[ DTHETA ]; }
};

/**
* @brief System model for a simple planar 3DOF robot
*
* This is the system model defining how our robot moves from one
* time-step to the next, i.e. how the system state evolves over time.
*
* @param T Numeric scalar type
* @param CovarianceBase Class template to determine the covariance representation
* (as covariance matrix (StandardBase) or as lower-triangular
* coveriace square root (SquareRootBase))
*/
template <typename T>
class SystemModel : public Kalman::LinearizedSystemModel<State<T>>
{
public:
//! State type shortcut definition
typedef State<T> S;

//! No control
typedef Kalman::Vector<T, 0> C;

S velocity;

// Wraps the system model cost function in an automatic differentiation functor
template <typename Parent>
struct LieFunctor_ : Functor<T>
{
Parent* m;

LieFunctor_(Parent* m) : m(m)
{
}

int operator()(const Eigen::VectorXd& x, Eigen::VectorXd& fvec) const
{
C c;
// Cost function
fvec = m->f(x, c);
return 0;
}

int inputs() const { return 6; } // There are two parameters of the model
int values() const { return 6; } // The number of observations
};
using LieFunctor = LieFunctor_<SystemModel<T>>;

NumericalDiffFunctor<LieFunctor> num_diff;

SystemModel() : num_diff(this)
{
}

/**
* @brief Definition of (non-linear) state transition function
* This function defines how the system state is propagated through time,
* i.e. it defines in which state \f$\hat{x}_{k+1}\f$ is system is expected to
* be in time-step \f$k+1\f$ given the current state \f$x_k\f$ in step \f$k\f$ and
* the system control input \f$u\f$.
*
* @param [in] x The system state in current time-step
* @param [in] u The control vector input
* @returns The (predicted) system state in the next time-step
*/
// XXX todo pass timestep
S f(const S& x, const C& u) const
{
//! Predicted state vector after transition
S x_;

//! Predict given current pose and velocity
// XXX equation for constant velocity model
x_ = S::Group::log(S::Group::exp(x) * S::Group::exp(velocity));

// Return transitioned state vector
return x_;
}

protected:
/**
* @brief Update jacobian matrices for the system state transition function using current state
*
* This will re-compute the (state-dependent) elements of the jacobian matrices
* to linearize the non-lineRowsAtCompileTimear state transition function \f$f(x,u)\f$ around the
* current state \f$x\f typedef typename Functor::Scalar Scalar;
*
* @note This is only needed when implementing a LinearizedSystemModel,
* for usage with an ExtendedKalmanFilter or SquareRootExtendedKalmanFilter.
* When using a fully non-linear filter such as the UnscentedKalmanFilter
* or its square-root form then this is not needed.
*
* @param x The current system state around which to linearize
* @param u The current system control input
*/
void updateJacobians(const S& x, const C& u)
{
// F = df/dx (Jacobian of state transition w.r.t. the state)
this->F.setZero();

Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> jac(6, 6);
num_diff.df(Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>(x), jac);
std::cout << "jacobian: " << jac.matrix() << std::endl;
this->F = jac;
}
};

} // namespace Robot
} // namespace KalmanExamples
39 changes: 39 additions & 0 deletions examples/Lie/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "SystemModel.hpp"
#include <kalman/ExtendedKalmanFilter.hpp>

using namespace KalmanExamples;

using T = double;
using State = Lie::State<T>;
// No control
using Control = Kalman::Vector<T, 0>;
using SystemModel = Lie::SystemModel<T>;

int main(int argc, char *argv[])
{
State x;
x = State::Identity();
std::cout << x.matrix().transpose() << std::endl;

// Extended Kalman Filter
Kalman::ExtendedKalmanFilter<State> ekf;

SystemModel sys;
sys.velocity = State::Zero();
sys.velocity(4) = .1;
std::cout << "System velocity: " << sys.velocity.matrix().transpose() << std::endl;

// Init filters with the true system state
ekf.init(x);



Control u;
State x_ = sys.f(x, u);
std::cout << "New State: " << x_.matrix().transpose() << std::endl;

auto x_ekf = ekf.predict(sys, u);
std::cout << "x_ekf: " << x_ekf.matrix().transpose() << std::endl;

return 0;
}
1 change: 1 addition & 0 deletions include/Sophus
Submodule Sophus added at e35641
1 change: 1 addition & 0 deletions include/kalman
Submodule kalman added at fd9bc7
47 changes: 47 additions & 0 deletions include/kalman_lie/NumericalDiff.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#include <Eigen/Dense>
#include <unsupported/Eigen/NumericalDiff>

/**
* @brief Generic Functor for Eigen AutoDiff
*
* @tparam _Scalar
*/
template <typename _Scalar>
struct Functor
{
typedef _Scalar Scalar;
enum
{
InputsAtCompileTime = Eigen::Dynamic,
ValuesAtCompileTime = Eigen::Dynamic
};
typedef Eigen::Matrix<Scalar, InputsAtCompileTime, 1> InputType;
typedef Eigen::Matrix<Scalar, ValuesAtCompileTime, 1> ValueType;
typedef Eigen::Matrix<Scalar, ValuesAtCompileTime, InputsAtCompileTime> JacobianType;

const int m_inputs, m_values;

Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
int inputs() const { return m_inputs; } // number of degree of freedom (= 2*nb_vertices)
int values() const { return m_values; } // number of energy terms (= nb_vertices + nb_edges)
// you should define that in the subclass :
// void operator() (const InputType& x, ValueType* v, JacobianType* _j=0) const;
};

/**
* @brief Eigen::NumericalDiff adds a df function to your functor
* that numerically computes the jacobian.
*/
template <class Functor>
struct NumericalDiffFunctor : Eigen::NumericalDiff<Functor>
{
// Perfect forwarding of constructor arguments
template <typename... Args>
NumericalDiffFunctor(Args&&... args)
: Eigen::NumericalDiff<Functor>(std::forward<Args>(args)...)
{
}
};

0 comments on commit 0869e54

Please sign in to comment.