MATLABを用いてカルマンフィルタをによる自律型ロボットの自己位置推定のプログラミングを学んでいるものです。
自分の実装しているコードの特徴として、
・ロボットへの入力が速度と角度(v、θ)などではなく、現在の位置から目標位置への引力(速度ベクトル)V =(Vx,Vy)を採用していることです。状態遷移式としては、X(t+1) = FX(t)+aV のようになります。(aは降下量係数)
・観測データは、1点をランドマークとして設置し、現在の位置からランドマークへの距離と角度をデータとして得られる設定にしています。
困っていることとしては、途中まで正しく推定できている位置が、ランドマークとの距離が最小になるステップ以降、暴走してしまうことです。
(図参照)青い点:実際のロボットの位置、赤い点:カルマンフィルタによる推定の位置、緑の点:ロボットが目指す目標位置、黒い点:ランドマーク 青い楕円:推定誤差楕円 です。
おそらく、観測データの中の角度の処理(atan2)がうまくいってないと思われるのですが、なかなか解決できません。
カルマンフィルタに詳しい方、ぜひアドバイスをいただきたいと思います。
ソースコードも載せておきますが、あまりきれいなコードではないと思います、、、
この方のページをよく参考にさせていただいています。↓
https://myenigma.hatenablog.com/entry/20130413/1365826157
function [] = VectorFieldKalmanFilterLocalization() close all; clear all; disp('Vector Field Kalman Filter sample program start!!') global xg xg = [20;20]; global cg cg = 300; global lg lg = 100; global a a= 0.1; x0=[0;0]; global LM LM= [15;10]; %plot(x0(1),x0(2),'o','MarkerSize',10,'MarkerFaceColor','y');hold on; plot(xg(1),xg(2),'o','MarkerSize',10,'MarkerFaceColor','g');hold on; plot(LM(1),LM(2),'o','MarkerSize',15,'MarkerFaceColor','k');hold on; result.xTrue=[]; result.xd=[]; result.xEst=[]; result.z=[]; result.PEst=[]; result.u=[]; Xact=[0;5]; Xdes=[0;0]; Xest=[0;5]; global z z = [0;0]; global F F=eye(2); H=eye(2); Pest = eye(2); w=[0.01;0.02]; v=[0.03;toRadian(1)]; Q=diag(w).^2; R=diag(v).^2; % Main loop for t=1:300 %目標軌道ベクトル %Vdes = VerocityVector(Xdes); %目標軌道 %Xdes = f(Xdes,Vdes); %実軌道ベクトル Vact = VerocityVectorIncludeNoise(Xact,w); %実軌道 Xact = f(Xact,Vact); %予測軌道ベクトル Vest = VerocityVector(Xest); %予測軌道と共分散 Xpred = f(Xest,Vest); [vxdx vxdy vydx vydy] = bibun(Vest,Xest,xg); Ft = jacobF(vxdx,vxdy,vydx,vydy); Ppred = Ft*Pest*Ft' + Q; %観測値 z = Observation(Xact,LM,v); zpred = Observation(Xpred,LM,v*0); %カルマンゲイン計算 y = z - zpred; Ht = JacobianH(Xpred,LM); S = R + Ht*Ppred*Ht'; K = Ppred*Ht'*inv(S); %更新値 Xest = Xpred + K*y'; Pest = (eye(2) - K*Ht)*Ppred; figure(1); set(gca, 'fontsize', 16, 'fontname', 'times'); %plot(Xdes(1), Xdes(2),'.k','linewidth', 7); hold on; plot(Xact(1), Xact(2),'.b','linewidth', 7); hold on; plot(Xest(1), Xest(2),'.r','linewidth', 7); hold on; title('EKF Localization Result', 'fontsize', 16, 'fontname', 'times'); xlabel('X (m)', 'fontsize', 16, 'fontname', 'times'); ylabel('Y (m)', 'fontsize', 16, 'fontname', 'times'); grid on; axis equal; if rem(t,5)==0 ShowErrorEllipse(Xest,Pest); end drawnow; end function ShowErrorEllipse(Xest,Pest) %誤差分散円を計算し、表示する関数 Pxy=Pest(1:2,1:2);%x,yの共分散を取得 [eigvec, eigval]=eig(Pxy);%固有値と固有ベクトルの計算 %固有値の大きい方のインデックスを探す if eigval(1,1)>=eigval(2,2) bigind=1; smallind=2; else bigind=2; smallind=1; end chi=9.21;%誤差楕円のカイの二乗分布値 99% %楕円描写 t=0:10:360; a=sqrt(eigval(bigind,bigind)*chi); b=sqrt(eigval(smallind,smallind)*chi); x=[a*cosd(t); b*sind(t)]; %誤差楕円の角度を計算 angle = atan2(eigvec(bigind,2),eigvec(bigind,1)); if(angle < 0) angle = angle + 2*pi; end %誤差楕円の回転 R=[cos(angle) sin(angle); -sin(angle) cos(angle)]; x=R*x; plot(x(1,:)+Xest(1),x(2,:)+Xest(2)) function V = VerocityVector(x) %位置xにおける速度ベクトルの計算 global xg; global cg; global lg; Vx = -(2*cg*(x(1)-xg(1))/lg^2)*exp(-(((x(1)-xg(1))^2)+(x(2)-xg(2))^2)/lg^2); Vy = -(2*cg*(x(2)-xg(2))/lg^2)*exp(-(((x(2)-xg(2))^2)+(x(2)-xg(2))^2)/lg^2); V = [Vx;Vy]; function V = VerocityVectorIncludeNoise(x,w) %位置xにおけるノイズを考慮した速度ベクトルの計算 global xg; global cg; global lg; Vx = -(2*cg*(x(1)-xg(1))/lg^2)*exp(-(((x(1)-xg(1))^2)+(x(2)-xg(2))^2)/lg^2)+w(1)*randn; Vy = -(2*cg*(x(2)-xg(2))/lg^2)*exp(-(((x(2)-xg(2))^2)+(x(2)-xg(2))^2)/lg^2)+w(2)*randn; V = [Vx;Vy]; function x1 = f(x,v) %動作モデル global a; x1 = x + v*a; function z = Observation(x,xm,v) %計測モデル z(1) = ((xm(1)-x(1))^2+(xm(2)-x(2))^2)^0.5 + v(1)*randn; z(2) = PI2PI(atan2(xm(2)-x(2),xm(1)-x(1)))+ v(2)*randn; %z(1) = x(1)+v(1)*randn; %z(2) = x(2)+v(2)*randn; function angle=PI2PI(angle) angle=atan2(sin(angle),cos(angle)); function Ft = jacobF(vxdx,vxdy,vydx,vydy) % Jacobian of Motion Model global F; global a; Ft=F+a*[vxdx vxdy;vydx vydy]; function Ht = JacobianH(x,LM) Ht = [ -(LM(1)-x(1))/((LM(1)-x(1))^2+(LM(2)-x(2))^2)^0.5, -(LM(2)-x(2))/((LM(1)-x(1))^2+(LM(2)-x(2))^2)^0.5; -(LM(2)-x(2))/((LM(2)-x(2))^2+(LM(1)-x(1))^2), -(LM(1)-x(1))/((LM(2)-x(2))^2+(LM(1)-x(1))^2)]; function [vxdx vxdy vydx vydy] = bibun(v,x,xg) global a; global cg; global lg; vxdx = -((2*cg*a)/lg^2)*(exp(-(((x(1)-xg(1))^2)+(x(2)-xg(2))^2)/lg^2))*(1+((x(1)-xg(1))*v(1))/2*a*cg); vxdy = -v(1)*(2*(x(2)-xg(2))/lg^2); vydx = -v(2)*(2*(x(1)-xg(1))/lg^2); vydy = -((2*cg*a)/lg^2)*(exp(-(((x(1)-xg(1))^2)+(x(2)-xg(2))^2)/lg^2))*(1+((x(2)-xg(2))*v(2))/2*a*cg); function radian = toRadian(degree) % degree to radian radian = degree/180*pi; ```![青い点:実際のロボットの位置、赤い点:カルマンフィルタによる推定の位置、緑の点:ロボットが目指す目標位置、黒い点:ランドマーク](7dc4059beb2f6517144a880658a4ab40.png)
回答1件
あなたの回答
tips
プレビュー