EKF-SLAM更新ステップ、カルマンゲインが特異になる


16

SLAMにEKFを使用していますが、更新手順に問題があります。Kが特異であり、とrcond評価されるという警告が表示されnear eps or NaNます。問題の原因はZの反転にあると思います。最後の項を反転せずにカルマンゲインを計算する方法はありますか?

私はこれが問題の原因であるという100%の肯定的ではないので、コード全体をここに入れまし。メインエントリポイントはslam2dです。

function [ x, P ] = expectation( x, P, lmk_idx, observation)
    % expectation
    r_idx = [1;2;3];
    rl = [r_idx; lmk_idx];

    [e, E_r, E_l] = project(x(r), x(lmk_idx)); 
    E_rl = [E_r E_l];
    E = E_rl * P(rl,rl) * E_rl';

    % innovation
    z = observation - e;
    Z = E;

    % Kalman gain
    K = P(:, rl) * E_rl' * Z^-1;

    % update
    x = x + K * z;
    P = P - K * Z * K';
end


function [y, Y_r, Y_p] = project(r, p)     
    [p_r, PR_r, PR_p] = toFrame2D(r, p);
    [y, Y_pr]   = scan(p_r);
    Y_r = Y_pr * PR_r;
    Y_p = Y_pr * PR_p;    
end


function [p_r, PR_r, PR_p] = toFrame2D(r , p)
    t = r(1:2);
    a = r(3);
    R = [cos(a) -sin(a) ; sin(a) cos(a)];
    p_r = R' * (p - t);
    px = p(1);
    py = p(2);
    x = t(1);
    y = t(2);
    PR_r = [...
        [ -cos(a), -sin(a),   cos(a)*(py - y) - sin(a)*(px - x)]
        [  sin(a), -cos(a), - cos(a)*(px - x) - sin(a)*(py - y)]];
    PR_p = R';    
end


function [y, Y_x] = scan(x)
    px = x(1);
    py = x(2);
    d = sqrt(px^2 + py^2);
    a = atan2(py, px);
    y = [d;a];
    Y_x =[...
    [     px/(px^2 + py^2)^(1/2), py/(px^2 + py^2)^(1/2)]
    [ -py/(px^2*(py^2/px^2 + 1)), 1/(px*(py^2/px^2 + 1))]];
end

編集: 修正されるproject(x(r), x(lmk))べきでありproject(x(r), x(lmk_idx))、現在修正されています。

Kはしばらくすると特異になりますが、すぐにはなりません。約20秒かそこらだと思います。今夜帰宅したときに@joshが提案した変更を試し、結果を投稿します。

更新1:

私のシミュレーションは最初に2つのランドマークを観察するため、Kはです。 結果は行列になるため、次の行でxに追加することはできません。 5 x 27 x 2(P(rl,rl) * E_rl') * inv( Z )5 x 2

Kは4.82秒後に特異になり、50Hz(241ステップ)で測定されます。ここでのアドバイスに従って、K = (P(:, rl) * E_rl')/ZKが特異であるという警告が生成される前に、250のステップが発生することを試みました。

これは、問題がマトリックスの反転ではないことを教えてくれますが、問題を引き起こしているのは他のどこかです。

更新2

私のメインループは(x、Pおよびランドマークポインターを格納するロボットオブジェクトを使用)です。

for t = 0:sample_time:max_time
    P = robot.P;
    x = robot.x;
    lmks = robot.lmks;
    mapspace = robot.mapspace;

    u = robot.control(t);
    m = robot.measure(t);

    % Added to show eigenvalues at each step
    [val, vec] = eig(P);
    disp('***')
    disp(val)

    %%% Motion/Prediction
    [x, P] = predict(x, P, u, dt);

    %%% Correction
    lids = intersect(m(1,:), lmks(1,:));  % find all observed landmarks
    lids_new = setdiff(m(1,:), lmks(1,:));
    for lid = lids
        % expectation
        idx = find (lmks(1,:) == lid, 1);
        lmk = lmks(2:3, idx);
        mid = m(1,:) == lid;
        yi = m(2:3, mid);

        [x, P] = expectation(x, P, lmk, yi);
    end  %end correction

    %%% New Landmarks

    for id = 1:length(lids_new)
    % if id ~= 0
        lid = lids_new(id);
        lmk = find(lmks(1,:)==false, 1);
        s = find(mapspace, 2);
        if ~isempty(s)
            mapspace(s) = 0;
            lmks(:,lmk) = [lid; s'];
            yi = m(2:3,m(1,:) == lid);

            [x(s), L_r, L_y] = backProject(x(r), yi);

            P(s,:) = L_r * P(r,:);
            P(:,s) = [P(s,:)'; eye(2)];
            P(s,s) = L_r * P(r,r) * L_r';
        end
    end  % end new landmarks

    %%% Save State
    robot.save_state(x, P, mapspace, lmks)
    end  
end

このループの最後で、xとPをロボットに保存します。そのため、各反復で共分散を伝播していると思います。

その他の編集 (できれば)正しい固有値がここにあります。負の固有値がいくつかあります。それらの大きさは決してほど大きくなることはありませんが、最初のランドマークが観察され、マップに追加された直後の反復で発生します(メインループの「新しいランドマーク」セクション)。102


1
不確実性を伝播していますか?共分散の固有値は任意に小さくなりますか、大きくなりますか?
ジョシュヴァンダーフック

1
pastebinに入れるのは、固有値ではなく固有ベクトルです。これを行う:[v、d] = eig(P)。disp(diag(d))。または単にdisp(eig(P))。その後、次の必要な条件を確認できます。すべての固有値がすべてのステップで0より大きい(実際にあるはずです)。伝播後に増加、測定/補正後に減少しますか?私の経験では、これは通常問題です。
ジョシュヴァンダーフック

2
固有値が負の場合、何かが間違っています。ランドマークを初期化するとき、最初の推定位置に関連する不確実性は何ですか?
ジョシュヴァンダーフック

観測はペアです。最初のランドマークが初期化されると、共分散は[5.8938、3.0941; 3.0941、2.9562]。2番目の場合、共分散は[22.6630 -14.3822; -14.3822、10.5484]完全なマトリックスはこちら
munk

回答:


5

私はあなたの投稿を今見ていますが、本当にあなたを助けるには遅すぎるかもしれません...しかし、あなたがまだこれに興味があるなら、私はあなたの問題を特定したと思います。

次の方法でイノベーション共分散行列を記述します

E = jacobian measure * P * jacobian measure

理論上は大丈夫かもしれませんが、アルゴリズムが効果的で、特にシミュレーションに取り組んでいる場合は、特に測定の方向で不確実性が減少します。だからE傾向があり[[0,0][0,0]]ます。

この問題を回避するには、測定の不確実性に対応する測定ノイズを追加すると、イノベーションの共分散が

E= Jac*P*Jac'+R

ここRで、測定ノイズの共分散です(対角の項がノイズの標準偏差の二乗である対角行列)。実際にノイズを考慮したくない場合は、必要なだけ小さくすることができます。

また、共分散の更新は奇妙なように思えますが、古典的な式は次のとおりです。

P=P - K * jacobian measure * P

私はあなたの式が他のどこかに書かれているのを見たことがありません、私は正しいかもしれませんが、あなたがそれを確信していないなら、あなたはそれをチェックするべきです。


ああ、古い「共分散の塩」トリック。
ジョシュヴァンダーフック

1

KPNr+Nl×Nr+NlNrNl

K = P(:, rl) * E_rl' * Z^-1

私はそうすべきだと思う

(P(rl,rl) * E_rl') * inv(Z)

(参照:行列の除算)。のサイズを確認しますK

また、もう少し情報を提供してください:Kすぐに単発になるのですか、それともしばらくしてからですか?

これは私を心配させます:project(x(r), x(lmk));以来、lmk定義されていません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.