AcceleratingScenario + some refactoring (v and a specified in nav frame)
							parent
							
								
									dfe3f3a348
								
							
						
					
					
						commit
						00b83ced7a
					
				|  | @ -54,25 +54,25 @@ class Scenario { | |||
|   Matrix3 gyroCovariance() const { return gyroNoiseModel_->covariance(); } | ||||
|   Matrix3 accCovariance() const { return accNoiseModel_->covariance(); } | ||||
| 
 | ||||
|   /// Pose of body in nav frame at time t
 | ||||
|   virtual Pose3 pose(double t) const = 0; | ||||
|   // Quantities a Scenario needs to specify:
 | ||||
| 
 | ||||
|   virtual Pose3 pose(double t) const = 0; | ||||
|   virtual Vector3 omega_b(double t) const = 0; | ||||
|   virtual Vector3 velocity_n(double t) const = 0; | ||||
|   virtual Vector3 acceleration_n(double t) const = 0; | ||||
| 
 | ||||
|   // Derived quantities:
 | ||||
| 
 | ||||
|   /// Rotation of body in nav frame at time t
 | ||||
|   virtual Rot3 rotation(double t) const { return pose(t).rotation(); } | ||||
| 
 | ||||
|   virtual Vector3 angularVelocityInBody(double t) const = 0; | ||||
|   virtual Vector3 linearVelocityInBody(double t) const = 0; | ||||
|   virtual Vector3 accelerationInBody(double t) const = 0; | ||||
| 
 | ||||
|   /// Velocity in nav frame at time t
 | ||||
|   Vector3 velocity(double t) const { | ||||
|     return rotation(t) * linearVelocityInBody(t); | ||||
|   Vector3 velocity_b(double t) const { | ||||
|     const Rot3 nRb = rotation(t); | ||||
|     return nRb.transpose() * velocity_n(t); | ||||
|   } | ||||
| 
 | ||||
|   // acceleration in nav frame
 | ||||
|   // TODO(frank): correct for rotating frames?
 | ||||
|   Vector3 acceleration(double t) const { | ||||
|     return rotation(t) * accelerationInBody(t); | ||||
|   Vector3 acceleration_b(double t) const { | ||||
|     const Rot3 nRb = rotation(t); | ||||
|     return nRb.transpose() * acceleration_n(t); | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|  | @ -80,9 +80,7 @@ class Scenario { | |||
|   noiseModel::Diagonal::shared_ptr gyroNoiseModel_, accNoiseModel_; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Simple IMU simulator with constant twist 3D trajectory. | ||||
|  */ | ||||
| /// Scenario with constant twist 3D trajectory.
 | ||||
| class ExpmapScenario : public Scenario { | ||||
|  public: | ||||
|   /// Construct scenario with constant twist [w,v]
 | ||||
|  | @ -91,21 +89,40 @@ class ExpmapScenario : public Scenario { | |||
|                  double accSigma = 0.01) | ||||
|       : Scenario(imuSampleTime, gyroSigma, accSigma), | ||||
|         twist_((Vector6() << w, v).finished()), | ||||
|         centripetalAcceleration_(twist_.head<3>().cross(twist_.tail<3>())) {} | ||||
|         a_b_(twist_.head<3>().cross(twist_.tail<3>())) {} | ||||
| 
 | ||||
|   Pose3 pose(double t) const { return Pose3::Expmap(twist_ * t); } | ||||
| 
 | ||||
|   Vector3 angularVelocityInBody(double t) const { return twist_.head<3>(); } | ||||
|   Vector3 linearVelocityInBody(double t) const { return twist_.tail<3>(); } | ||||
| 
 | ||||
|   Vector3 accelerationInBody(double t) const { | ||||
|     const Rot3 nRb = rotation(t); | ||||
|     return centripetalAcceleration_ - nRb.transpose() * gravity(); | ||||
|   } | ||||
|   Vector3 omega_b(double t) const { return twist_.head<3>(); } | ||||
|   Vector3 velocity_n(double t) const { return rotation(t) * twist_.tail<3>(); } | ||||
|   Vector3 acceleration_n(double t) const { return rotation(t) * a_b_; } | ||||
| 
 | ||||
|  private: | ||||
|   const Vector6 twist_; | ||||
|   const Vector3 centripetalAcceleration_; | ||||
|   const Vector3 a_b_;  // constant centripetal acceleration in body = w_b * v_b
 | ||||
| }; | ||||
| 
 | ||||
| /// Accelerating from an arbitrary initial state
 | ||||
| class AcceleratingScenario : public Scenario { | ||||
|  public: | ||||
|   /// Construct scenario with constant twist [w,v]
 | ||||
|   AcceleratingScenario(const Rot3& nRb, const Point3& p0, const Vector3& v0, | ||||
|                        const Vector3& accelerationInBody, | ||||
|                        double imuSampleTime = 1.0 / 100.0, | ||||
|                        double gyroSigma = 0.17, double accSigma = 0.01) | ||||
|       : Scenario(imuSampleTime, gyroSigma, accSigma), | ||||
|         nRb_(nRb), | ||||
|         p0_(p0.vector()), | ||||
|         v0_(v0), | ||||
|         a_n_(nRb_ * accelerationInBody) {} | ||||
| 
 | ||||
|   Pose3 pose(double t) const { return Pose3(nRb_, p0_ + a_n_ * t * t / 2.0); } | ||||
|   Vector3 omega_b(double t) const { return Vector3::Zero(); } | ||||
|   Vector3 velocity_n(double t) const { return v0_ + a_n_ * t; } | ||||
|   Vector3 acceleration_n(double t) const { return a_n_; } | ||||
| 
 | ||||
|  private: | ||||
|   const Rot3 nRb_; | ||||
|   const Vector3 p0_, v0_, a_n_; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace gtsam
 | ||||
|  |  | |||
|  | @ -48,9 +48,9 @@ class ScenarioRunner { | |||
|     const size_t nrSteps = T / dt; | ||||
|     double t = 0; | ||||
|     for (size_t k = 0; k < nrSteps; k++, t += dt) { | ||||
|       Vector3 measuredOmega = scenario_->angularVelocityInBody(t); | ||||
|       Vector3 measuredOmega = scenario_->omega_b(t); | ||||
|       if (gyroSampler) measuredOmega += gyroSampler->sample() / sqrt_dt; | ||||
|       Vector3 measuredAcc = scenario_->accelerationInBody(t); | ||||
|       Vector3 measuredAcc = scenario_->acceleration_b(t); | ||||
|       if (accSampler) measuredAcc += accSampler->sample() / sqrt_dt; | ||||
|       pim.integrateMeasurement(measuredAcc, measuredOmega, dt); | ||||
|     } | ||||
|  | @ -64,7 +64,7 @@ class ScenarioRunner { | |||
|     // TODO(frank): allow non-zero bias, omegaCoriolis
 | ||||
|     const imuBias::ConstantBias zeroBias; | ||||
|     const Pose3 pose_i = Pose3::identity(); | ||||
|     const Vector3 vel_i = scenario_->velocity(0); | ||||
|     const Vector3 vel_i = scenario_->velocity_n(0); | ||||
|     const Vector3 omegaCoriolis = Vector3::Zero(); | ||||
|     const bool use2ndOrderCoriolis = true; | ||||
|     return pim.predict(pose_i, vel_i, zeroBias, scenario_->gravity(), | ||||
|  |  | |||
|  | @ -27,9 +27,15 @@ static const double degree = M_PI / 180.0; | |||
| /* ************************************************************************* */ | ||||
| TEST(Scenario, Forward) { | ||||
|   const double v = 2;  // m/s
 | ||||
|   ExpmapScenario forward(Vector3::Zero(), Vector3(v, 0, 0)); | ||||
|   const Vector3 W(0, 0, 0), V(v, 0, 0); | ||||
|   const ExpmapScenario scenario(W, V); | ||||
| 
 | ||||
|   const Pose3 T15 = forward.pose(15); | ||||
|   const double T = 15; | ||||
|   EXPECT(assert_equal(W, scenario.omega_b(T), 1e-9)); | ||||
|   EXPECT(assert_equal(V, scenario.velocity_b(T), 1e-9)); | ||||
|   EXPECT(assert_equal(W.cross(V), scenario.acceleration_b(T), 1e-9)); | ||||
| 
 | ||||
|   const Pose3 T15 = scenario.pose(T); | ||||
|   EXPECT(assert_equal(Vector3(0, 0, 0), T15.rotation().xyz(), 1e-9)); | ||||
|   EXPECT(assert_equal(Point3(30, 0, 0), T15.translation(), 1e-9)); | ||||
| } | ||||
|  | @ -38,11 +44,17 @@ TEST(Scenario, Forward) { | |||
| TEST(Scenario, Circle) { | ||||
|   // Forward velocity 2m/s, angular velocity 6 degree/sec around Z
 | ||||
|   const double v = 2, w = 6 * degree; | ||||
|   ExpmapScenario circle(Vector3(0, 0, w), Vector3(v, 0, 0)); | ||||
|   const Vector3 W(0, 0, w), V(v, 0, 0); | ||||
|   const ExpmapScenario scenario(W, V); | ||||
| 
 | ||||
|   const double T = 15; | ||||
|   EXPECT(assert_equal(W, scenario.omega_b(T), 1e-9)); | ||||
|   EXPECT(assert_equal(V, scenario.velocity_b(T), 1e-9)); | ||||
|   EXPECT(assert_equal(W.cross(V), scenario.acceleration_b(T), 1e-9)); | ||||
| 
 | ||||
|   // R = v/w, so test if circle is of right size
 | ||||
|   const double R = v / w; | ||||
|   const Pose3 T15 = circle.pose(15); | ||||
|   const Pose3 T15 = scenario.pose(T); | ||||
|   EXPECT(assert_equal(Vector3(0, 0, 90 * degree), T15.rotation().xyz(), 1e-9)); | ||||
|   EXPECT(assert_equal(Point3(R, R, 0), T15.translation(), 1e-9)); | ||||
| } | ||||
|  | @ -52,15 +64,44 @@ TEST(Scenario, Loop) { | |||
|   // Forward velocity 2m/s
 | ||||
|   // Pitch up with angular velocity 6 degree/sec (negative in FLU)
 | ||||
|   const double v = 2, w = 6 * degree; | ||||
|   ExpmapScenario loop(Vector3(0, -w, 0), Vector3(v, 0, 0)); | ||||
|   const Vector3 W(0, -w, 0), V(v, 0, 0); | ||||
|   const ExpmapScenario scenario(W, V); | ||||
| 
 | ||||
|   const double T = 30; | ||||
|   EXPECT(assert_equal(W, scenario.omega_b(T), 1e-9)); | ||||
|   EXPECT(assert_equal(V, scenario.velocity_b(T), 1e-9)); | ||||
|   EXPECT(assert_equal(W.cross(V), scenario.acceleration_b(T), 1e-9)); | ||||
| 
 | ||||
|   // R = v/w, so test if loop crests at 2*R
 | ||||
|   const double R = v / w; | ||||
|   const Pose3 T30 = loop.pose(30); | ||||
|   const Pose3 T30 = scenario.pose(30); | ||||
|   EXPECT(assert_equal(Vector3(-M_PI, 0, -M_PI), T30.rotation().xyz(), 1e-9)); | ||||
|   EXPECT(assert_equal(Point3(0, 0, 2 * R), T30.translation(), 1e-9)); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| TEST(Scenario, Accelerating) { | ||||
|   // Set up body pointing towards y axis, and start at 10,20,0 with velocity
 | ||||
|   // going in X. The body itself has Z axis pointing down
 | ||||
|   const Rot3 nRb(Point3(0, 1, 0), Point3(1, 0, 0), Point3(0, 0, -1)); | ||||
|   const Point3 P0(10, 20, 0); | ||||
|   const Vector3 V0(50, 0, 0); | ||||
| 
 | ||||
|   const double a_b = 0.2;  // m/s^2
 | ||||
|   const AcceleratingScenario scenario(nRb, P0, V0, Vector3(a_b, 0, 0)); | ||||
| 
 | ||||
|   const double T = 3; | ||||
|   const Vector3 A = nRb * Vector3(a_b, 0, 0); | ||||
|   EXPECT(assert_equal(Vector3(0, 0, 0), scenario.omega_b(T), 1e-9)); | ||||
|   EXPECT(assert_equal(Vector3(V0 + T * A), scenario.velocity_n(T), 1e-9)); | ||||
|   EXPECT(assert_equal(A, scenario.acceleration_n(T), 1e-9)); | ||||
| 
 | ||||
|   const Pose3 T3 = scenario.pose(3); | ||||
|   EXPECT(assert_equal(nRb, T3.rotation(), 1e-9)); | ||||
|   EXPECT(assert_equal(Point3(P0.vector() + T * T * A / 2.0), T3.translation(), | ||||
|                       1e-9)); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| int main() { | ||||
|   TestResult tr; | ||||
|  |  | |||
|  | @ -78,6 +78,30 @@ TEST(ScenarioRunner, Loop) { | |||
|   EXPECT(assert_equal(estimatedCov, runner.poseCovariance(pim), 1e-5)); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| TEST(ScenarioRunner, Accelerating) { | ||||
|   // Set up body pointing towards y axis, and start at 10,20,0 with velocity
 | ||||
|   // going in X
 | ||||
|   // The body itself has Z axis pointing down
 | ||||
|   const Rot3 nRb(Point3(0, 1, 0), Point3(1, 0, 0), Point3(0, 0, -1)); | ||||
|   const Point3 initial_position(10, 20, 0); | ||||
|   const Vector3 initial_velocity(50, 0, 0); | ||||
| 
 | ||||
|   const double a = 0.2, dt = 3.0; | ||||
|   AcceleratingScenario scenario(nRb, initial_velocity, initial_velocity, | ||||
|                                 Vector3(a, 0, 0), dt / 10, kGyroSigma, | ||||
|                                 kAccelerometerSigma); | ||||
| 
 | ||||
|   ScenarioRunner runner(&scenario); | ||||
|   const double T = 3;  // seconds
 | ||||
| 
 | ||||
|   ImuFactor::PreintegratedMeasurements pim = runner.integrate(T); | ||||
|   EXPECT(assert_equal(scenario.pose(T), runner.predict(pim).pose, 1e-9)); | ||||
| 
 | ||||
|   Matrix6 estimatedCov = runner.estimatePoseCovariance(T); | ||||
|   EXPECT(assert_equal(estimatedCov, runner.poseCovariance(pim), 1e-5)); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| int main() { | ||||
|   TestResult tr; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue