Skip to content

Commit b8b393c

Browse files
author
Brad Carman
committed
multibody example
1 parent af32447 commit b8b393c

File tree

2 files changed

+158
-35
lines changed

2 files changed

+158
-35
lines changed
Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,101 @@
1-
function Link(; name, m, l, I, g)
1+
function Link(; name, m, l, I, g, x1_0=0, y1_0=0)
22
pars = @parameters begin
33
m = m
44
l = l
55
I = I
66
g = g
7+
x1_0=x1_0
8+
y1_0=y1_0
79
end
810

911
vars = @variables begin
1012
A(t) = 0
1113
dA(t) = 0
1214
ddA(t) = 0
1315

14-
x_cm(t) = l / 2
15-
y_cm(t) = 0
16-
17-
dx_cm(t) = 0
18-
dy_cm(t) = 0
19-
20-
ddx_cm(t) = 0
21-
ddy_cm(t) = 0
22-
2316
fx1(t) = 0
2417
fy1(t) = 0
2518

26-
x1(t) = 0
19+
fx2(t) = 0
20+
fy2(t) = 0
21+
22+
x1(t) = x1_0
2723
dx1(t) = 0
24+
25+
y1(t) = y1_0
26+
dy1(t) = 0
27+
28+
29+
x2(t) = l+x1_0
30+
dx2(t) = 0
31+
32+
33+
y2(t) = 0
34+
dy2(t) = 0
35+
36+
37+
x_cm(t) = l/2+x1_0
38+
dx_cm(t) = 0
39+
ddx_cm(t) = 0
40+
41+
y_cm(t) = 0
42+
dy_cm(t) = 0
43+
ddy_cm(t) = 0
2844
end
2945

3046
@named TX1 = MechanicalPort()
47+
@named TY1 = MechanicalPort()
3148

32-
eqs = [D(x_cm) ~ dx_cm
33-
D(y_cm) ~ dy_cm
34-
D(dx_cm) ~ ddx_cm
35-
D(dy_cm) ~ ddy_cm
49+
@named TX2 = MechanicalPort()
50+
@named TY2 = MechanicalPort()
51+
52+
eqs = [
3653
D(A) ~ dA
3754
D(dA) ~ ddA
3855

56+
D(x1) ~ dx1
57+
58+
D(y1) ~ dy1
59+
60+
D(x2) ~ dx2
61+
62+
D(y2) ~ dy2
63+
64+
D(x_cm) ~ dx_cm
65+
D(dx_cm) ~ ddx_cm
66+
67+
D(y_cm) ~ dy_cm
68+
D(dy_cm) ~ ddy_cm
69+
70+
3971
# x forces
40-
m * ddx_cm ~ fx1
72+
m * ddx_cm ~ fx1 + fx2
4173

4274
# y forces
43-
m * ddy_cm ~ m * g + fy1
75+
m * ddy_cm ~ m * g + fy1 + fy2
4476

4577
# torques
46-
I * ddA ~ m * g * (l / 2) * cos(A)
78+
I * ddA ~ -fy1 * (x2 - x1)/2 + fy2 * (x2 - x1)/2 + fx1 * (y2 - y1)/2 - fx2 * (y2 - y1)/2
4779

4880
# geometry
49-
x_cm ~ l * cos(A) / 2 + x1
50-
y_cm ~ l * sin(A) / 2
81+
x2 ~ l * cos(A) + x1
82+
y2 ~ l * sin(A) + y1
83+
84+
x_cm ~ l * cos(A)/2 + x1
85+
y_cm ~ l * sin(A)/2 + y1
86+
5187
TX1.f ~ fx1
52-
D(x1) ~ TX1.v]
88+
TX1.v ~ dx1
89+
90+
TY1.f ~ fy1
91+
TY1.v ~ dy1
92+
93+
TX2.f ~ fx2
94+
TX2.v ~ dx2
95+
96+
TY2.f ~ fy2
97+
TY2.v ~ dy2]
5398

54-
return ODESystem(eqs, t, vars, pars; name = name, systems = [TX1],
55-
defaults = [TX1.v => 0])
99+
return ODESystem(eqs, t, vars, pars; name = name, systems = [TX1, TY1, TX2, TY2],
100+
defaults = [TX1.v => 0, TY1.v => 0, TX2.v => 0, TY2.v => 0])
56101
end

test/Mechanical/multibody.jl

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,109 @@ using ModelingToolkitStandardLibrary.Mechanical.MultiBody2D
33
using ModelingToolkitStandardLibrary.Mechanical.Translational
44
using DifferentialEquations
55
# using Setfield
6+
using Test
67

78
@parameters t
89

9-
@named link = Link(; m = 1, l = 10, I = π * 8.33, g = -9.807)
10+
@named link1 = Link(; m = 1, l = 10, I = 84, g = -9.807)
11+
@named link2 = Link(; m = 1, l = 10, I = 84, g = -9.807, x1_0=10)
1012
@named cart = Mass(; m = 1, s_0 = 0)
1113
# @named force = SineForce(;amp=3e3, freq=15)
12-
# @named fixed = Fixed()
14+
@named fixed = Fixed()
1315
# @named m1 = Mass(;m=0.5)
1416
# @named m2 = Mass(;m=0.5)
1517

1618
eqs = [
17-
connect(link.TX1, cart.flange), #, force.flange)
18-
# connect(link.TY1, fixed.flange)
19-
# connect(link.TX2, m1.flange)
20-
# connect(link.TY2, m2.flange)
19+
connect(link1.TX1, cart.flange) #, force.flange)
20+
connect(link1.TY1, fixed.flange)
21+
connect(link1.TX2, link2.TX1)
22+
connect(link1.TY2, link2.TY1)
2123
]
2224

23-
@named model = ODESystem(eqs, t, [], []; systems = [link, cart])
25+
@named model = ODESystem(eqs, t, [], []; systems = [link1, link2, cart, fixed])
2426

27+
#TODO: This gives an error
2528
sys = structural_simplify(model)
26-
# sys = expand_connections(model)
27-
# @set! sys.eqs = [(typeof(eq.lhs) != ModelingToolkit.Connection) & !ModelingToolkit._iszero(eq.lhs) & !ModelingToolkit.isdifferential(eq.lhs) ? 0 ~ eq.rhs - eq.lhs : eq for eq in sys.eqs]
2829

29-
prob = ODEProblem(sys, [], (0.0, 5), []; jac = true)
30+
# The below code does work...
31+
#=
32+
sys = expand_connections(model)
33+
@set! sys.eqs = [(typeof(eq.lhs) != ModelingToolkit.Connection) & !ModelingToolkit._iszero(eq.lhs) & !ModelingToolkit.isdifferential(eq.lhs) ? 0 ~ eq.rhs - eq.lhs : eq for eq in sys.eqs]
34+
35+
prob = ODEProblem(sys, [], (0.0, 20), []; jac = true)
3036
NEWTON = NLNewton(check_div = false, always_new = true, max_iter = 100, relax = 4 // 10)
31-
sol = solve(prob, ImplicitEuler(nlsolve = NEWTON), dt = 0.0001, adaptive = false)
32-
# sol = solve(prob)
37+
sol = solve(prob, ImplicitEuler(nlsolve = NEWTON), dt = 0.001, adaptive = false)
38+
39+
@test sol[cart.s][end] ≈ 4.767 atol=1e-3
40+
3341
plot(sol, idxs = [cart.s])
42+
=#
43+
44+
45+
#=
46+
using CairoMakie
47+
f = Figure()
48+
a = Axis(f[1,1],xlabel="time [s]", ylabel="cart x pos. [m]")
49+
lines!(a, sol.t, sol[cart.s])
50+
f
51+
52+
53+
54+
function plot_link(sol, sys, tmax)
55+
tm = Observable(0.0)
56+
idx = Dict(reverse.(enumerate(states(sys))))
57+
58+
fig = Figure()
59+
a = Axis(fig[1,1], aspect=DataAspect(), )
60+
hidedecorations!(a)
61+
s = @lift(sol($tm))
62+
63+
m1x1 = @lift($s[idx[link1.x1]])
64+
m1x2 = @lift($s[idx[link1.x2]])
65+
m2x1 = @lift($s[idx[link2.x1]])
66+
m2x2 = @lift($s[idx[link2.x2]])
67+
68+
m1y1 = @lift($s[idx[link1.y1]])
69+
m1y2 = @lift($s[idx[link1.y2]])
70+
m2y1 = @lift($s[idx[link2.y1]])
71+
m2y2 = @lift($s[idx[link2.y2]])
72+
73+
sz1 = 0.5
74+
# lines!(a, [-sz1, sz1, sz1, -sz1, -sz1], @lift([$m1x1, $m1x1, $m1x1+sz1*2, $m1x1+sz1*2, $m1x1]))
75+
76+
77+
lines!(a, @lift([$m1x1, $m1x2]), @lift([$m1y1, $m1y2]), linewidth=10, color=:blue)
78+
lines!(a, @lift([$m2x1, $m2x2]), @lift([$m2y1, $m2y2]), linewidth=10, color=:red)
79+
80+
CairoMakie.ylims!(a, -40, 20)
81+
CairoMakie.xlims!(a, -20, 40)
82+
83+
# a = Axis(fig[1, 1], xlabel="time [s]", ylabel="position [m]")
84+
# lines!(a, sol.t, sol[2,:])
85+
# lines!(a, sol.t, sol[4,:])
86+
87+
# scatter!(a, tm, m1x)
88+
# scatter!(a, tm, m2x)
89+
# ylims!(a, -60, 30)
90+
91+
framerate = 30
92+
timestamps = range(0, tmax, step=1/framerate)
93+
94+
95+
record(fig, "links.mp4", timestamps;
96+
framerate = framerate) do t
97+
tm[] = t
98+
end
99+
100+
#=
101+
CairoMakie.Makie.Record(fig, timestamps; framerate=framerate) do t
102+
tm[] = t
103+
end
104+
=#
105+
106+
nothing
107+
end
108+
109+
plot_link(sol, sys, 20)
110+
111+
=#

0 commit comments

Comments
 (0)