167 lines
5.6 KiB
Python
167 lines
5.6 KiB
Python
"""
|
|
ImuFactor example with iSAM2.
|
|
Authors: Robert Truax (C++), Frank Dellaert, Varun Agrawal (Python)
|
|
"""
|
|
# pylint: disable=invalid-name, E1101
|
|
|
|
from __future__ import print_function
|
|
|
|
import math
|
|
|
|
import matplotlib.pyplot as plt
|
|
import numpy as np
|
|
from mpl_toolkits.mplot3d import Axes3D # pylint: disable=W0611
|
|
|
|
import gtsam
|
|
from gtsam import (ISAM2, BetweenFactorConstantBias, Cal3_S2,
|
|
ConstantTwistScenario, ImuFactor, NonlinearFactorGraph,
|
|
PinholeCameraCal3_S2, Point3, Pose3,
|
|
PriorFactorConstantBias, PriorFactorPose3,
|
|
PriorFactorVector, Rot3, Values)
|
|
from gtsam.symbol_shorthand import B, V, X
|
|
from gtsam.utils import plot
|
|
|
|
|
|
def vector3(x, y, z):
|
|
"""Create 3d double numpy array."""
|
|
return np.array([x, y, z], dtype=float)
|
|
|
|
|
|
g = 9.81
|
|
n_gravity = vector3(0, 0, -g)
|
|
|
|
|
|
def preintegration_parameters():
|
|
# IMU preintegration parameters
|
|
# Default Params for a Z-up navigation frame, such as ENU: gravity points along negative Z-axis
|
|
PARAMS = gtsam.PreintegrationParams.MakeSharedU(g)
|
|
I = np.eye(3)
|
|
PARAMS.setAccelerometerCovariance(I * 0.1)
|
|
PARAMS.setGyroscopeCovariance(I * 0.1)
|
|
PARAMS.setIntegrationCovariance(I * 0.1)
|
|
PARAMS.setUse2ndOrderCoriolis(False)
|
|
PARAMS.setOmegaCoriolis(vector3(0, 0, 0))
|
|
|
|
BIAS_COVARIANCE = gtsam.noiseModel.Isotropic.Variance(6, 0.1)
|
|
DELTA = Pose3(Rot3.Rodrigues(0, 0, 0),
|
|
Point3(0.05, -0.10, 0.20))
|
|
|
|
return PARAMS, BIAS_COVARIANCE, DELTA
|
|
|
|
|
|
def get_camera(radius):
|
|
up = Point3(0, 0, 1)
|
|
target = Point3(0, 0, 0)
|
|
position = Point3(radius, 0, 0)
|
|
camera = PinholeCameraCal3_S2.Lookat(position, target, up, Cal3_S2())
|
|
return camera
|
|
|
|
|
|
def get_scenario(radius, pose_0, angular_velocity, delta_t):
|
|
"""Create the set of ground-truth landmarks and poses"""
|
|
angular_velocity_vector = vector3(0, -angular_velocity, 0)
|
|
linear_velocity_vector = vector3(radius * angular_velocity, 0, 0)
|
|
scenario = ConstantTwistScenario(
|
|
angular_velocity_vector, linear_velocity_vector, pose_0)
|
|
|
|
return scenario
|
|
|
|
|
|
def IMU_example():
|
|
"""Run iSAM 2 example with IMU factor."""
|
|
|
|
# Start with a camera on x-axis looking at origin
|
|
radius = 30
|
|
camera = get_camera(radius)
|
|
pose_0 = camera.pose()
|
|
|
|
delta_t = 1.0/18 # makes for 10 degrees per step
|
|
angular_velocity = math.radians(180) # rad/sec
|
|
scenario = get_scenario(radius, pose_0, angular_velocity, delta_t)
|
|
|
|
PARAMS, BIAS_COVARIANCE, DELTA = preintegration_parameters()
|
|
|
|
# Create a factor graph
|
|
graph = NonlinearFactorGraph()
|
|
|
|
# Create (incremental) ISAM2 solver
|
|
isam = ISAM2()
|
|
|
|
# Create the initial estimate to the solution
|
|
# Intentionally initialize the variables off from the ground truth
|
|
initialEstimate = Values()
|
|
|
|
# Add a prior on pose x0. This indirectly specifies where the origin is.
|
|
# 30cm std on x,y,z 0.1 rad on roll,pitch,yaw
|
|
noise = gtsam.noiseModel.Diagonal.Sigmas(
|
|
np.array([0.1, 0.1, 0.1, 0.3, 0.3, 0.3]))
|
|
graph.push_back(PriorFactorPose3(X(0), pose_0, noise))
|
|
|
|
# Add imu priors
|
|
biasKey = B(0)
|
|
biasnoise = gtsam.noiseModel.Isotropic.Sigma(6, 0.1)
|
|
biasprior = PriorFactorConstantBias(biasKey, gtsam.imuBias.ConstantBias(),
|
|
biasnoise)
|
|
graph.push_back(biasprior)
|
|
initialEstimate.insert(biasKey, gtsam.imuBias.ConstantBias())
|
|
velnoise = gtsam.noiseModel.Isotropic.Sigma(3, 0.1)
|
|
|
|
# Calculate with correct initial velocity
|
|
n_velocity = vector3(0, angular_velocity * radius, 0)
|
|
velprior = PriorFactorVector(V(0), n_velocity, velnoise)
|
|
graph.push_back(velprior)
|
|
initialEstimate.insert(V(0), n_velocity)
|
|
|
|
accum = gtsam.PreintegratedImuMeasurements(PARAMS)
|
|
|
|
# Simulate poses and imu measurements, adding them to the factor graph
|
|
for i in range(80):
|
|
t = i * delta_t # simulation time
|
|
if i == 0: # First time add two poses
|
|
pose_1 = scenario.pose(delta_t)
|
|
initialEstimate.insert(X(0), pose_0.compose(DELTA))
|
|
initialEstimate.insert(X(1), pose_1.compose(DELTA))
|
|
elif i >= 2: # Add more poses as necessary
|
|
pose_i = scenario.pose(t)
|
|
initialEstimate.insert(X(i), pose_i.compose(DELTA))
|
|
|
|
if i > 0:
|
|
# Add Bias variables periodically
|
|
if i % 5 == 0:
|
|
biasKey += 1
|
|
factor = BetweenFactorConstantBias(
|
|
biasKey - 1, biasKey, gtsam.imuBias.ConstantBias(), BIAS_COVARIANCE)
|
|
graph.add(factor)
|
|
initialEstimate.insert(biasKey, gtsam.imuBias.ConstantBias())
|
|
|
|
# Predict acceleration and gyro measurements in (actual) body frame
|
|
nRb = scenario.rotation(t).matrix()
|
|
bRn = np.transpose(nRb)
|
|
measuredAcc = scenario.acceleration_b(t) - np.dot(bRn, n_gravity)
|
|
measuredOmega = scenario.omega_b(t)
|
|
accum.integrateMeasurement(measuredAcc, measuredOmega, delta_t)
|
|
|
|
# Add Imu Factor
|
|
imufac = ImuFactor(X(i - 1), V(i - 1), X(i), V(i), biasKey, accum)
|
|
graph.add(imufac)
|
|
|
|
# insert new velocity, which is wrong
|
|
initialEstimate.insert(V(i), n_velocity)
|
|
accum.resetIntegration()
|
|
|
|
# Incremental solution
|
|
isam.update(graph, initialEstimate)
|
|
result = isam.calculateEstimate()
|
|
plot.plot_incremental_trajectory(0, result,
|
|
start=i, scale=3, time_interval=0.01)
|
|
|
|
# reset
|
|
graph = NonlinearFactorGraph()
|
|
initialEstimate.clear()
|
|
|
|
plt.show()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
IMU_example()
|