メインコンテンツ

非同期のセンサーからの姿勢推定

この例では、さまざまなレートでセンサーを融合して姿勢を推定する方法を示します。加速度計、ジャイロスコープ、磁力計、および GPS を使用して、円形のパスに沿って移動するビークルの向きと位置を判別します。Figure ウィンドウのコントロールを使用してセンサーのレートを変え、推定姿勢に対する影響を確認しながらセンサーのドロップアウトを試すことができます。

シミュレーションの設定

事前に記録されたセンサー データを読み込みます。センサー データは、waypointTrajectory クラスを使用して作成された円形の軌跡に基づいています。センサーの値は gpsSensor クラスと imuSensor クラスを使用して作成されたものです。ここで使用している CircularTrajectorySensorData.mat ファイルは generateCircularTrajSensorData 関数で生成できます。

ld = load('CircularTrajectorySensorData.mat');

Fs = ld.Fs; % maximum MARG rate
gpsFs = ld.gpsFs; % maximum GPS rate
ratio = Fs./gpsFs;
refloc = ld.refloc;

trajOrient = ld.trajData.Orientation;
trajVel = ld.trajData.Velocity;
trajPos = ld.trajData.Position;
trajAcc = ld.trajData.Acceleration;
trajAngVel = ld.trajData.AngularVelocity;

accel = ld.accel;
gyro = ld.gyro;
mag = ld.mag;
lla = ld.lla;
gpsvel = ld.gpsvel;

フュージョン フィルター

IMU と GPS の測定を融合する insfilterAsync を作成します。このフュージョン フィルターでは、連続/離散の拡張カルマン フィルター (EKF) を使用して、向き (四元数として)、角速度、位置、速度、加速度、センサー バイアス、および地磁気ベクトルを追跡します。

この insfilterAsync には、センサー データを処理するメソッドがいくつかあります。fuseaccelfusegyrofusemag、および fusegps です。insfilterAsync で連続/離散の EKF を使用しているため、predict メソッドでフィルターをステップ実行して任意の時間まで進めることができます。

fusionfilt = insfilterAsync('ReferenceLocation', refloc);

insfilterAsync の状態ベクトルの初期化

insfilterAsync は姿勢の状態を 28 要素のベクトルで追跡します。以下の状態があります。

     States                          Units    Index
  Orientation (quaternion parts)             1:4
  Angular Velocity (XYZ)            rad/s    5:7
  Position (NED)                    m        8:10
  Velocity (NED)                    m/s      11:13
  Acceleration (NED)                m/s^2    14:16
  Accelerometer Bias (XYZ)          m/s^2    17:19
  Gyroscope Bias (XYZ)              rad/s    20:22
  Geomagnetic Field Vector (NED)    uT       23:25
  Magnetometer Bias (XYZ)           uT       26:28

フィルターが短時間で適切な回答に収束するよう、フィルターの状態の初期化を補助するためにグラウンド トゥルースが使用されます。

Nav = 100;
initstate = zeros(28,1);
initstate(1:4) = compact( meanrot(trajOrient(1:Nav)));
initstate(5:7) = mean( trajAngVel(10:Nav,:), 1);
initstate(8:10) = mean( trajPos(1:Nav,:), 1);
initstate(11:13) = mean( trajVel(1:Nav,:), 1);
initstate(14:16) = mean( trajAcc(1:Nav,:), 1);
initstate(23:25) = ld.magField;

% The gyroscope bias initial value estimate is low for the Z-axis. This is
% done to illustrate the effects of fusing the magnetometer in the
% simulation.
initstate(20:22) = deg2rad([3.125 3.125 3.125]);
fusionfilt.State = initstate;

insfilterAsync のプロセス ノイズ値の設定

フィルターで使用される運動モデルの不確かさをプロセス ノイズ分散として記述します。

fusionfilt.QuaternionNoise = 1e-2;
fusionfilt.AngularVelocityNoise = 100;
fusionfilt.AccelerationNoise = 100;
fusionfilt.MagnetometerBiasNoise = 1e-7;
fusionfilt.AccelerometerBiasNoise = 1e-7;
fusionfilt.GyroscopeBiasNoise = 1e-7;

センサー データの融合に使用する測定ノイズ値の定義

センサーの測定値には、それぞれ何らかのノイズがあります。通常、これらの値はセンサーのデータシートに記載されています。

Rmag = 0.4;
Rvel = 0.01;
Racc = 610;
Rgyro = 0.76e-5;
Rpos = 3.4;

fusionfilt.StateCovariance = diag(1e-3*ones(28,1));

スコープの初期化

HelperScrollingPlotter スコープを使うと、変数の経時的なプロットが可能になります。ここでは、姿勢の誤差を追跡するために使用します。PoseViewerWithSwitches スコープを使うと、フィルター推定値とグラウンド トゥルース姿勢を 3 次元で可視化できます。スコープによってシミュレーション速度は低下する場合があります。スコープを無効にするには、対応する論理変数を false に設定します。

useErrScope = true; % Turn on the streaming error plot.
usePoseView = true; % Turn on the 3D pose viewer.
if usePoseView
    posescope = PoseViewerWithSwitches(...
        'XPositionLimits', [-30 30], ...
        'YPositionLimits', [-30, 30], ...
        'ZPositionLimits', [-10 10]);
end
f = gcf;

if useErrScope
    errscope = HelperScrollingPlotter(...
        'NumInputs', 4, ...
        'TimeSpan', 10, ...
        'SampleRate', Fs, ...
        'YLabel', {'degrees', ...
        'meters', ...
        'meters', ...
        'meters'}, ...
        'Title', {'Quaternion Distance', ...
        'Position X Error', ...
        'Position Y Error', ...
        'Position Z Error'}, ...
        'YLimits', ...
        [ -1, 30
        -2, 2
        -2 2
        -2 2]);
end

シミュレーション ループ

フュージョン アルゴリズムのシミュレーションで、センサーのサンプル レートを変えたときの影響を検証できます。さらに、対応するチェックボックスをオフにして個々のセンサーの融合を回避できます。これを使用してセンサーのドロップアウトをシミュレートできます。

構成によっては劇的な結果になるものがあります。たとえば、GPS センサーをオフにすると、位置の推定のドリフトが速くなります。磁力計センサーをオフにすると、推定のローテーションが速すぎるために、向きの推定がグラウンド トゥルースから徐々に逸脱していきます。一方、ジャイロスコープをオフにして磁力計をオンにすると、推定される向きにゆがみが生じ、両方のセンサーを使用した場合に得られるような滑らかさに欠けたものになります。

すべてのセンサーをオンにしても、それらを最低のレートで動作するように設定している場合は、グラウンド トゥルースから明らかに逸脱した推定が生成され、その後にセンサーを融合した時点でより正確な結果が得られます。これは、実行時推定の誤差の HelperScrollingPlotter で最もよく見られます。

メインのシミュレーションは 100 Hz で実行されます。それぞれの反復で Figure ウィンドウのチェックボックスが検証され、センサーが有効になっていれば、そのセンサーのデータが適切なレートで融合されます。

for ii=1:size(accel,1)
    fusionfilt.predict(1./Fs);

    % Fuse Accelerometer
    if (f.UserData.Accelerometer) && ...
        mod(ii, fix(Fs/f.UserData.AccelerometerSampleRate)) == 0

        fusionfilt.fuseaccel(accel(ii,:), Racc);
    end

    % Fuse Gyroscope
    if (f.UserData.Gyroscope) && ...
        mod(ii, fix(Fs/f.UserData.GyroscopeSampleRate)) == 0

        fusionfilt.fusegyro(gyro(ii,:), Rgyro);
    end

    % Fuse Magnetometer
    if (f.UserData.Magnetometer) && ...
        mod(ii, fix(Fs/f.UserData.MagnetometerSampleRate)) == 0

        fusionfilt.fusemag(mag(ii,:), Rmag);
    end

    % Fuse GPS
    if (f.UserData.GPS) && mod(ii, fix(Fs/f.UserData.GPSSampleRate)) == 0
        fusionfilt.fusegps(lla(ii,:), Rpos, gpsvel(ii,:), Rvel);
    end

    % Plot the pose error
    [p,q] = pose(fusionfilt);
    posescope(p, q, trajPos(ii,:), trajOrient(ii));

    orientErr = rad2deg(dist(q, trajOrient(ii) ));
    posErr = p - trajPos(ii,:);
    errscope(orientErr, posErr(1), posErr(2), posErr(3));
end

まとめ

insfilterAsync では、サンプル レートをさまざまに変えることができます。推定出力の品質は個々のセンサー フュージョンのレートに大きく依存します。センサーのドロップアウトは、いずれも出力に大きく影響します。