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

fix: UnaryFactor Jacobian #724

Merged
merged 3 commits into from
Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion doc/Code/LocalizationFactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ class UnaryFactor: public NoiseModelFactor1<Pose2> {
Vector evaluateError(const Pose2& q,
boost::optional<Matrix&> H = boost::none) const
{
if (H) (*H) = (Matrix(2,3)<< 1.0,0.0,0.0, 0.0,1.0,0.0).finished();
const double cosTheta = cos(q.theta());
Copy link
Member

@dellaert dellaert Mar 23, 2021

Choose a reason for hiding this comment

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

Add comment, now that you figured it out :-) Also, GTSAM actually stores a Rot2 as sin and cos, so no need to re-compute. You can just use:

const Rot2& R = q.rotation();

and then use R.s() and R.c()

const double sinTheta = sin(q.theta());
if (H) (*H) = (gtsam::Matrix(2, 3) <<
cosTheta, -sinTheta, 0.0,
sinTheta, cosTheta, 0.0).finished();
return (Vector(2) << q.x() - mx_, q.y() - my_).finished();
}
};
34 changes: 18 additions & 16 deletions doc/gtsam.lyx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#LyX 2.1 created this file. For more info see http://www.lyx.org/
\lyxformat 474
#LyX 2.2 created this file. For more info see http://www.lyx.org/
\lyxformat 508
\begin_document
\begin_header
\save_transient_properties true
\origin unavailable
\textclass article
\begin_preamble
\usepackage{times}
Expand Down Expand Up @@ -50,16 +52,16 @@
\language_package default
\inputencoding auto
\fontencoding T1
\font_roman ae
\font_sans default
\font_typewriter default
\font_math auto
\font_roman "ae" "default"
\font_sans "default" "default"
\font_typewriter "default" "default"
\font_math "auto" "auto"
\font_default_family rmdefault
\use_non_tex_fonts false
\font_sc false
\font_osf false
\font_sf_scale 100
\font_tt_scale 100
\font_sf_scale 100 100
\font_tt_scale 100 100
\graphics default
\default_output_format default
\output_sync 0
Expand Down Expand Up @@ -1061,7 +1063,7 @@ noindent
\begin_layout Subsection
\begin_inset CommandInset label
LatexCommand label
name "sub:Full-Posterior-Inference"
name "subsec:Full-Posterior-Inference"

\end_inset

Expand Down Expand Up @@ -1272,7 +1274,7 @@ ing to odometry measurements.
(see Section
\begin_inset CommandInset ref
LatexCommand ref
reference "sub:Full-Posterior-Inference"
reference "subsec:Full-Posterior-Inference"

\end_inset

Expand Down Expand Up @@ -1469,7 +1471,7 @@ GPS-like
\begin_inset CommandInset include
LatexCommand lstinputlisting
filename "Code/LocalizationFactor.cpp"
lstparams "aboveskip=10pt,basicstyle={\\ttfamily\\small},caption={Excerpt from examples/LocalizationExample.cpp},captionpos=b,frame=single,identifierstyle={\\bfseries},label={listing:LocalizationFactor},language={C++},numbers=left"
lstparams "aboveskip=10pt,basicstyle={\\ttfamily\\small},captionpos=b,frame=single,identifierstyle={\\bfseries},language={C++},numbers=left,caption={Excerpt from examples/LocalizationExample.cpp},label={listing:LocalizationFactor}"

\end_inset

Expand Down Expand Up @@ -1590,15 +1592,15 @@ q_{y}
\begin_inset Formula $2\times3$
\end_inset

matrix:
matrix in tangent space which is the same the as the rotation matrix:
\end_layout

\begin_layout Standard
\begin_inset Formula
\[
H=\left[\begin{array}{ccc}
1 & 0 & 0\\
0 & 1 & 0
\cos(q_{\theta}) & -\sin(q_{\theta}) & 0\\
\sin(q_{\theta}) & \cos(q_{\theta}) & 0
\end{array}\right]
\]

Expand Down Expand Up @@ -1750,7 +1752,7 @@ global
The marginals can be recovered exactly as in Section
\begin_inset CommandInset ref
LatexCommand ref
reference "sub:Full-Posterior-Inference"
reference "subsec:Full-Posterior-Inference"

\end_inset

Expand All @@ -1770,7 +1772,7 @@ filename "Code/LocalizationOutput5.txt"
Comparing this with the covariance matrices in Section
\begin_inset CommandInset ref
LatexCommand ref
reference "sub:Full-Posterior-Inference"
reference "subsec:Full-Posterior-Inference"

\end_inset

Expand Down
Binary file modified doc/gtsam.pdf
Binary file not shown.
20 changes: 11 additions & 9 deletions examples/LocalizationExample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,17 @@ class UnaryFactor: public NoiseModelFactor1<Pose2> {
// The first is the 'evaluateError' function. This function implements the desired measurement
// function, returning a vector of errors when evaluated at the provided variable value. It
// must also calculate the Jacobians for this measurement function, if requested.
Vector evaluateError(const Pose2& q,
boost::optional<Matrix&> H = boost::none) const override {
// The measurement function for a GPS-like measurement is simple:
// error_x = pose.x - measurement.x
// error_y = pose.y - measurement.y
// Consequently, the Jacobians are:
// [ derror_x/dx derror_x/dy derror_x/dtheta ] = [1 0 0]
// [ derror_y/dx derror_y/dy derror_y/dtheta ] = [0 1 0]
if (H) (*H) = (Matrix(2, 3) << 1.0, 0.0, 0.0, 0.0, 1.0, 0.0).finished();
Vector evaluateError(const Pose2& q, boost::optional<Matrix&> H = boost::none) const override {
// The measurement function for a GPS-like measurement h(q) which predicts the measurement (m) is h(q) = q, q = [qx qy qtheta]
// The error is then simply calculated as E(q) = h(q) - m:
// error_x = q.x - mx
// error_y = q.y - my
// Node's orientation reflects in the Jacobian, in tangent space this is equal to the right-hand rule rotation matrix
// H = [ cos(q.theta) -sin(q.theta) 0 ]
// [ sin(q.theta) cos(q.theta) 0 ]
const double cosTheta = cos(q.theta());
Copy link
Member

Choose a reason for hiding this comment

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

same comments as above of course :-)

Copy link
Author

Choose a reason for hiding this comment

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

Right! it is smart to use the available feature, I will update the PR soon.

const double sinTheta = sin(q.theta());
if (H) (*H) = (gtsam::Matrix(2, 3) << cosTheta, -sinTheta, 0.0, sinTheta, cosTheta, 0.0).finished();
return (Vector(2) << q.x() - mx_, q.y() - my_).finished();
}

Expand Down