|
| 1 | +%% Rocket Landing with Constraints |
| 2 | +% Based on: https://github.com/TinyMPC/TinyMPC/blob/main/examples/rocket_landing_mpc.cpp |
| 3 | + |
| 4 | +% Add TinyMPC class to path |
| 5 | +currentFile = mfilename('fullpath'); |
| 6 | +[scriptPath, ~, ~] = fileparts(currentFile); |
| 7 | +repoRoot = fileparts(scriptPath); |
| 8 | +addpath(fullfile(repoRoot, 'src')); |
| 9 | +addpath(fullfile(repoRoot, 'build')); |
| 10 | + |
| 11 | +% Problem dimensions |
| 12 | +NSTATES = 6; % [x, y, z, vx, vy, vz] |
| 13 | +NINPUTS = 3; % [thrust_x, thrust_y, thrust_z] |
| 14 | +NHORIZON = 10; |
| 15 | + |
| 16 | +% System dynamics (from rocket_landing_params_20hz.hpp) |
| 17 | +A = [1.0, 0.0, 0.0, 0.05, 0.0, 0.0; |
| 18 | + 0.0, 1.0, 0.0, 0.0, 0.05, 0.0; |
| 19 | + 0.0, 0.0, 1.0, 0.0, 0.0, 0.05; |
| 20 | + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0; |
| 21 | + 0.0, 0.0, 0.0, 0.0, 1.0, 0.0; |
| 22 | + 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]; |
| 23 | + |
| 24 | +B = [0.000125, 0.0, 0.0; |
| 25 | + 0.0, 0.000125, 0.0; |
| 26 | + 0.0, 0.0, 0.000125; |
| 27 | + 0.005, 0.0, 0.0; |
| 28 | + 0.0, 0.005, 0.0; |
| 29 | + 0.0, 0.0, 0.005]; |
| 30 | + |
| 31 | +fdyn = [0.0; 0.0; -0.0122625; 0.0; 0.0; -0.4905]; |
| 32 | +Q = diag([101.0, 101.0, 101.0, 101.0, 101.0, 101.0]); % From parameter file |
| 33 | +R = diag([2.0, 2.0, 2.0]); % From parameter file |
| 34 | + |
| 35 | +% Box constraints |
| 36 | +x_min = [-5.0; -5.0; -0.5; -10.0; -10.0; -20.0]; |
| 37 | +x_max = [5.0; 5.0; 100.0; 10.0; 10.0; 20.0]; |
| 38 | +u_min = [-10.0; -10.0; -10.0]; |
| 39 | +u_max = [105.0; 105.0; 105.0]; |
| 40 | + |
| 41 | +% SOC constraints |
| 42 | +cx = [0.5]; % coefficients for state cones (mu) |
| 43 | +cu = [0.25]; % coefficients for input cones (mu) |
| 44 | +Acx = [0]; % start indices for state cones |
| 45 | +Acu = [0]; % start indices for input cones |
| 46 | +qcx = [3]; % dimensions for state cones |
| 47 | +qcu = [3]; % dimensions for input cones |
| 48 | + |
| 49 | +% Setup solver |
| 50 | +solver = TinyMPC(); |
| 51 | +solver.setup(A, B, Q, R, NHORIZON, 'rho', 1.0, 'fdyn', fdyn, ... |
| 52 | + 'max_iter', 100, 'abs_pri_tol', 2e-3, 'verbose', true); |
| 53 | + |
| 54 | +solver.set_bound_constraints(x_min, x_max, u_min, u_max); |
| 55 | + |
| 56 | +% Set cone constraints |
| 57 | +solver.set_cone_constraints(Acx, qcx, cx, Acu, qcu, cu); |
| 58 | + |
| 59 | +% Initial and goal states |
| 60 | +xinit = [4.0; 2.0; 20.0; -3.0; 2.0; -4.5]; |
| 61 | +xgoal = [0.0; 0.0; 0.0; 0.0; 0.0; 0.0]; |
| 62 | +xinit_scaled = xinit * 1.1; |
| 63 | + |
| 64 | +% Initial reference trajectory |
| 65 | +x_ref = zeros(NSTATES, NHORIZON); |
| 66 | +u_ref = zeros(NINPUTS, NHORIZON-1); |
| 67 | + |
| 68 | +NTOTAL = 100; |
| 69 | +x_current = xinit_scaled; |
| 70 | + |
| 71 | +% Set initial reference |
| 72 | +for i = 1:NHORIZON |
| 73 | + x_ref(:, i) = xinit + (xgoal - xinit) * (i-1) / (NTOTAL - 1); |
| 74 | +end |
| 75 | +u_ref(3, :) = 10.0; % Hover thrust |
| 76 | + |
| 77 | +solver.set_x_ref(x_ref); |
| 78 | +solver.set_u_ref(u_ref); |
| 79 | + |
| 80 | +% Store trajectory for plotting |
| 81 | +trajectory = []; |
| 82 | +controls = []; |
| 83 | +constraint_violations = []; |
| 84 | + |
| 85 | +fprintf('Starting rocket landing simulation...\n'); |
| 86 | +for k = 1:(NTOTAL - NHORIZON) |
| 87 | + % Calculate tracking error |
| 88 | + tracking_error = norm(x_current - x_ref(:, 2)); % MATLAB is 1-indexed |
| 89 | + fprintf('tracking error: %.5f\n', tracking_error); |
| 90 | + |
| 91 | + % 1. Update measurement (set current state) |
| 92 | + solver.set_x0(x_current); |
| 93 | + |
| 94 | + % 2. Update reference trajectory |
| 95 | + for i = 1:NHORIZON |
| 96 | + x_ref(:, i) = xinit + (xgoal - xinit) * (i + k - 2) / (NTOTAL - 1); |
| 97 | + if i <= NHORIZON - 1 |
| 98 | + u_ref(3, i) = 10.0; % uref stays constant |
| 99 | + end |
| 100 | + end |
| 101 | + |
| 102 | + solver.set_x_ref(x_ref); |
| 103 | + solver.set_u_ref(u_ref); |
| 104 | + |
| 105 | + % 3. Solve MPC problem |
| 106 | + solver.solve(); |
| 107 | + solution = solver.get_solution(); |
| 108 | + |
| 109 | + % 4. Simulate forward (apply first control) |
| 110 | + u_opt = solution.controls(:, 1); |
| 111 | + x_current = A * x_current + B * u_opt + fdyn; |
| 112 | + |
| 113 | + % Store data for plotting |
| 114 | + trajectory = [trajectory, x_current]; |
| 115 | + controls = [controls, u_opt]; |
| 116 | + |
| 117 | + % Check constraint violations |
| 118 | + altitude_violation = x_current(3) < 0; % Ground constraint |
| 119 | + thrust_violation = norm(u_opt(1:2)) > 0.25 * abs(u_opt(3)); % Cone constraint |
| 120 | + constraint_violations = [constraint_violations, (altitude_violation || thrust_violation)]; |
| 121 | +end |
| 122 | + |
| 123 | +fprintf('\nSimulation completed!\n'); |
| 124 | +fprintf('Initial state was: [%.2f, %.2f, %.2f, %.2f, %.2f, %.2f]\n', xinit_scaled'); |
| 125 | +fprintf('Final position: [%.2f, %.2f, %.2f]\n', x_current(1:3)'); |
| 126 | +fprintf('Final velocity: [%.2f, %.2f, %.2f]\n', x_current(4:6)'); |
| 127 | +fprintf('Distance to goal: %.3f m\n', norm(x_current(1:3))); |
| 128 | +fprintf('Constraint violations: %d/%d\n', sum(constraint_violations), length(constraint_violations)); |
| 129 | + |
| 130 | +% Plotting |
| 131 | +figure('Position', [100, 100, 1200, 900]); |
| 132 | +sgtitle('Rocket Landing with Constraints', 'FontSize', 16); |
| 133 | + |
| 134 | +% 2D trajectory (X-Y view) |
| 135 | +subplot(2, 2, 1); |
| 136 | +plot(trajectory(1, :), trajectory(2, :), 'b-', 'LineWidth', 2); hold on; |
| 137 | +scatter(xinit_scaled(1), xinit_scaled(2), 100, 'red', 'filled'); |
| 138 | +scatter(xgoal(1), xgoal(2), 100, 'green', 'filled'); |
| 139 | +xlabel('X (m)'); ylabel('Y (m)'); |
| 140 | +legend('Trajectory', 'Start', 'Goal', 'Location', 'best'); |
| 141 | +title('2D Trajectory (X-Y)'); |
| 142 | +grid on; |
| 143 | + |
| 144 | +% Position vs time |
| 145 | +subplot(2, 2, 2); |
| 146 | +time_steps = 1:size(trajectory, 2); |
| 147 | +plot(time_steps, trajectory(1, :), 'r-', 'LineWidth', 1.5); hold on; |
| 148 | +plot(time_steps, trajectory(2, :), 'g-', 'LineWidth', 1.5); |
| 149 | +plot(time_steps, trajectory(3, :), 'b-', 'LineWidth', 1.5); |
| 150 | +yline(0, 'k--', 'Alpha', 0.5); |
| 151 | +xlabel('Time Step'); ylabel('Position (m)'); |
| 152 | +legend('X', 'Y', 'Z', 'Ground', 'Location', 'best'); |
| 153 | +title('Position vs Time'); |
| 154 | +grid on; |
| 155 | + |
| 156 | +% Velocity vs time |
| 157 | +subplot(2, 2, 3); |
| 158 | +plot(time_steps, trajectory(4, :), 'r-', 'LineWidth', 1.5); hold on; |
| 159 | +plot(time_steps, trajectory(5, :), 'g-', 'LineWidth', 1.5); |
| 160 | +plot(time_steps, trajectory(6, :), 'b-', 'LineWidth', 1.5); |
| 161 | +xlabel('Time Step'); ylabel('Velocity (m/s)'); |
| 162 | +legend('Vx', 'Vy', 'Vz', 'Location', 'best'); |
| 163 | +title('Velocity vs Time'); |
| 164 | +grid on; |
| 165 | + |
| 166 | +% Thrust vs time |
| 167 | +subplot(2, 2, 4); |
| 168 | +plot(time_steps, controls(1, :), 'r-', 'LineWidth', 1.5); hold on; |
| 169 | +plot(time_steps, controls(2, :), 'g-', 'LineWidth', 1.5); |
| 170 | +plot(time_steps, controls(3, :), 'b-', 'LineWidth', 1.5); |
| 171 | +xlabel('Time Step'); ylabel('Thrust (N)'); |
| 172 | +legend('Thrust X', 'Thrust Y', 'Thrust Z', 'Location', 'best'); |
| 173 | +title('Thrust vs Time'); |
| 174 | +grid on; |
0 commit comments