Етап оновлення EKF-SLAM, Kalman Gain стає єдиним


16

Я використовую EKF для SLAM, і у мене є проблеми з кроком оновлення. Я отримую попередження про те, що 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 у наступному рядку. 7 х 2(P(rl,rl) * E_rl') * inv( Z )5 х 2

K стає сингулярним через 4,82 секунди з вимірюванням на 50 ГГц (241 крок). Дотримуючись поради тут , я спробував, K = (P(:, rl) * E_rl')/Zщо призводить до 250 кроків, перш ніж надходить попередження про те, що K є єдиним.

Це говорить про те, що проблема не в інверсії матриці, але це десь інше, що викликає проблему.

Оновлення 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 назад до робота, тому я вважаю, що я поширюю коваріацію через кожну ітерацію.

Більше редагувань Тут (сподіваємось) правильні власні значення тепер тут . Існує ряд власних значень, які є негативними. Хоча їх величина ніколи не буває дуже великою, максимум , , це відбувається під час ітерації одразу після того, як спостерігається перший орієнтир та додається до карти (у розділі «нові орієнтири» головного циклу).10-2


1
Ви пропагуєте невизначеність? Чи отримують власні значення вашої коваріації довільно малі чи великі?
Джош Вандер Хук

1
Те, що ви вкладаєте в пастебін, - це власні вектори, а не власні значення. зробіть це: [v, d] = eig (P). disp (diag (d)). або просто disp (eig (P)). Потім ви можете перевірити наступні необхідні умови: чи всі власні значення> 0 на кожному кроці (вони повинні бути на практиці). Вони збільшуються після розповсюдження та зменшуються після вимірювань / виправлень? На мій досвід, зазвичай це проблема.
Джош Вандер Хук

2
Щось не так, якщо ваші власні значення негативні. Коли ви ініціалізуєте орієнтир, яка невизначеність пов'язана з його першою оцінкою?
Джош Вандер Хук

Спостереження - пара. Коли ініціалізується перший орієнтир, він має коваріацію [5.8938, 3.0941; 3.0941, 2.9562]. По-друге, його коваріація є [22.6630 -14.3822; -14.3822, 10.5484] Повна матриця тут
манк

Відповіді:


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

KP(Nr+Nл)×(Nr+Nл)NrNл

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

що я думаю, що має бути

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

(див.: матричний поділ ). Перевірте розмір K.

Також: Будь ласка, надайте трохи більше інформації: Чи Kпереходить однина негайно або лише через деякий час?

Це мене хвилює: project(x(r), x(lmk));оскільки lmkне визначено.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.