Merge remote-tracking branch 'bitbucket/RSS_ImuFactor' into feature/scenarios

release/4.3a0
Frank 2015-12-23 16:18:59 -08:00
commit 8e1041c56a
3 changed files with 105 additions and 58 deletions

View File

@ -16,7 +16,6 @@
*/ */
#include <gtsam/navigation/ScenarioRunner.h> #include <gtsam/navigation/ScenarioRunner.h>
#include <gtsam/linear/Sampler.h>
#include <cmath> #include <cmath>
@ -26,24 +25,21 @@ static double intNoiseVar = 0.0000001;
static const Matrix3 kIntegrationErrorCovariance = intNoiseVar * I_3x3; static const Matrix3 kIntegrationErrorCovariance = intNoiseVar * I_3x3;
ImuFactor::PreintegratedMeasurements ScenarioRunner::integrate( ImuFactor::PreintegratedMeasurements ScenarioRunner::integrate(
double T, Sampler* gyroSampler, Sampler* accSampler) const { double T, const imuBias::ConstantBias& estimatedBias,
// TODO(frank): allow non-zero bool corrupted) const {
const imuBias::ConstantBias zeroBias;
const bool use2ndOrderIntegration = true; const bool use2ndOrderIntegration = true;
ImuFactor::PreintegratedMeasurements pim( ImuFactor::PreintegratedMeasurements pim(
zeroBias, accCovariance(), gyroCovariance(), kIntegrationErrorCovariance, estimatedBias, accCovariance(), gyroCovariance(),
use2ndOrderIntegration); kIntegrationErrorCovariance, use2ndOrderIntegration);
const double dt = imuSampleTime(); const double dt = imuSampleTime();
const double sqrt_dt = std::sqrt(dt);
const size_t nrSteps = T / dt; const size_t nrSteps = T / dt;
double t = 0; double t = 0;
for (size_t k = 0; k < nrSteps; k++, t += dt) { for (size_t k = 0; k < nrSteps; k++, t += dt) {
Vector3 measuredOmega = measured_angular_velocity(t); Vector3 measuredOmega = corrupted ? measured_omega_b(t) : actual_omega_b(t);
if (gyroSampler) measuredOmega += gyroSampler->sample() / sqrt_dt; Vector3 measuredAcc =
Vector3 measuredAcc = measured_acceleration(t); corrupted ? measured_specific_force_b(t) : actual_specific_force_b(t);
if (accSampler) measuredAcc += accSampler->sample() / sqrt_dt;
pim.integrateMeasurement(measuredAcc, measuredOmega, dt); pim.integrateMeasurement(measuredAcc, measuredOmega, dt);
} }
@ -51,28 +47,26 @@ ImuFactor::PreintegratedMeasurements ScenarioRunner::integrate(
} }
PoseVelocityBias ScenarioRunner::predict( PoseVelocityBias ScenarioRunner::predict(
const ImuFactor::PreintegratedMeasurements& pim) const { const ImuFactor::PreintegratedMeasurements& pim,
// TODO(frank): allow non-zero bias, omegaCoriolis const imuBias::ConstantBias& estimatedBias) const {
const imuBias::ConstantBias zeroBias; // TODO(frank): allow non-zero omegaCoriolis
const Vector3 omegaCoriolis = Vector3::Zero(); const Vector3 omegaCoriolis = Vector3::Zero();
const bool use2ndOrderCoriolis = true; const bool use2ndOrderCoriolis = true;
return pim.predict(scenario_->pose(0), scenario_->velocity_n(0), zeroBias, return pim.predict(scenario_->pose(0), scenario_->velocity_n(0),
gravity_n(), omegaCoriolis, use2ndOrderCoriolis); estimatedBias, gravity_n(), omegaCoriolis,
use2ndOrderCoriolis);
} }
Matrix6 ScenarioRunner::estimatePoseCovariance(double T, size_t N) const { Matrix6 ScenarioRunner::estimatePoseCovariance(
double T, size_t N, const imuBias::ConstantBias& estimatedBias) const {
// Get predict prediction from ground truth measurements // Get predict prediction from ground truth measurements
Pose3 prediction = predict(integrate(T)).pose; Pose3 prediction = predict(integrate(T)).pose;
// Create two samplers for acceleration and omega noise
Sampler gyroSampler(gyroNoiseModel(), 10);
Sampler accSampler(accNoiseModel(), 29284);
// Sample ! // Sample !
Matrix samples(9, N); Matrix samples(9, N);
Vector6 sum = Vector6::Zero(); Vector6 sum = Vector6::Zero();
for (size_t i = 0; i < N; i++) { for (size_t i = 0; i < N; i++) {
Pose3 sampled = predict(integrate(T, &gyroSampler, &accSampler)).pose; Pose3 sampled = predict(integrate(T, estimatedBias, true)).pose;
Vector6 xi = sampled.localCoordinates(prediction); Vector6 xi = sampled.localCoordinates(prediction);
samples.col(i) = xi; samples.col(i) = xi;
sum += xi; sum += xi;

View File

@ -18,11 +18,10 @@
#pragma once #pragma once
#include <gtsam/navigation/ImuFactor.h> #include <gtsam/navigation/ImuFactor.h>
#include <gtsam/navigation/Scenario.h> #include <gtsam/navigation/Scenario.h>
#include <gtsam/linear/Sampler.h>
namespace gtsam { namespace gtsam {
class Sampler;
/* /*
* Simple class to test navigation scenarios. * Simple class to test navigation scenarios.
* Takes a trajectory scenario as input, and can generate IMU measurements * Takes a trajectory scenario as input, and can generate IMU measurements
@ -30,27 +29,42 @@ class Sampler;
class ScenarioRunner { class ScenarioRunner {
public: public:
ScenarioRunner(const Scenario* scenario, double imuSampleTime = 1.0 / 100.0, ScenarioRunner(const Scenario* scenario, double imuSampleTime = 1.0 / 100.0,
double gyroSigma = 0.17, double accSigma = 0.01) double gyroSigma = 0.17, double accSigma = 0.01,
const imuBias::ConstantBias& bias = imuBias::ConstantBias())
: scenario_(scenario), : scenario_(scenario),
imuSampleTime_(imuSampleTime), imuSampleTime_(imuSampleTime),
gyroNoiseModel_(noiseModel::Isotropic::Sigma(3, gyroSigma)), gyroNoiseModel_(noiseModel::Isotropic::Sigma(3, gyroSigma)),
accNoiseModel_(noiseModel::Isotropic::Sigma(3, accSigma)) {} accNoiseModel_(noiseModel::Isotropic::Sigma(3, accSigma)),
bias_(bias),
// NOTE(duy): random seeds that work well:
gyroSampler_(gyroNoiseModel_, 10),
accSampler_(accNoiseModel_, 29284)
{}
// NOTE(frank): hardcoded for now with Z up (gravity points in negative Z) // NOTE(frank): hardcoded for now with Z up (gravity points in negative Z)
// also, uses g=10 for easy debugging // also, uses g=10 for easy debugging
static Vector3 gravity_n() { return Vector3(0, 0, -10.0); } static Vector3 gravity_n() { return Vector3(0, 0, -10.0); }
// A gyro simly measures angular velocity in body frame // A gyro simply measures angular velocity in body frame
Vector3 measured_angular_velocity(double t) const { Vector3 actual_omega_b(double t) const { return scenario_->omega_b(t); }
return scenario_->omega_b(t);
}
// An accelerometer measures acceleration in body, but not gravity // An accelerometer measures acceleration in body, but not gravity
Vector3 measured_acceleration(double t) const { Vector3 actual_specific_force_b(double t) const {
Rot3 bRn = scenario_->rotation(t).transpose(); Rot3 bRn = scenario_->rotation(t).transpose();
return scenario_->acceleration_b(t) - bRn * gravity_n(); return scenario_->acceleration_b(t) - bRn * gravity_n();
} }
// versions corrupted by bias and noise
Vector3 measured_omega_b(double t) const {
return actual_omega_b(t) + bias_.gyroscope() +
gyroSampler_.sample() / std::sqrt(imuSampleTime_);
}
Vector3 measured_specific_force_b(double t) const {
return actual_specific_force_b(t) + bias_.accelerometer() +
accSampler_.sample() / std::sqrt(imuSampleTime_);
}
const double& imuSampleTime() const { return imuSampleTime_; } const double& imuSampleTime() const { return imuSampleTime_; }
const noiseModel::Diagonal::shared_ptr& gyroNoiseModel() const { const noiseModel::Diagonal::shared_ptr& gyroNoiseModel() const {
@ -65,13 +79,15 @@ class ScenarioRunner {
Matrix3 accCovariance() const { return accNoiseModel_->covariance(); } Matrix3 accCovariance() const { return accNoiseModel_->covariance(); }
/// Integrate measurements for T seconds into a PIM /// Integrate measurements for T seconds into a PIM
ImuFactor::PreintegratedMeasurements integrate(double T, ImuFactor::PreintegratedMeasurements integrate(
Sampler* gyroSampler = 0, double T,
Sampler* accSampler = 0) const; const imuBias::ConstantBias& estimatedBias = imuBias::ConstantBias(),
bool corrupted = false) const;
/// Predict predict given a PIM /// Predict predict given a PIM
PoseVelocityBias predict( PoseVelocityBias predict(const ImuFactor::PreintegratedMeasurements& pim,
const ImuFactor::PreintegratedMeasurements& pim) const; const imuBias::ConstantBias& estimatedBias =
imuBias::ConstantBias()) const;
/// Return pose covariance by re-arranging pim.preintMeasCov() appropriately /// Return pose covariance by re-arranging pim.preintMeasCov() appropriately
Matrix6 poseCovariance( Matrix6 poseCovariance(
@ -84,12 +100,18 @@ class ScenarioRunner {
} }
/// Compute a Monte Carlo estimate of the PIM pose covariance using N samples /// Compute a Monte Carlo estimate of the PIM pose covariance using N samples
Matrix6 estimatePoseCovariance(double T, size_t N = 1000) const; Matrix6 estimatePoseCovariance(double T, size_t N = 1000,
const imuBias::ConstantBias& estimatedBias =
imuBias::ConstantBias()) const;
private: private:
const Scenario* scenario_; const Scenario* scenario_;
double imuSampleTime_; const double imuSampleTime_;
noiseModel::Diagonal::shared_ptr gyroNoiseModel_, accNoiseModel_; const noiseModel::Diagonal::shared_ptr gyroNoiseModel_, accNoiseModel_;
const imuBias::ConstantBias bias_;
// Create two samplers for acceleration and omega noise
mutable Sampler gyroSampler_, accSampler_;
}; };
} // namespace gtsam } // namespace gtsam

View File

@ -25,14 +25,20 @@ using namespace gtsam;
static const double kDegree = M_PI / 180.0; static const double kDegree = M_PI / 180.0;
static const double kDeltaT = 1e-2; static const double kDeltaT = 1e-2;
static const double kGyroSigma = 0.02; static const double kGyroSigma = 0.02;
static const double kAccelerometerSigma = 0.1; static const double kAccelSigma = 0.1;
static const Vector3 kAccBias(0.2, 0, 0), kRotBias(0.1, 0, 0.3);
static const imuBias::ConstantBias kNonZeroBias(kAccBias, kRotBias);
/* ************************************************************************* */
namespace forward {
const double v = 2; // m/s
ExpmapScenario scenario(Vector3::Zero(), Vector3(v, 0, 0));
}
/* ************************************************************************* */ /* ************************************************************************* */
TEST(ScenarioRunner, Forward) { TEST(ScenarioRunner, Forward) {
const double v = 2; // m/s using namespace forward;
ExpmapScenario scenario(Vector3::Zero(), Vector3(v, 0, 0)); ScenarioRunner runner(&scenario, kDeltaT, kGyroSigma, kAccelSigma);
ScenarioRunner runner(&scenario, kDeltaT, kGyroSigma, kAccelerometerSigma);
const double T = 0.1; // seconds const double T = 0.1; // seconds
ImuFactor::PreintegratedMeasurements pim = runner.integrate(T); ImuFactor::PreintegratedMeasurements pim = runner.integrate(T);
@ -42,13 +48,24 @@ TEST(ScenarioRunner, Forward) {
EXPECT(assert_equal(estimatedCov, runner.poseCovariance(pim), 1e-5)); EXPECT(assert_equal(estimatedCov, runner.poseCovariance(pim), 1e-5));
} }
/* ************************************************************************* */
TEST(ScenarioRunner, ForwardWithBias) {
using namespace forward;
ScenarioRunner runner(&scenario, kDeltaT, kGyroSigma, kAccelSigma);
const double T = 0.1; // seconds
ImuFactor::PreintegratedMeasurements pim = runner.integrate(T, kNonZeroBias);
Matrix6 estimatedCov = runner.estimatePoseCovariance(T, 1000, kNonZeroBias);
EXPECT(assert_equal(estimatedCov, runner.poseCovariance(pim), 0.1));
}
/* ************************************************************************* */ /* ************************************************************************* */
TEST(ScenarioRunner, Circle) { TEST(ScenarioRunner, Circle) {
// Forward velocity 2m/s, angular velocity 6 kDegree/sec // Forward velocity 2m/s, angular velocity 6 kDegree/sec
const double v = 2, w = 6 * kDegree; const double v = 2, w = 6 * kDegree;
ExpmapScenario scenario(Vector3(0, 0, w), Vector3(v, 0, 0)); ExpmapScenario scenario(Vector3(0, 0, w), Vector3(v, 0, 0));
ScenarioRunner runner(&scenario, kDeltaT, kGyroSigma, kAccelerometerSigma); ScenarioRunner runner(&scenario, kDeltaT, kGyroSigma, kAccelSigma);
const double T = 0.1; // seconds const double T = 0.1; // seconds
ImuFactor::PreintegratedMeasurements pim = runner.integrate(T); ImuFactor::PreintegratedMeasurements pim = runner.integrate(T);
@ -65,7 +82,7 @@ TEST(ScenarioRunner, Loop) {
const double v = 2, w = 6 * kDegree; const double v = 2, w = 6 * kDegree;
ExpmapScenario scenario(Vector3(0, -w, 0), Vector3(v, 0, 0)); ExpmapScenario scenario(Vector3(0, -w, 0), Vector3(v, 0, 0));
ScenarioRunner runner(&scenario, kDeltaT, kGyroSigma, kAccelerometerSigma); ScenarioRunner runner(&scenario, kDeltaT, kGyroSigma, kAccelSigma);
const double T = 0.1; // seconds const double T = 0.1; // seconds
ImuFactor::PreintegratedMeasurements pim = runner.integrate(T); ImuFactor::PreintegratedMeasurements pim = runner.integrate(T);
@ -85,22 +102,36 @@ const Vector3 V0(50, 0, 0);
} }
/* ************************************************************************* */ /* ************************************************************************* */
TEST(ScenarioRunner, Accelerating) { namespace accelerating {
using namespace initial; using namespace initial;
const double a = 0.2; // m/s^2 const double a = 0.2; // m/s^2
const Vector3 A(0, a, 0); const Vector3 A(0, a, 0);
const AcceleratingScenario scenario(nRb, P0, V0, A); const AcceleratingScenario scenario(nRb, P0, V0, A);
const double T = 3; // seconds const double T = 3; // seconds
ScenarioRunner runner(&scenario, T / 10, kGyroSigma, kAccelerometerSigma); }
/* ************************************************************************* */
TEST(ScenarioRunner, Accelerating) {
using namespace accelerating;
ScenarioRunner runner(&scenario, T / 10, kGyroSigma, kAccelSigma);
ImuFactor::PreintegratedMeasurements pim = runner.integrate(T); ImuFactor::PreintegratedMeasurements pim = runner.integrate(T);
EXPECT(assert_equal(scenario.pose(T), runner.predict(pim).pose, 1e-9)); EXPECT(assert_equal(scenario.pose(T), runner.predict(pim).pose, 1e-9));
Matrix6 estimatedCov = runner.estimatePoseCovariance(T,10000); Matrix6 estimatedCov = runner.estimatePoseCovariance(T);
EXPECT(assert_equal(estimatedCov, runner.poseCovariance(pim), 0.1));
}
/* ************************************************************************* */
TEST(ScenarioRunner, AcceleratingWithBias) {
using namespace accelerating;
ScenarioRunner runner(&scenario, T / 10, kGyroSigma, kAccelSigma,
kNonZeroBias);
ImuFactor::PreintegratedMeasurements pim = runner.integrate(T, kNonZeroBias);
Matrix6 estimatedCov = runner.estimatePoseCovariance(T, 1000, kNonZeroBias);
EXPECT(assert_equal(estimatedCov, runner.poseCovariance(pim), 0.1)); EXPECT(assert_equal(estimatedCov, runner.poseCovariance(pim), 0.1));
cout << estimatedCov << endl << endl;
cout << runner.poseCovariance(pim) << endl;
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -111,12 +142,12 @@ TEST(ScenarioRunner, AcceleratingAndRotating) {
const AcceleratingScenario scenario(nRb, P0, V0, A, W); const AcceleratingScenario scenario(nRb, P0, V0, A, W);
const double T = 3; // seconds const double T = 3; // seconds
ScenarioRunner runner(&scenario, T / 10, kGyroSigma, kAccelerometerSigma); ScenarioRunner runner(&scenario, T / 10, kGyroSigma, kAccelSigma);
ImuFactor::PreintegratedMeasurements pim = runner.integrate(T); ImuFactor::PreintegratedMeasurements pim = runner.integrate(T);
EXPECT(assert_equal(scenario.pose(T), runner.predict(pim).pose, 1e-9)); EXPECT(assert_equal(scenario.pose(T), runner.predict(pim).pose, 1e-9));
Matrix6 estimatedCov = runner.estimatePoseCovariance(T,10000); Matrix6 estimatedCov = runner.estimatePoseCovariance(T);
EXPECT(assert_equal(estimatedCov, runner.poseCovariance(pim), 0.1)); EXPECT(assert_equal(estimatedCov, runner.poseCovariance(pim), 0.1));
} }