Something went wrong on our end
-
Austin Rohlfing authoredAustin Rohlfing authored
linearization.m 4.30 KiB
% Implements the nonlinear model and creates state-space matrices A and B
% using MATLAB's symbolic differentiation.
%
% The model physics is taken from Matt Rich's "Model Development..."
% sections 4.1 and 4.2
%
% This linearization assumes the rotor orientation in the simulink model:
% 1 2
% +dx
% +dy
%
% 3 4
% In some of the internal simulink files, these are indexed 0, ..., 3
% instead of 1, .., 4. The order is unchanged.
% Note that the final result should be the same regardless of rotor
% orientation, but everything internal to this function and its parameters
% need to be consistent.
function [A, B] = linearization(m, g, Kt, Kh, Kd, delta_T_z, rx, ry, rz, J, Jreq, Vb, Rm, Kv, Kq, If, signal_mixer)
% Symbolic state variables
syms u v w p q r x y z ph th ps
% Rotation matrices. After linearization, these are equivalent to I
L_EB = [...
cos(th)*cos(ps), sin(ph)*sin(th)*cos(ps)-cos(ph)*sin(ps), cos(ph)*sin(th)*cos(ps)+sin(ph)*sin(ps)
cos(th)*sin(ps), sin(ph)*sin(th)*sin(ps)+cos(ph)*cos(ps), cos(ph)*sin(th)*sin(ps)-sin(ph)*cos(ps)
-sin(th), sin(ph)*cos(th), cos(ph)*cos(th)];
A_EB = [...
1, 0, -sin(th)
0, cos(ph), sin(ph)*cos(th)
0, -sin(ph), cos(ph)*cos(th)];
% Rotor positions
r_h = [...
-rx, rx, -rx, rx
ry, ry, -ry, -ry
-rz, -rz, -rz, -rz
];
% Gamma matrices select force dimensions
Gamma_H = diag([1, 1, 0]);
Gamma_Omega = [zeros(2,4); 1, -1, -1, 1];
% uT, uA, uE, uR
u_c = sym('u_c_%d', [1 4]);
% Individual rotor commands
u_p = (signal_mixer * u_c')';
% Rotor angular velocities
% These values assume no motor transient
% (i.e. speeds reached immediately)
omega = sym('w_%d', [1 4]);
for i = 1:4
omega(i) = (-1 + sqrt(1 - 4*Rm*Kv*Kq*Kd*(Kv*Rm*If - Kv*u_p(i)*Vb)))/(2*Rm*Kv*Kq*Kd);
end
% Variable vectors
v_B_0 = [u; v; w];
Omega_B = [p; q; r];
% Rotor velocity
for i = 1:4
v_h(:,i) = v_B_0 + cross(Omega_B, r_h(:,i));
end
% Gravity
G_B = m*g*[-sin(th); cos(th)*sin(ph); cos(th)*cos(ph)];
% Force
% Rotor Thrust (3 directions x 4 rotors matrix)
T_B = [zeros(2, 4); -(Kt*omega.^2 + delta_T_z*v_h(3,:).*omega)];
% Rotor In-plane drag (3 directions x 4 rotors matrix)
H_B = -(Kh*ones(3,1)*omega).*(Gamma_H*v_h);
% Total Force (Gravity + rotor force summed over all rotors)
F_B = G_B + sum(T_B + H_B, 2);
% Torque
for i = 1:4
% Force Lever-arm Torque
Q_B_F(:,i) = cross(r_h(:,i), T_B(:,i) + H_B(:,i));
% Change of Angular Momentum Torque (assuming no motor transient)
Q_B_L(:,i) = -Jreq*cross(Omega_B, omega(i)*Gamma_Omega(:,i));
% Drag/Induced Torque
Q_B_d(:,i) = -Kd*omega(i)^2*Gamma_Omega(:,i);
end
% Total Torque
Q_B = sum(Q_B_F + Q_B_d + Q_B_L, 2);
% Define state vector Lambda and its time derivative, Lambda_dot
Lambda = [u, v, w, p, q, r, x, y, z, ph, th, ps];
Lambda_dot = [...
1/m * F_B - cross(Omega_B, v_B_0)
J^-1 * Q_B - cross(J^-1 * Omega_B, J * Omega_B)
L_EB * v_B_0
A_EB * Omega_B
];
% A is partial of Lambda_dot wrt Lambda
for i = 1:12
for j = 1:12
symA(i, j) = diff(Lambda_dot(i), Lambda(j));
end
end
% B is partial of Lambda_dot wrt u_T, u_A, u_E, u_R
for i = 1:12
for j = 1:4
symB(i, j) = diff(Lambda_dot(i), u_c(j));
end
end
% Set equilibrium values
u = 0; v = 0; w = 0; p = 0; q = 0; r = 0; x = 0; y = 0; z = 0; ph = 0; th = 0; ps = 0;
u_c_1 = 0; u_c_2 = 0; u_c_3 = 0; u_c_4 = 0;
% Binary search for equilibrium throttle value
throttle_max = 1; throttle_min = 0;
while (abs(double(subs(F_B(3)))) > 1e-7)
u_c_1 = (throttle_max + throttle_min)/2;
if (double(subs(F_B(3))) > 0)
throttle_min = double(u_c_1);
else
throttle_max = double(u_c_1);
end
end
% Convert symbolic linearization matrices to double values
A = double(subs(symA));
B = double(subs(symB));
end
%#ok<*AGROW>