2013-04-16 05:31:47 +08:00
/**
* @ file Pendulum . h
* @ brief Three - way factors for the pendulum dynamics as in [ Stern06siggraph ] for
* ( 1 ) explicit Euler method , ( 2 ) implicit Euler method , and ( 3 ) sympletic Euler method .
* Note that all methods use the same formulas for the factors . They are only different in
* the way we connect variables using those factors in the graph .
* @ author Duy - Nguyen Ta
*/
# pragma once
# include <gtsam/nonlinear/NonlinearFactor.h>
namespace gtsam {
2013-04-17 03:07:59 +08:00
//*************************************************************************
2013-04-16 05:31:47 +08:00
/**
* This class implements the first constraint .
2013-04-17 03:07:59 +08:00
* - For explicit Euler method : q_ { k + 1 } = q_k + h * v_k
* - For implicit Euler method : q_ { k + 1 } = q_k + h * v_ { k + 1 }
* - For sympletic Euler method : q_ { k + 1 } = q_k + h * v_ { k + 1 }
2013-04-16 05:31:47 +08:00
*/
2022-12-23 06:25:48 +08:00
class PendulumFactor1 : public NoiseModelFactorN < double , double , double > {
2013-04-16 05:31:47 +08:00
public :
protected :
2022-12-23 06:25:48 +08:00
typedef NoiseModelFactorN < double , double , double > Base ;
2013-04-16 05:31:47 +08:00
/** default constructor to allow for serialization */
PendulumFactor1 ( ) { }
2013-04-17 03:07:59 +08:00
double h_ ; // time step
2013-04-16 05:31:47 +08:00
public :
typedef boost : : shared_ptr < PendulumFactor1 > shared_ptr ;
2013-04-17 03:07:59 +08:00
///Constructor. k1: q_{k+1}, k: q_k, velKey: velocity variable depending on the chosen method, h: time step
PendulumFactor1 ( Key k1 , Key k , Key velKey , double h , double mu = 1000.0 )
2019-09-19 03:24:09 +08:00
: Base ( noiseModel : : Constrained : : All ( 1 , std : : abs ( mu ) ) , k1 , k , velKey ) , h_ ( h ) { }
2013-04-16 05:31:47 +08:00
/// @return a deep copy of this factor
2020-07-26 15:57:54 +08:00
gtsam : : NonlinearFactor : : shared_ptr clone ( ) const override {
2013-04-16 05:31:47 +08:00
return boost : : static_pointer_cast < gtsam : : NonlinearFactor > (
gtsam : : NonlinearFactor : : shared_ptr ( new PendulumFactor1 ( * this ) ) ) ; }
2013-04-17 03:07:59 +08:00
/** q_k + h*v - q_k1 = 0, with optional derivatives */
2014-11-04 22:41:14 +08:00
Vector evaluateError ( const double & qk1 , const double & qk , const double & v ,
2013-04-16 05:31:47 +08:00
boost : : optional < Matrix & > H1 = boost : : none ,
boost : : optional < Matrix & > H2 = boost : : none ,
2020-07-26 15:57:54 +08:00
boost : : optional < Matrix & > H3 = boost : : none ) const override {
2014-11-04 22:41:14 +08:00
const size_t p = 1 ;
2016-04-12 04:04:24 +08:00
if ( H1 ) * H1 = - Matrix : : Identity ( p , p ) ;
if ( H2 ) * H2 = Matrix : : Identity ( p , p ) ;
if ( H3 ) * H3 = Matrix : : Identity ( p , p ) * h_ ;
2014-11-23 08:35:27 +08:00
return ( Vector ( 1 ) < < qk + v * h_ - qk1 ) . finished ( ) ;
2013-04-16 05:31:47 +08:00
}
} ; // \PendulumFactor1
2013-04-17 03:07:59 +08:00
//*************************************************************************
2013-04-16 05:31:47 +08:00
/**
* This class implements the second constraint the
2013-04-17 03:07:59 +08:00
* - For explicit Euler method : v_ { k + 1 } = v_k - h * g / L * sin ( q_k )
* - For implicit Euler method : v_ { k + 1 } = v_k - h * g / L * sin ( q_ { k + 1 } )
* - For sympletic Euler method : v_ { k + 1 } = v_k - h * g / L * sin ( q_k )
2013-04-16 05:31:47 +08:00
*/
2022-12-23 06:25:48 +08:00
class PendulumFactor2 : public NoiseModelFactorN < double , double , double > {
2013-04-16 05:31:47 +08:00
public :
protected :
2022-12-23 06:25:48 +08:00
typedef NoiseModelFactorN < double , double , double > Base ;
2013-04-16 05:31:47 +08:00
/** default constructor to allow for serialization */
PendulumFactor2 ( ) { }
2013-04-17 03:07:59 +08:00
double h_ ;
2013-04-16 05:31:47 +08:00
double g_ ;
2013-04-17 03:07:59 +08:00
double r_ ;
2013-04-16 05:31:47 +08:00
public :
typedef boost : : shared_ptr < PendulumFactor2 > shared_ptr ;
2013-04-17 03:07:59 +08:00
///Constructor. vk1: v_{k+1}, vk: v_k, qkey: q's key depending on the chosen method, h: time step
PendulumFactor2 ( Key vk1 , Key vk , Key qkey , double h , double r = 1.0 , double g = 9.81 , double mu = 1000.0 )
2019-09-19 03:24:09 +08:00
: Base ( noiseModel : : Constrained : : All ( 1 , std : : abs ( mu ) ) , vk1 , vk , qkey ) , h_ ( h ) , g_ ( g ) , r_ ( r ) { }
2013-04-16 05:31:47 +08:00
/// @return a deep copy of this factor
2020-07-26 15:57:54 +08:00
gtsam : : NonlinearFactor : : shared_ptr clone ( ) const override {
2013-04-16 05:31:47 +08:00
return boost : : static_pointer_cast < gtsam : : NonlinearFactor > (
gtsam : : NonlinearFactor : : shared_ptr ( new PendulumFactor2 ( * this ) ) ) ; }
2013-04-17 03:07:59 +08:00
/** v_k - h*g/L*sin(q) - v_k1 = 0, with optional derivatives */
2014-11-04 22:41:14 +08:00
Vector evaluateError ( const double & vk1 , const double & vk , const double & q ,
2013-04-16 05:31:47 +08:00
boost : : optional < Matrix & > H1 = boost : : none ,
boost : : optional < Matrix & > H2 = boost : : none ,
2020-07-26 15:57:54 +08:00
boost : : optional < Matrix & > H3 = boost : : none ) const override {
2014-11-04 22:41:14 +08:00
const size_t p = 1 ;
2016-04-12 04:04:24 +08:00
if ( H1 ) * H1 = - Matrix : : Identity ( p , p ) ;
if ( H2 ) * H2 = Matrix : : Identity ( p , p ) ;
if ( H3 ) * H3 = - Matrix : : Identity ( p , p ) * h_ * g_ / r_ * cos ( q ) ;
2014-11-23 08:35:27 +08:00
return ( Vector ( 1 ) < < vk - h_ * g_ / r_ * sin ( q ) - vk1 ) . finished ( ) ;
2013-04-16 05:31:47 +08:00
}
} ; // \PendulumFactor2
2013-04-17 03:07:59 +08:00
//*************************************************************************
/**
* This class implements the first position - momentum update rule
2022-07-27 04:00:33 +08:00
* \ f $ p_k = - D_1 L_d ( q_k , q_ { k + 1 } , h ) = \ frac { 1 } { h } mr ^ { 2 } \ left ( q_ { k + 1 } - q_ { k } \ right ) + mgrh ( 1 - \ alpha ) \ , \ sin \ left ( ( 1 - \ alpha ) q_ { k } + \ alpha q_ { k + 1 } \ right ) \ f $
* \ f $ = ( 1 / h ) mr ^ 2 ( q_ { k + 1 } - q_k ) + mgrh ( 1 - alpha ) sin ( ( 1 - alpha ) q_k + \ alpha q_ { k + 1 } ) \ f $
2013-04-17 03:07:59 +08:00
*/
2022-12-23 06:25:48 +08:00
class PendulumFactorPk : public NoiseModelFactorN < double , double , double > {
2013-04-17 03:07:59 +08:00
public :
protected :
2022-12-23 06:25:48 +08:00
typedef NoiseModelFactorN < double , double , double > Base ;
2013-04-17 03:07:59 +08:00
/** default constructor to allow for serialization */
PendulumFactorPk ( ) { }
double h_ ; //! time step
double m_ ; //! mass
double r_ ; //! length
double g_ ; //! gravity
double alpha_ ; //! in [0,1], define the mid-point between [q_k,q_{k+1}] for approximation. The sympletic rule above can be obtained as a special case when alpha = 0.
public :
typedef boost : : shared_ptr < PendulumFactorPk > shared_ptr ;
///Constructor
PendulumFactorPk ( Key pKey , Key qKey , Key qKey1 ,
double h , double m = 1.0 , double r = 1.0 , double g = 9.81 , double alpha = 0.0 , double mu = 1000.0 )
2019-09-19 03:24:09 +08:00
: Base ( noiseModel : : Constrained : : All ( 1 , std : : abs ( mu ) ) , pKey , qKey , qKey1 ) ,
2013-04-17 03:07:59 +08:00
h_ ( h ) , m_ ( m ) , r_ ( r ) , g_ ( g ) , alpha_ ( alpha ) { }
/// @return a deep copy of this factor
2020-07-26 15:57:54 +08:00
gtsam : : NonlinearFactor : : shared_ptr clone ( ) const override {
2013-04-17 03:07:59 +08:00
return boost : : static_pointer_cast < gtsam : : NonlinearFactor > (
gtsam : : NonlinearFactor : : shared_ptr ( new PendulumFactorPk ( * this ) ) ) ; }
/** 1/h mr^2 (qk1-qk)+mgrh (1-a) sin((1-a)pk + a*pk1) - pk = 0, with optional derivatives */
2014-11-04 22:41:14 +08:00
Vector evaluateError ( const double & pk , const double & qk , const double & qk1 ,
2013-04-17 03:07:59 +08:00
boost : : optional < Matrix & > H1 = boost : : none ,
boost : : optional < Matrix & > H2 = boost : : none ,
2020-07-26 15:57:54 +08:00
boost : : optional < Matrix & > H3 = boost : : none ) const override {
2014-11-04 22:41:14 +08:00
const size_t p = 1 ;
2013-04-17 03:07:59 +08:00
double qmid = ( 1 - alpha_ ) * qk + alpha_ * qk1 ;
double mr2_h = 1 / h_ * m_ * r_ * r_ ;
double mgrh = m_ * g_ * r_ * h_ ;
2016-04-12 04:04:24 +08:00
if ( H1 ) * H1 = - Matrix : : Identity ( p , p ) ;
if ( H2 ) * H2 = Matrix : : Identity ( p , p ) * ( - mr2_h + mgrh * ( 1 - alpha_ ) * ( 1 - alpha_ ) * cos ( qmid ) ) ;
if ( H3 ) * H3 = Matrix : : Identity ( p , p ) * ( mr2_h + mgrh * ( 1 - alpha_ ) * ( alpha_ ) * cos ( qmid ) ) ;
2013-04-17 03:07:59 +08:00
2014-11-23 08:35:27 +08:00
return ( Vector ( 1 ) < < mr2_h * ( qk1 - qk ) + mgrh * ( 1 - alpha_ ) * sin ( qmid ) - pk ) . finished ( ) ;
2013-04-17 03:07:59 +08:00
}
} ; // \PendulumFactorPk
//*************************************************************************
/**
* This class implements the second position - momentum update rule
2022-07-27 04:00:33 +08:00
* \ f $ p_k1 = D_2 L_d ( q_k , q_ { k + 1 } , h ) = \ frac { 1 } { h } mr ^ { 2 } \ left ( q_ { k + 1 } - q_ { k } \ right ) - mgrh \ alpha \ sin \ left ( ( 1 - \ alpha ) q_ { k } + \ alpha q_ { k + 1 } \ right ) \ f $
* \ f $ = ( 1 / h ) mr ^ 2 ( q_ { k + 1 } - q_k ) - mgrh alpha sin ( ( 1 - alpha ) q_k + \ alpha q_ { k + 1 } ) \ f $
2013-04-17 03:07:59 +08:00
*/
2022-12-23 06:25:48 +08:00
class PendulumFactorPk1 : public NoiseModelFactorN < double , double , double > {
2013-04-17 03:07:59 +08:00
public :
protected :
2022-12-23 06:25:48 +08:00
typedef NoiseModelFactorN < double , double , double > Base ;
2013-04-17 03:07:59 +08:00
/** default constructor to allow for serialization */
PendulumFactorPk1 ( ) { }
double h_ ; //! time step
double m_ ; //! mass
double r_ ; //! length
double g_ ; //! gravity
double alpha_ ; //! in [0,1], define the mid-point between [q_k,q_{k+1}] for approximation. The sympletic rule above can be obtained as a special case when alpha = 0.
public :
typedef boost : : shared_ptr < PendulumFactorPk1 > shared_ptr ;
///Constructor
PendulumFactorPk1 ( Key pKey1 , Key qKey , Key qKey1 ,
double h , double m = 1.0 , double r = 1.0 , double g = 9.81 , double alpha = 0.0 , double mu = 1000.0 )
2019-09-19 03:24:09 +08:00
: Base ( noiseModel : : Constrained : : All ( 1 , std : : abs ( mu ) ) , pKey1 , qKey , qKey1 ) ,
2013-04-17 03:07:59 +08:00
h_ ( h ) , m_ ( m ) , r_ ( r ) , g_ ( g ) , alpha_ ( alpha ) { }
/// @return a deep copy of this factor
2020-07-26 15:57:54 +08:00
gtsam : : NonlinearFactor : : shared_ptr clone ( ) const override {
2013-04-17 03:07:59 +08:00
return boost : : static_pointer_cast < gtsam : : NonlinearFactor > (
gtsam : : NonlinearFactor : : shared_ptr ( new PendulumFactorPk1 ( * this ) ) ) ; }
/** 1/h mr^2 (qk1-qk) - mgrh a sin((1-a)pk + a*pk1) - pk1 = 0, with optional derivatives */
2014-11-04 22:41:14 +08:00
Vector evaluateError ( const double & pk1 , const double & qk , const double & qk1 ,
2013-04-17 03:07:59 +08:00
boost : : optional < Matrix & > H1 = boost : : none ,
boost : : optional < Matrix & > H2 = boost : : none ,
2020-07-26 15:57:54 +08:00
boost : : optional < Matrix & > H3 = boost : : none ) const override {
2014-11-04 22:41:14 +08:00
const size_t p = 1 ;
2013-04-17 03:07:59 +08:00
double qmid = ( 1 - alpha_ ) * qk + alpha_ * qk1 ;
double mr2_h = 1 / h_ * m_ * r_ * r_ ;
double mgrh = m_ * g_ * r_ * h_ ;
2016-04-12 04:04:24 +08:00
if ( H1 ) * H1 = - Matrix : : Identity ( p , p ) ;
if ( H2 ) * H2 = Matrix : : Identity ( p , p ) * ( - mr2_h - mgrh * ( 1 - alpha_ ) * alpha_ * cos ( qmid ) ) ;
if ( H3 ) * H3 = Matrix : : Identity ( p , p ) * ( mr2_h - mgrh * alpha_ * alpha_ * cos ( qmid ) ) ;
2013-04-17 03:07:59 +08:00
2014-11-23 08:35:27 +08:00
return ( Vector ( 1 ) < < mr2_h * ( qk1 - qk ) - mgrh * alpha_ * sin ( qmid ) - pk1 ) . finished ( ) ;
2013-04-17 03:07:59 +08:00
}
} ; // \PendulumFactorPk1
2013-04-16 05:31:47 +08:00
}