Skip to content

Commit 4c7de64

Browse files
committed
Merge branch 'nav'
2 parents 497cc13 + 7177cc3 commit 4c7de64

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1250
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
A = [0,1;0,0];
2+
B = [0; 1];
3+
4+
L = 100:100:1000;
5+
6+
Qp_t = 1;
7+
Qw_t = 2;
8+
9+
Qp_a = 1;
10+
Qw_a = 2;
11+
12+
for i = 1:length(L)
13+
[Kt, Ktr] = controller_gains_torque(L(i), Qp_t, Qw_t)
14+
[Ka, Kar] = controller_gains_angle(L(i), Qp_a/L(i)^2, Qw_a/L(i)^2)
15+
16+
sys_t = ss(A, B*L(i), Kt, 0);
17+
sys_a = ss(A, B*L(i), Ka, 0);
18+
sys_array_t(:,:,1,i) = sys_t;
19+
sys_array_a(:,:,1,i) = sys_a;
20+
21+
cl_t = Ktr*ss(A+B*L(i)*Kt, B*L(i), eye(2), 0);
22+
cl_a = Kar*ss(A+B*L(i)*Ka, B*L(i), eye(2), 0);
23+
cl_array_t(:,:,1,i) = cl_t;
24+
cl_array_a(:,:,1,i) = cl_a;
25+
26+
end
27+
28+
figure(1)
29+
bode(sys_array_a, "r")
30+
hold on
31+
bode(sys_array_t, "b")
32+
hold on
33+
34+
figure(2)
35+
step(cl_array_a, "r")
36+
hold on
37+
step(cl_array_t, "b")
38+
hold on
152 KB
Binary file not shown.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
function [params, K] = param_estimator_gradient(time, w, d, c)
2+
% w : angular rate measurement
3+
% d : canard angle measurement / command
4+
% p : parameters
5+
% r : regressors
6+
% Q : weights
7+
% K : gain
8+
9+
10+
%%% initialize persistent variables
11+
persistent t p w_old
12+
if isempty(t)
13+
t = -0.01;
14+
end
15+
if isempty(p)
16+
p = [2; 0]; % parameters, initial guess of CL_delta and CL_0
17+
end
18+
if isempty(w_old)
19+
w_old = w;
20+
end
21+
22+
%%% set up
23+
dt = time - t;
24+
dw = (w - w_old) / dt; % actual roll acceleration
25+
r = [d; 0.1] ; % regressors, delta (cmd or encoder) and constant disturbance
26+
r = r * c;
27+
28+
%%% measurement prediction
29+
dw_hat = r' * p;
30+
31+
%%% correction
32+
Q = diag([1, 0.1]); % weights
33+
Q = Q / (norm(r)^2); % normalized gradient
34+
K = Q * r; % gain
35+
p = p + K * (dw - dw_hat); % correct parameters
36+
37+
%%% outputs and update persistent
38+
t = time;
39+
w_old = w;
40+
params = p;
41+
end
166 KB
Binary file not shown.

gnc/control/controller_estimator.m

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
function [C_l_delta, C_l_0] = controller_estimator(time, w, delta, pdyn_params)
2+
% estimates the canard aerodynamic coefficients from canard angle, roll rates, air data
3+
% coeffs : canard coefficients C_l_delta and C_l_0
4+
% time : current time stamp (s)
5+
% w : angular rate measurement (rad/s)
6+
% d : canard angle measurement or command (rad)
7+
% pdyn_params : dynamic pressure * constant parameters (pressure * area * arm / inertia)
8+
9+
% dw/dt = c * Cl * d + C0 * c = phi_k' * p
10+
% C_l_delta = canard lift coeff
11+
% C_l_0 = rocket induced angular acceleration / (rho * area * arm)
12+
13+
%% tuning parameters
14+
Q = diag([1e-5, 1e-9]);
15+
16+
%% initialize
17+
persistent t c P_minus w_old d_old w_dot_old
18+
if isempty(t)
19+
t = -0.01; % for /(time - t)
20+
end
21+
if isempty(c)
22+
c = [2; 0]; % initial coefficient guess
23+
end
24+
if isempty(P_minus)
25+
P_minus = Q;
26+
end
27+
if isempty(w_old)
28+
w_old = w;
29+
end
30+
if isempty(d_old)
31+
d_old = 0;
32+
end
33+
if isempty(w_dot_old)
34+
w_dot_old = 0;
35+
end
36+
37+
%% lowpass command and measurement
38+
tau = 0.25;
39+
delta = (1 - tau) * d_old + tau * delta;
40+
w_dot = (1 - tau) * w_dot_old + tau * (w - w_old) / (time - t);
41+
42+
%% Kalman filter
43+
r = pdyn_params * [delta; 1]; % regression
44+
P = P_minus + Q; % covariance prediction
45+
K = P * r / (r' * P * r + 1); % correction gain. the stuff inside in brackets is just a scalar so you can just divide
46+
coeffs = c + K * (w_dot - r' * c); % coefficient correction
47+
P_plus = (eye(2) - K * r') * P * (eye(2) - K * r')' + K * 1* K'; % covariance correction. Joseph form for numerical stability
48+
49+
%% update for next cycle
50+
t = time;
51+
c = coeffs;
52+
P_minus = P_plus;
53+
w_old = w;
54+
d_old = delta;
55+
w_dot_old = w_dot;
56+
C_l_delta = coeffs(1);
57+
C_l_0 = coeffs(2);
58+
59+
end

gnc/control/controller_law.m

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
function [u, K, Kr] = controller_law(xR, r, L_delta)
2+
% computes the optimal control signal for a flight condition
3+
% u : control signal, desired canard angle (rad)
4+
% xR : roll state [roll angle (rad); roll rate (rad/s)]
5+
% r : reference signal, desired roll angle (rad)
6+
% L_delta : roll acceleration control derivative (rad/s^2 / rad)
7+
8+
%% tuning parameters
9+
Q_phi = 10; % weight of angle error
10+
Q_omega = 10; % weight of rate error
11+
12+
%% feedback gains
13+
K = - 1/L_delta * [ sqrt(Q_phi), sqrt( 2*sqrt(Q_phi) + Q_omega ) ];
14+
15+
%% feedforward gain
16+
% A = [0, 1; 0, 0];
17+
% B = [0; L_delta];
18+
% C = [1, 0]; % tracking channel
19+
% Kr = -1 / ( C * inv(A+B*K) * B );
20+
Kr = - K(1); % simplifies to this
21+
22+
%% control command
23+
u = K * xR + Kr * r;
24+
end

gnc/control/controller_module.m

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
function [u, r] = controller_module(time, xR, pdyn)
2+
% Top-level controller module.
3+
% u : control command, desired canard angle (rad)
4+
% r : roll angle target (rad)
5+
% time : current time stamp (s)
6+
% xR : roll state [roll angle (rad), roll rate (rad/s)]
7+
% pdyn : dynamic pressure (Pa)
8+
9+
%% settings
10+
time_launch = 10; % pad delay time
11+
time_coast = 10; % time from launch to burnout
12+
time_program = 10; % time from launch to start of roll program
13+
u_max = deg2rad(10); % limit output to this angle
14+
L_min = 0.1; % limit roll control derivative for low authority conditions
15+
16+
%% parameters
17+
persistent param
18+
if isempty(param)
19+
param = coder.load("model_params.mat");
20+
end
21+
22+
%% Reference signal
23+
% Generates reference signal r (rad) for roll program
24+
% includes multiple roll angle steps
25+
26+
t = time - time_launch;
27+
r = 0;
28+
if t > (time_program + 7)
29+
if t < (time_program + 12)
30+
r = 0.5;
31+
elseif t < (time_program + 17)
32+
r = -0.5;
33+
elseif t < (time_program + 24)
34+
r = 0.5;
35+
elseif t > (time_program + 31)
36+
r = 0;
37+
end
38+
end
39+
40+
%% controller algorithm
41+
% Computes control signal of the adaptive LQR controller.
42+
43+
%%% Coefficient Estimation
44+
pdyn_params = pdyn * params.c_canard;
45+
C_l_delta = controller_estimator(time, w, delta, pdyn_params);
46+
47+
L_delta = C_l_delta * pdyn_params;
48+
L_delta = 1 / (max(min(1/L_delta, 1/L_min), -1/L_min)); % lower bounds
49+
50+
%%% Feedback law
51+
u = controller_law(xR, r, L_delta);
52+
53+
%%% limit output to allowable angle
54+
u = min(max(u, -u_max), u_max); % upper bounds
55+
56+
if t < time_coast % disable during boost
57+
u = 0;
58+
end
59+
end
60+

gnc/model_params.m

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
clear
2+
3+
%% Launch site
4+
elevation = 420; % m above sea level
5+
6+
%% Rocket body
7+
m = 54.9; %mass in kg
8+
Jx = 0.46; % inertia roll
9+
Jy = 49.5; % inertia pitch, yaw
10+
J = diag([Jx, Jy, Jy]);
11+
Jinv = inv(J);
12+
13+
length_cg = 0; % center of gravity
14+
length_cp = -0.5; % center of pressure
15+
area_reference = pi*(0.203/2)^2; % cross section of body tube
16+
c_aero = area_reference * (length_cp-length_cg);
17+
Cn_alpha = 10; % pitch forcing coefficent
18+
Cn_omega = 0; % pitch damping coefficent
19+
20+
%% Canards
21+
area_canard = 2 * 0.102 * 0.0508 / 2; % total canard area
22+
length_canard = 0.203/2 + 0.0508/3; % lever arm of canard to x-axis
23+
c_canard = area_canard*length_canard; % moment arm * area of canard
24+
25+
%% Environment
26+
g = [-9.81; 0; 0]; % gravitational acceleration in the geographic inertial frame
27+
28+
29+
%% Sensors
30+
S1 = [0, 0, 1;
31+
1, 0, 0;
32+
0, 1, 0]; % IMU 1, rotation transform from sensor frame to body frame
33+
S2 = [0, 0, -1;
34+
-1, 0, 0;
35+
0, 1, 0]; % IMU 2, rotation transform from sensor frame to body frame
36+
37+
d1 = [1.2; 0.074; -0.027]; % center of sensor frame
38+
d2 = [1.2; 0.065; 0.047]; % center of sensor frame
39+
40+
B1 = eye(3); % Soft iron compensation
41+
B2 = eye(3); % Soft iron compensation
42+
b1 = [0;0;0]; % Hard iron compensation
43+
b2 = [0;0;0]; % Hard iron compensation
44+
45+
%% save and export
46+
save("design/model/model_params.mat");
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
function [airdata] = airdata_atmos(altitude)
2+
% computes atmospheric stanadard data from altitude, according to US standard atmosphere
3+
% atmosphere data: static pressure, temperature, density, local speed of sound
4+
% calculations found in Stengel 2004, pp. 30
5+
6+
% parameters
7+
air_gamma = 1.4; % adiabatic index
8+
air_R = 287.0579; % specific gas constant for air
9+
air_atmosphere = [0, 101325, 288.15, 0.0065; % troposphere
10+
11000, 22632.1, 216.65, 0; % tropopause
11+
20000, 5474.9, 216.65, -0.001; % stratosphere
12+
32000, 868.02, 228.65, -0.0028]; % stratosphere 2
13+
% base height, P_base, T_base, lapse rate;
14+
earth_r0 = 6356766; % mean earth radius
15+
earth_g0 = 9.81; % zero height gravity
16+
17+
% geopotential altitude
18+
altitude = earth_r0*altitude / (earth_r0 -altitude);
19+
20+
% select atmosphere behaviour from table
21+
layer = air_atmosphere(1,:);
22+
if altitude > air_atmosphere(2,1)
23+
if altitude < air_atmosphere(3,1)
24+
layer = air_atmosphere(2,:);
25+
elseif altitude < air_atmosphere(4,1)
26+
layer = air_atmosphere(3,:);
27+
elseif altitude >= air_atmosphere(4,1)
28+
layer = air_atmosphere(4,:);
29+
end
30+
end
31+
32+
b = layer(1); % base height
33+
P_B = layer(2); % base pressure
34+
T_B = layer(3); % base temperature
35+
k = layer(4); % temperature lapse rate
36+
37+
if k == 0
38+
pressure = P_B * exp(-earth_g0*(altitude-b)/(air_R*T_B));
39+
else
40+
pressure = P_B * (1 - k/T_B*(altitude-b))^(earth_g0/(air_R*k));
41+
end
42+
temperature = T_B - k*(altitude-b);
43+
density = pressure / (air_R*temperature);
44+
sonic_speed = sqrt(air_gamma*air_R*temperature);
45+
46+
% return values
47+
airdata.pressure = pressure;
48+
airdata.temperature = temperature;
49+
airdata.density = density;
50+
airdata.sonic_speed = sonic_speed;
51+
end
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
function [airdata_altitude, airdata] = airdata_atmos_jacobian(altitude)
2+
% computes atmospheric data and gradient w.r.t. altitude from altitude, according to US standard atmosphere
3+
% atmospheric data: static pressure, temperature, density, local speed of sound
4+
% calculations found in Stengel 2004, pp. 30
5+
6+
% parameters
7+
air_gamma = 1.4; % adiabatic index
8+
air_R = 287.0579; % specific gas constant for air
9+
air_atmosphere = [0, 101325, 288.15, 0.0065; % troposphere
10+
11000, 22632.1, 216.65, 0; % tropopause
11+
20000, 5474.9, 216.65, -0.001; % stratosphere
12+
32000, 868.02, 228.65, -0.0028]; % stratosphere 2
13+
% base height, P_base, T_base, lapse rate;
14+
earth_r0 = 6356766; % mean earth radius
15+
earth_g0 = 9.81; % zero height gravity
16+
17+
% geopotential altitude
18+
altitude_ratio = earth_r0 / (earth_r0 - altitude);
19+
altitude = altitude_ratio * altitude;
20+
21+
% select atmosphere behaviour from table
22+
layer = air_atmosphere(1,:);
23+
if altitude > air_atmosphere(2,1)
24+
if altitude < air_atmosphere(3,1)
25+
layer = air_atmosphere(2,:);
26+
elseif altitude < air_atmosphere(4,1)
27+
layer = air_atmosphere(3,:);
28+
elseif altitude >= air_atmosphere(4,1)
29+
layer = air_atmosphere(4,:);
30+
end
31+
end
32+
33+
b = layer(1); % base height
34+
P_B = layer(2); % base pressure
35+
T_B = layer(3); % base temperature
36+
k = layer(4); % temperature lapse rate
37+
38+
if k == 0
39+
pressure = P_B * exp(-earth_g0*(altitude-b)/(air_R*T_B));
40+
pressure_altitude = - P_B*earth_g0 / (T_B*air_R) * (altitude_ratio^2) * exp( - earth_g0*(altitude - b) / (T_B*air_R) );
41+
else
42+
pressure = P_B * (1 - k/T_B*(altitude-b))^(earth_g0/(air_R*k));
43+
pressure_altitude = - P_B*earth_g0 / (T_B*air_R) * (altitude_ratio^2) * ( 1 - k/T_B*(altitude - b) )^(earth_g0/(air_R*k) - 1);
44+
end
45+
temperature = T_B - k * (altitude - b);
46+
temperature_altitude = - k * altitude_ratio^2;
47+
density = pressure / (air_R*temperature);
48+
density_altitude = 1/air_R * (pressure_altitude * temperature - pressure * temperature_altitude) / temperature^2;
49+
sonic_speed = sqrt(air_gamma*air_R*temperature);
50+
sonic_speed_altitude = 1/2 * temperature_altitude * sqrt(air_gamma*air_R / temperature);
51+
52+
% return values
53+
airdata.pressure = pressure;
54+
airdata_altitude.pressure = pressure_altitude;
55+
airdata.density = density;
56+
airdata_altitude.density = density_altitude;
57+
airdata.sonic_speed = sonic_speed;
58+
airdata_altitude.sonic_speed = sonic_speed_altitude;
59+
end

0 commit comments

Comments
 (0)