| 
									
										
										
										
											2013-04-22 16:34:40 +08:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @file testPendulumExplicitEuler.cpp | 
					
						
							|  |  |  |  * @author Duy-Nguyen Ta | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <CppUnitLite/TestHarness.h>
 | 
					
						
							|  |  |  | #include <gtsam/base/numericalDerivative.h>
 | 
					
						
							| 
									
										
										
										
											2013-08-19 23:32:16 +08:00
										 |  |  | #include <gtsam/inference/Symbol.h>
 | 
					
						
							| 
									
										
										
										
											2013-04-22 16:34:40 +08:00
										 |  |  | #include <gtsam_unstable/dynamics/SimpleHelicopter.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | using namespace gtsam; | 
					
						
							|  |  |  | using namespace gtsam::symbol_shorthand; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const double tol=1e-5; | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  | const double h = 0.01; | 
					
						
							| 
									
										
										
										
											2013-04-22 16:34:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-04 00:23:49 +08:00
										 |  |  | //const double deg2rad = M_PI/180.0;
 | 
					
						
							| 
									
										
										
										
											2016-01-27 15:09:58 +08:00
										 |  |  | //Pose3 g1(Rot3::Ypr(deg2rad*10.0, deg2rad*20.0, deg2rad*30.0), Point3(100.0, 200.0, 300.0));
 | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  | Pose3 g1(Rot3(), Point3(100.0, 0.0, 300.0)); | 
					
						
							| 
									
										
										
										
											2014-11-23 08:35:27 +08:00
										 |  |  | //Vector6 v1((Vector(6) << 0.1, 0.05, 0.02, 10.0, 20.0, 30.0).finished());
 | 
					
						
							|  |  |  | Vector6 V1_w((Vector(6) << 0.0, 0.0, M_PI/3, 0.0, 0.0, 30.0).finished()); | 
					
						
							| 
									
										
										
										
											2014-10-22 07:32:59 +08:00
										 |  |  | Vector6 V1_g1 = g1.inverse().Adjoint(V1_w); | 
					
						
							| 
									
										
										
										
											2014-12-26 03:04:28 +08:00
										 |  |  | Pose3 g2(g1.expmap(h*V1_g1)); | 
					
						
							| 
									
										
										
										
											2014-10-22 07:32:59 +08:00
										 |  |  | //Vector6 v2 = Pose3::Logmap(g1.between(g2));
 | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | double mass = 100.0; | 
					
						
							| 
									
										
										
										
											2014-11-24 02:22:25 +08:00
										 |  |  | Vector gamma2 = Vector2(0.0, 0.0);  // no shape
 | 
					
						
							|  |  |  | Vector u2 = Vector2(0.0, 0.0); // no control at time 2
 | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  | double distT = 1.0; // distance from the body-centered x axis to the big top motor
 | 
					
						
							|  |  |  | double distR = 5.0; // distance from the body-centered z axis to the small motor
 | 
					
						
							| 
									
										
										
										
											2016-04-12 03:11:29 +08:00
										 |  |  | Matrix Mass = ((Vector(3) << mass, mass, mass).finished()).asDiagonal(); | 
					
						
							|  |  |  | Matrix Inertia = (Vector(6) << 2.0/5.0*mass*distR*distR, 2.0/5.0*mass*distR*distR, 2.0/5.0*mass*distR*distR, mass, mass, mass).finished().asDiagonal(); | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Vector computeFu(const Vector& gamma, const Vector& control) { | 
					
						
							|  |  |  |   double gamma_r = gamma(0), gamma_p = gamma(1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-17 05:33:12 +08:00
										 |  |  |   Matrix F = (Matrix(6, 2) << distT*sin(gamma_r), 0.0, | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  |                            distT*sin(gamma_p*cos(gamma_r)), 0.0, | 
					
						
							|  |  |  |                            0.0, distR, | 
					
						
							|  |  |  |                            sin(gamma_p)*cos(gamma_r), 0.0, | 
					
						
							|  |  |  |                           -sin(gamma_r), -1.0, | 
					
						
							|  |  |  |                            cos(gamma_p)*sin(gamma_r), 0.0 | 
					
						
							| 
									
										
										
										
											2014-11-23 08:35:27 +08:00
										 |  |  |                             ).finished(); | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  |   return F*control; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-22 16:34:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | TEST( Reconstruction, evaluateError) { | 
					
						
							|  |  |  |   // hard constraints don't need a noise model
 | 
					
						
							|  |  |  |   Reconstruction constraint(G(2), G(1), V(1), h); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // verify error function
 | 
					
						
							|  |  |  |   Matrix H1, H2, H3; | 
					
						
							| 
									
										
										
										
											2014-12-26 07:16:10 +08:00
										 |  |  |   EXPECT( | 
					
						
							| 
									
										
										
										
											2016-04-16 04:54:46 +08:00
										 |  |  |       assert_equal(Z_6x1, constraint.evaluateError(g2, g1, V1_g1, H1, H2, H3), tol)); | 
					
						
							| 
									
										
										
										
											2013-04-22 16:34:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Matrix numericalH1 = numericalDerivative31( | 
					
						
							| 
									
										
										
										
											2014-10-22 07:32:59 +08:00
										 |  |  |       boost::function<Vector(const Pose3&, const Pose3&, const Vector6&)>( | 
					
						
							| 
									
										
										
										
											2014-12-26 07:16:10 +08:00
										 |  |  |           boost::bind(&Reconstruction::evaluateError, constraint, _1, _2, _3, | 
					
						
							|  |  |  |               boost::none, boost::none, boost::none)), g2, g1, V1_g1, 1e-5); | 
					
						
							| 
									
										
										
										
											2013-04-22 16:34:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Matrix numericalH2 = numericalDerivative32( | 
					
						
							| 
									
										
										
										
											2014-10-22 07:32:59 +08:00
										 |  |  |       boost::function<Vector(const Pose3&, const Pose3&, const Vector6&)>( | 
					
						
							| 
									
										
										
										
											2014-12-26 07:16:10 +08:00
										 |  |  |           boost::bind(&Reconstruction::evaluateError, constraint, _1, _2, _3, | 
					
						
							|  |  |  |               boost::none, boost::none, boost::none)), g2, g1, V1_g1, 1e-5); | 
					
						
							| 
									
										
										
										
											2013-04-22 16:34:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Matrix numericalH3 = numericalDerivative33( | 
					
						
							| 
									
										
										
										
											2014-10-22 07:32:59 +08:00
										 |  |  |       boost::function<Vector(const Pose3&, const Pose3&, const Vector6&)>( | 
					
						
							| 
									
										
										
										
											2014-12-26 07:16:10 +08:00
										 |  |  |           boost::bind(&Reconstruction::evaluateError, constraint, _1, _2, _3, | 
					
						
							|  |  |  |               boost::none, boost::none, boost::none)), g2, g1, V1_g1, 1e-5); | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   EXPECT(assert_equal(numericalH1,H1,1e-5)); | 
					
						
							|  |  |  |   EXPECT(assert_equal(numericalH2,H2,1e-5)); | 
					
						
							| 
									
										
										
										
											2013-12-21 09:37:45 +08:00
										 |  |  | #ifdef GTSAM_USE_QUATERNIONS // TODO: why is the quaternion version much less accurate??
 | 
					
						
							|  |  |  |   EXPECT(assert_equal(numericalH3,H3,1e-3)); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |   EXPECT(assert_equal(numericalH3,H3,1e-3)); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | // Implement Newton-Euler equation for rigid body dynamics
 | 
					
						
							|  |  |  | Vector newtonEuler(const Vector& Vb, const Vector& Fb, const Matrix& Inertia) { | 
					
						
							| 
									
										
										
										
											2014-11-23 08:35:27 +08:00
										 |  |  |   Matrix W = Pose3::adjointMap((Vector(6) << Vb(0), Vb(1), Vb(2), 0., 0., 0.).finished()); | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  |   Vector dV = Inertia.inverse()*(Fb - W*Inertia*Vb); | 
					
						
							|  |  |  |   return dV; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST( DiscreteEulerPoincareHelicopter, evaluateError) { | 
					
						
							|  |  |  |   Vector Fu = computeFu(gamma2, u2); | 
					
						
							| 
									
										
										
										
											2016-04-16 04:54:46 +08:00
										 |  |  |   Vector fGravity_g1 = Z_6x1; | 
					
						
							| 
									
										
										
										
											2016-03-13 09:49:00 +08:00
										 |  |  |   fGravity_g1.segment<3>(3) = g1.rotation().unrotate(Vector3(0, 0, -mass*9.81));  // gravity force in g1 frame
 | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  |   Vector Fb = Fu+fGravity_g1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Vector dV = newtonEuler(V1_g1, Fb, Inertia); | 
					
						
							|  |  |  |   Vector V2_g1 = dV*h + V1_g1; | 
					
						
							|  |  |  |   Pose3 g21 = g2.between(g1); | 
					
						
							|  |  |  |   Vector V2_g2 = g21.Adjoint(V2_g1);  // convert the new velocity to g2's frame
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-22 07:32:59 +08:00
										 |  |  |   Vector6 expectedv2(V2_g2); | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // hard constraints don't need a noise model
 | 
					
						
							|  |  |  |   DiscreteEulerPoincareHelicopter constraint(V(2), V(1), G(2), h, | 
					
						
							|  |  |  |       Inertia, Fu, mass); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // verify error function
 | 
					
						
							|  |  |  |   Matrix H1, H2, H3; | 
					
						
							| 
									
										
										
										
											2016-04-16 04:54:46 +08:00
										 |  |  |   EXPECT(assert_equal(Z_6x1, constraint.evaluateError(expectedv2, V1_g1, g2, H1, H2, H3), 1e0)); | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Matrix numericalH1 = numericalDerivative31( | 
					
						
							| 
									
										
										
										
											2014-10-22 07:32:59 +08:00
										 |  |  |       boost::function<Vector(const Vector6&, const Vector6&, const Pose3&)>( | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  |           boost::bind(&DiscreteEulerPoincareHelicopter::evaluateError, constraint, _1, _2, _3, boost::none, boost::none, boost::none) | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           expectedv2, V1_g1, g2, 1e-5 | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Matrix numericalH2 = numericalDerivative32( | 
					
						
							| 
									
										
										
										
											2014-10-22 07:32:59 +08:00
										 |  |  |       boost::function<Vector(const Vector6&, const Vector6&, const Pose3&)>( | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  |           boost::bind(&DiscreteEulerPoincareHelicopter::evaluateError, constraint, _1, _2, _3, boost::none, boost::none, boost::none) | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           expectedv2, V1_g1, g2, 1e-5 | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Matrix numericalH3 = numericalDerivative33( | 
					
						
							| 
									
										
										
										
											2014-10-22 07:32:59 +08:00
										 |  |  |       boost::function<Vector(const Vector6&, const Vector6&, const Pose3&)>( | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  |           boost::bind(&DiscreteEulerPoincareHelicopter::evaluateError, constraint, _1, _2, _3, boost::none, boost::none, boost::none) | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           expectedv2, V1_g1, g2, 1e-5 | 
					
						
							| 
									
										
										
										
											2013-04-22 16:34:40 +08:00
										 |  |  |       ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   EXPECT(assert_equal(numericalH1,H1,1e-5)); | 
					
						
							|  |  |  |   EXPECT(assert_equal(numericalH2,H2,1e-5)); | 
					
						
							| 
									
										
										
										
											2013-04-30 01:21:13 +08:00
										 |  |  |   EXPECT(assert_equal(numericalH3,H3,5e-5)); | 
					
						
							| 
									
										
										
										
											2013-04-22 16:34:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | int main() { TestResult tr; return TestRegistry::runAllTests(tr); } | 
					
						
							|  |  |  | /* ************************************************************************* */ |