Skip to content

Commit 0962e16

Browse files
committed
getting rocket landing example to work
1 parent 35ea33e commit 0962e16

3 files changed

Lines changed: 330 additions & 29 deletions

File tree

cvxpy/sandbox/control_of_car.py

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import cvxpy as cp
55

66

7-
def solve_car_control(x_final, L=0.1, N=10, h=0.1, gamma=10):
7+
def solve_car_control(x_final, L=0.1, N=25, h=0.1, gamma=10):
88
"""
99
Solve the nonlinear optimal control problem for car trajectory planning.
1010
@@ -19,9 +19,9 @@ def solve_car_control(x_final, L=0.1, N=10, h=0.1, gamma=10):
1919
- x_opt: optimal states (N+1 x 3)
2020
- u_opt: optimal controls (N x 2)
2121
"""
22-
23-
# Variables
24-
# States: x[k] = [p1(k), p2(k), theta(k)]
22+
# Add random seed for reproducibility
23+
np.random.seed(78)
24+
2525
x = [cp.Variable(3) for _ in range(N+1)]
2626
# Controls: u[k] = [s(k), phi(k)]
2727
u = [cp.Variable(2) for _ in range(N)]
@@ -78,10 +78,6 @@ def plot_trajectory(x_opt, u_opt, L, h, title="Car Trajectory"):
7878
Plot the car trajectory with orientation indicators.
7979
"""
8080
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
81-
82-
# Convert x_opt to numpy array for easier indexing
83-
x_opt = np.array([xi.value for xi in x_opt])
84-
u_opt = np.array([ui.value for ui in u_opt])
8581
# Plot trajectory
8682
ax.plot(x_opt[:, 0], x_opt[:, 1], 'b-', linewidth=2, label='Trajectory')
8783

@@ -150,29 +146,28 @@ def plot_trajectory(x_opt, u_opt, L, h, title="Car Trajectory"):
150146
f"p2={x_opt[-1].value[1]:.3f}, "
151147
f"theta={x_opt[-1].value[2]:.3f}"
152148
)
153-
149+
x_opt = np.array([xi.value for xi in x_opt])
150+
u_opt = np.array([ui.value for ui in u_opt])
154151
# Plot the trajectory
155152
fig, ax = plot_trajectory(x_opt, u_opt, L=0.1, h=0.1, title=description)
156153
plt.show()
157154
else:
158155
print("Optimization failed!")
159-
"""
160-
# Additional analysis: plot control inputs
161-
if x_opt is not None and u_opt is not None:
162-
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6))
163-
164-
time_steps = np.arange(len(u_opt)) * 0.1 # h = 0.1
165-
166-
ax1.plot(time_steps, u_opt[:, 0], 'b-', linewidth=2)
167-
ax1.set_ylabel('Speed s(t)')
168-
ax1.set_xlabel('Time')
169-
ax1.grid(True, alpha=0.3)
170-
171-
ax2.plot(time_steps, u_opt[:, 1], 'r-', linewidth=2)
172-
ax2.set_ylabel('Steering angle φ(t)')
173-
ax2.set_xlabel('Time')
174-
ax2.grid(True, alpha=0.3)
175-
176-
plt.tight_layout()
177-
plt.show()
178-
"""
156+
# Additional analysis: plot control inputs
157+
if x_opt is not None and u_opt is not None:
158+
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6))
159+
160+
time_steps = np.arange(len(u_opt)) * 0.1 # h = 0.1
161+
162+
ax1.plot(time_steps, u_opt[:, 0], 'b-', linewidth=2)
163+
ax1.set_ylabel('Speed s(t)')
164+
ax1.set_xlabel('Time')
165+
ax1.grid(True, alpha=0.3)
166+
167+
ax2.plot(time_steps, u_opt[:, 1], 'r-', linewidth=2)
168+
ax2.set_ylabel('Steering angle φ(t)')
169+
ax2.set_xlabel('Time')
170+
ax2.grid(True, alpha=0.3)
171+
172+
plt.tight_layout()
173+
plt.show()
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import cvxpy as cp
2+
import numpy as np
3+
import matplotlib.pyplot as plt
4+
5+
6+
def solve_car_control(x_final, L=0.1, N=10, h=0.1, gamma=10):
7+
"""
8+
Solve the nonlinear optimal control problem for car trajectory planning.
9+
10+
Parameters:
11+
- x_final: tuple (p1, p2, theta) for final position and orientation
12+
- L: wheelbase length
13+
- N: number of time steps
14+
- h: time step size
15+
- gamma: weight for control smoothness term
16+
17+
Returns:
18+
- x_opt: optimal states (N+1 x 3)
19+
- u_opt: optimal controls (N x 2)
20+
"""
21+
# Add random seed for reproducibility
22+
np.random.seed(42)
23+
# Variables
24+
# States: x[k] = [p1(k), p2(k), theta(k)]
25+
x = cp.Variable((N+1, 3))
26+
# Controls: u[k] = [s(k), phi(k)]
27+
u = cp.Variable((N, 2))
28+
29+
# Initial state (starting at origin with zero orientation)
30+
x_init = np.array([0, 0, 0])
31+
32+
# Objective function
33+
objective = 0
34+
35+
# Sum of squared control inputs
36+
for k in range(N):
37+
objective += cp.sum_squares(u[k, :])
38+
39+
# Control smoothness term
40+
for k in range(N-1):
41+
objective += gamma * cp.sum_squares(u[k+1, :] - u[k, :])
42+
43+
# Constraints
44+
constraints = []
45+
46+
# Initial state constraint
47+
constraints.append(x[0, :] == x_init)
48+
49+
# Dynamics constraints
50+
# Note: We're pretending cp.sin, cp.cos, and cp.tan exist as atoms
51+
for k in range(N):
52+
# x[k+1] = f(x[k], u[k])
53+
# where f(x, u) = x + h * [u[0]*cos(x[2]), u[0]*sin(x[2]), u[0]*tan(u[1])/L]
54+
55+
# Position dynamics
56+
constraints.append(x[k+1, 0] == x[k, 0] + h * u[k, 0] * cp.cos(x[k, 2]))
57+
constraints.append(x[k+1, 1] == x[k, 1] + h * u[k, 0] * cp.sin(x[k, 2]))
58+
59+
# Orientation dynamics
60+
constraints.append(x[k+1, 2] == x[k, 2] + h * (u[k, 0] / L) * cp.tan(u[k, 1]))
61+
62+
# Final state constraint
63+
constraints.append(x[N, :] == x_final)
64+
65+
# Steering angle limits (optional but realistic)
66+
# Assuming max steering angle of 45 degrees
67+
max_steering = np.pi / 4
68+
constraints.append(u[:, 1] >= -max_steering)
69+
constraints.append(u[:, 1] <= max_steering)
70+
71+
# Create and solve the problem
72+
problem = cp.Problem(cp.Minimize(objective), constraints)
73+
74+
# Solve using an appropriate solver
75+
# For nonlinear problems, we might need special solver options
76+
problem.solve(solver=cp.SCS, verbose=True)
77+
78+
# Extract solution
79+
x_opt = x.value
80+
u_opt = u.value
81+
82+
return x_opt, u_opt
83+
84+
85+
def plot_trajectory(x_opt, u_opt, L, h, title="Car Trajectory"):
86+
"""
87+
Plot the car trajectory with orientation indicators.
88+
"""
89+
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
90+
91+
# Plot trajectory
92+
ax.plot(x_opt[:, 0], x_opt[:, 1], 'b-', linewidth=2, label='Trajectory')
93+
94+
# Plot car position and orientation at several time steps
95+
car_length = L
96+
car_width = L * 0.6
97+
98+
# Select time steps to show car outline (every 5th step)
99+
steps_to_show = range(0, len(x_opt), 5)
100+
101+
for k in steps_to_show:
102+
p1, p2, theta = x_opt[k]
103+
104+
# Car outline (simplified rectangle)
105+
# Front of car
106+
front_x = p1 + (car_length/2) * np.cos(theta)
107+
front_y = p2 + (car_length/2) * np.sin(theta)
108+
109+
# Rear of car
110+
rear_x = p1 - (car_length/2) * np.cos(theta)
111+
rear_y = p2 - (car_length/2) * np.sin(theta)
112+
113+
# Draw car as a line with orientation
114+
ax.plot([rear_x, front_x], [rear_y, front_y], 'k-', linewidth=3, alpha=0.5)
115+
116+
# Draw steering angle indicator if not at final position
117+
if k < len(u_opt):
118+
phi = u_opt[k, 1]
119+
# Steering direction from front of car
120+
steer_x = front_x + (car_length/3) * np.cos(theta + phi)
121+
steer_y = front_y + (car_length/3) * np.sin(theta + phi)
122+
ax.plot([front_x, steer_x], [front_y, steer_y], 'r-', linewidth=2, alpha=0.7)
123+
124+
# Mark start and end points
125+
ax.plot(x_opt[0, 0], x_opt[0, 1], 'go', markersize=10, label='Start')
126+
ax.plot(x_opt[-1, 0], x_opt[-1, 1], 'ro', markersize=10, label='Goal')
127+
128+
ax.set_xlabel('p1')
129+
ax.set_ylabel('p2')
130+
ax.set_title(title)
131+
ax.legend()
132+
ax.grid(True, alpha=0.3)
133+
ax.axis('equal')
134+
135+
return fig, ax
136+
137+
138+
# Example usage
139+
if __name__ == "__main__":
140+
# Test cases from the figure
141+
test_cases = [
142+
((0, 1, 0), "Move forward to (0, 1)"),
143+
#((0, 1, np.pi/2), "Move to (0, 1) and turn 90°"),
144+
#((0, 0.5, 0), "Move forward to (0, 0.5)"),
145+
#((0.5, 0.5, -np.pi/2), "Move to (0.5, 0.5) and turn -90°")
146+
]
147+
148+
# Solve for each test case
149+
for x_final, description in test_cases:
150+
print(f"\nSolving for: {description}")
151+
print(f"Target state: p1={x_final[0]}, p2={x_final[1]}, theta={x_final[2]:.2f}")
152+
153+
try:
154+
x_opt, u_opt = solve_car_control(x_final)
155+
156+
if x_opt is not None and u_opt is not None:
157+
print("Optimization successful!")
158+
print(f"Final position: p1={x_opt[-1, 0]:.3f}, p2={x_opt[-1, 1]:.3f}, theta={x_opt[-1, 2]:.3f}")
159+
160+
# Plot the trajectory
161+
fig, ax = plot_trajectory(x_opt, u_opt, L=0.1, h=0.1, title=description)
162+
plt.show()
163+
else:
164+
print("Optimization failed!")
165+
166+
except Exception as e:
167+
print(f"Error: {e}")
168+
169+
# Additional analysis: plot control inputs
170+
if x_opt is not None and u_opt is not None:
171+
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6))
172+
173+
time_steps = np.arange(len(u_opt)) * 0.1 # h = 0.1
174+
175+
ax1.plot(time_steps, u_opt[:, 0], 'b-', linewidth=2)
176+
ax1.set_ylabel('Speed s(t)')
177+
ax1.set_xlabel('Time')
178+
ax1.grid(True, alpha=0.3)
179+
180+
ax2.plot(time_steps, u_opt[:, 1], 'r-', linewidth=2)
181+
ax2.set_ylabel('Steering angle φ(t)')
182+
ax2.set_xlabel('Time')
183+
ax2.grid(True, alpha=0.3)
184+
185+
plt.tight_layout()
186+
plt.show()

cvxpy/sandbox/rocket_landing.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import matplotlib.pyplot as plt
2+
import numpy as np
3+
4+
import cvxpy as cp
5+
6+
# Data - all parameters normalized to be dimensionless
7+
h_0 = 1 # Initial height
8+
v_0 = 0 # Initial velocity
9+
m_0 = 1.0 # Initial mass
10+
m_T = 0.6 # Final mass
11+
g_0 = 1 # Gravity at the surface
12+
h_c = 500 # Used for drag
13+
c = 0.5 * np.sqrt(g_0 * h_0) # Thrust-to-fuel mass
14+
D_c = 0.5 * 620 * m_0 / g_0 # Drag scaling
15+
u_t_max = 3.5 * g_0 * m_0 # Maximum thrust
16+
T_max = 0.2 # Number of seconds
17+
T = 10 # Number of time steps
18+
dt = 0.2 / T # Time per discretized step
19+
20+
# Create variables
21+
x_v = cp.Variable(T, bounds=[0, np.inf]) # Velocity
22+
x_h = cp.Variable(T, bounds=[0,np.inf]) # Height
23+
x_m = cp.Variable(T) # Mass
24+
u_t = cp.Variable(T, bounds=[0, u_t_max]) # Thrust
25+
26+
# Set starting values (equivalent to JuMP's start parameter)
27+
x_v.value = np.full(T, v_0) # start = v_0
28+
x_h.value = np.full(T, h_0) # start = h_0
29+
x_m.value = np.full(T, m_0) # start = m_0
30+
u_t.value = np.zeros(T) # start = 0
31+
32+
# Define forces as functions
33+
def D(x_h_val, x_v_val):
34+
"""Drag force function"""
35+
return D_c * cp.square(x_v_val) * cp.exp(-h_c * (x_h_val - h_0) / h_0)
36+
37+
def g(x_h_val):
38+
"""Gravity function"""
39+
return g_0 * cp.square(h_0 / x_h_val)
40+
41+
# Define time derivative function
42+
def ddt(x, t):
43+
"""Time derivative using backward difference"""
44+
return (x[t] - x[t-1]) / dt
45+
46+
# Initialize constraints list
47+
constraints = []
48+
49+
# Boundary conditions
50+
constraints.append(x_v[0] == v_0)
51+
constraints.append(x_h[0] == h_0)
52+
constraints.append(x_m[0] == m_0)
53+
constraints.append(u_t[T-1] == 0.0)
54+
55+
# Mass constraints
56+
constraints.append(x_m >= m_T)
57+
58+
# Thrust constraints
59+
constraints.append(u_t <= u_t_max)
60+
61+
# Dynamical equations as constraints
62+
for t in range(1, T):
63+
# Rate of ascent: dx_h/dt = x_v
64+
constraints.append(ddt(x_h, t) == x_v[t-1])
65+
66+
# Acceleration: dx_v/dt = (u_t - D(x_h, x_v))/x_m - g(x_h)
67+
constraints.append(
68+
ddt(x_v, t) == (u_t[t-1] - D(x_h[t-1], x_v[t-1])) / x_m[t-1] - g(x_h[t-1])
69+
)
70+
71+
# Rate of mass loss: dx_m/dt = -u_t/c
72+
constraints.append(ddt(x_m, t) == -u_t[t-1] / c)
73+
74+
# Objective: maximize altitude at end of time of flight
75+
objective = cp.Maximize(x_h[T-1])
76+
77+
# Create and solve problem
78+
problem = cp.Problem(objective, constraints)
79+
80+
# Solve the problem
81+
problem.solve(solver=cp.IPOPT, nlp=True, verbose=True)
82+
83+
# Check if solution was found
84+
if problem.status == cp.OPTIMAL:
85+
print(f"Optimal value: {problem.value}")
86+
print(f"Final altitude: {x_h.value[T-1]}")
87+
print(f"Final mass: {x_m.value[T-1]}")
88+
print(f"Final velocity: {x_v.value[T-1]}")
89+
else:
90+
print(f"Problem status: {problem.status}")
91+
92+
# Plot results if solution found
93+
if problem.status == cp.OPTIMAL:
94+
def plot_trajectory(y, ylabel, subplot_idx):
95+
"""Plot trajectory over time"""
96+
time = np.arange(T) * dt
97+
plt.subplot(2, 2, subplot_idx)
98+
plt.plot(time, y)
99+
plt.xlabel('Time (s)')
100+
plt.ylabel(ylabel)
101+
plt.grid(True)
102+
103+
plt.figure(figsize=(12, 8))
104+
105+
plot_trajectory(x_h.value, 'Altitude', 1)
106+
plot_trajectory(x_m.value, 'Mass', 2)
107+
plot_trajectory(x_v.value, 'Velocity', 3)
108+
plot_trajectory(u_t.value, 'Thrust', 4)
109+
110+
plt.tight_layout()
111+
plt.show()
112+
113+
# Print some statistics
114+
print("\nSolution Statistics:")
115+
print(f"Maximum altitude reached: {np.max(x_h.value):.6f}")
116+
print(f"Maximum velocity reached: {np.max(x_v.value):.6f}")
117+
print(f"Maximum thrust used: {np.max(u_t.value):.6f}")
118+
print(f"Total fuel consumed: {m_0 - x_m.value[T-1]:.6f}")
119+
else:
120+
print("No optimal solution found. Check problem formulation.")

0 commit comments

Comments
 (0)