Skip to content

Commit 89cdcab

Browse files
Merge pull request #5 from moisesmata/linear-cone-equal-constraints
Add more support for constraints: Linear, Equality, Cone, Bound
2 parents c100de4 + 244fe6c commit 89cdcab

7 files changed

+412
-97
lines changed

README.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,13 @@ controls_trajectory = solution.controls; % All predicted controls (1×19)
8888
### Code Generation Workflow
8989

9090
```matlab
91-
% Setup solver with constraints
91+
% Setup solver
9292
solver = TinyMPC();
9393
u_min = -0.5; u_max = 0.5; % Control bounds
94-
solver.setup(A, B, Q, R, N, 'u_min', u_min, 'u_max', u_max, 'rho', 1.0);
94+
solver.setup(A, B, Q, R, N, 'rho', 1.0);
95+
96+
% Set bounds explicitly
97+
solver.set_bound_constraints([], [], u_min, u_max);
9598
9699
% Generate C++ code
97100
solver.codegen('out');
@@ -148,6 +151,25 @@ solver.codegen_with_sensitivity(output_dir, dK, dP, dC1, dC2)
148151
[dK, dP, dC1, dC2] = solver.compute_sensitivity_autograd()
149152
```
150153

154+
### Constraints API
155+
156+
```matlab
157+
% Bounds (box constraints)
158+
solver.set_bound_constraints(x_min, x_max, u_min, u_max);
159+
160+
% Linear inequalities
161+
solver.set_linear_constraints(Alin_x, blin_x, Alin_u, blin_u);
162+
163+
% Second-order cones (states first, then inputs)
164+
solver.set_cone_constraints(Acx, qcx, cx, Acu, qcu, cu);
165+
166+
% Equality constraints (implemented as paired inequalities)
167+
% Aeq_x * x == beq_x, Aeq_u * u == beq_u
168+
solver.set_equality_constraints(Aeq_x, beq_x, Aeq_u, beq_u);
169+
```
170+
171+
Each call auto-enables the corresponding constraint(s) in the C++ layer.
172+
151173
### Configuration
152174

153175
```matlab

examples/cartpole_example_code_generation.m

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@
2626
% Create solver
2727
solver = TinyMPC();
2828

29-
% Setup solver with matrices and constraints
30-
solver.setup(A, B, Q, R, N, 'u_min', u_min, 'u_max', u_max, 'rho', 1.0, 'verbose', true);
29+
% Setup solver
30+
solver.setup(A, B, Q, R, N, 'rho', 1.0, 'verbose', true);
31+
32+
% Set bounds explicitly
33+
solver.set_bound_constraints([], [], u_min, u_max);
3134

3235
% Generate code
3336
solver.codegen('out');

examples/cartpole_example_mpc_reference_constrained.m

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@
2626
% Create solver
2727
solver = TinyMPC();
2828

29-
% Setup solver with matrices and constraints
30-
solver.setup(A, B, Q, R, N, 'u_min', u_min, 'u_max', u_max);
29+
% Setup solver
30+
solver.setup(A, B, Q, R, N);
31+
32+
% Set bounds explicitly
33+
solver.set_bound_constraints([], [], u_min, u_max);
3134

3235
% Set reference trajectory (goal must be another equilibrium position)
3336
x_ref = repmat([1.0; 0; 0; 0], 1, N); % 4x20 matrix

examples/interactive_cartpole.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
u_min = -5; % Force constraint (min)
3939
u_max = 5; % Force constraint (max)
4040

41-
prob.setup(A, B, Q, R, N, 'u_min', u_min, 'u_max', u_max, 'rho', 0.1);
41+
prob.setup(A, B, Q, R, N, 'rho', 0.1);
42+
prob.set_bound_constraints([], [], u_min, u_max);
4243

4344
% Set reference trajectory (origin stabilization)
4445
Xref = zeros(n, N); % nx x N
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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

Comments
 (0)