Container Crane Control#

Mathematical Formulation#

Problem Statement#

Find the optimal control inputs \(u_1(t)\) and \(u_2(t)\) that minimize the performance index:

\[J = \int_0^{t_f} \frac{1}{2}\left( x_3^2 + x_6^2 + \rho (u_1^2 + u_2^2) \right) dt\]

Subject to the crane dynamic constraints:

\[\frac{dx_1}{dt} = x_4\]
\[\frac{dx_2}{dt} = x_5\]
\[\frac{dx_3}{dt} = x_6\]
\[\frac{dx_4}{dt} = u_1 + c_4 x_3\]
\[\frac{dx_5}{dt} = u_2\]
\[\frac{dx_6}{dt} = -\frac{u_1 + c_5 x_3 + 2 x_5 x_6}{x_2}\]

Boundary Conditions#

  • Initial conditions: \(x_1(0) = 0\), \(x_2(0) = 22\), \(x_3(0) = 0\), \(x_4(0) = 0\), \(x_5(0) = -1\), \(x_6(0) = 0\)

  • Final conditions: \(x_1(t_f) = 10\), \(x_2(t_f) = 14\), \(x_3(t_f) = 0\), \(x_4(t_f) = 2.5\), \(x_5(t_f) = 0\), \(x_6(t_f) = 0\)

  • Control bounds: \(-c_1 \leq u_1 \leq c_1\), \(c_2 \leq u_2 \leq c_3\)

  • State bounds: \(-2.5 \leq x_4 \leq 2.5\), \(-1 \leq x_5 \leq 1\)

Physical Parameters#

  • Final time: \(t_f = 9.0\) s

  • Control penalty: \(\rho = 0.01\)

  • System constants: \(c_1 = 2.83374\), \(c_2 = -0.80865\), \(c_3 = 0.71265\), \(c_4 = 17.2656\), \(c_5 = 27.0756\)

State Variables#

  • \(x_1(t)\)

  • \(x_2(t)\)

  • \(x_3(t)\)

  • \(x_4(t)\)

  • \(x_5(t)\)

  • \(x_6(t)\)

Control Variables#

  • \(u_1(t)\)

  • \(u_2(t)\)

Notes#

This problem involves controlling a container crane to transport a load while minimizing swing oscillations and control effort.

Running This Example#

cd examples/container_crane
python container_crane.py

Code Implementation#

examples/container_crane/container_crane.py#
 1import numpy as np
 2
 3import maptor as mtor
 4
 5
 6# Constants
 7p_rho = 0.01
 8c1 = 2.83374
 9c2 = -0.80865
10c3 = 0.71265
11c4 = 17.2656
12c5 = 27.0756
13t_final = 9.0
14
15# Problem setup
16problem = mtor.Problem("Container Crane")
17phase = problem.set_phase(1)
18
19# Variables
20t = phase.time(initial=0.0, final=t_final)
21x1 = phase.state("x1", initial=0.0, final=10.0)
22x2 = phase.state("x2", initial=22.0, final=14.0)
23x3 = phase.state("x3", initial=0.0, final=0.0)
24x4 = phase.state("x4", initial=0, final=2.5, boundary=(-2.5, 2.5))
25x5 = phase.state("x5", initial=-1, final=0.0, boundary=(-1.0, 1.0))
26x6 = phase.state("x6", initial=0.0, final=0.0)
27u1 = phase.control("u1", boundary=(-c1, c1))
28u2 = phase.control("u2", boundary=(c2, c3))
29
30# Dynamics
31phase.dynamics(
32    {
33        x1: x4,
34        x2: x5,
35        x3: x6,
36        x4: u1 + c4 * x3,
37        x5: u2,
38        x6: -(u1 + c5 * x3 + 2.0 * x5 * x6) / x2,
39    }
40)
41
42# Objective
43integrand = 0.5 * (x3**2 + x6**2 + p_rho * (u1**2 + u2**2))
44integral_var = phase.add_integral(integrand)
45problem.minimize(integral_var)
46
47# Mesh and guess
48phase.mesh([6, 6, 6], [-1.0, -1 / 3, 1 / 3, 1.0])
49
50states_guess = []
51controls_guess = []
52for N in [6, 6, 6]:
53    tau = np.linspace(-1, 1, N + 1)
54    t_norm = (tau + 1) / 2
55    x1_vals = 0.0 + (10.0 - 0.0) * t_norm
56    x2_vals = 22.0 + (14.0 - 22.0) * t_norm
57    x3_vals = 0.0 + (0.0 - 0.0) * t_norm
58    x4_vals = 0.0 + (2.5 - 0.0) * t_norm
59    x5_vals = -1.0 + (0.0 - (-1.0)) * t_norm
60    x6_vals = 0.0 + (0.0 - 0.0) * t_norm
61    states_guess.append(np.vstack([x1_vals, x2_vals, x3_vals, x4_vals, x5_vals, x6_vals]))
62
63    u1_mid = (-c1 + c1) / 2.0
64    u2_mid = (c2 + c3) / 2.0
65    controls_guess.append(np.vstack([np.full(N, u1_mid), np.full(N, u2_mid)]))
66
67phase.guess(states=states_guess, controls=controls_guess, integrals=0.1)
68
69# Solve
70solution = mtor.solve_adaptive(
71    problem,
72    error_tolerance=5e-7,
73    ode_method="Radau",
74    ode_solver_tolerance=1e-9,
75    nlp_options={"ipopt.print_level": 0, "ipopt.max_iter": 2000, "ipopt.tol": 1e-7},
76)
77
78# Results
79if solution.status["success"]:
80    print(f"Objective: {solution.status['objective']:.8f}")
81    print(
82        f"Reference: 0.0375195 (Error: {abs(solution.status['objective'] - 0.0375195) / 0.0375195 * 100:.2f}%)"
83    )
84    solution.plot()
85else:
86    print(f"Failed: {solution.status['message']}")