Pendulum.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /**
  2. * @file Pendulum.h
  3. * @brief Three-way factors for the pendulum dynamics as in [Stern06siggraph] for
  4. * (1) explicit Euler method, (2) implicit Euler method, and (3) sympletic Euler method.
  5. * Note that all methods use the same formulas for the factors. They are only different in
  6. * the way we connect variables using those factors in the graph.
  7. * @author Duy-Nguyen Ta
  8. */
  9. #pragma once
  10. #include <gtsam/nonlinear/NonlinearFactor.h>
  11. namespace gtsam {
  12. //*************************************************************************
  13. /**
  14. * This class implements the first constraint.
  15. * - For explicit Euler method: q_{k+1} = q_k + h*v_k
  16. * - For implicit Euler method: q_{k+1} = q_k + h*v_{k+1}
  17. * - For sympletic Euler method: q_{k+1} = q_k + h*v_{k+1}
  18. */
  19. class PendulumFactor1: public NoiseModelFactor3<double, double, double> {
  20. public:
  21. protected:
  22. typedef NoiseModelFactor3<double, double, double> Base;
  23. /** default constructor to allow for serialization */
  24. PendulumFactor1() {}
  25. double h_; // time step
  26. public:
  27. typedef boost::shared_ptr<PendulumFactor1> shared_ptr;
  28. ///Constructor. k1: q_{k+1}, k: q_k, velKey: velocity variable depending on the chosen method, h: time step
  29. PendulumFactor1(Key k1, Key k, Key velKey, double h, double mu = 1000.0)
  30. : Base(noiseModel::Constrained::All(1, std::abs(mu)), k1, k, velKey), h_(h) {}
  31. /// @return a deep copy of this factor
  32. gtsam::NonlinearFactor::shared_ptr clone() const override {
  33. return boost::static_pointer_cast<gtsam::NonlinearFactor>(
  34. gtsam::NonlinearFactor::shared_ptr(new PendulumFactor1(*this))); }
  35. /** q_k + h*v - q_k1 = 0, with optional derivatives */
  36. Vector evaluateError(const double& qk1, const double& qk, const double& v,
  37. boost::optional<Matrix&> H1 = boost::none,
  38. boost::optional<Matrix&> H2 = boost::none,
  39. boost::optional<Matrix&> H3 = boost::none) const override {
  40. const size_t p = 1;
  41. if (H1) *H1 = -Matrix::Identity(p,p);
  42. if (H2) *H2 = Matrix::Identity(p,p);
  43. if (H3) *H3 = Matrix::Identity(p,p)*h_;
  44. return (Vector(1) << qk+v*h_-qk1).finished();
  45. }
  46. }; // \PendulumFactor1
  47. //*************************************************************************
  48. /**
  49. * This class implements the second constraint the
  50. * - For explicit Euler method: v_{k+1} = v_k - h*g/L*sin(q_k)
  51. * - For implicit Euler method: v_{k+1} = v_k - h*g/L*sin(q_{k+1})
  52. * - For sympletic Euler method: v_{k+1} = v_k - h*g/L*sin(q_k)
  53. */
  54. class PendulumFactor2: public NoiseModelFactor3<double, double, double> {
  55. public:
  56. protected:
  57. typedef NoiseModelFactor3<double, double, double> Base;
  58. /** default constructor to allow for serialization */
  59. PendulumFactor2() {}
  60. double h_;
  61. double g_;
  62. double r_;
  63. public:
  64. typedef boost::shared_ptr<PendulumFactor2 > shared_ptr;
  65. ///Constructor. vk1: v_{k+1}, vk: v_k, qkey: q's key depending on the chosen method, h: time step
  66. PendulumFactor2(Key vk1, Key vk, Key qkey, double h, double r = 1.0, double g = 9.81, double mu = 1000.0)
  67. : Base(noiseModel::Constrained::All(1, std::abs(mu)), vk1, vk, qkey), h_(h), g_(g), r_(r) {}
  68. /// @return a deep copy of this factor
  69. gtsam::NonlinearFactor::shared_ptr clone() const override {
  70. return boost::static_pointer_cast<gtsam::NonlinearFactor>(
  71. gtsam::NonlinearFactor::shared_ptr(new PendulumFactor2(*this))); }
  72. /** v_k - h*g/L*sin(q) - v_k1 = 0, with optional derivatives */
  73. Vector evaluateError(const double & vk1, const double & vk, const double & q,
  74. boost::optional<Matrix&> H1 = boost::none,
  75. boost::optional<Matrix&> H2 = boost::none,
  76. boost::optional<Matrix&> H3 = boost::none) const override {
  77. const size_t p = 1;
  78. if (H1) *H1 = -Matrix::Identity(p,p);
  79. if (H2) *H2 = Matrix::Identity(p,p);
  80. if (H3) *H3 = -Matrix::Identity(p,p)*h_*g_/r_*cos(q);
  81. return (Vector(1) << vk - h_ * g_ / r_ * sin(q) - vk1).finished();
  82. }
  83. }; // \PendulumFactor2
  84. //*************************************************************************
  85. /**
  86. * This class implements the first position-momentum update rule
  87. * 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)
  88. * = (1/h)mr^2 (q_{k+1}-q_k) + mgrh(1-alpha) sin ((1-alpha)q_k+\alpha q_{k+1})
  89. */
  90. class PendulumFactorPk: public NoiseModelFactor3<double, double, double> {
  91. public:
  92. protected:
  93. typedef NoiseModelFactor3<double, double, double> Base;
  94. /** default constructor to allow for serialization */
  95. PendulumFactorPk() {}
  96. double h_; //! time step
  97. double m_; //! mass
  98. double r_; //! length
  99. double g_; //! gravity
  100. 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.
  101. public:
  102. typedef boost::shared_ptr<PendulumFactorPk > shared_ptr;
  103. ///Constructor
  104. PendulumFactorPk(Key pKey, Key qKey, Key qKey1,
  105. double h, double m = 1.0, double r = 1.0, double g = 9.81, double alpha = 0.0, double mu = 1000.0)
  106. : Base(noiseModel::Constrained::All(1, std::abs(mu)), pKey, qKey, qKey1),
  107. h_(h), m_(m), r_(r), g_(g), alpha_(alpha) {}
  108. /// @return a deep copy of this factor
  109. gtsam::NonlinearFactor::shared_ptr clone() const override {
  110. return boost::static_pointer_cast<gtsam::NonlinearFactor>(
  111. gtsam::NonlinearFactor::shared_ptr(new PendulumFactorPk(*this))); }
  112. /** 1/h mr^2 (qk1-qk)+mgrh (1-a) sin((1-a)pk + a*pk1) - pk = 0, with optional derivatives */
  113. Vector evaluateError(const double & pk, const double & qk, const double & qk1,
  114. boost::optional<Matrix&> H1 = boost::none,
  115. boost::optional<Matrix&> H2 = boost::none,
  116. boost::optional<Matrix&> H3 = boost::none) const override {
  117. const size_t p = 1;
  118. double qmid = (1-alpha_)*qk + alpha_*qk1;
  119. double mr2_h = 1/h_*m_*r_*r_;
  120. double mgrh = m_*g_*r_*h_;
  121. if (H1) *H1 = -Matrix::Identity(p,p);
  122. if (H2) *H2 = Matrix::Identity(p,p)*(-mr2_h + mgrh*(1-alpha_)*(1-alpha_)*cos(qmid));
  123. if (H3) *H3 = Matrix::Identity(p,p)*( mr2_h + mgrh*(1-alpha_)*(alpha_)*cos(qmid));
  124. return (Vector(1) << mr2_h * (qk1 - qk) + mgrh * (1 - alpha_) * sin(qmid) - pk).finished();
  125. }
  126. }; // \PendulumFactorPk
  127. //*************************************************************************
  128. /**
  129. * This class implements the second position-momentum update rule
  130. * 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)
  131. * = (1/h)mr^2 (q_{k+1}-q_k) - mgrh alpha sin ((1-alpha)q_k+\alpha q_{k+1})
  132. */
  133. class PendulumFactorPk1: public NoiseModelFactor3<double, double, double> {
  134. public:
  135. protected:
  136. typedef NoiseModelFactor3<double, double, double> Base;
  137. /** default constructor to allow for serialization */
  138. PendulumFactorPk1() {}
  139. double h_; //! time step
  140. double m_; //! mass
  141. double r_; //! length
  142. double g_; //! gravity
  143. 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.
  144. public:
  145. typedef boost::shared_ptr<PendulumFactorPk1 > shared_ptr;
  146. ///Constructor
  147. PendulumFactorPk1(Key pKey1, Key qKey, Key qKey1,
  148. double h, double m = 1.0, double r = 1.0, double g = 9.81, double alpha = 0.0, double mu = 1000.0)
  149. : Base(noiseModel::Constrained::All(1, std::abs(mu)), pKey1, qKey, qKey1),
  150. h_(h), m_(m), r_(r), g_(g), alpha_(alpha) {}
  151. /// @return a deep copy of this factor
  152. gtsam::NonlinearFactor::shared_ptr clone() const override {
  153. return boost::static_pointer_cast<gtsam::NonlinearFactor>(
  154. gtsam::NonlinearFactor::shared_ptr(new PendulumFactorPk1(*this))); }
  155. /** 1/h mr^2 (qk1-qk) - mgrh a sin((1-a)pk + a*pk1) - pk1 = 0, with optional derivatives */
  156. Vector evaluateError(const double & pk1, const double & qk, const double & qk1,
  157. boost::optional<Matrix&> H1 = boost::none,
  158. boost::optional<Matrix&> H2 = boost::none,
  159. boost::optional<Matrix&> H3 = boost::none) const override {
  160. const size_t p = 1;
  161. double qmid = (1-alpha_)*qk + alpha_*qk1;
  162. double mr2_h = 1/h_*m_*r_*r_;
  163. double mgrh = m_*g_*r_*h_;
  164. if (H1) *H1 = -Matrix::Identity(p,p);
  165. if (H2) *H2 = Matrix::Identity(p,p)*(-mr2_h - mgrh*(1-alpha_)*alpha_*cos(qmid));
  166. if (H3) *H3 = Matrix::Identity(p,p)*( mr2_h - mgrh*alpha_*alpha_*cos(qmid));
  167. return (Vector(1) << mr2_h * (qk1 - qk) - mgrh * alpha_ * sin(qmid) - pk1).finished();
  168. }
  169. }; // \PendulumFactorPk1
  170. }