Merge pull request #903 from borglab/feature/python-examples

release/4.3a0
Varun Agrawal 2021-10-23 01:06:09 -04:00 committed by GitHub
commit c56579c61d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 481 additions and 400 deletions

View File

@ -9,15 +9,17 @@ CustomFactor demo that simulates a 1-D sensor fusion task.
Author: Fan Jiang, Frank Dellaert Author: Fan Jiang, Frank Dellaert
""" """
from functools import partial
from typing import List, Optional
import gtsam import gtsam
import numpy as np import numpy as np
from typing import List, Optional I = np.eye(1)
from functools import partial
def simulate_car(): def simulate_car() -> List[float]:
# Simulate a car for one second """Simulate a car for one second"""
x0 = 0 x0 = 0
dt = 0.25 # 4 Hz, typical GPS dt = 0.25 # 4 Hz, typical GPS
v = 144 * 1000 / 3600 # 144 km/hour = 90mph, pretty fast v = 144 * 1000 / 3600 # 144 km/hour = 90mph, pretty fast
@ -26,21 +28,87 @@ def simulate_car():
return x return x
def error_gps(measurement: np.ndarray, this: gtsam.CustomFactor,
values: gtsam.Values,
jacobians: Optional[List[np.ndarray]]) -> float:
"""GPS Factor error function
:param measurement: GPS measurement, to be filled with `partial`
:param this: gtsam.CustomFactor handle
:param values: gtsam.Values
:param jacobians: Optional list of Jacobians
:return: the unwhitened error
"""
key = this.keys()[0]
estimate = values.atVector(key)
error = estimate - measurement
if jacobians is not None:
jacobians[0] = I
return error
def error_odom(measurement: np.ndarray, this: gtsam.CustomFactor,
values: gtsam.Values,
jacobians: Optional[List[np.ndarray]]) -> float:
"""Odometry Factor error function
:param measurement: Odometry measurement, to be filled with `partial`
:param this: gtsam.CustomFactor handle
:param values: gtsam.Values
:param jacobians: Optional list of Jacobians
:return: the unwhitened error
"""
key1 = this.keys()[0]
key2 = this.keys()[1]
pos1, pos2 = values.atVector(key1), values.atVector(key2)
error = measurement - (pos1 - pos2)
if jacobians is not None:
jacobians[0] = I
jacobians[1] = -I
return error
def error_lm(measurement: np.ndarray, this: gtsam.CustomFactor,
values: gtsam.Values,
jacobians: Optional[List[np.ndarray]]) -> float:
"""Landmark Factor error function
:param measurement: Landmark measurement, to be filled with `partial`
:param this: gtsam.CustomFactor handle
:param values: gtsam.Values
:param jacobians: Optional list of Jacobians
:return: the unwhitened error
"""
key = this.keys()[0]
pos = values.atVector(key)
error = pos - measurement
if jacobians is not None:
jacobians[0] = I
return error
def main():
"""Main runner."""
x = simulate_car() x = simulate_car()
print(f"Simulated car trajectory: {x}") print(f"Simulated car trajectory: {x}")
# %%
add_noise = True # set this to False to run with "perfect" measurements add_noise = True # set this to False to run with "perfect" measurements
# GPS measurements # GPS measurements
sigma_gps = 3.0 # assume GPS is +/- 3m sigma_gps = 3.0 # assume GPS is +/- 3m
g = [x[k] + (np.random.normal(scale=sigma_gps) if add_noise else 0) g = [
for k in range(5)] x[k] + (np.random.normal(scale=sigma_gps) if add_noise else 0)
for k in range(5)
]
# Odometry measurements # Odometry measurements
sigma_odo = 0.1 # assume Odometry is 10cm accurate at 4Hz sigma_odo = 0.1 # assume Odometry is 10cm accurate at 4Hz
o = [x[k + 1] - x[k] + (np.random.normal(scale=sigma_odo) if add_noise else 0) o = [
for k in range(4)] x[k + 1] - x[k] +
(np.random.normal(scale=sigma_odo) if add_noise else 0)
for k in range(4)
]
# Landmark measurements: # Landmark measurements:
sigma_lm = 1 # assume landmark measurement is accurate up to 1m sigma_lm = 1 # assume landmark measurement is accurate up to 1m
@ -61,30 +129,12 @@ print("unknowns = ", list(map(gtsam.DefaultKeyFormatter, unknown)))
factor_graph = gtsam.NonlinearFactorGraph() factor_graph = gtsam.NonlinearFactorGraph()
# Add factors for GPS measurements # Add factors for GPS measurements
I = np.eye(1)
gps_model = gtsam.noiseModel.Isotropic.Sigma(1, sigma_gps) gps_model = gtsam.noiseModel.Isotropic.Sigma(1, sigma_gps)
def error_gps(measurement: np.ndarray, this: gtsam.CustomFactor, values, jacobians: Optional[List[np.ndarray]]):
"""GPS Factor error function
:param measurement: GPS measurement, to be filled with `partial`
:param this: gtsam.CustomFactor handle
:param values: gtsam.Values
:param jacobians: Optional list of Jacobians
:return: the unwhitened error
"""
key = this.keys()[0]
estimate = values.atVector(key)
error = estimate - measurement
if jacobians is not None:
jacobians[0] = I
return error
# Add the GPS factors # Add the GPS factors
for k in range(5): for k in range(5):
gf = gtsam.CustomFactor(gps_model, [unknown[k]], partial(error_gps, np.array([g[k]]))) gf = gtsam.CustomFactor(gps_model, [unknown[k]],
partial(error_gps, np.array([g[k]])))
factor_graph.add(gf) factor_graph.add(gf)
# New Values container # New Values container
@ -102,36 +152,19 @@ optimizer = gtsam.GaussNewtonOptimizer(factor_graph, v, params)
result = optimizer.optimize() result = optimizer.optimize()
# calculate the error from ground truth # calculate the error from ground truth
error = np.array([(result.atVector(unknown[k]) - x[k])[0] for k in range(5)]) error = np.array([(result.atVector(unknown[k]) - x[k])[0]
for k in range(5)])
print("Result with only GPS") print("Result with only GPS")
print(result, np.round(error, 2), f"\nJ(X)={0.5 * np.sum(np.square(error))}") print(result, np.round(error, 2),
f"\nJ(X)={0.5 * np.sum(np.square(error))}")
# Adding odometry will improve things a lot # Adding odometry will improve things a lot
odo_model = gtsam.noiseModel.Isotropic.Sigma(1, sigma_odo) odo_model = gtsam.noiseModel.Isotropic.Sigma(1, sigma_odo)
def error_odom(measurement: np.ndarray, this: gtsam.CustomFactor, values, jacobians: Optional[List[np.ndarray]]):
"""Odometry Factor error function
:param measurement: Odometry measurement, to be filled with `partial`
:param this: gtsam.CustomFactor handle
:param values: gtsam.Values
:param jacobians: Optional list of Jacobians
:return: the unwhitened error
"""
key1 = this.keys()[0]
key2 = this.keys()[1]
pos1, pos2 = values.atVector(key1), values.atVector(key2)
error = measurement - (pos1 - pos2)
if jacobians is not None:
jacobians[0] = I
jacobians[1] = -I
return error
for k in range(4): for k in range(4):
odof = gtsam.CustomFactor(odo_model, [unknown[k], unknown[k + 1]], partial(error_odom, np.array([o[k]]))) odof = gtsam.CustomFactor(odo_model, [unknown[k], unknown[k + 1]],
partial(error_odom, np.array([o[k]])))
factor_graph.add(odof) factor_graph.add(odof)
params = gtsam.GaussNewtonParams() params = gtsam.GaussNewtonParams()
@ -139,41 +172,35 @@ optimizer = gtsam.GaussNewtonOptimizer(factor_graph, v, params)
result = optimizer.optimize() result = optimizer.optimize()
error = np.array([(result.atVector(unknown[k]) - x[k])[0] for k in range(5)]) error = np.array([(result.atVector(unknown[k]) - x[k])[0]
for k in range(5)])
print("Result with GPS+Odometry") print("Result with GPS+Odometry")
print(result, np.round(error, 2), f"\nJ(X)={0.5 * np.sum(np.square(error))}") print(result, np.round(error, 2),
f"\nJ(X)={0.5 * np.sum(np.square(error))}")
# This is great, but GPS noise is still apparent, so now we add the two landmarks # This is great, but GPS noise is still apparent, so now we add the two landmarks
lm_model = gtsam.noiseModel.Isotropic.Sigma(1, sigma_lm) lm_model = gtsam.noiseModel.Isotropic.Sigma(1, sigma_lm)
factor_graph.add(
def error_lm(measurement: np.ndarray, this: gtsam.CustomFactor, values, jacobians: Optional[List[np.ndarray]]): gtsam.CustomFactor(lm_model, [unknown[0]],
"""Landmark Factor error function partial(error_lm, np.array([lm_0 + z_0]))))
:param measurement: Landmark measurement, to be filled with `partial` factor_graph.add(
:param this: gtsam.CustomFactor handle gtsam.CustomFactor(lm_model, [unknown[3]],
:param values: gtsam.Values partial(error_lm, np.array([lm_3 + z_3]))))
:param jacobians: Optional list of Jacobians
:return: the unwhitened error
"""
key = this.keys()[0]
pos = values.atVector(key)
error = pos - measurement
if jacobians is not None:
jacobians[0] = I
return error
factor_graph.add(gtsam.CustomFactor(lm_model, [unknown[0]], partial(error_lm, np.array([lm_0 + z_0]))))
factor_graph.add(gtsam.CustomFactor(lm_model, [unknown[3]], partial(error_lm, np.array([lm_3 + z_3]))))
params = gtsam.GaussNewtonParams() params = gtsam.GaussNewtonParams()
optimizer = gtsam.GaussNewtonOptimizer(factor_graph, v, params) optimizer = gtsam.GaussNewtonOptimizer(factor_graph, v, params)
result = optimizer.optimize() result = optimizer.optimize()
error = np.array([(result.atVector(unknown[k]) - x[k])[0] for k in range(5)]) error = np.array([(result.atVector(unknown[k]) - x[k])[0]
for k in range(5)])
print("Result with GPS+Odometry+Landmark") print("Result with GPS+Odometry+Landmark")
print(result, np.round(error, 2), f"\nJ(X)={0.5 * np.sum(np.square(error))}") print(result, np.round(error, 2),
f"\nJ(X)={0.5 * np.sum(np.square(error))}")
if __name__ == "__main__":
main()

View File

@ -13,13 +13,8 @@ Author: Mandy Xie
from __future__ import print_function from __future__ import print_function
import numpy as np
import gtsam import gtsam
import matplotlib.pyplot as plt
import gtsam.utils.plot as gtsam_plot
# ENU Origin is where the plane was in hold next to runway # ENU Origin is where the plane was in hold next to runway
lat0 = 33.86998 lat0 = 33.86998
lon0 = -84.30626 lon0 = -84.30626
@ -29,6 +24,9 @@ h0 = 274
GPS_NOISE = gtsam.noiseModel.Isotropic.Sigma(3, 0.1) GPS_NOISE = gtsam.noiseModel.Isotropic.Sigma(3, 0.1)
PRIOR_NOISE = gtsam.noiseModel.Isotropic.Sigma(6, 0.25) PRIOR_NOISE = gtsam.noiseModel.Isotropic.Sigma(6, 0.25)
def main():
"""Main runner."""
# Create an empty nonlinear factor graph # Create an empty nonlinear factor graph
graph = gtsam.NonlinearFactorGraph() graph = gtsam.NonlinearFactorGraph()
@ -54,3 +52,6 @@ optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial, params)
result = optimizer.optimize() result = optimizer.optimize()
print("\nFinal Result:\n{}".format(result)) print("\nFinal Result:\n{}".format(result))
if __name__ == "__main__":
main()

View File

@ -13,17 +13,18 @@ Author: Frank Dellaert
from __future__ import print_function from __future__ import print_function
import numpy as np
import gtsam import gtsam
import matplotlib.pyplot as plt
import gtsam.utils.plot as gtsam_plot import gtsam.utils.plot as gtsam_plot
import matplotlib.pyplot as plt
import numpy as np
# Create noise models # Create noise models
ODOMETRY_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.2, 0.2, 0.1])) ODOMETRY_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.2, 0.2, 0.1]))
PRIOR_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.3, 0.3, 0.1])) PRIOR_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.3, 0.3, 0.1]))
def main():
"""Main runner"""
# Create an empty nonlinear factor graph # Create an empty nonlinear factor graph
graph = gtsam.NonlinearFactorGraph() graph = gtsam.NonlinearFactorGraph()
@ -57,13 +58,15 @@ print("\nFinal Result:\n{}".format(result))
# 5. Calculate and print marginal covariances for all variables # 5. Calculate and print marginal covariances for all variables
marginals = gtsam.Marginals(graph, result) marginals = gtsam.Marginals(graph, result)
for i in range(1, 4): for i in range(1, 4):
print("X{} covariance:\n{}\n".format(i, marginals.marginalCovariance(i))) print("X{} covariance:\n{}\n".format(i,
marginals.marginalCovariance(i)))
fig = plt.figure(0)
for i in range(1, 4): for i in range(1, 4):
gtsam_plot.plot_pose2(0, result.atPose2(i), 0.5, marginals.marginalCovariance(i)) gtsam_plot.plot_pose2(0, result.atPose2(i), 0.5,
marginals.marginalCovariance(i))
plt.axis('equal') plt.axis('equal')
plt.show() plt.show()
if __name__ == "__main__":
main()

View File

@ -13,16 +13,19 @@ Author: Alex Cunningham (C++), Kevin Deng & Frank Dellaert (Python)
from __future__ import print_function from __future__ import print_function
import numpy as np
import gtsam import gtsam
from gtsam.symbol_shorthand import X, L import numpy as np
from gtsam.symbol_shorthand import L, X
# Create noise models # Create noise models
PRIOR_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.3, 0.3, 0.1])) PRIOR_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.3, 0.3, 0.1]))
ODOMETRY_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.2, 0.2, 0.1])) ODOMETRY_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.2, 0.2, 0.1]))
MEASUREMENT_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.1, 0.2])) MEASUREMENT_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.1, 0.2]))
def main():
"""Main runner"""
# Create an empty nonlinear factor graph # Create an empty nonlinear factor graph
graph = gtsam.NonlinearFactorGraph() graph = gtsam.NonlinearFactorGraph()
@ -34,21 +37,27 @@ L1 = L(4)
L2 = L(5) L2 = L(5)
# Add a prior on pose X1 at the origin. A prior factor consists of a mean and a noise model # Add a prior on pose X1 at the origin. A prior factor consists of a mean and a noise model
graph.add(gtsam.PriorFactorPose2(X1, gtsam.Pose2(0.0, 0.0, 0.0), PRIOR_NOISE)) graph.add(
gtsam.PriorFactorPose2(X1, gtsam.Pose2(0.0, 0.0, 0.0), PRIOR_NOISE))
# Add odometry factors between X1,X2 and X2,X3, respectively # Add odometry factors between X1,X2 and X2,X3, respectively
graph.add(gtsam.BetweenFactorPose2( graph.add(
X1, X2, gtsam.Pose2(2.0, 0.0, 0.0), ODOMETRY_NOISE)) gtsam.BetweenFactorPose2(X1, X2, gtsam.Pose2(2.0, 0.0, 0.0),
graph.add(gtsam.BetweenFactorPose2( ODOMETRY_NOISE))
X2, X3, gtsam.Pose2(2.0, 0.0, 0.0), ODOMETRY_NOISE)) graph.add(
gtsam.BetweenFactorPose2(X2, X3, gtsam.Pose2(2.0, 0.0, 0.0),
ODOMETRY_NOISE))
# Add Range-Bearing measurements to two different landmarks L1 and L2 # Add Range-Bearing measurements to two different landmarks L1 and L2
graph.add(gtsam.BearingRangeFactor2D( graph.add(
X1, L1, gtsam.Rot2.fromDegrees(45), np.sqrt(4.0+4.0), MEASUREMENT_NOISE)) gtsam.BearingRangeFactor2D(X1, L1, gtsam.Rot2.fromDegrees(45),
graph.add(gtsam.BearingRangeFactor2D( np.sqrt(4.0 + 4.0), MEASUREMENT_NOISE))
X2, L1, gtsam.Rot2.fromDegrees(90), 2.0, MEASUREMENT_NOISE)) graph.add(
graph.add(gtsam.BearingRangeFactor2D( gtsam.BearingRangeFactor2D(X2, L1, gtsam.Rot2.fromDegrees(90), 2.0,
X3, L2, gtsam.Rot2.fromDegrees(90), 2.0, MEASUREMENT_NOISE)) MEASUREMENT_NOISE))
graph.add(
gtsam.BearingRangeFactor2D(X3, L2, gtsam.Rot2.fromDegrees(90), 2.0,
MEASUREMENT_NOISE))
# Print graph # Print graph
print("Factor Graph:\n{}".format(graph)) print("Factor Graph:\n{}".format(graph))
@ -71,11 +80,18 @@ print("Initial Estimate:\n{}".format(initial_estimate))
# Here we will use the default set of parameters. See the # Here we will use the default set of parameters. See the
# documentation for the full set of parameters. # documentation for the full set of parameters.
params = gtsam.LevenbergMarquardtParams() params = gtsam.LevenbergMarquardtParams()
optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial_estimate, params) optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial_estimate,
params)
result = optimizer.optimize() result = optimizer.optimize()
print("\nFinal Result:\n{}".format(result)) print("\nFinal Result:\n{}".format(result))
# Calculate and print marginal covariances for all variables # Calculate and print marginal covariances for all variables
marginals = gtsam.Marginals(graph, result) marginals = gtsam.Marginals(graph, result)
for (key, str) in [(X1, "X1"), (X2, "X2"), (X3, "X3"), (L1, "L1"), (L2, "L2")]: for (key, s) in [(X1, "X1"), (X2, "X2"), (X3, "X3"), (L1, "L1"),
print("{} covariance:\n{}\n".format(str, marginals.marginalCovariance(key))) (L2, "L2")]:
print("{} covariance:\n{}\n".format(s,
marginals.marginalCovariance(key)))
if __name__ == "__main__":
main()

View File

@ -15,21 +15,17 @@ from __future__ import print_function
import math import math
import numpy as np
import gtsam import gtsam
import matplotlib.pyplot as plt
import gtsam.utils.plot as gtsam_plot import gtsam.utils.plot as gtsam_plot
import matplotlib.pyplot as plt
def vector3(x, y, z): def main():
"""Create 3d double numpy array.""" """Main runner."""
return np.array([x, y, z], dtype=float)
# Create noise models # Create noise models
PRIOR_NOISE = gtsam.noiseModel.Diagonal.Sigmas(vector3(0.3, 0.3, 0.1)) PRIOR_NOISE = gtsam.noiseModel.Diagonal.Sigmas(gtsam.Point3(0.3, 0.3, 0.1))
ODOMETRY_NOISE = gtsam.noiseModel.Diagonal.Sigmas(vector3(0.2, 0.2, 0.1)) ODOMETRY_NOISE = gtsam.noiseModel.Diagonal.Sigmas(
gtsam.Point3(0.2, 0.2, 0.1))
# 1. Create a factor graph container and add factors to it # 1. Create a factor graph container and add factors to it
graph = gtsam.NonlinearFactorGraph() graph = gtsam.NonlinearFactorGraph()
@ -40,20 +36,25 @@ graph.add(gtsam.PriorFactorPose2(1, gtsam.Pose2(0, 0, 0), PRIOR_NOISE))
# 2b. Add odometry factors # 2b. Add odometry factors
# Create odometry (Between) factors between consecutive poses # Create odometry (Between) factors between consecutive poses
graph.add(gtsam.BetweenFactorPose2(1, 2, gtsam.Pose2(2, 0, 0), ODOMETRY_NOISE)) graph.add(
graph.add(gtsam.BetweenFactorPose2( gtsam.BetweenFactorPose2(1, 2, gtsam.Pose2(2, 0, 0), ODOMETRY_NOISE))
2, 3, gtsam.Pose2(2, 0, math.pi / 2), ODOMETRY_NOISE)) graph.add(
graph.add(gtsam.BetweenFactorPose2( gtsam.BetweenFactorPose2(2, 3, gtsam.Pose2(2, 0, math.pi / 2),
3, 4, gtsam.Pose2(2, 0, math.pi / 2), ODOMETRY_NOISE)) ODOMETRY_NOISE))
graph.add(gtsam.BetweenFactorPose2( graph.add(
4, 5, gtsam.Pose2(2, 0, math.pi / 2), ODOMETRY_NOISE)) gtsam.BetweenFactorPose2(3, 4, gtsam.Pose2(2, 0, math.pi / 2),
ODOMETRY_NOISE))
graph.add(
gtsam.BetweenFactorPose2(4, 5, gtsam.Pose2(2, 0, math.pi / 2),
ODOMETRY_NOISE))
# 2c. Add the loop closure constraint # 2c. Add the loop closure constraint
# This factor encodes the fact that we have returned to the same pose. In real # This factor encodes the fact that we have returned to the same pose. In real
# systems, these constraints may be identified in many ways, such as appearance-based # systems, these constraints may be identified in many ways, such as appearance-based
# techniques with camera images. We will use another Between Factor to enforce this constraint: # techniques with camera images. We will use another Between Factor to enforce this constraint:
graph.add(gtsam.BetweenFactorPose2( graph.add(
5, 2, gtsam.Pose2(2, 0, math.pi / 2), ODOMETRY_NOISE)) gtsam.BetweenFactorPose2(5, 2, gtsam.Pose2(2, 0, math.pi / 2),
ODOMETRY_NOISE))
print("\nFactor Graph:\n{}".format(graph)) # print print("\nFactor Graph:\n{}".format(graph)) # print
# 3. Create the data structure to hold the initial_estimate estimate to the # 3. Create the data structure to hold the initial_estimate estimate to the
@ -86,11 +87,16 @@ print("Final Result:\n{}".format(result))
# 5. Calculate and print marginal covariances for all variables # 5. Calculate and print marginal covariances for all variables
marginals = gtsam.Marginals(graph, result) marginals = gtsam.Marginals(graph, result)
for i in range(1, 6): for i in range(1, 6):
print("X{} covariance:\n{}\n".format(i, marginals.marginalCovariance(i))) print("X{} covariance:\n{}\n".format(i,
marginals.marginalCovariance(i)))
fig = plt.figure(0)
for i in range(1, 6): for i in range(1, 6):
gtsam_plot.plot_pose2(0, result.atPose2(i), 0.5, marginals.marginalCovariance(i)) gtsam_plot.plot_pose2(0, result.atPose2(i), 0.5,
marginals.marginalCovariance(i))
plt.axis('equal') plt.axis('equal')
plt.show() plt.show()
if __name__ == "__main__":
main()

View File

@ -12,32 +12,38 @@ and does the optimization. Output is written on a file, in g2o format
# pylint: disable=invalid-name, E1101 # pylint: disable=invalid-name, E1101
from __future__ import print_function from __future__ import print_function
import argparse import argparse
import math
import numpy as np
import matplotlib.pyplot as plt
import gtsam import gtsam
import matplotlib.pyplot as plt
from gtsam.utils import plot from gtsam.utils import plot
def vector3(x, y, z): def main():
"""Create 3d double numpy array.""" """Main runner."""
return np.array([x, y, z], dtype=float)
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="A 2D Pose SLAM example that reads input from g2o, " description="A 2D Pose SLAM example that reads input from g2o, "
"converts it to a factor graph and does the optimization. " "converts it to a factor graph and does the optimization. "
"Output is written on a file, in g2o format") "Output is written on a file, in g2o format")
parser.add_argument('-i', '--input', help='input file g2o format') parser.add_argument('-i', '--input', help='input file g2o format')
parser.add_argument('-o', '--output', parser.add_argument(
'-o',
'--output',
help="the path to the output file with optimized graph") help="the path to the output file with optimized graph")
parser.add_argument('-m', '--maxiter', type=int, parser.add_argument('-m',
'--maxiter',
type=int,
help="maximum number of iterations for optimizer") help="maximum number of iterations for optimizer")
parser.add_argument('-k', '--kernel', choices=['none', 'huber', 'tukey'], parser.add_argument('-k',
default="none", help="Type of kernel used") '--kernel',
parser.add_argument("-p", "--plot", action="store_true", choices=['none', 'huber', 'tukey'],
default="none",
help="Type of kernel used")
parser.add_argument("-p",
"--plot",
action="store_true",
help="Flag to plot results") help="Flag to plot results")
args = parser.parse_args() args = parser.parse_args()
@ -53,7 +59,7 @@ graph, initial = gtsam.readG2o(g2oFile, is3D)
assert args.kernel == "none", "Supplied kernel type is not yet implemented" assert args.kernel == "none", "Supplied kernel type is not yet implemented"
# Add prior on the pose having index (key) = 0 # Add prior on the pose having index (key) = 0
priorModel = gtsam.noiseModel.Diagonal.Variances(vector3(1e-6, 1e-6, 1e-8)) priorModel = gtsam.noiseModel.Diagonal.Variances(gtsam.Point3(1e-6, 1e-6, 1e-8))
graph.add(gtsam.PriorFactorPose2(0, gtsam.Pose2(), priorModel)) graph.add(gtsam.PriorFactorPose2(0, gtsam.Pose2(), priorModel))
params = gtsam.GaussNewtonParams() params = gtsam.GaussNewtonParams()
@ -69,7 +75,6 @@ print("Optimization complete")
print("initial error = ", graph.error(initial)) print("initial error = ", graph.error(initial))
print("final error = ", graph.error(result)) print("final error = ", graph.error(result))
if args.output is None: if args.output is None:
print("\nFactor Graph:\n{}".format(graph)) print("\nFactor Graph:\n{}".format(graph))
print("\nInitial Estimate:\n{}".format(initial)) print("\nInitial Estimate:\n{}".format(initial))
@ -86,3 +91,7 @@ if args.plot:
for i in range(resultPoses.shape[0]): for i in range(resultPoses.shape[0]):
plot.plot_pose2(1, gtsam.Pose2(resultPoses[i, :])) plot.plot_pose2(1, gtsam.Pose2(resultPoses[i, :]))
plt.show() plt.show()
if __name__ == "__main__":
main()

View File

@ -8,13 +8,14 @@
# pylint: disable=invalid-name, E1101 # pylint: disable=invalid-name, E1101
from __future__ import print_function from __future__ import print_function
import argparse import argparse
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import gtsam import gtsam
import matplotlib.pyplot as plt
import numpy as np
from gtsam.utils import plot from gtsam.utils import plot
from mpl_toolkits.mplot3d import Axes3D
def vector6(x, y, z, a, b, c): def vector6(x, y, z, a, b, c):
@ -22,13 +23,20 @@ def vector6(x, y, z, a, b, c):
return np.array([x, y, z, a, b, c], dtype=float) return np.array([x, y, z, a, b, c], dtype=float)
def main():
"""Main runner."""
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="A 3D Pose SLAM example that reads input from g2o, and " description="A 3D Pose SLAM example that reads input from g2o, and "
"initializes Pose3") "initializes Pose3")
parser.add_argument('-i', '--input', help='input file g2o format') parser.add_argument('-i', '--input', help='input file g2o format')
parser.add_argument('-o', '--output', parser.add_argument(
'-o',
'--output',
help="the path to the output file with optimized graph") help="the path to the output file with optimized graph")
parser.add_argument("-p", "--plot", action="store_true", parser.add_argument("-p",
"--plot",
action="store_true",
help="Flag to plot results") help="Flag to plot results")
args = parser.parse_args() args = parser.parse_args()
@ -39,15 +47,16 @@ is3D = True
graph, initial = gtsam.readG2o(g2oFile, is3D) graph, initial = gtsam.readG2o(g2oFile, is3D)
# Add Prior on the first key # Add Prior on the first key
priorModel = gtsam.noiseModel.Diagonal.Variances(vector6(1e-6, 1e-6, 1e-6, priorModel = gtsam.noiseModel.Diagonal.Variances(
1e-4, 1e-4, 1e-4)) vector6(1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4))
print("Adding prior to g2o file ") print("Adding prior to g2o file ")
firstKey = initial.keys()[0] firstKey = initial.keys()[0]
graph.add(gtsam.PriorFactorPose3(firstKey, gtsam.Pose3(), priorModel)) graph.add(gtsam.PriorFactorPose3(firstKey, gtsam.Pose3(), priorModel))
params = gtsam.GaussNewtonParams() params = gtsam.GaussNewtonParams()
params.setVerbosity("Termination") # this will show info about stopping conds params.setVerbosity(
"Termination") # this will show info about stopping conds
optimizer = gtsam.GaussNewtonOptimizer(graph, initial, params) optimizer = gtsam.GaussNewtonOptimizer(graph, initial, params)
result = optimizer.optimize() result = optimizer.optimize()
print("Optimization complete") print("Optimization complete")
@ -69,3 +78,7 @@ if args.plot:
for i in range(resultPoses.size()): for i in range(resultPoses.size()):
plot.plot_pose3(1, resultPoses.atPose3(i)) plot.plot_pose3(1, resultPoses.atPose3(i))
plt.show() plt.show()
if __name__ == "__main__":
main()

View File

@ -13,10 +13,12 @@ Author: Luca Carlone, Frank Dellaert (python port)
from __future__ import print_function from __future__ import print_function
import gtsam
import numpy as np import numpy as np
import gtsam
def main():
"""Main runner."""
# Read graph from file # Read graph from file
g2oFile = gtsam.findExampleDataFile("pose3example.txt") g2oFile = gtsam.findExampleDataFile("pose3example.txt")
@ -29,7 +31,11 @@ priorModel = gtsam.noiseModel.Diagonal.Variances(
firstKey = initial.keys()[0] firstKey = initial.keys()[0]
graph.add(gtsam.PriorFactorPose3(0, gtsam.Pose3(), priorModel)) graph.add(gtsam.PriorFactorPose3(0, gtsam.Pose3(), priorModel))
# Initializing Pose3 - chordal relaxation" # Initializing Pose3 - chordal relaxation
initialization = gtsam.InitializePose3.initialize(graph) initialization = gtsam.InitializePose3.initialize(graph)
print(initialization) print(initialization)
if __name__ == "__main__":
main()