Adding imuSimulator directory from old branch for new imu factors
parent
fe55148dd7
commit
29ae7226bc
|
@ -0,0 +1,7 @@
|
|||
function S = antisim(v)
|
||||
|
||||
% costruisce la matrice antisimmetrica S (3x3) a partire dal vettore v
|
||||
% Uso: S = antisim(v)
|
||||
|
||||
S=[0 -v(3) v(2); v(3) 0 -v(1); -v(2) v(1) 0];
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
function arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio, rhoRatio)
|
||||
|
||||
% arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%
|
||||
% Used to plot a single 3D arrow with a cylindrical stem and cone arrowhead
|
||||
% pos = [X,Y,Z] - spatial location of the starting point of the arrow (end of stem)
|
||||
% deltaValues = [QX,QY,QZ] - delta parameters denoting the magnitude of the arrow along the x,y,z-axes (relative to 'pos')
|
||||
% colorCode - Color parameters as per the 'surf' command. For example, 'r', 'red', [1 0 0] are all examples of a red-colored arrow
|
||||
% stemRatio - The ratio of the length of the stem in proportion to the arrowhead. For example, a call of:
|
||||
% arrow3D([0,0,0], [100,0,0] , 'r', 0.82) will produce a red arrow of magnitude 100, with the arrowstem spanning a distance
|
||||
% of 82 (note 0.82 ratio of length 100) while the arrowhead (cone) spans 18.
|
||||
% rhoRatio - The ratio of the cylinder radius (0.05 is the default)
|
||||
% value)
|
||||
%
|
||||
% Example:
|
||||
% arrow3D([0,0,0], [4,3,7]); %---- arrow with default parameters
|
||||
% axis equal;
|
||||
%
|
||||
% Author: Shawn Arseneau
|
||||
% Created: September 14, 2006
|
||||
% Updated: September 18, 2006
|
||||
%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
if nargin<2 || nargin>5
|
||||
error('Incorrect number of inputs to arrow3D');
|
||||
end
|
||||
if numel(pos)~=3 || numel(deltaValues)~=3
|
||||
error('pos and/or deltaValues is incorrect dimensions (should be three)');
|
||||
end
|
||||
if nargin<3
|
||||
colorCode = 'interp';
|
||||
end
|
||||
if nargin<4
|
||||
stemRatio = 0.75;
|
||||
end
|
||||
if nargin<5
|
||||
rhoRatio = 0.05;
|
||||
end
|
||||
|
||||
X = pos(1); %---- with this notation, there is no need to transpose if the user has chosen a row vs col vector
|
||||
Y = pos(2);
|
||||
Z = pos(3);
|
||||
|
||||
[sphi, stheta, srho] = cart2sph(deltaValues(1), deltaValues(2), deltaValues(3));
|
||||
|
||||
%******************************************* CYLINDER == STEM *********************************************
|
||||
cylinderRadius = srho*rhoRatio;
|
||||
cylinderLength = srho*stemRatio;
|
||||
[CX,CY,CZ] = cylinder(cylinderRadius);
|
||||
CZ = CZ.*cylinderLength; %---- lengthen
|
||||
|
||||
%----- ROTATE CYLINDER
|
||||
[row, col] = size(CX); %---- initial rotation to coincide with X-axis
|
||||
|
||||
newEll = rotatePoints([0 0 -1], [CX(:), CY(:), CZ(:)]);
|
||||
CX = reshape(newEll(:,1), row, col);
|
||||
CY = reshape(newEll(:,2), row, col);
|
||||
CZ = reshape(newEll(:,3), row, col);
|
||||
|
||||
[row, col] = size(CX);
|
||||
newEll = rotatePoints(deltaValues, [CX(:), CY(:), CZ(:)]);
|
||||
stemX = reshape(newEll(:,1), row, col);
|
||||
stemY = reshape(newEll(:,2), row, col);
|
||||
stemZ = reshape(newEll(:,3), row, col);
|
||||
|
||||
%----- TRANSLATE CYLINDER
|
||||
stemX = stemX + X;
|
||||
stemY = stemY + Y;
|
||||
stemZ = stemZ + Z;
|
||||
|
||||
%******************************************* CONE == ARROWHEAD *********************************************
|
||||
coneLength = srho*(1-stemRatio);
|
||||
coneRadius = cylinderRadius*1.5;
|
||||
incr = 4; %---- Steps of cone increments
|
||||
coneincr = coneRadius/incr;
|
||||
[coneX, coneY, coneZ] = cylinder(cylinderRadius*2:-coneincr:0); %---------- CONE
|
||||
coneZ = coneZ.*coneLength;
|
||||
|
||||
%----- ROTATE CONE
|
||||
[row, col] = size(coneX);
|
||||
newEll = rotatePoints([0 0 -1], [coneX(:), coneY(:), coneZ(:)]);
|
||||
coneX = reshape(newEll(:,1), row, col);
|
||||
coneY = reshape(newEll(:,2), row, col);
|
||||
coneZ = reshape(newEll(:,3), row, col);
|
||||
|
||||
newEll = rotatePoints(deltaValues, [coneX(:), coneY(:), coneZ(:)]);
|
||||
headX = reshape(newEll(:,1), row, col);
|
||||
headY = reshape(newEll(:,2), row, col);
|
||||
headZ = reshape(newEll(:,3), row, col);
|
||||
|
||||
%---- TRANSLATE CONE
|
||||
V = [0, 0, srho*stemRatio]; %---- centerline for cylinder: the multiplier is to set the cone 'on the rim' of the cylinder
|
||||
Vp = rotatePoints([0 0 -1], V);
|
||||
Vp = rotatePoints(deltaValues, Vp);
|
||||
headX = headX + Vp(1) + X;
|
||||
headY = headY + Vp(2) + Y;
|
||||
headZ = headZ + Vp(3) + Z;
|
||||
%************************************************************************************************************
|
||||
hStem = surf(stemX, stemY, stemZ, 'FaceColor', colorCode, 'EdgeColor', 'none');
|
||||
hold on;
|
||||
hHead = surf(headX, headY, headZ, 'FaceColor', colorCode, 'EdgeColor', 'none');
|
||||
|
||||
if nargout==1
|
||||
arrowHandle = [hStem, hHead];
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
function [c] = getxyz(poses, j)
|
||||
% The function extract the Cartesian variables from pose (pose.p = positions,
|
||||
% pose.R = rotations). In particular, if there are T poses,
|
||||
% - getxyz(pose, 1) estracts the vector x \in R^T,
|
||||
% - getxyz(pose, 2) estracts the vector y \in R^T,
|
||||
% - getxyz(pose, 3) estracts the vector z \in R^T.
|
||||
|
||||
L = length(poses);
|
||||
c = [];
|
||||
for i=1:L % for each pose
|
||||
c = [c poses(i).p(j)];
|
||||
end
|
||||
|
||||
c = c(:); % column vector
|
|
@ -0,0 +1,19 @@
|
|||
function [] = plot_trajectory(pose, step, color, plot_name,a,b,c)
|
||||
% Plot a collection of poses: positions are connected by a solid line
|
||||
% of color "color" and it is shown a ref frame for each pose.
|
||||
% Plot_name defines the name of the created figure.
|
||||
|
||||
x = getxyz(pose,1);
|
||||
y = getxyz(pose,2);
|
||||
z = getxyz(pose,3);
|
||||
plot3(x,y,z,color)
|
||||
n = length(x)-1;
|
||||
hold on
|
||||
for i=1:step:n+1
|
||||
ref_frame_plot(pose(i).R,pose(i).p,a,b,c)
|
||||
end
|
||||
title(plot_name);
|
||||
xlabel('x')
|
||||
ylabel('y')
|
||||
zlabel('z')
|
||||
view(3)
|
|
@ -0,0 +1,54 @@
|
|||
function ref_frame_plot(Ref,OriginRef,rhoRatio,stemRatio,axsize)
|
||||
% ref_frame plot a 3D representation of a reference frame
|
||||
% given by three unit vectors
|
||||
%
|
||||
% ref_frame(Ref,DimSpace,OriginRef)
|
||||
% Ref is a 3 x 3 orthogonal matrix representing the unit vectors
|
||||
% of the reference frame to be drawn
|
||||
% DimSpace is a 3 x 2 matrix with min an max dimensions of the space
|
||||
% [xmin xmax; ymin ymax; zmin zmax]
|
||||
% default value = [-1,5 +1.5] for all dimensions
|
||||
% OriginRef is the reference frame origin point
|
||||
% default value = [0 0 0]'
|
||||
|
||||
% Copright (C) Basilio Bona 2007
|
||||
|
||||
n=nargin;
|
||||
if n == 1
|
||||
OriginRef=[0 0 0]';
|
||||
colorcode=['r','g','b'];
|
||||
rhoRatio=0.05;
|
||||
stemRatio=0.75;
|
||||
axsize=1;
|
||||
end
|
||||
if n == 2
|
||||
colorcode=['r','g','b'];
|
||||
rhoRatio=0.05;
|
||||
stemRatio=0.75;
|
||||
axsize=1;
|
||||
end
|
||||
if n == 3
|
||||
colorcode=['r','g','b'];
|
||||
stemRatio=0.75;
|
||||
axsize=1;
|
||||
end
|
||||
|
||||
if n == 4
|
||||
colorcode=['r','g','b'];
|
||||
axsize=1;
|
||||
end
|
||||
|
||||
if n == 5
|
||||
colorcode=['r','g','b'];
|
||||
end
|
||||
|
||||
|
||||
% xproj=DimSpace(1,2); yproj=DimSpace(2,2); zproj=DimSpace(3,1);
|
||||
|
||||
%hold off;
|
||||
arrow3d(OriginRef, axsize*Ref(:,1), colorcode(1), stemRatio, rhoRatio);
|
||||
arrow3d(OriginRef, axsize*Ref(:,2), colorcode(2), stemRatio, rhoRatio);
|
||||
arrow3d(OriginRef, axsize*Ref(:,3), colorcode(3), stemRatio, rhoRatio);
|
||||
axis equal; xlabel('X'); ylabel('Y'); zlabel('Z');
|
||||
% lighting phong;
|
||||
% camlight left;
|
|
@ -0,0 +1,82 @@
|
|||
function rotatedData = rotatePoints(alignmentVector, originalData)
|
||||
|
||||
% rotatedData = rotatePoints(alignmentVector, originalData) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%
|
||||
% Rotate the 'originalData' in the form of Nx2 or Nx3 about the origin by aligning the x-axis with the alignment vector
|
||||
%
|
||||
% Rdata = rotatePoints([1,2,-1], [Xpts(:), Ypts(:), Zpts(:)]) - rotate the (X,Y,Z)pts in 3D with respect to the vector [1,2,-1]
|
||||
%
|
||||
% Rotating using spherical components can be done by first converting using [dX,dY,dZ] = cart2sph(theta, phi, rho); alignmentVector = [dX,dY,dZ];
|
||||
%
|
||||
% Example:
|
||||
% %% Rotate the point [3,4,-7] with respect to the following:
|
||||
% %%%% Original associated vector is always [1,0,0]
|
||||
% %%%% Calculate the appropriate rotation requested with respect to the x-axis. For example, if only a rotation about the z-axis is
|
||||
% %%%% sought, alignmentVector = [2,1,0] %% Note that the z-component is zero
|
||||
% rotData = rotatePoints(alignmentVector, [3,4,-7]);
|
||||
%
|
||||
% Author: Shawn Arseneau
|
||||
% Created: Feb.2, 2006
|
||||
%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
alignmentDim = numel(alignmentVector);
|
||||
DOF = size(originalData,2); %---- DOF = Degrees of Freedom (i.e. 2 for two dimensional and 3 for three dimensional data)
|
||||
|
||||
if alignmentDim~=DOF
|
||||
error('Alignment vector does not agree with originalData dimensions');
|
||||
end
|
||||
if DOF<2 || DOF>3
|
||||
error('rotatePoints only does rotation in two or three dimensions');
|
||||
end
|
||||
|
||||
|
||||
if DOF==2 % 2D rotation...
|
||||
[rad_theta, rho] = cart2pol(alignmentVector(1), alignmentVector(2));
|
||||
deg_theta = -1 * rad_theta * (180/pi);
|
||||
ctheta = cosd(deg_theta); stheta = sind(deg_theta);
|
||||
|
||||
Rmatrix = [ctheta, -1.*stheta;...
|
||||
stheta, ctheta];
|
||||
rotatedData = originalData*Rmatrix;
|
||||
|
||||
else % 3D rotation...
|
||||
[rad_theta, rad_phi, rho] = cart2sph(alignmentVector(1), alignmentVector(2), alignmentVector(3));
|
||||
rad_theta = rad_theta * -1;
|
||||
deg_theta = rad_theta * (180/pi);
|
||||
deg_phi = rad_phi * (180/pi);
|
||||
ctheta = cosd(deg_theta); stheta = sind(deg_theta);
|
||||
Rz = [ctheta, -1.*stheta, 0;...
|
||||
stheta, ctheta, 0;...
|
||||
0, 0, 1]; %% First rotate as per theta around the Z axis
|
||||
rotatedData = originalData*Rz;
|
||||
|
||||
[rotX, rotY, rotZ] = sph2cart(-1* (rad_theta+(pi/2)), 0, 1); %% Second rotation corresponding to phi
|
||||
rotationAxis = [rotX, rotY, rotZ];
|
||||
u = rotationAxis(:)/norm(rotationAxis); %% Code extract from rotate.m from MATLAB
|
||||
cosPhi = cosd(deg_phi);
|
||||
sinPhi = sind(deg_phi);
|
||||
invCosPhi = 1 - cosPhi;
|
||||
x = u(1);
|
||||
y = u(2);
|
||||
z = u(3);
|
||||
Rmatrix = [cosPhi+x^2*invCosPhi x*y*invCosPhi-z*sinPhi x*z*invCosPhi+y*sinPhi; ...
|
||||
x*y*invCosPhi+z*sinPhi cosPhi+y^2*invCosPhi y*z*invCosPhi-x*sinPhi; ...
|
||||
x*z*invCosPhi-y*sinPhi y*z*invCosPhi+x*sinPhi cosPhi+z^2*invCosPhi]';
|
||||
|
||||
rotatedData = rotatedData*Rmatrix;
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
function R = uth2rot(u,teta)
|
||||
|
||||
% Uso: R = uth2rot(u,teta)
|
||||
%
|
||||
% calcola la matrice R
|
||||
% a partire da asse u ed angolo di rotazione teta (in rad)
|
||||
|
||||
S=antisim(u);
|
||||
t=teta;
|
||||
|
||||
n=norm(u);
|
||||
|
||||
R = eye(3) + sin(t)/n*S + (1-cos(t))/n^2*S^2;
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
import gtsam.*;
|
||||
|
||||
deltaT = 0.001;
|
||||
summarizedDeltaT = 0.1;
|
||||
timeElapsed = 1;
|
||||
times = 0:deltaT:timeElapsed;
|
||||
|
||||
omega = [0;0;2*pi];
|
||||
velocity = [1;0;0];
|
||||
|
||||
summaryTemplate = gtsam.ImuFactorPreintegratedMeasurements( ...
|
||||
gtsam.imuBias.ConstantBias([0;0;0], [0;0;0]), ...
|
||||
1e-3 * eye(3), 1e-3 * eye(3), 1e-3 * eye(3));
|
||||
|
||||
%% Set initial conditions for the true trajectory and for the estimates
|
||||
% (one estimate is obtained by integrating in the body frame, the other
|
||||
% by integrating in the navigation frame)
|
||||
% Initial state (body)
|
||||
currentPoseGlobal = Pose3;
|
||||
currentVelocityGlobal = velocity;
|
||||
% Initial state estimate (integrating in navigation frame)
|
||||
currentPoseGlobalIMUnav = currentPoseGlobal;
|
||||
currentVelocityGlobalIMUnav = currentVelocityGlobal;
|
||||
% Initial state estimate (integrating in the body frame)
|
||||
currentPoseGlobalIMUbody = currentPoseGlobal;
|
||||
currentVelocityGlobalIMUbody = currentVelocityGlobal;
|
||||
|
||||
%% Prepare data structures for actual trajectory and estimates
|
||||
% Actual trajectory
|
||||
positions = zeros(3, length(times)+1);
|
||||
positions(:,1) = currentPoseGlobal.translation.vector;
|
||||
poses(1).p = positions(:,1);
|
||||
poses(1).R = currentPoseGlobal.rotation.matrix;
|
||||
|
||||
% Trajectory estimate (integrated in the navigation frame)
|
||||
positionsIMUnav = zeros(3, length(times)+1);
|
||||
positionsIMUnav(:,1) = currentPoseGlobalIMUbody.translation.vector;
|
||||
posesIMUnav(1).p = positionsIMUnav(:,1);
|
||||
posesIMUnav(1).R = poses(1).R;
|
||||
|
||||
% Trajectory estimate (integrated in the body frame)
|
||||
positionsIMUbody = zeros(3, length(times)+1);
|
||||
positionsIMUbody(:,1) = currentPoseGlobalIMUbody.translation.vector;
|
||||
posesIMUbody(1).p = positionsIMUbody(:,1);
|
||||
posesIMUbody(1).R = poses(1).R;
|
||||
|
||||
%% Solver object
|
||||
isamParams = ISAM2Params;
|
||||
isamParams.setRelinearizeSkip(1);
|
||||
isam = gtsam.ISAM2(isamParams);
|
||||
|
||||
initialValues = Values;
|
||||
initialValues.insert(symbol('x',0), currentPoseGlobal);
|
||||
initialValues.insert(symbol('v',0), LieVector(currentVelocityGlobal));
|
||||
initialValues.insert(symbol('b',0), imuBias.ConstantBias([0;0;0],[0;0;0]));
|
||||
initialFactors = NonlinearFactorGraph;
|
||||
initialFactors.add(PriorFactorPose3(symbol('x',0), ...
|
||||
currentPoseGlobal, noiseModel.Isotropic.Sigma(6, 1.0)));
|
||||
initialFactors.add(PriorFactorLieVector(symbol('v',0), ...
|
||||
LieVector(currentVelocityGlobal), noiseModel.Isotropic.Sigma(3, 1.0)));
|
||||
initialFactors.add(PriorFactorConstantBias(symbol('b',0), ...
|
||||
imuBias.ConstantBias([0;0;0],[0;0;0]), noiseModel.Isotropic.Sigma(6, 1.0)));
|
||||
|
||||
%% Main loop
|
||||
i = 2;
|
||||
lastSummaryTime = 0;
|
||||
lastSummaryIndex = 0;
|
||||
currentSummarizedMeasurement = ImuFactorPreintegratedMeasurements(summaryTemplate);
|
||||
for t = times
|
||||
%% Create the actual trajectory, using the velocities and
|
||||
% accelerations in the inertial frame to compute the positions
|
||||
[ currentPoseGlobal, currentVelocityGlobal ] = imuSimulator.integrateTrajectory( ...
|
||||
currentPoseGlobal, omega, velocity, velocity, deltaT);
|
||||
|
||||
%% Simulate IMU measurements, considering Coriolis effect
|
||||
% (in this simple example we neglect gravity and there are no other forces acting on the body)
|
||||
acc_omega = imuSimulator.calculateIMUMeas_coriolis( ...
|
||||
omega, omega, velocity, velocity, deltaT);
|
||||
|
||||
%% Accumulate preintegrated measurement
|
||||
currentSummarizedMeasurement.integrateMeasurement(acc_omega(1:3), acc_omega(4:6), deltaT);
|
||||
|
||||
%% Update solver
|
||||
if t - lastSummaryTime >= summarizedDeltaT
|
||||
% Create IMU factor
|
||||
initialFactors.add(ImuFactor( ...
|
||||
symbol('x',lastSummaryIndex), symbol('v',lastSummaryIndex), ...
|
||||
symbol('x',lastSummaryIndex+1), symbol('v',lastSummaryIndex+1), ...
|
||||
symbol('b',0), currentSummarizedMeasurement, [0;0;1], [0;0;0], ...
|
||||
noiseModel.Isotropic.Sigma(9, 1e-6)));
|
||||
|
||||
% Predict movement in a straight line (bad initialization)
|
||||
if lastSummaryIndex > 0
|
||||
initialPose = isam.calculateEstimate(symbol('x',lastSummaryIndex)) ...
|
||||
.compose(Pose3(Rot3, Point3( velocity * t - lastSummaryTime) ));
|
||||
initialVel = isam.calculateEstimate(symbol('v',lastSummaryIndex));
|
||||
else
|
||||
initialPose = Pose3;
|
||||
initialVel = LieVector(velocity);
|
||||
end
|
||||
initialValues.insert(symbol('x',lastSummaryIndex+1), initialPose);
|
||||
initialValues.insert(symbol('v',lastSummaryIndex+1), initialVel);
|
||||
|
||||
% Update solver
|
||||
isam.update(initialFactors, initialValues);
|
||||
initialFactors = NonlinearFactorGraph;
|
||||
initialValues = Values;
|
||||
|
||||
lastSummaryIndex = lastSummaryIndex + 1;
|
||||
lastSummaryTime = t;
|
||||
currentSummarizedMeasurement = ImuFactorPreintegratedMeasurements(summaryTemplate);
|
||||
end
|
||||
|
||||
%% Integrate in the body frame
|
||||
[ currentPoseGlobalIMUbody, currentVelocityGlobalIMUbody ] = imuSimulator.integrateIMUTrajectory_bodyFrame( ...
|
||||
currentPoseGlobalIMUbody, currentVelocityGlobalIMUbody, acc_omega, deltaT, velocity);
|
||||
|
||||
%% Integrate in the navigation frame
|
||||
[ currentPoseGlobalIMUnav, currentVelocityGlobalIMUnav ] = imuSimulator.integrateIMUTrajectory_navFrame( ...
|
||||
currentPoseGlobalIMUnav, currentVelocityGlobalIMUnav, acc_omega, deltaT);
|
||||
|
||||
%% Store data in some structure for statistics and plots
|
||||
positions(:,i) = currentPoseGlobal.translation.vector;
|
||||
positionsIMUbody(:,i) = currentPoseGlobalIMUbody.translation.vector;
|
||||
positionsIMUnav(:,i) = currentPoseGlobalIMUnav.translation.vector;
|
||||
% -
|
||||
poses(i).p = positions(:,i);
|
||||
posesIMUbody(i).p = positionsIMUbody(:,i);
|
||||
posesIMUnav(i).p = positionsIMUnav(:,i);
|
||||
% -
|
||||
poses(i).R = currentPoseGlobal.rotation.matrix;
|
||||
posesIMUbody(i).R = currentPoseGlobalIMUbody.rotation.matrix;
|
||||
posesIMUnav(i).R = currentPoseGlobalIMUnav.rotation.matrix;
|
||||
i = i + 1;
|
||||
end
|
||||
|
||||
figure(1)
|
||||
hold on;
|
||||
plot(positions(1,:), positions(2,:), '-b');
|
||||
plot(positionsIMUbody(1,:), positionsIMUbody(2,:), '-r');
|
||||
plot(positionsIMUnav(1,:), positionsIMUnav(2,:), ':k');
|
||||
plot3DTrajectory(isam.calculateEstimate, 'g-');
|
||||
axis equal;
|
||||
legend('true trajectory', 'traj integrated in body', 'traj integrated in nav')
|
||||
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
close all
|
||||
clc
|
||||
|
||||
import gtsam.*;
|
||||
|
||||
deltaT = 0.001;
|
||||
summarizedDeltaT = 0.1;
|
||||
timeElapsed = 1;
|
||||
times = 0:deltaT:timeElapsed;
|
||||
|
||||
omega = [0;0;2*pi];
|
||||
velocity = [1;0;0];
|
||||
|
||||
g = [0;0;0];
|
||||
cor_v = [0;0;0];
|
||||
|
||||
summaryTemplate = gtsam.ImuFactorPreintegratedMeasurements( ...
|
||||
gtsam.imuBias.ConstantBias([0;0;0], [0;0;0]), ...
|
||||
1e-3 * eye(3), 1e-3 * eye(3), 1e-3 * eye(3));
|
||||
|
||||
%% Set initial conditions for the true trajectory and for the estimates
|
||||
% (one estimate is obtained by integrating in the body frame, the other
|
||||
% by integrating in the navigation frame)
|
||||
% Initial state (body)
|
||||
currentPoseGlobal = Pose3;
|
||||
currentVelocityGlobal = velocity;
|
||||
|
||||
%% Prepare data structures for actual trajectory and estimates
|
||||
% Actual trajectory
|
||||
positions = zeros(3, length(times)+1);
|
||||
positions(:,1) = currentPoseGlobal.translation.vector;
|
||||
poses(1).p = positions(:,1);
|
||||
poses(1).R = currentPoseGlobal.rotation.matrix;
|
||||
|
||||
%% Solver object
|
||||
isamParams = ISAM2Params;
|
||||
isamParams.setRelinearizeSkip(1);
|
||||
isam = gtsam.ISAM2(isamParams);
|
||||
|
||||
sigma_init_x = 1.0;
|
||||
sigma_init_v = 1.0;
|
||||
sigma_init_b = 1.0;
|
||||
|
||||
initialValues = Values;
|
||||
initialValues.insert(symbol('x',0), currentPoseGlobal);
|
||||
initialValues.insert(symbol('v',0), LieVector(currentVelocityGlobal));
|
||||
initialValues.insert(symbol('b',0), imuBias.ConstantBias([0;0;0],[0;0;0]));
|
||||
initialFactors = NonlinearFactorGraph;
|
||||
% Prior on initial pose
|
||||
initialFactors.add(PriorFactorPose3(symbol('x',0), ...
|
||||
currentPoseGlobal, noiseModel.Isotropic.Sigma(6, sigma_init_x)));
|
||||
% Prior on initial velocity
|
||||
initialFactors.add(PriorFactorLieVector(symbol('v',0), ...
|
||||
LieVector(currentVelocityGlobal), noiseModel.Isotropic.Sigma(3, sigma_init_v)));
|
||||
% Prior on initial bias
|
||||
initialFactors.add(PriorFactorConstantBias(symbol('b',0), ...
|
||||
imuBias.ConstantBias([0;0;0],[0;0;0]), noiseModel.Isotropic.Sigma(6, sigma_init_b)));
|
||||
|
||||
%% Main loop
|
||||
i = 2;
|
||||
lastSummaryTime = 0;
|
||||
lastSummaryIndex = 0;
|
||||
currentSummarizedMeasurement = ImuFactorPreintegratedMeasurements(summaryTemplate);
|
||||
for t = times
|
||||
%% Create the ground truth trajectory, using the velocities and accelerations in the inertial frame to compute the positions
|
||||
[ currentPoseGlobal, currentVelocityGlobal ] = imuSimulator.integrateTrajectory( ...
|
||||
currentPoseGlobal, omega, velocity, velocity, deltaT);
|
||||
|
||||
%% Simulate IMU measurements, considering Coriolis effect
|
||||
% (in this simple example we neglect gravity and there are no other forces acting on the body)
|
||||
acc_omega = imuSimulator.calculateIMUMeas_coriolis( ...
|
||||
omega, omega, velocity, velocity, deltaT);
|
||||
|
||||
%% Accumulate preintegrated measurement
|
||||
currentSummarizedMeasurement.integrateMeasurement(acc_omega(1:3), acc_omega(4:6), deltaT);
|
||||
|
||||
%% Update solver
|
||||
if t - lastSummaryTime >= summarizedDeltaT
|
||||
|
||||
% Create IMU factor
|
||||
initialFactors.add(ImuFactor( ...
|
||||
symbol('x',lastSummaryIndex), symbol('v',lastSummaryIndex), ...
|
||||
symbol('x',lastSummaryIndex+1), symbol('v',lastSummaryIndex+1), ...
|
||||
symbol('b',0), currentSummarizedMeasurement, g, cor_v, ...
|
||||
noiseModel.Isotropic.Sigma(9, 1e-6)));
|
||||
|
||||
% Predict movement in a straight line (bad initialization)
|
||||
if lastSummaryIndex > 0
|
||||
initialPose = isam.calculateEstimate(symbol('x',lastSummaryIndex)) ...
|
||||
.compose(Pose3(Rot3, Point3( velocity * t - lastSummaryTime) ));
|
||||
initialVel = isam.calculateEstimate(symbol('v',lastSummaryIndex));
|
||||
else
|
||||
initialPose = Pose3;
|
||||
initialVel = LieVector(velocity);
|
||||
end
|
||||
initialValues.insert(symbol('x',lastSummaryIndex+1), initialPose);
|
||||
initialValues.insert(symbol('v',lastSummaryIndex+1), initialVel);
|
||||
|
||||
key_pose = symbol('x',lastSummaryIndex+1);
|
||||
|
||||
% Update solver
|
||||
isam.update(initialFactors, initialValues);
|
||||
initialFactors = NonlinearFactorGraph;
|
||||
initialValues = Values;
|
||||
|
||||
isam.calculateEstimate(key_pose);
|
||||
M = isam.marginalCovariance(key_pose);
|
||||
|
||||
lastSummaryIndex = lastSummaryIndex + 1;
|
||||
lastSummaryTime = t;
|
||||
currentSummarizedMeasurement = ImuFactorPreintegratedMeasurements(summaryTemplate);
|
||||
end
|
||||
|
||||
%% Store data in some structure for statistics and plots
|
||||
positions(:,i) = currentPoseGlobal.translation.vector;
|
||||
i = i + 1;
|
||||
end
|
||||
|
||||
figure(1)
|
||||
hold on;
|
||||
plot(positions(1,:), positions(2,:), '-b');
|
||||
plot3DTrajectory(isam.calculateEstimate, 'g-');
|
||||
|
||||
|
||||
axis equal;
|
||||
legend('true trajectory', 'traj integrated in body', 'traj integrated in nav')
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
function [ acc_omega ] = calculateIMUMeas_coriolis(omega1Body, omega2Body, velocity1Body, velocity2Body, deltaT)
|
||||
|
||||
import gtsam.*;
|
||||
|
||||
% gyro measured rotation rate
|
||||
measuredOmega = omega1Body;
|
||||
|
||||
% Acceleration measurement (in this simple toy example no other forces
|
||||
% act on the body and the only acceleration is the centripetal Coriolis acceleration)
|
||||
measuredAcc = Point3(cross(omega1Body, velocity1Body)).vector;
|
||||
acc_omega = [ measuredAcc; measuredOmega ];
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
function [ acc_omega ] = calculateIMUMeasurement(omega1Body, omega2Body, velocity1Body, velocity2Body, deltaT, imuFrame)
|
||||
%CALCULATEIMUMEASUREMENT Calculate measured body frame acceleration in
|
||||
%frame 1 and measured angular rates in frame 1.
|
||||
|
||||
import gtsam.*;
|
||||
|
||||
% Calculate gyro measured rotation rate by transforming body rotation rate
|
||||
% into the IMU frame.
|
||||
measuredOmega = imuFrame.rotation.unrotate(Point3(omega1Body)).vector;
|
||||
|
||||
% Transform both velocities into IMU frame, accounting for the velocity
|
||||
% induced by rigid body rotation on a lever arm (Coriolis effect).
|
||||
velocity1inertial = imuFrame.rotation.unrotate( ...
|
||||
Point3(velocity1Body + cross(omega1Body, imuFrame.translation.vector))).vector;
|
||||
|
||||
imu2in1 = Rot3.Expmap(measuredOmega * deltaT);
|
||||
velocity2inertial = imu2in1.rotate(imuFrame.rotation.unrotate( ...
|
||||
Point3(velocity2Body + cross(omega2Body, imuFrame.translation.vector)))).vector;
|
||||
|
||||
% Acceleration in IMU frame
|
||||
measuredAcc = (velocity2inertial - velocity1inertial) / deltaT;
|
||||
|
||||
acc_omega = [ measuredAcc; measuredOmega ];
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
function [ finalPose, finalVelocityGlobal ] = integrateIMUTrajectory( ...
|
||||
initialPoseGlobal, initialVelocityGlobal, acc_omegaIMU, deltaT)
|
||||
%INTEGRATETRAJECTORY Integrate one trajectory step from IMU measurement
|
||||
|
||||
import gtsam.*;
|
||||
|
||||
imu2in1 = Rot3.Expmap(acc_omegaIMU(4:6) * deltaT);
|
||||
accelGlobal = initialPoseGlobal.rotation().rotate(Point3(acc_omegaIMU(1:3))).vector;
|
||||
|
||||
finalPosition = Point3(initialPoseGlobal.translation.vector ...
|
||||
+ initialVelocityGlobal * deltaT + 0.5 * accelGlobal * deltaT * deltaT);
|
||||
finalVelocityGlobal = initialVelocityGlobal + accelGlobal * deltaT;
|
||||
finalRotation = initialPoseGlobal.rotation.compose(imu2in1);
|
||||
finalPose = Pose3(finalRotation, finalPosition);
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
function [ finalPose, finalVelocityGlobal ] = integrateIMUTrajectory_bodyFrame( ...
|
||||
initialPoseGlobal, initialVelocityGlobal, acc_omegaIMU, deltaT, velocity1Body)
|
||||
|
||||
% Before integrating in the body frame we need to compensate for the Coriolis
|
||||
% effect
|
||||
acc_body = acc_omegaIMU(1:3) - Point3(cross(acc_omegaIMU(4:6), velocity1Body)).vector;
|
||||
% after compensating for coriolis this will be essentially zero
|
||||
% since we are moving at constant body velocity
|
||||
|
||||
import gtsam.*;
|
||||
%% Integrate in the body frame
|
||||
% Integrate rotations
|
||||
imu2in1 = Rot3.Expmap(acc_omegaIMU(4:6) * deltaT);
|
||||
% Integrate positions
|
||||
finalPositionBody = velocity1Body * deltaT + 0.5 * acc_body * deltaT * deltaT;
|
||||
finalVelocityBody = velocity1Body + acc_body * deltaT;
|
||||
|
||||
%% Express the integrated quantities in the global frame
|
||||
finalVelocityGlobal = initialVelocityGlobal + (initialPoseGlobal.rotation().rotate(Point3(finalVelocityBody)).vector() );
|
||||
finalPosition = initialPoseGlobal.translation().vector() + initialPoseGlobal.rotation().rotate( Point3(finalPositionBody)).vector() ;
|
||||
finalRotation = initialPoseGlobal.rotation.compose(imu2in1);
|
||||
% Include position and rotation in a pose
|
||||
finalPose = Pose3(finalRotation, Point3(finalPosition) );
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
function [ finalPose, finalVelocityGlobal ] = integrateIMUTrajectory_navFrame( ...
|
||||
initialPoseGlobal, initialVelocityGlobal, acc_omegaIMU, deltaT)
|
||||
%INTEGRATETRAJECTORY Integrate one trajectory step from IMU measurement
|
||||
|
||||
import gtsam.*;
|
||||
% Integrate rotations
|
||||
imu2in1 = Rot3.Expmap(acc_omegaIMU(4:6) * deltaT);
|
||||
finalRotation = initialPoseGlobal.rotation.compose(imu2in1);
|
||||
|
||||
intermediateRotation = initialPoseGlobal.rotation.compose( Rot3.Expmap(acc_omegaIMU(4:6) * deltaT/2 ));
|
||||
% Integrate positions (equation (1) in Lupton)
|
||||
accelGlobal = intermediateRotation.rotate(Point3(acc_omegaIMU(1:3))).vector;
|
||||
finalPosition = Point3(initialPoseGlobal.translation.vector ...
|
||||
+ initialVelocityGlobal * deltaT + 0.5 * accelGlobal * deltaT * deltaT);
|
||||
finalVelocityGlobal = initialVelocityGlobal + accelGlobal * deltaT;
|
||||
|
||||
% Include position and rotation in a pose
|
||||
finalPose = Pose3(finalRotation, finalPosition);
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
function [ finalPose, finalVelocityGlobal ] = integrateTrajectory( ...
|
||||
initialPose, omega1Body, velocity1Body, velocity2Body, deltaT)
|
||||
%INTEGRATETRAJECTORY Integrate one trajectory step
|
||||
|
||||
import gtsam.*;
|
||||
% Rotation: R^1_2
|
||||
body2in1 = Rot3.Expmap(omega1Body * deltaT);
|
||||
% Velocity 2 in frame 1: v^1_2 = R^1_2 v^2_2
|
||||
velocity2inertial = body2in1.rotate(Point3(velocity2Body)).vector;
|
||||
% Acceleration: a^1 = (v^1_2 - v^1_1)/dt
|
||||
accelBody1 = (velocity2inertial - velocity1Body) / deltaT;
|
||||
|
||||
% Velocity 1 in frame W: v^W_1 = R^W_1 v^1_1
|
||||
initialVelocityGlobal = initialPose.rotation().rotate(Point3(velocity1Body)).vector;
|
||||
% Acceleration in frame W: a^W = R^W_1 a^1
|
||||
accelGlobal = initialPose.rotation().rotate(Point3(accelBody1)).vector;
|
||||
|
||||
finalPosition = Point3(initialPose.translation.vector + initialVelocityGlobal * deltaT + 0.5 * accelGlobal * deltaT * deltaT);
|
||||
finalVelocityGlobal = initialVelocityGlobal + accelGlobal * deltaT;
|
||||
finalRotation = initialPose.rotation.compose(body2in1);
|
||||
finalPose = Pose3(finalRotation, finalPosition);
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import gtsam.*;
|
||||
|
||||
deltaT = 0.01;
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Constant global velocity w/ lever arm
|
||||
disp('--------------------------------------------------------');
|
||||
disp('Constant global velocity w/ lever arm');
|
||||
omega = [0;0;0.1];
|
||||
velocity = [1;0;0];
|
||||
R = Rot3.Expmap(omega * deltaT);
|
||||
|
||||
velocity2body = R.unrotate(Point3(velocity)).vector;
|
||||
acc_omegaExpected = [-0.01; 0; 0; 0; 0; 0.1];
|
||||
acc_omegaActual = imuSimulator.calculateIMUMeasurement(omega, omega, velocity, velocity2body, deltaT, Pose3(Rot3, Point3([1;0;0])));
|
||||
disp('IMU measurement discrepancy:');
|
||||
disp(acc_omegaActual - acc_omegaExpected);
|
||||
|
||||
initialPose = Pose3;
|
||||
finalPoseExpected = Pose3(Rot3.Expmap(omega * deltaT), Point3(velocity * deltaT));
|
||||
finalVelocityExpected = velocity;
|
||||
[ finalPoseActual, finalVelocityActual ] = imuSimulator.integrateTrajectory(initialPose, omega, velocity, velocity2body, deltaT);
|
||||
disp('Final pose discrepancy:');
|
||||
disp(finalPoseExpected.between(finalPoseActual).matrix);
|
||||
disp('Final velocity discrepancy:');
|
||||
disp(finalVelocityActual - finalVelocityExpected);
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Constant body velocity w/ lever arm
|
||||
disp('--------------------------------------------------------');
|
||||
disp('Constant body velocity w/ lever arm');
|
||||
omega = [0;0;0.1];
|
||||
velocity = [1;0;0];
|
||||
|
||||
acc_omegaExpected = [-0.01; 0.1; 0; 0; 0; 0.1];
|
||||
acc_omegaActual = imuSimulator.calculateIMUMeasurement(omega, omega, velocity, velocity, deltaT, Pose3(Rot3, Point3([1;0;0])));
|
||||
disp('IMU measurement discrepancy:');
|
||||
disp(acc_omegaActual - acc_omegaExpected);
|
||||
|
||||
initialPose = Pose3;
|
||||
initialVelocity = velocity;
|
||||
finalPoseExpected = Pose3.Expmap([ omega; velocity ] * deltaT);
|
||||
finalVelocityExpected = finalPoseExpected.rotation.rotate(Point3(velocity)).vector;
|
||||
[ finalPoseActual, finalVelocityActual ] = imuSimulator.integrateTrajectory(initialPose, omega, velocity, velocity, deltaT);
|
||||
disp('Final pose discrepancy:');
|
||||
disp(finalPoseExpected.between(finalPoseActual).matrix);
|
||||
disp('Final velocity discrepancy:');
|
||||
disp(finalVelocityActual - finalVelocityExpected);
|
|
@ -0,0 +1,34 @@
|
|||
import gtsam.*;
|
||||
|
||||
deltaT = 0.01;
|
||||
timeElapsed = 1000;
|
||||
|
||||
times = 0:deltaT:timeElapsed;
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Constant global velocity w/ lever arm
|
||||
disp('--------------------------------------------------------');
|
||||
disp('Constant global velocity w/ lever arm');
|
||||
omega = [0;0;0.1];
|
||||
velocity = [1;0;0];
|
||||
|
||||
% Initial state
|
||||
currentPoseGlobal = Pose3;
|
||||
currentVelocityGlobal = velocity;
|
||||
|
||||
% Positions
|
||||
positions = zeros(3, length(times)+1);
|
||||
|
||||
i = 2;
|
||||
for t = times
|
||||
velocity1body = currentPoseGlobal.rotation.unrotate(Point3(currentVelocityGlobal)).vector;
|
||||
R = Rot3.Expmap(omega * deltaT);
|
||||
velocity2body = currentPoseGlobal.rotation.compose(R).unrotate(Point3(currentVelocityGlobal)).vector;
|
||||
[ currentPoseGlobal, currentVelocityGlobal ] = imuSimulator.integrateTrajectory(currentPoseGlobal, omega, velocity1body, velocity2body, deltaT);
|
||||
|
||||
positions(:,i) = currentPoseGlobal.translation.vector;
|
||||
i = i + 1;
|
||||
end
|
||||
|
||||
figure;
|
||||
plot(positions(1,:), positions(2,:), '.-');
|
|
@ -0,0 +1,96 @@
|
|||
clc
|
||||
clear all
|
||||
close all
|
||||
|
||||
import gtsam.*;
|
||||
|
||||
addpath(genpath('./Libraries'))
|
||||
|
||||
deltaT = 0.01;
|
||||
timeElapsed = 25;
|
||||
|
||||
times = 0:deltaT:timeElapsed;
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Constant body velocity w/ lever arm
|
||||
disp('--------------------------------------------------------');
|
||||
disp('Constant body velocity w/ lever arm');
|
||||
omega = [0;0;0.1];
|
||||
velocity = [1;0;0];
|
||||
RIMUinBody = Rot3.Rz(-pi/2);
|
||||
% RIMUinBody = eye(3)
|
||||
IMUinBody = Pose3(RIMUinBody, Point3([1;0;0]));
|
||||
|
||||
% Initial state (body)
|
||||
currentPoseGlobal = Pose3;
|
||||
currentVelocityGlobal = velocity;
|
||||
% Initial state (IMU)
|
||||
currentPoseGlobalIMU = Pose3; %currentPoseGlobal.compose(IMUinBody);
|
||||
%currentVelocityGlobalIMU = IMUinBody.rotation.unrotate(Point3(velocity)).vector; % no Coriolis here?
|
||||
currentVelocityGlobalIMU = IMUinBody.rotation.unrotate( ...
|
||||
Point3(velocity + cross(omega, IMUinBody.translation.vector))).vector;
|
||||
|
||||
|
||||
% Positions
|
||||
% body trajectory
|
||||
positions = zeros(3, length(times)+1);
|
||||
positions(:,1) = currentPoseGlobal.translation.vector;
|
||||
poses(1).p = positions(:,1);
|
||||
poses(1).R = currentPoseGlobal.rotation.matrix;
|
||||
|
||||
% Expected IMU trajectory (from body trajectory and lever arm)
|
||||
positionsIMUe = zeros(3, length(times)+1);
|
||||
positionsIMUe(:,1) = IMUinBody.compose(currentPoseGlobalIMU).translation.vector;
|
||||
posesIMUe(1).p = positionsIMUe(:,1);
|
||||
posesIMUe(1).R = poses(1).R * IMUinBody.rotation.matrix;
|
||||
|
||||
% Integrated IMU trajectory (from IMU measurements)
|
||||
positionsIMU = zeros(3, length(times)+1);
|
||||
positionsIMU(:,1) = IMUinBody.compose(currentPoseGlobalIMU).translation.vector;
|
||||
posesIMU(1).p = positionsIMU(:,1);
|
||||
posesIMU(1).R = IMUinBody.compose(currentPoseGlobalIMU).rotation.matrix;
|
||||
|
||||
i = 2;
|
||||
for t = times
|
||||
[ currentPoseGlobal, currentVelocityGlobal ] = imuSimulator.integrateTrajectory( ...
|
||||
currentPoseGlobal, omega, velocity, velocity, deltaT);
|
||||
|
||||
acc_omega = imuSimulator.calculateIMUMeasurement( ...
|
||||
omega, omega, velocity, velocity, deltaT, IMUinBody);
|
||||
|
||||
[ currentPoseGlobalIMU, currentVelocityGlobalIMU ] = imuSimulator.integrateIMUTrajectory( ...
|
||||
currentPoseGlobalIMU, currentVelocityGlobalIMU, acc_omega, deltaT);
|
||||
|
||||
% Store data in some structure for statistics and plots
|
||||
positions(:,i) = currentPoseGlobal.translation.vector;
|
||||
positionsIMUe(:,i) = currentPoseGlobal.translation.vector + currentPoseGlobal.rotation.matrix * IMUinBody.translation.vector;
|
||||
positionsIMU(:,i) = IMUinBody.compose(currentPoseGlobalIMU).translation.vector;
|
||||
|
||||
poses(i).p = positions(:,i);
|
||||
posesIMUe(i).p = positionsIMUe(:,i);
|
||||
posesIMU(i).p = positionsIMU(:,i);
|
||||
|
||||
poses(i).R = currentPoseGlobal.rotation.matrix;
|
||||
posesIMUe(i).R = poses(i).R * IMUinBody.rotation.matrix;
|
||||
posesIMU(i).R = IMUinBody.compose(currentPoseGlobalIMU).rotation.matrix;
|
||||
i = i + 1;
|
||||
end
|
||||
|
||||
|
||||
figure(1)
|
||||
plot_trajectory(poses, 50, '-k', 'body trajectory',0.1,0.75,1)
|
||||
hold on
|
||||
plot_trajectory(posesIMU, 50, '-r', 'imu trajectory',0.1,0.75,1)
|
||||
|
||||
figure(2)
|
||||
hold on;
|
||||
plot(positions(1,:), positions(2,:), '-b');
|
||||
plot(positionsIMU(1,:), positionsIMU(2,:), '-r');
|
||||
plot(positionsIMUe(1,:), positionsIMUe(2,:), ':k');
|
||||
axis equal;
|
||||
|
||||
disp('Mismatch between final integrated IMU position and expected IMU position')
|
||||
disp(norm(posesIMUe(end).p - posesIMU(end).p))
|
||||
disp('Mismatch between final integrated IMU orientation and expected IMU orientation')
|
||||
disp(norm(posesIMUe(end).R - posesIMU(end).R))
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
clc
|
||||
clear all
|
||||
close all
|
||||
|
||||
import gtsam.*;
|
||||
|
||||
deltaT = 0.001;
|
||||
timeElapsed = 1;
|
||||
times = 0:deltaT:timeElapsed;
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
disp('--------------------------------------------------------');
|
||||
disp('Integration in body frame VS integration in navigation frame');
|
||||
disp('TOY EXAMPLE:');
|
||||
disp('- Body moves along a circular trajectory with constant rotation rate -omega- and constant -velocity- (in the body frame)');
|
||||
disp('- We compare two integration schemes: integating in the navigation frame (similar to Lupton approach) VS integrating in the body frame')
|
||||
disp('- Navigation frame is assumed inertial for simplicity')
|
||||
omega = [0;0;2*pi];
|
||||
velocity = [1;0;0];
|
||||
|
||||
%% Set initial conditions for the true trajectory and for the estimates
|
||||
% (one estimate is obtained by integrating in the body frame, the other
|
||||
% by integrating in the navigation frame)
|
||||
% Initial state (body)
|
||||
currentPoseGlobal = Pose3;
|
||||
currentVelocityGlobal = velocity;
|
||||
% Initial state estimate (integrating in navigation frame)
|
||||
currentPoseGlobalIMUnav = currentPoseGlobal;
|
||||
currentVelocityGlobalIMUnav = currentVelocityGlobal;
|
||||
% Initial state estimate (integrating in the body frame)
|
||||
currentPoseGlobalIMUbody = currentPoseGlobal;
|
||||
currentVelocityGlobalIMUbody = currentVelocityGlobal;
|
||||
|
||||
%% Prepare data structures for actual trajectory and estimates
|
||||
% Actual trajectory
|
||||
positions = zeros(3, length(times)+1);
|
||||
positions(:,1) = currentPoseGlobal.translation.vector;
|
||||
poses(1).p = positions(:,1);
|
||||
poses(1).R = currentPoseGlobal.rotation.matrix;
|
||||
|
||||
% Trajectory estimate (integrated in the navigation frame)
|
||||
positionsIMUnav = zeros(3, length(times)+1);
|
||||
positionsIMUnav(:,1) = currentPoseGlobalIMUbody.translation.vector;
|
||||
posesIMUnav(1).p = positionsIMUnav(:,1);
|
||||
posesIMUnav(1).R = poses(1).R;
|
||||
|
||||
% Trajectory estimate (integrated in the body frame)
|
||||
positionsIMUbody = zeros(3, length(times)+1);
|
||||
positionsIMUbody(:,1) = currentPoseGlobalIMUbody.translation.vector;
|
||||
posesIMUbody(1).p = positionsIMUbody(:,1);
|
||||
posesIMUbody(1).R = poses(1).R;
|
||||
|
||||
%% Main loop
|
||||
i = 2;
|
||||
for t = times
|
||||
%% Create the actual trajectory, using the velocities and
|
||||
% accelerations in the inertial frame to compute the positions
|
||||
[ currentPoseGlobal, currentVelocityGlobal ] = imuSimulator.integrateTrajectory( ...
|
||||
currentPoseGlobal, omega, velocity, velocity, deltaT);
|
||||
|
||||
%% Simulate IMU measurements, considering Coriolis effect
|
||||
% (in this simple example we neglect gravity and there are no other forces acting on the body)
|
||||
acc_omega = imuSimulator.calculateIMUMeas_coriolis( ...
|
||||
omega, omega, velocity, velocity, deltaT);
|
||||
|
||||
%% Integrate in the body frame
|
||||
[ currentPoseGlobalIMUbody, currentVelocityGlobalIMUbody ] = imuSimulator.integrateIMUTrajectory_bodyFrame( ...
|
||||
currentPoseGlobalIMUbody, currentVelocityGlobalIMUbody, acc_omega, deltaT, velocity);
|
||||
|
||||
%% Integrate in the navigation frame
|
||||
[ currentPoseGlobalIMUnav, currentVelocityGlobalIMUnav ] = imuSimulator.integrateIMUTrajectory_navFrame( ...
|
||||
currentPoseGlobalIMUnav, currentVelocityGlobalIMUnav, acc_omega, deltaT);
|
||||
|
||||
%% Store data in some structure for statistics and plots
|
||||
positions(:,i) = currentPoseGlobal.translation.vector;
|
||||
positionsIMUbody(:,i) = currentPoseGlobalIMUbody.translation.vector;
|
||||
positionsIMUnav(:,i) = currentPoseGlobalIMUnav.translation.vector;
|
||||
% -
|
||||
poses(i).p = positions(:,i);
|
||||
posesIMUbody(i).p = positionsIMUbody(:,i);
|
||||
posesIMUnav(i).p = positionsIMUnav(:,i);
|
||||
% -
|
||||
poses(i).R = currentPoseGlobal.rotation.matrix;
|
||||
posesIMUbody(i).R = currentPoseGlobalIMUbody.rotation.matrix;
|
||||
posesIMUnav(i).R = currentPoseGlobalIMUnav.rotation.matrix;
|
||||
i = i + 1;
|
||||
end
|
||||
|
||||
figure(1)
|
||||
hold on;
|
||||
plot(positions(1,:), positions(2,:), '-b');
|
||||
plot(positionsIMUbody(1,:), positionsIMUbody(2,:), '-r');
|
||||
plot(positionsIMUnav(1,:), positionsIMUnav(2,:), ':k');
|
||||
axis equal;
|
||||
legend('true trajectory', 'traj integrated in body', 'traj integrated in nav')
|
||||
|
||||
|
Loading…
Reference in New Issue