Skip to content

Commit 2c75f0f

Browse files
committed
miqp cleanup
1 parent 1650814 commit 2c75f0f

File tree

4 files changed

+591
-1
lines changed

4 files changed

+591
-1
lines changed

examples/flamingo/flat.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ vis = ContactImplicitMPC.Visualizer()
7474
open(vis)
7575

7676
# ## Visualize
77-
anim = visualize_meshrobot!(vis, model, sim.traj, sample=10);
77+
anim = visualize_robot!(vis, model, sim.traj, sample=10)
78+
79+
anim = visualize_meshrobot!(vis, model, sim.traj, sample=10)
7880

7981
# ## Timing result
8082
# Julia is [JIT-ed](https://en.wikipedia.org/wiki/Just-in-time_compilation) so re-run the MPC setup through Simulate for correct timing results.

examples/miqp/methods/structures.jl

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
2+
################################################################################
3+
# Model
4+
################################################################################
5+
6+
mutable struct WallPendulum{T} <: ContactModel
7+
n::Int # state dim
8+
m::Int # control dim
9+
mp::T # mass
10+
l::T # length
11+
g::T # gravity
12+
k::T # spring
13+
d::T # distance to wall
14+
end
15+
16+
function dynamics_model(model::WallPendulum{T}, dt::T; mode::Symbol = :none) where {T}
17+
mp = model.mp
18+
l = model.l
19+
g = model.g
20+
k = model.k
21+
d = model.d
22+
B = dt * [0 1 / (mp*l^2)]'
23+
if mode == :none
24+
A = I + dt * [0 1;
25+
g/l 0]
26+
c = dt * [0, 0]
27+
elseif mode == :left
28+
A = I + dt * [0 1;
29+
g/l - k/mp 0]
30+
c = dt * [0, k*d / (mp*l)]
31+
elseif mode == :right
32+
A = I + dt * [0 1;
33+
g/l - k/mp 0]
34+
c = dt * [0, -k*d / (mp*l)]
35+
else
36+
error("Unknown contact mode.")
37+
end
38+
return A, B, c
39+
end
40+
41+
function get_mode(x::AbstractVector{T}, u::AbstractVector{T}, model::WallPendulum{T}) where {T}
42+
d = model.d
43+
l = model.l
44+
if -d/l <= x[1] <= d/l # none
45+
return 1
46+
elseif x[1] > d/l # left
47+
return 2
48+
elseif x[1] < -d/l # right
49+
return 3
50+
end
51+
end
52+
53+
function dynamics(x0::AbstractVector{T}, u0::AbstractVector{T},
54+
A::Vector{Matrix{T}}, B::Vector{Matrix{T}}, c::Vector{Vector{T}},
55+
model::WallPendulum{T}) where {T}
56+
i = get_mode(x0, u0, model)
57+
x1 = A[i] * x0 + B[i] * u0 + c[i]
58+
return x1
59+
end
60+
61+
62+
function kinematics(x::AbstractVector{T}) where {T}
63+
θ = x[1] + π/2
64+
θd = x[2]
65+
p = l * [cos(θ), sin(θ)]
66+
return p
67+
end
68+
69+
################################################################################
70+
# Domain
71+
################################################################################
72+
73+
"""
74+
Box domain for the state-control vector (x, u).
75+
Domain C = {x_min <= x <= x_max} × {u_min <= u <= u_max}.
76+
C = {S x + R u <= T}
77+
"""
78+
mutable struct BoxDomain12{T}
79+
n::Int # state dim
80+
m::Int # control dim
81+
x_min::Vector{T} # box boundary
82+
x_max::Vector{T} # box boundary
83+
u_min::Vector{T} # box boundary
84+
u_max::Vector{T} # box boundary
85+
S::Matrix{T} # affine inequality representation
86+
R::Matrix{T} # affine inequality representation
87+
T::Vector{T} # affine inequality representation
88+
end
89+
90+
function BoxDomain12(x_min, x_max, u_min, u_max)
91+
n = length(x_min)
92+
m = length(u_min)
93+
S = Matrix([-I(n); I(n); zeros(m, n); zeros(m, n)])
94+
R = Matrix([zeros(n, m); zeros(n, m); -I(m); I(m)])
95+
T = [-x_min; x_max; -u_min; u_max]
96+
return BoxDomain12(n, m, x_min, x_max, u_min, u_max, S, R, T)
97+
end
98+
99+
function inclusion(C::BoxDomain12, x, u)
100+
all(C.S * x + C.R * u .<= C.T)
101+
end
102+
103+
function domain(model::WallPendulum{T}; mode::Symbol = :none) where{T}
104+
m = model.m
105+
l = model.l
106+
g = model.g
107+
k = model.k
108+
d = model.d
109+
110+
u_min = [-4.0]
111+
u_max = [ 4.0]
112+
113+
if mode == :none
114+
# @warn "need to revise when adding right wall."
115+
x_min = [-d/l, -1.5]
116+
# x_min = [-d/l*2, -1.5]
117+
x_max = [ d/l, 1.5]
118+
elseif mode == :left
119+
x_min = [ d/l, -1.5]
120+
x_max = [ d/l*2, 1.5]
121+
elseif mode == :right
122+
x_min = [-d/l*2, -1.5]
123+
x_max = [-d/l, 1.5]
124+
else
125+
error("Unknown contact mode.")
126+
end
127+
return BoxDomain12(x_min, x_max, u_min, u_max)
128+
end
129+
130+
# @testset "Domain" begin
131+
# # Test
132+
# x_min = [-d/l*2, -1.5]
133+
# x_max = [ d/l*2, 1.5]
134+
#
135+
# x_min_1 = [-d/l*2, -1.5]
136+
# x_max_1 = [ d/l, 1.5]
137+
#
138+
# x_min_2 = [ d/l, -1.5]
139+
# x_max_2 = [ d/l*2, 1.5]
140+
#
141+
# u_min = [-4.0]
142+
# u_max = [ 4.0]
143+
#
144+
# C0 = BoxDomain12(x_min, x_max, u_min, u_max)
145+
# C1 = BoxDomain12(x_min_1, x_max_1, u_min, u_max)
146+
# C2 = BoxDomain12(x_min_2, x_max_2, u_min, u_max)
147+
#
148+
# xu1 = [[d/l/2, -1.0], [-2.0]]
149+
# xu2 = [[1.5*d/l, 1.0], [ 2.0]]
150+
# xu3 = [[2.1d/l, 0.0], [ 0.0]]
151+
#
152+
# @test inclusion(C0, xu1...)
153+
# @test inclusion(C0, xu2...)
154+
# @test !inclusion(C0, xu3...)
155+
# @test inclusion(C1, xu1...)
156+
# @test !inclusion(C1, xu2...)
157+
# @test !inclusion(C1, xu3...)
158+
# @test !inclusion(C2, xu1...)
159+
# @test inclusion(C2, xu2...)
160+
# @test !inclusion(C2, xu3...)
161+
# end
162+
163+
################################################################################
164+
# Problem
165+
################################################################################
166+
167+
mutable struct WallProblem16{F}
168+
model::WallPendulum{F}
169+
T::Int
170+
x0::Vector{F}
171+
Q::F
172+
Qf::F
173+
R::F
174+
β::F
175+
A::Vector{Matrix{F}}
176+
B::Vector{Matrix{F}}
177+
c::Vector{Vector{F}}
178+
C::Vector{BoxDomain12{F}}
179+
end
180+
181+
function build_optimizer(prob::WallProblem16{F}) where {F}
182+
n = prob.model.n
183+
m = prob.model.m
184+
nd = length(C)
185+
T = prob.T
186+
x0 = prob.x0
187+
Q = prob.Q
188+
Qf = prob.Qf
189+
R = prob.R
190+
β = prob.β
191+
192+
Mstar =* ones(2n+2m) for i = 1:nd]
193+
MU = β * ones(n) # upper bound
194+
ML = - β * ones(n) # lower bound
195+
196+
optimizer = Model(Gurobi.Optimizer)
197+
set_silent(optimizer)
198+
199+
# variables
200+
@variable(optimizer, x[1:T+1, 1:n])
201+
@variable(optimizer, u[1:T, 1:m])
202+
@variable(optimizer, δ[1:nd, 1:T], Bin)
203+
@variable(optimizer, z[1:nd, 1:T, 1:n])
204+
205+
# constraints
206+
# intitial state
207+
@constraint(optimizer, initial_state, x[1,:] .== x0);
208+
# 16.a
209+
@constraint(optimizer, c16a[i in 1:nd, t in 1:T], C[i].S * x[t,:] + C[i].R * u[t,:] - C[i].T .<= Mstar[i] * (1 - δ[i,t]));
210+
# 16.b
211+
@constraint(optimizer, c16b[t in 1:T], sum(δ[:, t]) == 1)
212+
# 18
213+
@constraint(optimizer, c18[t in 1:T], x[t+1, :] .== sum([z[i,t,:] for i = 1:nd]))
214+
# 22.a
215+
@constraint(optimizer, c22a[i in 1:nd, t in 1:T], z[i,t,:] .<= MU * δ[i,t])
216+
# 22.b
217+
@constraint(optimizer, c22b[i in 1:nd, t in 1:T], z[i,t,:] .>= ML * δ[i,t])
218+
# 22.c
219+
@constraint(optimizer, c22c[i in 1:nd, t in 1:T], z[i,t,:] .<= A[i] * x[t,:] + B[i] * u[t,:] + c[i] - ML * (1 - δ[i,t]))
220+
# 22.d
221+
@constraint(optimizer, c22d[i in 1:nd, t in 1:T], z[i,t,:] .>= A[i] * x[t,:] + B[i] * u[t,:] + c[i] - MU * (1 - δ[i,t]))
222+
223+
# objective
224+
@objective(optimizer, Min, Q * sum(x[1:T,:].^2) + Qf * sum(x[T+1,:].^2) + R * sum(u.^2))
225+
226+
return optimizer, x, u, δ, z
227+
end
228+
229+
function get_control(prob::WallProblem16{T}) where {T}
230+
optimizer, x, u, δ, z = build_optimizer(prob)
231+
optimize!(optimizer)
232+
return value.(u)[1,:]
233+
end
234+
235+
function simulate!(prob::WallProblem16{T}, x0::Vector{T}, H::Int;
236+
w::Vector{Vector{T}} = Vector{Vector{T}}(), iw::Vector{Int} = Vector{Int}()) where {T}
237+
x = Vector{Vector{T}}([x0])
238+
u = Vector{Vector{T}}()
239+
s = Vector{T}()
240+
for h = 1:H
241+
println(h, "/", H)
242+
prob.x0 = deepcopy(x0)
243+
s0 = @elapsed begin
244+
u0 = get_control(prob)
245+
end
246+
i = findfirst(x -> x == h, iw)
247+
(i != nothing) && (u0 += w[i])
248+
x0 = dynamics(x0, u0, prob.A, prob.B, prob.c, prob.model)
249+
push!(x, deepcopy(x0))
250+
push!(u, deepcopy(u0))
251+
push!(s, s0)
252+
end
253+
return x, u, s
254+
end
255+
256+
257+
258+
259+
abstract type ControlPolicy{T}
260+
end
261+
262+
mutable struct OpenLoopPolicy16{T} <: ControlPolicy{T}
263+
u::Vector{Vector{T}}
264+
N::Int
265+
N_sample::Int
266+
count::Int
267+
dt::T
268+
end
269+
270+
function OpenLoopPolicy16(u::AbstractVector{V}; N_sample::Int = 1, dt::T = 0.01) where {V,T}
271+
OpenLoopPolicy16(u, length(u), N_sample, 0, dt)
272+
end
273+
274+
mutable struct Simulator12{T}
275+
p::ControlPolicy{T}
276+
x::Vector{Vector{T}}
277+
u::Vector{Vector{T}}
278+
N_sample::Int
279+
dt::T
280+
end
281+
282+
function Simulator12(p::ControlPolicy{T}; dt::T = 0.01) where {T}
283+
x = Vector{Vector{T}}()
284+
u = Vector{Vector{T}}()
285+
Simulator12(p, x, u, p.N_sample, p.dt)
286+
end
287+
288+
function simulate!(sim::Simulator12{T}, x0::Vector{T}, H::Int) where {T}
289+
N_sample = sim.N_sample
290+
cnt = 0
291+
x = deepcopy(x0)
292+
push!(sim.x, deepcopy(x0))
293+
for t = 1:H
294+
x, u = step!(p, x, t)
295+
push!(sim.x, deepcopy(x))
296+
push!(sim.u, deepcopy(u))
297+
end
298+
return nothing
299+
end
300+
301+
302+
function step!(p::OpenLoopPolicy16{T}, x0::AbstractVector{T}, t::Int) where{T}
303+
@show t
304+
@show t%p.N_sample
305+
((t-1) % p.N_sample) == 0 && (p.count += 1)
306+
u0 = p.u[p.count]
307+
x1 = dyna(x0, u0)
308+
return x1, u0
309+
end

0 commit comments

Comments
 (0)