Open
Description
So my student is building a model from MTK components based on the great Planarmechanics Modelica library.
simple model
One of our simpler test models is nothing but a planar pendulum which causes the error in the title.
That model consists of
- a Fixed (fixed bearing),
- a Revolute (revolute joint),
- FixedTranslation (massless rod),
- a Body (rigid body),
- a Torque (torque source),
- a Constant (constant input)
Here's a sketch of the system:
code to reproduce the error
using ModelingToolkit, DifferentialEquations, LinearAlgebra
using GLMakie
@variables t
D= Differential(t)
##
# connectors
@connector function frame_a(;name, pos=[0., 0.], phi=0.0, _f=[0., 0.], tau=0.0)
sts = @variables ox(t)=pos[1] oy(t)=pos[2] phi(t) fx(t)=_f [connect=Flow] fy(t)=_f [connect=Flow] tau(t) [connect=Flow]
ODESystem(Equation[], t, sts, []; name=name)
end
@connector function flange_a(;name)
sts = @variables phi(t) tau(t) [connect=Flow]
ODESystem(Equation[], t, sts, []; name=name, defaults = Dict(phi => 0.0, tau => 0.0))
end
@connector function realInput(;name, x=0.0)
sts = @variables x(t) [input=true]
ODESystem(Equation[], t, sts, []; name=name)
end
@connector function realOutput(;name, x=0.0)
sts = @variables x(t) [output=true]
ODESystem(Equation[], t, sts, []; name=name)
end
##
# components
function Fixed(;name, pos=[0., 0.], phi=0.0)
@named fa = frame_a()
ps = @parameters posx=pos[1] posy=pos[2] phi=phi
eqs = [
fa.ox ~ posx
fa.oy ~ posy
fa.phi ~ phi
]
compose(ODESystem(eqs, t, [], ps; name=name), fa)
end
function Revolute(;name, phi=0.0, w=0.0, z=0.0, tau=0.0)
@named fa= frame_a()
@named fb= frame_a()
@named fla= flange_a()
sts= @variables phi(t)=phi w(t)=w z(t)=z tau(t)=tau
eqs= [ D.(phi) ~ w
D.(w) ~ z
fla.phi ~ phi
fla.tau ~ tau
fa.ox ~ fb.ox
fa.oy ~ fb.oy
fa.phi + phi ~ fb.phi
fa.fx + fb.fx ~ 0
fa.fy + fb.fy ~ 0
fa.tau + fb.tau ~ 0
fa.tau ~ tau
]
compose(ODESystem(eqs, t, sts, []; name=name), [fa,fb,fla])
end
function FixedTranslation(;name, r0 =[1. , 0.])
@named fa= frame_a()
@named fb= frame_a()
ps= @parameters rx=r0[1] ry=r0[2]
sts= @variables r0x(t) r0y(t) Rx(t) Rp(t) Ry(t) Rq(t)
eqs= [
Rx ~ cos(fa.phi)
Rp ~ -sin(fa.phi)
Ry ~ sin(fa.phi)
Rq ~ cos(fa.phi)
Rx * rx + Rp * ry ~ r0x
Ry * rx + Rq * ry ~ r0y
fa.ox + r0x ~ fb.ox
fa.oy + r0y ~ fb.oy
fa.phi ~ fb.phi
fa.fx + fb.fx ~ 0
fa.fy + fb.fy ~ 0
fa.tau + fb.tau + r0x * fb.fy - r0y * fb.fx ~ 0
]
compose(ODESystem(eqs, t, sts, ps; name=name), [fa,fb])
end
function Body(;name, v=[0., 0.], a=[0., 0.],phi=0.0, w=0.0, z=0.0)
@named fa = frame_a()
ps = @parameters m=1.0 I=1.0
sts= @variables vx(t)=v[1] vy(t)=v[2] ax(t) ay(t) phi(t)=0.0 w(t)=w z(t)=z
eqs = [fa.tau ~ I * z
D.(fa.ox) ~ vx
D.(fa.oy) ~ vy
D.(vx) ~ ax
D.(vy) ~ ay
D.(phi) ~ w
D.(w) ~ z
fa.phi ~ phi
fa.fx ~ m * ax
fa.fy ~ m * ay ]
compose(ODESystem(eqs, t, sts, ps; name=name), fa)
end
function Torque(;name)
@named in = realInput()
@named flb = flange_a()
eqs = [-in.x ~ flb.tau,]
compose(ODESystem(eqs, t, [],[]; name=name), [flb,in])
end
function Constant(;name, k=1.0)
@named y = realOutput()
ps = @parameters k=k
eqs = [
y.x ~ k
]
compose(ODESystem(eqs, t, [],ps; name=name), y)
end
##
# the actual model
@named fixed = Fixed()
@named revolute = Revolute()
@named trans = FixedTranslation()
@named body = Body()
@named torque = Torque()
@named const_ = Constant(k=1)
eqs = [
connect(fixed.fa, revolute.fa),
connect(revolute.fb, trans.fa),
connect(trans.fb, body.fa),
connect(torque.flb, revolute.fla),
connect(const_.y, torque.in)
]
@named model = compose(
ODESystem(eqs, t, name=:tmp),
[
fixed,
revolute,
trans,
body,
torque,
const_
]
)
modelTorque = model
sys = structural_simplify(model)
##
u0 = [
# instantly crashing parametrization for trans
trans.rx => 1.0,
trans.ry => 0.0,
# initially working parametrization for trans (until t ~ sqrt(2*pi), i.e. until the pendulum has rotated by pi/2)
#trans.rx => 1/sqrt(2),
#trans.ry => 1/sqrt(2),
# supposedly sufficient initial conditions
body.phi => 0.0,
D(body.phi) => 0.0,
# initial conditions required by MTK
D(D(body.fa.oy)) => 1.0,
D(D(trans.r0x)) => 0.0,
trans.r0y => 0.0,
D(trans.r0y) => 0.0,
]
prob = ODEProblem(sys, u0, (0, 10.0))
sol = solve(prob, Rodas4())
fig = Figure()
ax = Axis(fig[1, 1])
lines!(ax, sol.t, sol[D(D(body.fa.oy))])
display(fig)
observations
Search the code for "u0 =
", where we set our initial conditions/states and parameters.
- if the code stays as it is, it leads to the error mentioned above
- the equations that form the unsolvable non-linear system
> full_equations(sys)[1]
Differential(t)(trans₊r0y(t)) ~ trans₊r0yˍt(t)
> full_equations(sys)[3]
0 ~ (trans₊rx*sin(body₊phi(t)) - trans₊r0y(t)) / trans₊ry + cos(body₊phi(t))
- the issue seems to be that eq. 3 includes a division by parameter
trans₊ry
, which can be0
.- this can be verified by uncommenting the 2 lines below
# initially working parametrization [...]
- however, then the model crashes a bit later after ~
sqrt(2*pi)
seconds (i.e. after a rotation bypi
)
- this can be verified by uncommenting the 2 lines below
- Apparently, the model has been transformed in a very unfortunate manner
- What can be done about this?
- the equations that form the unsolvable non-linear system
- the model requires a.. surprising and redundant set of initial conditions
- it requires the lines below
# initial conditions required by MTK
- otherwise, we're greeted by a
ERROR: ArgumentError: SymbolicUtils.Symbolic{Real}[body₊fa₊oyˍtt(t)] are missing from the variable map.
where the list of missing symbols grows as you comment out more "required" initial conditions.
- otherwise, we're greeted by a
- theoretically, the 2 lines below
# supposedly sufficient initial conditions
should be enough to specify the (control theoretical) system state - Is there any solution to this?
- it requires the lines below