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

Adding lever-arm to GPS factors #1975

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from

Conversation

mnissov
Copy link

@mnissov mnissov commented Jan 13, 2025

I noticed the GPS factors had no option for a non-zero lever arm, the feature became necessary for me so I figured I would make this PR.

Of course similar behavior is possible with setBodyPSensor but this comes at the cost of additional linearization error I believe (ref). As a result the performance is actually different.

@mnissov
Copy link
Author

mnissov commented Jan 14, 2025

I see the macos-14-xcode-15.4 Release Python 3 check failed. This I have very little experience with, but in hindsight I see the serialization and interfacing were not appropriately updated.

Perhaps I should ask the following questions

  • Is this of interest for GTSAM?
  • Would you prefer the extrinsic added as an estimated state?
  • Do you have any tips for resolving the aforementioned failed check, or how I can test this locally. Because running make check succeeds across the board.

@dellaert
Copy link
Member

I’ll take a look and then answer your questions. If it can be done easily with another state then probably that is preferred.

Copy link
Member

@dellaert dellaert left a comment

Choose a reason for hiding this comment

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

I think this is great, and I think it should be added to a factor. But I propose to add a GpsFactor2 or GpsFactorArm in the same file, because the Jacobians are more expensive. Adding documentation of the nature I suggested in both the old and the new factor would make it easier to see the difference.

PS we will soon start adding notebooks to document factors in the source tree itself. Consider authoring a small colab that demonstrates both factors that we could include :-) That’s not needed for this PR to merge, though.

}

//***************************************************************************
Vector GPSFactor2::evaluateError(const NavState& p,
OptionalMatrixType H) const {
return p.position(H) -nT_;
const Matrix3 rot = p.attitude().matrix();
Copy link
Member

Choose a reason for hiding this comment

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

Please use aRb naming convention, where R transforms b coordinates into a coordinates.

@@ -39,6 +39,7 @@ class GTSAM_EXPORT GPSFactor: public NoiseModelFactorN<Pose3> {
typedef NoiseModelFactorN<Pose3> Base;

Point3 nT_; ///< Position measurement in cartesian coordinates
Point3 B_t_BG_; ///< Lever arm between GPS and BODY frame
Copy link
Member

Choose a reason for hiding this comment

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

The naming convention ‘nT_’ says that T is in the navigation frame. I think if you want to include a lever arm in this factor you need to include more documentation about the frames involved.

@@ -61,10 +64,12 @@ TEST( GPSFactor, Constructor ) {
// Factor
Key key(1);
SharedNoiseModel model = noiseModel::Isotropic::Sigma(3, 0.25);
GPSFactor factor(key, Point3(E, N, U), model);
GPSFactor factor(key, Point3(E, N, U), model, leverArm);
Copy link
Member

Choose a reason for hiding this comment

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

I would not expect you to change an existing test, but rather add an additional test with a non-zero lever arm.

}

//***************************************************************************
Vector GPSFactor2::evaluateError(const NavState& p,
OptionalMatrixType H) const {
return p.position(H) -nT_;
const Matrix3 rot = p.attitude().matrix();
if (H) {
Copy link
Member

Choose a reason for hiding this comment

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

I did not see a numerical derivative test on this Jacobian (right?) so in my book all bets are off :-)

H->block<3, 3>(0, 6).setZero();
}

return p.position() - (nT_ - rot * B_t_BG_);
Copy link
Member

Choose a reason for hiding this comment

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

This formula is a bit counter-intuitive to me. I would expect to see $h(x)-z$, where $h(x)$ is the measurement prediction and $z$ the measurement, in this case nT_. If I rewrite your equation that way I get

h(x) = p.position() + rot * B_t_BG_

From which I deduce that rot==nRb which matches my definition of NavState, and B_t_BG_==bL_, a lever arm in the body frame. So, I think the documentation/notation I’m looking for is

bL_ is a lever arm in the body frame, denoting the 3D position of the GPS antenna in the body frame. Because the actual location of the antenna depends on both position and attitude, providing a lever arm makes components of the attitude observable in turns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants