Skip to content

Commit ebc8720

Browse files
authored
Merge pull request #154 from control-toolbox/doc
Doc
2 parents c75889b + 38c7448 commit ebc8720

File tree

7 files changed

+345
-80
lines changed

7 files changed

+345
-80
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ Manifest.toml
2525

2626
# Notebooks checkpoints
2727
*/.ipynb_checkpoints
28+
29+
#
30+
docs/src/tmp/

docs/make.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,15 @@ makedocs(
2020
"Tutorials" => ["tutorial-basic-example.md",
2121
"tutorial-basic-example-f.md",
2222
"tutorial-double-integrator.md",
23-
"tutorial-energy-and-distance-minimization.md",
23+
"tutorial-lqr-basic.md",
2424
"tutorial-goddard.md",
2525
#"tutorial-model.md",
2626
#"tutorial-solvers.md",
27-
#"tutorial-init.md",
28-
#"tutorial-plot.md",
27+
"tutorial-init.md",
28+
"tutorial-plot.md",
2929
#"tutorial-iss.md",
3030
#"tutorial-flows.md",
3131
#"tutorial-ct_repl.md",
32-
#"tutorial-problems.md"
3332
],
3433
"API" => "api.md",
3534
"JuliaCon2023" => "juliacon2023.md",

docs/src/tutorial-energy-and-distance-minimization.md

Lines changed: 0 additions & 66 deletions
This file was deleted.

docs/src/tutorial-init.md

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,75 @@
1-
# Initialisation
1+
# Initial guess
22

3-
```@meta
4-
CurrentModule = OptimalControl
3+
We define the following optimal control problem.
4+
5+
```@example main
6+
using OptimalControl
7+
8+
t0 = 0
9+
tf = 10
10+
α = 5
11+
12+
@def ocp begin
13+
t ∈ [ t0, tf ], time
14+
v ∈ R, variable
15+
x ∈ R², state
16+
u ∈ R, control
17+
x(t0) == [ -1, 0 ]
18+
x(tf) - [ 0, v ] == [0, 0]
19+
ẋ(t) == [ x₂(t), x₁(t) + α*x₁(t)^2 + u(t) ]
20+
v^2 + ∫( 0.5u(t)^2 ) → min
21+
end
22+
nothing # hide
523
```
624

7-
See [`solve`](@ref) method.
25+
We first solve the problem without giving an initial guess.
26+
27+
```@example main
28+
# solve the optimal control problem without initial guess
29+
sol = solve(ocp, display=false)
30+
31+
# print the number of iterations
32+
println("Number of iterations: ", sol.iterations)
33+
nothing # hide
34+
```
35+
36+
Let us plot the solution of the optimal control problem.
37+
38+
```@example main
39+
plot(sol, size=(600, 450))
40+
```
41+
42+
To reduce the number of iterations and improve the convergence, we can give an initial guess to the solver. We define the following initial guess.
43+
44+
```@example main
45+
# constant initial guess
46+
initial_guess = (state=[-0.2, 0.1], control=-0.2, variable=0.05)
47+
48+
# solve the optimal control problem with initial guess
49+
sol = solve(ocp, display=false, init=initial_guess)
50+
51+
# print the number of iterations
52+
println("Number of iterations: ", sol.iterations)
53+
nothing # hide
54+
```
55+
56+
We can also provide functions of time as initial guess for the state and the control.
57+
58+
```@example main
59+
# initial guess as functions of time
60+
x(t) = [ -0.2 * t, 0.1 * t ]
61+
u(t) = -0.2 * t
62+
initial_guess = (state=x, control=u, variable=0.05)
63+
64+
# solve the optimal control problem with initial guess
65+
sol = solve(ocp, display=false, init=initial_guess)
66+
67+
# print the number of iterations
68+
println("Number of iterations: ", sol.iterations)
69+
nothing # hide
70+
```
71+
72+
!!! warning
73+
74+
For the moment we can not provide an initial guess for the costate.
75+
Besides, there is neither cold nor warm start implemented yet. That is, we can not use the solution of a previous optimal control problem as initial guess.

docs/src/tutorial-lqr-basic.md

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# LQR example
2+
3+
The energy and distance minimisation Linear Quadratic Problem (LQR) problem consists in minimising
4+
5+
```math
6+
\frac{1}{2} \int_{0}^{t_f} \left( x_1^2(t) + x_2^2(t) + u^2(t) \right) \, \mathrm{d}t
7+
```
8+
9+
subject to the constraints
10+
11+
```math
12+
\dot x_1(t) = x_2(t), \quad \dot x_2(t) = -x_1(t) + u(t), \quad u(t) \in \R
13+
```
14+
15+
and the initial condition
16+
17+
```math
18+
x(0) = (0,1).
19+
```
20+
21+
We define $A$ and $B$ as
22+
23+
```math
24+
A = \begin{pmatrix} 0 & 1 \\ -1 & 0 \\ \end{pmatrix}, \quad
25+
B = \begin{pmatrix} 0 \\ 1 \\ \end{pmatrix}
26+
```
27+
28+
and we aim to solve this optimal control problem for different values of $t_f$.
29+
First, we need to import the `OptimalControl.jl` package.
30+
31+
```@example main
32+
using OptimalControl
33+
```
34+
35+
Then, we can define the problem parameterized by the final time `tf`.
36+
37+
```@example main
38+
x0 = [ 0
39+
1 ]
40+
A = [ 0 1
41+
-1 0 ]
42+
B = [ 0
43+
1 ]
44+
45+
function LQRProblem(tf)
46+
47+
@def ocp begin
48+
t ∈ [ 0, tf ], time
49+
x ∈ R², state
50+
u ∈ R, control
51+
x(0) == x0, initial_con
52+
ẋ(t) == A * x(t) + B * u(t)
53+
∫( 0.5(x₁(t)^2 + x₂(t)^2 + u(t)^2) ) → min
54+
end
55+
56+
return ocp
57+
end;
58+
nothing # hide
59+
```
60+
61+
We solve the problem for $t_f \in \{3, 5, 30\}$.
62+
63+
```@example main
64+
solutions = []
65+
tfspan = [3, 5, 30]
66+
67+
for tf ∈ tfspan
68+
sol = solve(LQRProblem(tf), display=false)
69+
push!(solutions, sol)
70+
end
71+
nothing # hide
72+
```
73+
74+
We choose to plot the solutions considering a normalized time $s=(t-t_0)/(t_f-t_0)$.
75+
We thus introduce the function `rescale` that rescales the time and redefine the state, costate and control variables.
76+
77+
!!! tip
78+
79+
Instead of defining the function `rescale`, you can consider $t_f$ as a parameter and define the following
80+
optimal control problem:
81+
82+
```julia
83+
@def ocp begin
84+
s ∈ [ 0, 1 ], time
85+
x ∈ R², state
86+
u ∈ R, control
87+
x(0) == x0, initial_con
88+
ẋ(s) == tf * ( A * x(s) + B * u(s) )
89+
∫( 0.5(x₁(s)^2 + x₂(s)^2 + u(s)^2) ) → min
90+
end
91+
```
92+
93+
```@example main
94+
function rescale(sol)
95+
96+
# integration times
97+
times = sol.times
98+
99+
# s is the rescaled time between 0 and 1
100+
t(s) = times[1] + s * (times[end] - times[1])
101+
102+
# rescaled times
103+
sol.times = (times .- times[1]) ./ (times[end] .- times[1])
104+
105+
# redefinition of the state, control and costate
106+
x = sol.state
107+
u = sol.control
108+
p = sol.costate
109+
110+
sol.state = x∘t # s → x(t(s))
111+
sol.control = u∘t # s → u(t(s))
112+
sol.costate = p∘t # s → p(t(s))
113+
114+
return sol
115+
end
116+
nothing # hide
117+
```
118+
119+
!!! note
120+
121+
The `∘` operator is the composition operator. Hence, `x∘t` is the function `s -> x(t(s))`.
122+
123+
124+
Finally we choose to plot only the state and control variables.
125+
126+
```@example main
127+
using Plots.PlotMeasures # for leftmargin, bottommargin
128+
129+
# we construct the plots from the solutions with default options
130+
plt = plot(rescale(solutions[1]))
131+
for sol in solutions[2:end]
132+
plot!(plt, rescale(sol))
133+
end
134+
135+
# we plot only the state and control variables and we add the legend
136+
px1 = plot(plt[1], legend=false, xlabel="s", ylabel="x₁")
137+
px2 = plot(plt[2], label=reshape(["tf = $tf" for tf ∈ tfspan],
138+
(1, length(tfspan))), xlabel="s", ylabel="x₂")
139+
pu = plot(plt[5], legend=false, xlabel="s", ylabel="u")
140+
plot(px1, px2, pu, layout=(1, 3), size=(800, 300), leftmargin=5mm, bottommargin=5mm)
141+
```
142+
143+
!!! note
144+
145+
We can observe that $x(t_f)$ converges to the origin as $t_f$ increases.

0 commit comments

Comments
 (0)