用MATLAB仿真仿射队形变换(Affine Formation Maneuver)

写在前面

原论文标题:Affine Formation Maneuver Control of Multiagent Systems.

之前的文章讲了赵世钰的仿射编队控制原理[1],进行了相关理论分析,发出来之后有不少同学私信问我如何复现他的论文。于是我现在再写这篇文章填个坑,把如何用MATLAB复现的思路讲一下,给之前的文章做个结尾。

如何仿真静态编队控制

读完赵的论文后,相信大家对控制算法已经掌握了,毕竟在形式上和一般的consensus极其相似。但是相比拉普拉斯矩阵,stress matrix的构建更加麻烦。下面详细讲一下在MATLAB中如何构建stress matrix。

我们首先给出一个任意的连通图,由关联矩阵DD定义。

% incidence matrix
D = [1,-1,0,0,0,0,0,0,0,-1,0,1;
    -1,0,0,0,0,0,1,-1,0,0,0,0;
    0,1,-1,0,0,0,0,0,1,0,0,0;
    0,0,0,0,0,1,-1,0,0,1,-1,0;
    0,0,1,-1,0,0,0,0,0,0,1,-1;
    0,0,0,0,1,-1,0,0,-1,0,0,0;
    0,0,0,1,-1,0,0,1,0,0,0,0];
L = D*D';
H = D';

为了确定stress matrix Ω\Omega,还需要再给出期望的队形位置rr。为了简单起见,代码中r代表P(r)P(r)P代表Pˉ(r)\bar P(r)

%% dimensions
[n,m] = size(D);
d = 2;

% r represents P(r)
r = [2,0;
    1,1;
    1,-1;
    0,1;
    0,-1;
    -1,1;
    -1,-1];
    
% P represents \bar P(r)
P = [r,ones(n,1)];

构建stress matrix

接下来,我们按照论文VII-A的方法构建stress matrix Ω\Omega

第一步,创建EE矩阵,使得Eω=0E\omega=0,其中ωRm\omega\in\mathbb R^m为每条边对应的权重,各元素与DD的列对应。

由于Ω=HTdiag(ω)H\Omega=H^T\operatorname{diag}(\omega)HΩPˉ(r)=0\Omega \bar P(r)=0PˉT(r)HTdiag(ω)H=PˉT(r)HTdiag(ω)[h1,,hn]=0\bar P^T(r)H^T\operatorname{diag}(\omega)H=\bar P^T(r)H^T\operatorname{diag}(\omega)[h_1,\cdots,h_n]=0。因为diag(ω)hi=diag(hi)ω\operatorname{diag}(\omega)h_i=\operatorname{diag}(h_i)\omega,所以PˉT(r)HTdiag(hi)ω=0,i=1,,n\bar P^T(r)H^T\operatorname{diag}(h_i)\omega=0,\forall i=1,\cdots,n

E = [];
for i=1:n 
    E = [E;P'*H'*diag(H(:,i))];
end

定义Z=[z1,,zq]null(E)Z=[z_1,\cdots,z_q]\in\operatorname{null}(E),则ω=Zc\omega=Zc,其中cRqc\in\mathbb R^q是系数。

z = null(E);
c = zeros(size(z,2),1);

第二步,求系数cc。对Pˉ(r)\bar P(r)奇异值分解,Pˉ(r)=UΣVT\bar P(r)=U\Sigma V^T。令U=[U1,U2]U=[U_1,U_2],其中U1U_1包含前d+1d+1列。因为rank(Pˉ(r))=d+1\operatorname{rank}(\bar P(r))=d+1U1U_1Pˉ(r)\bar P(r)的列空间,U2U_2PˉT(r)\bar P^T(r)的零空间,所以U1TΩU1=0U_1^T\Omega U_1=0U2TΩU2>0U_2^T\Omega U_2>0。将ω=Zc\omega=Zc代入,U2THTdiag(Zc)HU2=i=1qciU2THTdiag(zi)HU2>0U_2^TH^T\operatorname{diag}(Zc)HU_2=\sum_{i=1}^q c_iU_2^TH^T\operatorname{diag}(z_i)HU_2>0

% svd
[U,S,V] = svd(P);
U1 = U(:,1:d+1);
U2 = U(:,d+2:end);
% calculate M
for i=1:size(z,2)
	M{i} = U2'*H'*diag(z(:,i))*H*U2;
end

Mi=U2THTdiag(zi)HU2M_i=U_2^TH^T\operatorname{diag}(z_i)HU_2,则只需求解LMI问题:i=1qciMi>0\sum_{i=1}^q c_iM_i>0

MATLAB求解LMI问题

MATLAB求解LMI问题步骤如下:

  • 初始化;
% Initialization
setlmis([]);
  • 确定待定变量和不等式;

lmivar(type,struct)指定变量为未知变量,type=1表示变量为对称矩阵,struct=[1,0]表示只有1个block,且为scalar。

lmiterm(termid,A,B,flag)指定相应的不等式,termid=[-1,1,1,c(i)],第一项表示第1个不等式,负号表示>0>0,第二、三项表示处于哪个位置,如(1,1)表示处于第1行第1列,第四项表示该不等式对应哪一个未知变量。这里令c=[c1,,cq]c=[c_1,\cdots,c_q],不等式为c1M1++cqMq>0c_1M_1+\cdots+c_qM_q>0lmiterm定义每一个ciMic_iM_i,不等式号为1,位置都为(1,1)。

for i=1:size(z,2)
	% Defining the Decision Variables
    c(i) = lmivar(1,[1,0]);
    % Define the LMIs one by one
    lmiterm([-1,1,1,c(i)],1,M{i});
end
  • 建立模型和求解。

getlmis得到对应LMI问题模型,feasp求解LMI问题。

lmi = getlmis;
[~,csol] = feasp(lmi);
for i=1:size(null_E,2)
    c(i) = dec2mat(lmi,csol,c(i));
end
c = c/norm(c);
cM = [M{:}]*kron(c,eye(size(M{1},2)));
% check if cM>0

求解出cc之后即可得到Ω=HTZcH\Omega=H^TZcH

w =  z*c;
Omega = H'*diag(w)*H;

静态编队控制源代码

静态编队控制源代码见我的GitHub,见项目paper-simulation。运行Zhao2018Affine文件夹下的文件affine_formation.m,即可得到下面的仿真结果。

如何仿真时变轨迹和队形变换

时变队形有两个难点,一个是轨迹生成,另一个是时变leader控制律。

轨迹生成

轨迹生成部分我是对给定队形做仿射变换,即xr=Ar+bx_r=Ar+b

bb对应代码里的viaAA对应代码里的T_1*T_2,要对A,bA,b的每一个元素生成轨迹,最后再合并成xrx_r

via = [0,0;
    5,0;
    10,0;
    10,-5;
    10,-10;
    5,-10;
    0,-10];
for j=1:size(via,1)
    if ~mod(j,2)
        if j==4
            T1 = diag([0.1,1]);
        else
            T1 = diag([1,0.1]);
        end
    else
        T1 = eye(2);
    end
    T2 = rot2(-pi/2*floor((j-1)/2));
    ra(:,:,j) = r*T2'*T1'+via(j,:);
    qvia(j,:) = [vec(T1*T2)',via(j,:)];
    for i=1:m
        plot(ra(edge(:,i),1,j),ra(edge(:,i),2,j),'k','linewidth',2); hold on
    end
end
[qr,dqr,ddqr,tr] = mstraj_(qvia,ones(1,6),0.1,0.2);
A = reshape(qr(1,1:4)',[2,2]);
b = qr(1,5:6)';
xr = r*A'+b';

时变leader控制律

写这个控制律其实不难,只是有点麻烦,不能像拉普拉斯矩阵一样写成矩阵形式,所以只能一条边一条边的求和。

gamma = diag(Omega);
% follower 4:n
for i=4:n
    err_sum = [0,0];
    edge_ind = find(D(i,:)~=0);
    for k=edge_ind
        node_ind = find(D(:,k)~=0);
        j = node_ind(node_ind~=i);
        err_sum = err_sum+z(k)*(x(i,:)-x(j,:)-dx(j,:));
    end
    dx(i,:) = -1/gamma(i)*err_sum;
end
% leader 1:3
dx(1:3,:) = dxr(1:3,:)-alpha*(x(1:3,:)-xr(1:3,:));

时变轨迹和队形变换源代码

时变轨迹和队形变换源代码见我的GitHub,见项目paper-simulation。运行Zhao2018Affine文件夹下的文件affine_maneuver.m,即可得到下面的仿真结果。


  1. Zhao, S. (2018). Affine Formation Maneuver Control of Multiagent Systems. IEEE Transactions on Automatic Control, 63(12), 4140–4155. https://doi.org/10.1109/TAC.2018.2798805 ↩︎