Skip to content

Commit ddad85a

Browse files
committed
dynamics constructor for user-generated dynamics
1 parent 4189b38 commit ddad85a

File tree

11 files changed

+234
-13
lines changed

11 files changed

+234
-13
lines changed

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
99
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1010
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
1111
Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a"
12+
Scratch = "6c6a2e73-6563-6170-7368-637461726353"
1213
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1314
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
1415

@@ -17,5 +18,6 @@ IfElse = "0.1"
1718
Ipopt = "0.8"
1819
MathOptInterface = "0.10"
1920
Parameters = "0.12"
20-
Symbolics = "0.1.29"
21+
Scratch = "1.0"
22+
Symbolics = "0.1.29 - 0.1.29"
2123
julia = "1.6"

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,22 @@
22
[![CI](https://github.com/thowell/DirectTrajectoryOptimization.jl/actions/workflows/CI.yml/badge.svg)](https://github.com/thowell/DirectTrajectoryOptimization.jl/actions/workflows/CI.yml)
33
[![codecov](https://codecov.io/gh/thowell/DirectTrajectoryOptimization.jl/branch/main/graph/badge.svg?token=821EI7HJEL)](https://codecov.io/gh/thowell/DirectTrajectoryOptimization.jl)
44

5-
This package solves constrained trajectory optimization problems:
5+
A Julia package for solving constrained trajectory optimization problems:
66

77
```
88
minimize gT(xT; wT) + sum(gt(xt, ut; wt))
99
xt, ut
1010
subject to xt+1 = ft(xt, ut; wt) , t = 1,...,T-1
11-
ct(xt, ut; wt) {>,=} 0, t = 1,...,T
11+
ct(xt, ut; wt) {<,=} 0, t = 1,...,T
1212
xt_L <= xt <= xt_U, t = 1,...,T
1313
ut_L <= ut <= ut_U, t = 1,...,T-1.
1414
```
1515

16+
with direct trajectory optimization.
17+
1618
Fast and allocation-free gradients and sparse Jacobians are automatically generated using [Symbolics.jl](https://github.com/JuliaSymbolics/Symbolics.jl) for user-provided costs, constraints, and dynamics. The problem is solved with [Ipopt](https://coin-or.github.io/Ipopt/).
1719

1820
## Installation
1921
```
2022
Pkg.add("DirectTrajectoryOptimization")
21-
```
23+
```

examples/car/car.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ p_obs = [0.5; 0.5]
5252
r_obs = 0.1
5353
function obs(x, u, w)
5454
e = x[1:2] - p_obs
55-
return [dot(e, e) - r_obs^2.0]
55+
return [r_obs^2.0 - dot(e, e)]
5656
end
5757
cont = StageConstraint(obs, nx, nu, nw, [t for t = 1:T-1], :inequality)
5858
conT = StageConstraint(obs, nx, 0, nw, [T], :inequality)

examples/double_integrator.jl

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# PREAMBLE
2+
3+
# PKG_SETUP
4+
5+
# ## Setup
6+
7+
using DirectTrajectoryOptimization
8+
using LinearAlgebra
9+
using Plots
10+
11+
# ## horizon
12+
T = 11
13+
14+
# ## double integrator
15+
nx = 2
16+
nu = 1
17+
nw = 0
18+
nz = nx + nu + nx
19+
20+
# ## dynamics
21+
function double_integrator(d, y, x, u, w)
22+
A = [1.0 1.0; 0.0 1.0]
23+
B = [0.0; 1.0]
24+
d .= y - (A * x + B * u[1])
25+
end
26+
27+
# ## user-provided dynamics gradient
28+
function double_integrator_grad(dz, y, x, u, w)
29+
A = [1.0 1.0; 0.0 1.0]
30+
B = [0.0; 1.0]
31+
dz .= [-A -B I]
32+
end
33+
34+
# ## fast methods
35+
function double_integrator(y, x, u, w)
36+
A = [1.0 1.0; 0.0 1.0]
37+
B = [0.0; 1.0]
38+
y - (A * x + B * u[1])
39+
end
40+
41+
function double_integrator_grad(y, x, u, w)
42+
A = [1.0 1.0; 0.0 1.0]
43+
B = [0.0; 1.0]
44+
[-A -B I]
45+
end
46+
47+
@variables y[1:nx] x[1:nx] u[1:nu] w[1:nw]
48+
49+
di = double_integrator(y, x, u, w)
50+
diz = double_integrator_grad(y, x, u, w)
51+
di_func = eval(Symbolics.build_function(di, y, x, u, w)[2])
52+
diz_func = eval(Symbolics.build_function(diz, y, x, u, w)[2])
53+
54+
# ## model
55+
dt = Dynamics(di_func, diz_func, nx, nx, nu)
56+
dyn = [dt for t = 1:T-1]
57+
model = DynamicsModel(dyn)
58+
59+
# ## initialization
60+
x1 = [0.0; 0.0]
61+
xT = [1.0; 0.0]
62+
63+
# ## objective
64+
ot = (x, u, w) -> 0.1 * dot(x, x) + 0.1 * dot(u, u)
65+
oT = (x, u, w) -> 0.1 * dot(x, x)
66+
ct = Cost(ot, nx, nu, nw, [t for t = 1:T-1])
67+
cT = Cost(oT, nx, 0, nw, [T])
68+
obj = [ct, cT]
69+
70+
# ## constraints
71+
x_init = Bound(nx, nu, [1], xl=x1, xu=x1)
72+
x_goal = Bound(nx, 0, [T], xl=xT, xu=xT)
73+
cons = ConstraintSet([x_init, x_goal], [StageConstraint()])
74+
75+
# ## problem
76+
trajopt = TrajectoryOptimizationProblem(obj, model, cons)
77+
s = Solver(trajopt, options=Options())
78+
79+
# ## initialize
80+
x_interpolation = linear_interpolation(x1, xT, T)
81+
u_guess = [1.0 * randn(nu) for t = 1:T-1]
82+
z0 = zeros(s.p.num_var)
83+
for (t, idx) in enumerate(s.p.trajopt.model.idx.x)
84+
z0[idx] = x_interpolation[t]
85+
end
86+
for (t, idx) in enumerate(s.p.trajopt.model.idx.u)
87+
z0[idx] = u_guess[t]
88+
end
89+
initialize!(s, z0)
90+
91+
# ## solve
92+
@time solve!(s)
93+
94+
# ## solution
95+
@show trajopt.x[1]
96+
@show trajopt.x[T]
97+
98+
# ## state
99+
plot(hcat(trajopt.x...)')
100+
101+
# ## control
102+
plot(hcat(trajopt.u[1:end-1]..., trajopt.u[end-1])', linetype = :steppost)

src/dynamics.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,35 @@ function Dynamics(f::Function, ny::Int, nx::Int, nu::Int; nw::Int=0, eval_hess=f
4141
sp_jac, sp_hess, zeros(ny), zeros(nj), zeros(nh))
4242
end
4343

44+
function Dynamics(g::Function, gz::Function, ny::Int, nx::Int, nu::Int; nw::Int=0)
45+
# jacobian function
46+
nz = nx + nu + ny
47+
jac_func = (nj, y, x, u, w) -> gz(reshape(view(nj, :), ny, nz), y, x, u, w)
48+
49+
# number of Jacobian elements
50+
nj = ny * nz
51+
52+
# Jacobian sparsity
53+
row = Int[]
54+
col = Int[]
55+
for j = 1:nz
56+
for i = 1:ny
57+
push!(row, i)
58+
push!(col, j)
59+
end
60+
end
61+
62+
sp_jac = [row, col]
63+
64+
# Hessian
65+
hess_func = Expr(:null)
66+
sp_hess = [Int[]]
67+
nh = 0
68+
69+
return Dynamics(g, jac_func, hess_func, ny, nx, nu, nw, nj, nh,
70+
sp_jac, sp_hess, zeros(ny), zeros(nj), zeros(nh))
71+
end
72+
4473
function eval_con!(c, idx, cons::Vector{Dynamics{T}}, x, u, w) where T
4574
for (t, con) in enumerate(cons)
4675
con.val(con.val_cache, x[t+1], x[t], u[t], w[t])

src/problem.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ function constraint_bounds(dyn::Vector{Dynamics{T}}, stage::StageConstraints{T},
8282
for con in stage
8383
for t in con.idx
8484
if con.type == :inequality
85-
cu[idx.stage_con[i]] .= Inf
85+
cl[idx.stage_con[i]] .= -Inf
8686
end
8787
i += 1
8888
end

test/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
66
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
77

88
[compat]
9-
Symbolics = "0.1.29"
9+
Symbolics = "0.1.29 - 0.1.29"

test/dynamics.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
j = zeros(DirectTrajectoryOptimization.num_jac(dyn))
3838

3939
dt.val(dt.val_cache, x1, x1, u1, w1)
40+
# @benchmark $dt.val($dt.val_cache, $x1, $x1, $u1, $w1)
4041
@test norm(dt.val_cache - euler_implicit(x1, x1, u1, w1)) < 1.0e-8
4142
dt.jac(dt.jac_cache, x1, x1, u1, w1)
4243
jac_dense = zeros(dt.ny, dt.nx + dt.nu + dt.ny)

test/hessian_lagrangian.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@testset "Hessian of Lagrangian" begin
2-
2+
MOI = DirectTrajectoryOptimization.MOI
33
# horizon
44
T = 3
55

@@ -186,9 +186,9 @@
186186
@test norm(h0_full - Lxx_func(z0)) < 1.0e-8
187187
@test norm(norm(h0 - Lxx_sp_func(z0))) < 1.0e-8
188188

189-
# h0 = zeros(nh)
190-
# MOI.eval_hessian_lagrangian(s.p, h0, z0[1:np], σ, z0[np .+ (1:nd)])
191-
# @test norm(norm(h0 - Lxx_sp_func(z0))) < 1.0e-8
189+
h0 = zeros(nh)
190+
MOI.eval_hessian_lagrangian(s.p, h0, z0[1:np], σ, z0[np .+ (1:nd)])
191+
@test norm(norm(h0 - Lxx_sp_func(z0))) < 1.0e-8
192192

193193
# a = z0[1:np]
194194
# b = z0[np .+ (1:nd)]

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ using DirectTrajectoryOptimization
88
include("objective.jl")
99
include("dynamics.jl")
1010
include("constraints.jl")
11-
include("hessian_lagrangian.jl")
11+
include("hessian_lagrangian.jl") #TODO: fix
1212
include("solve.jl")

0 commit comments

Comments
 (0)