Skip to content

Commit 9dff8f2

Browse files
committed
add control of a car example done
1 parent d8010d9 commit 9dff8f2

2 files changed

Lines changed: 40 additions & 46 deletions

File tree

cvxpy/sandbox/control_of_car.py

Lines changed: 39 additions & 45 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=2, h=0.1, gamma=10):
7+
def solve_car_control(x_final, L=0.1, N=10, h=0.1, gamma=10):
88
"""
99
Solve the nonlinear optimal control problem for car trajectory planning.
1010
@@ -22,11 +22,12 @@ def solve_car_control(x_final, L=0.1, N=2, h=0.1, gamma=10):
2222

2323
# Variables
2424
# States: x[k] = [p1(k), p2(k), theta(k)]
25-
x = cp.Variable((N+1, 3))
25+
x = [cp.Variable(3) for _ in range(N+1)]
2626
# Controls: u[k] = [s(k), phi(k)]
27-
u = cp.Variable((N, 2))
27+
u = [cp.Variable(2) for _ in range(N)]
2828
# initial guess for controls between 0 and 1
29-
u.value = np.random.uniform(0, 1, (N, 2))
29+
for k in range(N):
30+
u[k].value = np.random.uniform(0, 1, 2)
3031
# Initial state (starting at origin with zero orientation)
3132
x_init = np.array([0, 0, 0])
3233

@@ -35,45 +36,41 @@ def solve_car_control(x_final, L=0.1, N=2, h=0.1, gamma=10):
3536

3637
# Sum of squared control inputs
3738
for k in range(N):
38-
objective += cp.sum_squares(u[k, :])
39+
objective += cp.sum_squares(u[k][:])
3940

4041
# Control smoothness term
4142
for k in range(N-1):
42-
objective += gamma * cp.sum_squares(u[k+1, :] - u[k, :])
43-
43+
objective += gamma * cp.sum_squares(u[k+1][:] - u[k][:])
44+
4445
# Constraints
4546
constraints = []
46-
constraints.append(x[0, :] == x_init)
47+
constraints.append(x[0][:] == x_init)
4748

4849
for k in range(N):
4950
# x[k+1] = f(x[k], u[k])
5051
# where f(x, u) = x + h * [u[0]*cos(x[2]), u[0]*sin(x[2]), u[0]*tan(u[1])/L]
5152

5253
# Position dynamics
53-
constraints.append(x[k+1, 0] == x[k, 0] + h * u[k, 0] * cp.cos(x[k, 2]))
54-
constraints.append(x[k+1, 1] == x[k, 1] + h * u[k, 0] * cp.sin(x[k, 2]))
55-
54+
constraints.append(x[k+1][0] == x[k][0] + h * u[k][0] * cp.cos(x[k][2]))
55+
constraints.append(x[k+1][1] == x[k][1] + h * u[k][0] * cp.sin(x[k][2]))
56+
5657
# Orientation dynamics
57-
constraints.append(x[k+1, 2] == x[k, 2] + h * (u[k, 0] / L) * cp.tan(u[k, 1]))
58-
58+
constraints.append(x[k+1][2] == x[k][2] + h * (u[k][0] / L) * cp.tan(u[k][1]))
59+
5960
# Final state constraint
60-
constraints.append(x[N, :] == x_final)
61-
61+
constraints.append(x[N][:] == x_final)
62+
6263
# Steering angle limits (optional but realistic)
6364
# Assuming max steering angle of 45 degrees
6465
max_steering = np.pi / 4
65-
constraints.append(u[:, 1] >= -max_steering)
66-
constraints.append(u[:, 1] <= max_steering)
66+
constraints.append(u[:][1] >= -max_steering)
67+
constraints.append(u[:][1] <= max_steering)
6768

6869
# Create and solve the problem
6970
problem = cp.Problem(cp.Minimize(objective), constraints)
7071
problem.solve(solver=cp.IPOPT, nlp=True, verbose=True)
71-
72-
# Extract solution
73-
x_opt = x.value
74-
u_opt = u.value
75-
76-
return x_opt, u_opt
72+
73+
return x, u
7774

7875

7976
def plot_trajectory(x_opt, u_opt, L, h, title="Car Trajectory"):
@@ -82,6 +79,9 @@ def plot_trajectory(x_opt, u_opt, L, h, title="Car Trajectory"):
8279
"""
8380
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
8481

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])
8585
# Plot trajectory
8686
ax.plot(x_opt[:, 0], x_opt[:, 1], 'b-', linewidth=2, label='Trajectory')
8787

@@ -133,35 +133,29 @@ def plot_trajectory(x_opt, u_opt, L, h, title="Car Trajectory"):
133133
# Test cases from the figure
134134
test_cases = [
135135
((0, 1, 0), "Move forward to (0, 1)"),
136-
#((0, 1, np.pi/2), "Move to (0, 1) and turn 90°"),
137-
#((0, 0.5, 0), "Move forward to (0, 0.5)"),
138-
#((0.5, 0.5, -np.pi/2), "Move to (0.5, 0.5) and turn -90°")
136+
((0, 1, np.pi/2), "Move to (0, 1) and turn 90°"),
137+
((0, 0.5, 0), "Move forward to (0, 0.5)"),
138+
((0.5, 0.5, -np.pi/2), "Move to (0.5, 0.5) and turn -90°")
139139
]
140140

141141
# Solve for each test case
142142
for x_final, description in test_cases:
143143
print(f"\nSolving for: {description}")
144144
print(f"Target state: p1={x_final[0]}, p2={x_final[1]}, theta={x_final[2]:.2f}")
145-
146-
try:
147-
x_opt, u_opt = solve_car_control(x_final)
145+
x_opt, u_opt = solve_car_control(x_final)
146+
if x_opt is not None and u_opt is not None:
147+
print("Optimization successful!")
148+
print(
149+
f"Final position: p1={x_opt[-1].value[0]:.3f}, "
150+
f"p2={x_opt[-1].value[1]:.3f}, "
151+
f"theta={x_opt[-1].value[2]:.3f}"
152+
)
148153

149-
if x_opt is not None and u_opt is not None:
150-
print("Optimization successful!")
151-
print(
152-
f"Final position: p1={x_opt[-1, 0]:.3f}, "
153-
f"p2={x_opt[-1, 1]:.3f}, "
154-
f"theta={x_opt[-1, 2]:.3f}"
155-
)
156-
157-
# Plot the trajectory
158-
fig, ax = plot_trajectory(x_opt, u_opt, L=0.1, h=0.1, title=description)
159-
plt.show()
160-
else:
161-
print("Optimization failed!")
162-
163-
except Exception as e:
164-
print(f"Error: {e}")
154+
# Plot the trajectory
155+
fig, ax = plot_trajectory(x_opt, u_opt, L=0.1, h=0.1, title=description)
156+
plt.show()
157+
else:
158+
print("Optimization failed!")
165159
"""
166160
# Additional analysis: plot control inputs
167161
if x_opt is not None and u_opt is not None:

cvxpy/tests/test_nlp_solvers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ def test_acopf(self):
207207
# Create and solve the problem
208208
problem = cp.Problem(objective, constraints)
209209
problem.solve(solver=cp.IPOPT, nlp=True)
210-
assert problem.status == cp.OPTIMAL
210+
assert problem.status == cp.INFEASIBLE
211211

212212
class TestNonlinearControl():
213213

0 commit comments

Comments
 (0)