Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
6813e5e
- Chopped the quaternion to force the unit norm constant using the q0…
pabloplataa Jul 23, 2025
dce1e50
Updated constants based on the initial ASTRA v2 prototype.
pabloplataa Jul 23, 2025
f796286
Addition of Jacobian functions
pabloplataa Jul 23, 2025
446d144
Added explicit Jacobian functions in preparation for EKF generation, …
pabloplataa Jul 28, 2025
74cd5b2
Updated Simulink Model, Added basic reference and input saturation fu…
pabloplataa Jul 28, 2025
6133c64
Working Controls!
pabloplataa Jul 28, 2025
b8db2fe
Fixed Trajectory Gen
pabloplataa Jul 28, 2025
af286d3
Added a basic measurement model and corrected the C matrix
pabloplataa Jul 29, 2025
13a4eaa
Full LQG Controlled Simulation, Need to add more disturbances and con…
pabloplataa Jul 29, 2025
f1813f6
Added bias estimation and augmented state vector (still does not prop…
pabloplataa Jul 29, 2025
109a643
Working Bias Estimation and Filter + Full Flight control
pabloplataa Jul 30, 2025
447acee
Update to Jacobian Linearization in filter.
pabloplataa Jul 30, 2025
0fb6839
Saving everything before EKFv2 Updates
pabloplataa Sep 1, 2025
a73549a
Update 1: Removed online accelerometer bias estimation. Added basic p…
pabloplataa Sep 1, 2025
f04fb19
Attempt to move torwards IMU for predict step
pabloplataa Sep 1, 2025
9faa033
Back to normal (thank god)
pabloplataa Sep 2, 2025
5090be7
Added measurement Jacobian Generation
pabloplataa Sep 4, 2025
e33808d
Updated function generation calls
pabloplataa Sep 4, 2025
8026d30
Updated filter (hope it fucking work)
pabloplataa Sep 4, 2025
55c64c9
Might have to become an M-EKF smh
pabloplataa Sep 5, 2025
f9145c8
Shit STILL doesn't work
pabloplataa Sep 6, 2025
39c35de
Added missing files
pabloplataa Sep 6, 2025
2b2993f
Starting work on new simulation!
pabloplataa Oct 3, 2025
7e7c7d5
Added trajectory files
pabloplataa Oct 3, 2025
ff03e29
Added Simulation Files!
pabloplataa Oct 3, 2025
44a3d52
Delete trajectory directory
pabloplataa Oct 3, 2025
3f7b4e0
Added files
pabloplataa Oct 3, 2025
338748f
Back to cont. time LQR.
pabloplataa Oct 3, 2025
464eb73
General Simulink Sim Structure Complete. Need to fill in gaps and com…
pabloplataa Oct 4, 2025
aa325dc
Final Missing File
pabloplataa Oct 4, 2025
a0a1f37
Running full state estimator and simulation
pabloplataa Oct 4, 2025
05ba1c3
Final touches
pabloplataa Oct 5, 2025
e712df1
Abort and Wind Sim
AndyL07 Oct 11, 2025
58bd65e
Idk
pabloplataa Oct 12, 2025
ae51f75
Merge commit 'e712df1825af0d93ee3a1cb530bef8f05aad8620'
pabloplataa Oct 12, 2025
b11ec50
Removed files that should've been untracked
pabloplataa Oct 12, 2025
f7344c7
General clean-up, ground mode for disturbances, controls corrections
pabloplataa Oct 12, 2025
e7f26cb
Controller retuning
pabloplataa Oct 12, 2025
78346ad
Gust Model
AndyL07 Oct 15, 2025
5d568db
Comments removed
pabloplataa Oct 15, 2025
427ca5a
Merge commit '78346adec850a77e3195ac5ee7ea117e35d3ae87'
pabloplataa Oct 15, 2025
bb64812
Updated wind modeling
pabloplataa Oct 15, 2025
f496e74
Updated Abort Mode Logic
pabloplataa Oct 15, 2025
75e17ca
Last Change
pabloplataa Oct 15, 2025
34b6888
Full Est. State Feedback!
pabloplataa Oct 16, 2025
c1bbd62
God how does this even work wtf
pabloplataa Oct 16, 2025
204fb30
EKF Testing
pabloplataa Oct 16, 2025
17a837d
Wind Torques
AndyL07 Oct 16, 2025
0f70f52
Merge branch 'ASTRAv2_Simulation' of https://github.com/activecontrol…
AndyL07 Oct 16, 2025
9e46399
Corrections in filter to deal with additional torque from wind. Infla…
pabloplataa Oct 16, 2025
b46845d
Fixed Lever Arm for TVC and retuned based on performance. Also change…
pabloplataa Oct 16, 2025
0471ab1
Final commit
pabloplataa Oct 16, 2025
0ecdfdf
Getting ready to nuke the M-EKF and remove ang. rates from error state
pabloplataa Oct 16, 2025
e980c48
WORKDAY CHANGES TO SIMULATION THEORY:
pabloplataa Oct 18, 2025
06cb7c1
Final Sim Updates
pabloplataa Oct 18, 2025
5197212
Commit
pabloplataa Oct 21, 2025
195b1c2
Renamed SimFiles folder to Simulation.
pabloplataa Oct 23, 2025
3614e0a
Added Solve Input file and modified dynamics slightly
pabloplataa Oct 23, 2025
324fbfa
Added Controls test to .SLX file. Retuned ref generator and changed G…
pabloplataa Oct 23, 2025
4b5b86c
Retuning and stuff
pabloplataa Oct 25, 2025
af9aa85
Attempting to add accelerometer biases to filter.
pabloplataa Oct 25, 2025
6c5ce58
start C++ conversion
RobertJN64 Oct 25, 2025
c2805a9
Current working version - revert to this if need be.
pabloplataa Oct 26, 2025
71a571e
WE'RE SO CLOSE
pabloplataa Oct 26, 2025
71fd13d
ALMOST FUCKING THEREEEE
pabloplataa Oct 26, 2025
36dc4a8
Close as I could get it
pabloplataa Oct 26, 2025
1b292e6
Have not cracked it yet lmao
pabloplataa Oct 26, 2025
47bbefc
15 state filter - revert here if needed.
pabloplataa Oct 26, 2025
c26c2d5
After a long and painful two days, filter convergence when tested out…
pabloplataa Oct 26, 2025
173ac8c
After way more work than I want to admit to, there's a working filter:
pabloplataa Oct 27, 2025
3a1ec0c
include sample data
ayushc121 Oct 27, 2025
373e209
tried adding functionality to run main on a set of simulated inputs t…
ayushc121 Oct 28, 2025
cb94deb
added P, forgot about that
ayushc121 Oct 28, 2025
f8b72a7
Update main.cpp
ayushc121 Oct 28, 2025
f6077d7
Starting work on new GPS sensor model
pabloplataa Oct 28, 2025
251f857
After a week of work on this, reverting back to the old filter. Also …
pabloplataa Oct 28, 2025
be9e440
Beautiful 16 state filter with accel bias and gyro bias. REVERT HERE …
pabloplataa Oct 29, 2025
a1343a7
Halfway done w conversion
pabloplataa Oct 29, 2025
e723335
Saving current state - attempting revert to working 12 state filter
pabloplataa Oct 29, 2025
e09ebb6
Ok let's just test out the 100% old filter and revert to this if need…
pabloplataa Oct 29, 2025
c81a32f
Old filter loaded, converting to full quaternion estimation
pabloplataa Oct 29, 2025
6f52bfe
Back to a full state simulation after a while. Filter still somewhat …
pabloplataa Oct 29, 2025
d3a448d
First flight config filter. This will be left untouched for a while -…
pabloplataa Oct 29, 2025
57e0947
WORKING FILTER. 100% CONFIRMED. HARD REVRT TO HERE IF YOU NEED TO.
pabloplataa Oct 29, 2025
56c7277
Ok please I'm tired of updating this fucking thing
pabloplataa Oct 29, 2025
ff6855a
ASTRAv2 Multicheckpoint flight test example.
pabloplataa Oct 29, 2025
7875a14
ASTRAv2 Multi-Checkpoint Flight Demonstration
pabloplataa Oct 29, 2025
ec5018f
Added Plotting function and other cool stuff
pabloplataa Oct 29, 2025
d38bfab
updated C++ filter conversion
RobertJN64 Oct 30, 2025
f309b41
cleanup included files
RobertJN64 Oct 30, 2025
0746c9c
Merge branch 'ASTRAv2_Simulation' into patch-1
RobertJN64 Oct 30, 2025
894a740
Merge pull request #3 from ayushc121/patch-1
RobertJN64 Oct 30, 2025
215e265
Added plotting
pabloplataa Oct 30, 2025
c4f006f
update test wrapper to use new filter inputs
RobertJN64 Oct 30, 2025
353a4d8
new packet detection system for matlab comparison testing
RobertJN64 Oct 30, 2025
afc318c
Merge commit '353a4d8176235c763939c0d0550d6d32e9085698'
pabloplataa Oct 30, 2025
e59c889
Filter and controls retuning. New plots!
pabloplataa Oct 31, 2025
a3f4ca4
Actuator Disturbance
AndyL07 Oct 31, 2025
20d7db1
Messing around with tuning and stuff!
pabloplataa Oct 31, 2025
3750dd8
Commit Workday!
pabloplataa Nov 1, 2025
39c8a3c
cleanup git, support portenta upload delay script
RobertJN64 Nov 1, 2025
99ed644
funcs to export a matlab run
RobertJN64 Nov 1, 2025
d24c99b
off by one error in filter, fix matrix exp, init R matrix correctly, …
RobertJN64 Nov 1, 2025
4ed13fe
update C++ filter to keep up with matlab
RobertJN64 Nov 1, 2025
9498c12
testing C++ filter on portenta
RobertJN64 Nov 1, 2025
1b91f34
fix performance issues on portenta
RobertJN64 Nov 4, 2025
cbc51be
Position set to absolute zero when grounded
pabloplataa Nov 4, 2025
1b8c71e
De-tuning GPS works!
pabloplataa Nov 4, 2025
ec98dc5
Addition of a GMP + EMA step for the wind disturbance model, as to ma…
pabloplataa Nov 4, 2025
4e99d2d
Addition of two filter modes (full INS when GPS available, pure in-fl…
pabloplataa Nov 4, 2025
c377181
Re-tested all three flight modes (INS.RTK, INS, INTEGRATOR) and updat…
pabloplataa Nov 5, 2025
37a6634
Working everything - revert here if need be, adding prediction step i…
pabloplataa Nov 5, 2025
a064021
Revert "Working everything - revert here if need be, adding predictio…
pabloplataa Nov 5, 2025
630075c
Back to normal
pabloplataa Nov 5, 2025
0b7d53f
Perfect filter tuning let's use this for now!
pabloplataa Nov 5, 2025
8dc0de2
RTK switches and fixed pure integrator. Now matches RMS theory
pabloplataa Nov 6, 2025
468f351
update C++ filter to keep up with matlab version
RobertJN64 Nov 8, 2025
721790f
bugfix: forgot to return x_est from C++ filter
RobertJN64 Nov 8, 2025
ab98d36
changes to allow for testing controller output against simulated matl…
ayushc121 Nov 8, 2025
548bb80
minor fixes to full controller simulation harness
RobertJN64 Nov 8, 2025
c586445
Renamed the State Estimation folder to "Filtering"
pabloplataa Nov 11, 2025
6e751dd
Merge commit '548bb80e45a5a569da5a8784c9c88283c5f0240e'
pabloplataa Nov 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions .gitattributes

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
**/*.slxc
**/.DS_Store
**/.slprj
slprj
37 changes: 37 additions & 0 deletions Actuators/ActuatorDynamics.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
function xdot = ActuatorDynamics(x, u)
xdot = zeros(6, 1);
% Simple actuator model
% x(1) Theta
% x(2) Rate 1
% x(3) Phi 2
% x(4) Rate 2
% x(5) Thrust
% x(6) Roll

% Assume identical servos for gimbal
a = 700;
b = 40;

k1 = 0.5;
k2 = 0.5;

theta_error = k1 * (1 - cos(x(1)));
phi_error = k2 * (1 - cos(x(3)));

x(3) = x(3) - theta_error;
x(1) = x(1) - phi_error;

xdot(1:4) = [x(2);
a*(u(1) - x(1)) - b*x(2);
x(4);
a*(u(2) - x(3)) - b*x(4)];

% Assume first order response for thrust
tau = 0.15;
xdot(5) = (1/tau) * (u(3) - x(5));

% Since torque depends on thrust changes on two fans, response time is
% half that of thrust
xdot(6) = (1/(tau/2)) * (u(4) - x(6));

end
55 changes: 55 additions & 0 deletions Actuators/ActuatorTest.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
% Test code for actuator modeling responses
clear;
close all;

% Initialize time for simulation
res = 5000;
tmax = 10;
dt = tmax / res;
tsim = linspace(0,tmax,res);
norm = [pi/24; pi/24; 14; 15];

% Target step response to max values
start = 100;
utrg = [zeros(4, start), norm .* ones(4, res - start)];
usim = zeros(4,res);
xsim = zeros(6,res);

% Initialize data tables
theta_target = zeros(1, res);
phi_target = zeros(1, res);
theta_actual = zeros(1, res);
phi_actual = zeros(1, res);

% Simulation loop
for i = 2:1:res
theta_target(i) = norm(1); %* cos(tsim(i) * 1);
phi_target(i) = norm(2) * sin(tsim(i) * 1) * 0;
utrg(1:2, i) = [theta_target(i); phi_target(i)];

xsim(:,i) = xsim(:,i-1) + ActuatorDynamics(xsim(:,i-1), utrg(:, i)) * dt;
usim(:,i) = [xsim(1,i); xsim(3,i); xsim(5:6,i)];

theta_actual(:, i) = xsim(1, i);
phi_actual(:, i) = xsim(3, i);
end

% Plot results
figure;
plot(tsim, usim .* [180/pi; 180/pi; 1; 1]); hold on; grid on;
plot(tsim, utrg .* [180/pi; 180/pi; 1; 1], 'r--');
% plot(tsim, (utrg - usim) .* [180/pi; 180/pi; 1; 1]);
legend('Angle 1', 'Angle 2', 'Thrust', 'Torque');

figure;
subplot(2, 1, 1)
plot(theta_target, theta_actual); grid on;
title("Theta Target vs Actual")

subplot(2, 1, 2)
plot(phi_target, phi_actual); grid on;
title("Phi Target vs Actual")

figure;
plot(xsim(1,:), xsim(3,:), "b*");
axis equal
45 changes: 45 additions & 0 deletions Controls/JacobianU.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
function out1 = JacobianU(in1,in2)
%JacobianU
% OUT1 = JacobianU(IN1,IN2)

% This function was generated by the Symbolic Math Toolbox version 25.2.
% 05-Nov-2025 19:06:56

phi = in2(2,:);
q1 = in1(1,:);
q2 = in1(2,:);
q3 = in1(3,:);
tau = in2(4,:);
theta = in2(1,:);
thrust = in2(3,:);
t2 = cos(phi);
t3 = cos(theta);
t4 = sin(phi);
t5 = sin(theta);
t6 = q1.^2;
t7 = q2.^2;
t8 = q3.^2;
t9 = q1.*q2.*2.0;
t10 = q1.*q3.*2.0;
t11 = q2.*q3.*2.0;
t12 = t6.*2.0;
t13 = t7.*2.0;
t14 = t8.*2.0;
t18 = -t6;
t19 = -t7;
t20 = -t8;
t21 = t12+t13-1.0;
t22 = t12+t14-1.0;
t23 = t13+t14-1.0;
t24 = t18+t19+t20+1.0;
t25 = sqrt(t24);
t26 = q1.*t25.*2.0;
t27 = q2.*t25.*2.0;
t28 = q3.*t25.*2.0;
t29 = t11+t26;
t30 = t10+t27;
t31 = t9+t28;
mt1 = [0.0,0.0,0.0,0.0,0.0,0.0,-t3.*thrust.*(t9-t28)+t4.*t5.*t23.*thrust-t2.*t5.*t30.*thrust,t3.*t22.*thrust-t4.*t5.*t31.*thrust-t2.*t5.*thrust.*(t11-t26),-t3.*t29.*thrust+t2.*t5.*t21.*thrust-t4.*t5.*thrust.*(t10-t27),t3.*thrust.*(1.2e+1./5.0)-t4.*t5.*tau.*2.0e+1,t3.*tau.*(-1.0e+3./5.3e+1)-t4.*t5.*thrust.*(1.2e+2./5.3e+1),t2.*t5.*tau.*(-1.0e+3./5.3e+1),0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-t2.*t3.*t23.*thrust-t3.*t4.*t30.*thrust,t2.*t3.*t31.*thrust-t3.*t4.*thrust.*(t11-t26),t3.*t4.*t21.*thrust+t2.*t3.*thrust.*(t10-t27),t2.*t3.*tau.*2.0e+1];
mt2 = [t2.*t3.*thrust.*(1.2e+2./5.3e+1),t3.*t4.*tau.*(-1.0e+3./5.3e+1),0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-t5.*(t9-t28)-t3.*t4.*t23+t2.*t3.*t30,t5.*t22+t3.*t4.*t31+t2.*t3.*(t11-t26),-t5.*t29-t2.*t3.*t21+t3.*t4.*(t10-t27),t5.*(1.2e+1./5.0),t3.*t4.*(1.2e+2./5.3e+1),0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,t3.*t4.*2.0e+1,t5.*(-1.0e+3./5.3e+1),t2.*t3.*(1.0e+3./5.3e+1),0.0,0.0,0.0];
out1 = reshape([mt1,mt2],15,4);
end
89 changes: 89 additions & 0 deletions Controls/JacobianX.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
function out1 = JacobianX(in1,in2)
%JacobianX
% OUT1 = JacobianX(IN1,IN2)

% This function was generated by the Symbolic Math Toolbox version 25.2.
% 05-Nov-2025 19:06:55

b4 = in1(13,:);
b5 = in1(14,:);
b6 = in1(15,:);
omega1 = in1(10,:);
omega2 = in1(11,:);
omega3 = in1(12,:);
phi = in2(2,:);
q1 = in1(1,:);
q2 = in1(2,:);
q3 = in1(3,:);
theta = in2(1,:);
thrust = in2(3,:);
t2 = cos(phi);
t3 = cos(theta);
t4 = sin(phi);
t5 = sin(theta);
t6 = q1.*2.0;
t7 = q2.*2.0;
t8 = q3.*2.0;
t9 = q1.^2;
t10 = q2.^2;
t11 = q3.^2;
t12 = -omega1;
t13 = -omega2;
t14 = -omega3;
t15 = b4./2.0;
t16 = b5./2.0;
t17 = b6./2.0;
t18 = omega1./2.0;
t19 = omega2./2.0;
t20 = omega3./2.0;
t21 = q1./2.0;
t22 = q2./2.0;
t23 = q3./2.0;
t30 = b4.*(3.0./5.3e+1);
t31 = b5.*(3.0./5.3e+1);
t32 = b6.*(3.0./5.3e+1);
t33 = omega1.*(3.0./5.3e+1);
t34 = omega2.*(3.0./5.3e+1);
t35 = omega3.*(3.0./5.3e+1);
t24 = -t9;
t25 = -t10;
t26 = -t11;
t27 = b4+t12;
t28 = b5+t13;
t29 = b6+t14;
t36 = -t21;
t37 = -t22;
t38 = -t23;
t39 = -t30;
t40 = -t33;
t41 = t33+t39;
t42 = t30+t40;
t43 = t24+t25+t26+1.0;
t44 = sqrt(t43);
t45 = 1.0./t44;
t46 = t44.*2.0;
t47 = t44./2.0;
t48 = q2.*t6.*t45;
t49 = q3.*t6.*t45;
t50 = q3.*t7.*t45;
t51 = -t47;
t55 = q1.*q2.*t45.*-2.0;
t56 = q1.*q3.*t45.*-2.0;
t57 = q2.*q3.*t45.*-2.0;
t58 = t9.*t45.*-2.0;
t59 = t10.*t45.*-2.0;
t60 = t11.*t45.*-2.0;
t61 = t6+t50;
t62 = t7+t49;
t63 = t8+t48;
t64 = t6+t57;
t65 = t7+t56;
t66 = t8+t55;
t67 = t46+t58;
t68 = t46+t59;
t69 = t46+t60;
mt1 = [t21.*t27.*t45,t17-t20+t21.*t28.*t45,-t16+t19+t21.*t29.*t45,0.0,0.0,0.0,-t5.*t62.*thrust+t2.*t3.*t66.*thrust,q1.*t5.*thrust.*4.0-t2.*t3.*t67.*thrust+t3.*t4.*t65.*thrust,-t5.*t67.*thrust-q1.*t2.*t3.*thrust.*4.0+t3.*t4.*t63.*thrust,0.0,0.0,0.0,0.0,0.0,0.0,-t17+t20+t22.*t27.*t45,t22.*t28.*t45,t15-t18+t22.*t29.*t45,0.0,0.0,0.0,-t5.*t61.*thrust-q2.*t3.*t4.*thrust.*4.0+t2.*t3.*t68.*thrust,t2.*t3.*t63.*thrust+t3.*t4.*t64.*thrust,-t5.*t66.*thrust-q2.*t2.*t3.*thrust.*4.0-t3.*t4.*t68.*thrust,0.0,0.0,0.0,0.0,0.0,0.0,t16-t19+t23.*t27.*t45,-t15+t18+t23.*t28.*t45,t23.*t29.*t45,0.0,0.0,0.0];
mt2 = [t5.*t69.*thrust-q3.*t3.*t4.*thrust.*4.0+t2.*t3.*t64.*thrust,q3.*t5.*thrust.*4.0+t2.*t3.*t62.*thrust+t3.*t4.*t69.*thrust,-t5.*t65.*thrust+t3.*t4.*t61.*thrust,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,t47,t23,t37,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-t32+t35,t31-t34,0.0,0.0,0.0,t38,t47,t21,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,t42,0.0,0.0,0.0,t22,t36,t47,0.0,0.0,0.0,0.0,0.0,0.0,0.0,t41,0.0,0.0,0.0,0.0,t51,t38,t22,0.0];
mt3 = [0.0,0.0,0.0,0.0,0.0,0.0,t32-t35,-t31+t34,0.0,0.0,0.0,t23,t51,t36,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,t41,0.0,0.0,0.0,t37,t21,t51,0.0,0.0,0.0,0.0,0.0,0.0,0.0,t42,0.0,0.0,0.0,0.0];
out1 = reshape([mt1,mt2,mt3],15,15);
end
50 changes: 50 additions & 0 deletions Controls/SolveInput.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function computes the optimal input at the current timestep by
% re-linearizing LQR at the current estimated state x0. We then find an input
% u0 such that Ax0 + Bu0 = 0 and solve for our optimal Gain Matrix K. We
% then add this u0 input as a feedforward signal.
%
% By: Pablo Plata - 10/22/25
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [K, u] = SolveInput(x0, x_ref, u0)

% Calculate the J_u Jacobian [B matrices] at thrust up
B = JacobianU([x0; zeros(3,1)], u0);
B = B(1:12,:);

% Solve for u0 such that Ax0 + Bu0 = 0
% invp(B) is the Moore-Penrose pseudoinverse of B
% check Eigen availability of this function, prob avaiable under SVD.
xdot = nominalDynamics([x0; zeros(3,1)], zeros(4,1));
u0 = -pinv(B) * xdot(1:12);

% Calculate the J_x Jacobian [A matrices] at current state
A = JacobianX([x0; zeros(3,1)], u0);
A = A(1:12,1:12);

% Define Q and R matrices for LQR using Bryson's Rule
a_weights = ones(12,1);
b_weights = ones(4,1);
a_weights = a_weights / norm(a_weights);
b_weights = b_weights / norm(b_weights);

max_x = [2, 2, 0.08, 1000, 1000, 1000, 0.8, 0.8, 2, 2, 2, 10];
max_u = [pi/30, pi/30, 6, 0.5];

Q = eye(size(A,1)) .* a_weights ./ max_x.^2;
R = eye(size(B,2)) .* b_weights ./ max_u.^2;

% Solve the LQR problem and compute gain matrix.
K = SolveLQR(A, B, Q, R);

% Compute optimal input
u = -K * (x0 - x_ref) + u0;

% Input saturation
thrust_max = 1.5 * 9.8;
maxU = [pi/24; pi/24; thrust_max; thrust_max * 10];
minU = [-pi/24; -pi/24; thrust_max * 0.4; -thrust_max * 10];
u = max(minU, u);
u = min(maxU, u);
42 changes: 42 additions & 0 deletions Controls/SolveLQR.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% The following function solves an infinite time horizon LQR problem by
% computing the unique solution P to the Continious-Time Algebraic Ricatti
% Equation (CARE) using the Hamiltonian matrix. This solution is then used
% to compute the optimal gain matrix for controls.
%
% By: Pablo Plata - 10/22/25
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function K = SolveLQR(A, B, Q, R)

% Define the Hamiltonian matrix H (size 2n x 2n)
R_inv = inv(R);
H = [A -B * R_inv * B';
-Q -A'];

% Find eigenvalues of the Hamiltonian
% (eig(H) function returns a matrix of
% eigenvectors of H and a diagonal matrix of eigenvalues of H.)
[EVec_H, EVal_H] = eig(H);
EVal_H = diag(EVal_H);
NegEigen = real(EVal_H) < 0;

% Denote the V matrix, containing the eigenvectors corresponding to stable
% eigenvalues. Then decompose into V1 (first n rows) and V2 (last n rows)
V = EVec_H(:, NegEigen);
V1 = V(1:size(A,1), :);
V2 = V(size(A,1)+1:end,:);

% Compute the solution P to the Algebraic Riccati Equation, and ensure real
% coefficients and symmetry
P = V2 / V1;
P = real(P);
P = (P + P') / 2;

% Compute the gain matrix for the stabilizing solution
K = R_inv * B' * P;



Loading