Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constant Velocity Constraint between NavStates #701

Merged
merged 13 commits into from
Mar 11, 2021
53 changes: 53 additions & 0 deletions gtsam/navigation/ConstantVelocityFactor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include <gtsam/base/numericalDerivative.h>
#include <gtsam/geometry/Pose3.h>
#include <gtsam/inference/Symbol.h>
#include <gtsam/navigation/NavState.h>
#include <gtsam/nonlinear/NonlinearFactor.h>

namespace gtsam {

class ConstantVelocityFactor : public NoiseModelFactor2<NavState, NavState> {
asa marked this conversation as resolved.
Show resolved Hide resolved
double dt_;

public:
using Base = NoiseModelFactor2<NavState, NavState>;

public:
ConstantVelocityFactor(Key i, Key j, double dt, const SharedNoiseModel &model)
asa marked this conversation as resolved.
Show resolved Hide resolved
: NoiseModelFactor2<NavState, NavState>(model, i, j), dt_(dt) {}
~ConstantVelocityFactor() override{};

gtsam::Vector evaluateError(const NavState &x1, const NavState &x2,
asa marked this conversation as resolved.
Show resolved Hide resolved
boost::optional<gtsam::Matrix &> H1 = boost::none,
boost::optional<gtsam::Matrix &> H2 = boost::none) const override {
// so we can reuse this calculation below
auto evaluateErrorInner = [dt = dt_](const NavState &x1, const NavState &x2) -> gtsam::Vector {
const Velocity3 &v1 = x1.v();
const Velocity3 &v2 = x2.v();
const Point3 &p1 = x1.t();
const Point3 &p2 = x2.t();

// trapezoidal integration constant accelleration
// const Point3 hx = p1 + Point3((v1 + v2) * dt / 2.0);

// euler start
// const Point3 hx = p1 + Point3(v1 * dt);

// euler end
const Point3 hx = p1 + Point3(v2 * dt);

return p2 - hx;
};

if (H1) {
(*H1) = numericalDerivative21<gtsam::Vector, NavState, NavState>(evaluateErrorInner, x1, x2, 1e-5);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what is needed here is a call to

Vector9 NavState::localCoordinates(const NavState& g, OptionalJacobian<9, 9> H1, OptionalJacobian<9, 9> H2) const {

where you evaluate the difference between predicted and x2, as in:

NavState predicted = (something that yields predicted_H_x1)
Vector9 error = predicted.localCoordinates(x2, error_H_predicted, H2);
if (H1) *H1 = error_H_predicted * predicted_H_x1;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason I can't just leverage the navstate.update(body_accel,body_omega, dt) function here to get my predicted NavState? I will want to use those terms later (and build out a NavState++ that can store those states as well) so this would get me closer to that final goal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a pass at this style. Seems to behave, but let me know if I missunderstood something. Obviously I need to test the rotation cases and find a cleaner way to init a Vector9 to clean up the verbosity of the tests.

}
if (H2) {
(*H2) = numericalDerivative22<gtsam::Vector, NavState, NavState>(evaluateErrorInner, x1, x2, 1e-5);
}

return evaluateErrorInner(x1, x2);
}
};

} // namespace gtsam
74 changes: 74 additions & 0 deletions gtsam/navigation/tests/testConstantVelocityFactor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/* ----------------------------------------------------------------------------

* GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415
* All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)

* See LICENSE for the license information

* -------------------------------------------------------------------------- */

/**
* @file testConstantVelocityFactor.cpp
* @brief Unit test for ConstantVelocityFactor
* @author Alex Cunningham
* @author Asa Hammond
*/

#include <gtsam/base/TestableAssertions.h>
#include <gtsam/base/numericalDerivative.h>
#include <gtsam/geometry/Pose3.h>
#include <gtsam/inference/Symbol.h>
#include <gtsam/navigation/ConstantVelocityFactor.h>
#include <gtsam/nonlinear/Values.h>

#include <CppUnitLite/TestHarness.h>

#include <boost/bind.hpp>
#include <list>

/* ************************************************************************* */
TEST(ConstantVelocityFactor, VelocityFactor) {
using namespace gtsam;

const auto tol = double{1e-5};
asa marked this conversation as resolved.
Show resolved Hide resolved

const auto x1 = Key{1};
const auto x2 = Key{2};

const auto dt = double{1.0};
const auto mu = double{1000};

// moving upward with groundtruth velocity"
const auto origin = NavState{Pose3{Rot3::Yaw(0), Point3{0.0, 0.0, 0.0}}, Velocity3{0.0, 0.0, 0.0}};

const auto state0 = NavState{Pose3{Rot3::Yaw(0), Point3{0.0, 0.0, 0.0}}, Velocity3{0.0, 0.0, 1.0}};

const auto state1 = NavState{Pose3{Rot3::Yaw(0), Point3{0.0, 0.0, 1.0}}, Velocity3{0.0, 0.0, 1.0}};

const auto state2 = NavState{Pose3{Rot3::Yaw(0), Point3{0.0, 0.0, 2.0}}, Velocity3{0.0, 0.0, 1.0}};

const auto noise_model = noiseModel::Constrained::All(3, mu);
asa marked this conversation as resolved.
Show resolved Hide resolved

const auto factor = ConstantVelocityFactor(x1, x2, dt, noise_model);

// positions are the same, secondary state has velocity 1.0 ,
EXPECT(assert_equal(Unit3{0.0, 0.0, -1.0}.unitVector(), factor.evaluateError(origin, state0), tol));

// same velocities, different position
// second state agrees with initial state + velocity * dt
EXPECT(assert_equal(Unit3{0.0, 0.0, 0.0}.unitVector(), factor.evaluateError(state0, state1), tol));

// both bodies have the same velocity,
// but state2.pose() != state0.pose() + state0.velocity * dt
// error comes from this pose difference
EXPECT(assert_equal(Unit3{0.0, 0.0, 1.0}.unitVector(), factor.evaluateError(state0, state2), tol));
}

/* ************************************************************************* */
int main() {
TestResult tr;
return TestRegistry::runAllTests(tr);
}
/* ************************************************************************* */