Skip to content

Commit d69666a

Browse files
committed
fixes for prismatic joint with axisflange.
Also add a Kinematic loop test
1 parent 7e11e7e commit d69666a

File tree

3 files changed

+97
-17
lines changed

3 files changed

+97
-17
lines changed

src/PlanarMechanics/components.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,13 +568,18 @@ The force depends with friction characteristics on the slip. The slip is split i
568568
- lateral slip: the lateral velocity divided by the rolling velocity.
569569
- longitudinal slip: the longitudinal slip velocity divided by the rolling velocity.
570570
571-
For low rolling velocity this definition become ill-conditioned. Hence a dry-friction model is used for low rolling velocities. For zero rolling velocity, the intitialization might fail if automatic differentiation is used. Either start with a non-zero (but tiny) rolling velocity or pass `autodiff=false` to the solver.
571+
For low rolling velocity this definition become ill-conditioned. Hence a dry-friction model is used for low rolling velocities. For **zero rolling velocity**, the intitialization might fail if automatic differentiation is used. Either start with a non-zero (but tiny) rolling velocity or pass `autodiff=false` to the solver.
572572
573573
The radius of the wheel can be specified by the parameter `radius`. The driving direction (for `phi = 0`) can be specified by the parameter `r`. The normal load is set by `N`.
574574
575575
The wheel contains a 2D connector `frame_a` for the steering on the plane. The rolling motion of the wheel can be actuated by the 1D connector `flange_a`.
576576
577577
In addition there is an input `dynamicLoad` for a dynamic component of the normal load.
578+
579+
# Connectors:
580+
- `frame_a` (Frame) Coordinate system fixed to the component with one cut-force and cut-torque
581+
- `flange_a` (Rotational.Flange) Flange for the rolling motion
582+
- `dynamicLoad` (Blocks.RealInput) Input for the dynamic component of the normal load (must be connected)
578583
"""
579584
@component function SlipBasedWheelJoint(;
580585
name,

src/PlanarMechanics/joints.jl

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ https://github.com/dzimmer/PlanarMechanics/blob/743462f58858a808202be93b70839146
2525
@component function Revolute(;
2626
name,
2727
axisflange = false, render = true, radius = 0.1, color = [1.0, 0.0, 0.0, 1.0], phi=0, w=0,
28+
iscut = false,
2829
state_priority = 10)
2930
@named partial_frames = PartialTwoFrames()
3031
@unpack frame_a, frame_b = partial_frames
@@ -33,7 +34,7 @@ https://github.com/dzimmer/PlanarMechanics/blob/743462f58858a808202be93b70839146
3334
vars = @variables begin
3435
(phi(t) = phi), [state_priority=state_priority]
3536
(w(t) = w), [state_priority=state_priority]
36-
α(t)
37+
α(t), [state_priority=state_priority]
3738
tau(t)
3839
end
3940

@@ -49,14 +50,16 @@ https://github.com/dzimmer/PlanarMechanics/blob/743462f58858a808202be93b70839146
4950
# rigidly connect positions
5051
frame_a.x ~ frame_b.x,
5152
frame_a.y ~ frame_b.y,
52-
frame_a.phi + phi ~ frame_b.phi,
5353
# balance forces
5454
frame_a.fx + frame_b.fx ~ 0,
5555
frame_a.fy + frame_b.fy ~ 0,
5656
# balance torques
5757
frame_a.tau + frame_b.tau ~ 0,
5858
frame_a.tau ~ tau
5959
]
60+
if !iscut
61+
push!(eqs, frame_a.phi + phi ~ frame_b.phi)
62+
end
6063

6164
if axisflange
6265
@named fixed = Rotational.Fixed()
@@ -85,10 +88,11 @@ end
8588
A prismatic joint
8689
8790
# Parameters
88-
- `r`: [m, m] x,y-direction of the rod wrt. body system at phi=0
89-
- `constant_f`: [N] Constant force in direction of elongation
90-
- `constant_s`: [m] Constant elongation of the joint"
91-
- `axisflange=false`: If `true`, a force flange is enabled, otherwise implicitly grounded"
91+
- `r`: [m, m] x,y-direction of the rod wrt. body system at phi=0
92+
- `axisflange=false`: If `true`, a force flange is enabled, otherwise implicitly grounded"
93+
- `render`: Render the joint in animations
94+
- `radius`: Radius of the body in animations
95+
- `color`: Color of the body in animations
9296
9397
# Variables
9498
- `s(t)`: [m] Elongation of the joint
@@ -110,25 +114,26 @@ https://github.com/dzimmer/PlanarMechanics/blob/743462f58858a808202be93b70839146
110114
r = [0,0],
111115
s = 0,
112116
v = 0,
113-
constant_f = 0,
114-
constant_s = 0,
115117
axisflange = false,
116118
render = true,
117119
radius = 0.1,
118120
color = [0,0.8,1,1],
121+
state_priority = 2,
122+
iscut = false,
119123
)
120124
@named partial_frames = PartialTwoFrames()
125+
@unpack frame_a, frame_b = partial_frames
126+
121127
systems = @named begin
122128
fixed = TranslationalModelica.Support()
123129
end
124-
@unpack frame_a, frame_b = partial_frames
125130

126131
if axisflange
127132
more_systems = @named begin
128-
flange_a = TranslationalModelica.Flange(; f = constant_f, constant_s)
129-
support = TranslationalModelica.Support()
133+
flange_a = TranslationalModelica.Flange()
134+
support = TranslationalModelica.Flange()
130135
end
131-
systems = [systems, more_systems]
136+
systems = [systems; more_systems]
132137
end
133138

134139
pars = @parameters begin
@@ -139,8 +144,8 @@ https://github.com/dzimmer/PlanarMechanics/blob/743462f58858a808202be93b70839146
139144
end
140145

141146
vars = @variables begin
142-
(s(t) = s), [state_priority = 2, description="Joint coordinate"]
143-
(v(t) = v), [state_priority = 2]
147+
(s(t) = s), [state_priority = state_priority, description="Joint coordinate"]
148+
(v(t) = v), [state_priority = state_priority]
144149
a(t)
145150
f(t)
146151
e0(t)[1:2]
@@ -158,15 +163,21 @@ https://github.com/dzimmer/PlanarMechanics/blob/743462f58858a808202be93b70839146
158163
# rigidly connect positions
159164
frame_a.x + r0[1] ~ frame_b.x
160165
frame_a.y + r0[2] ~ frame_b.y
161-
frame_a.phi ~ frame_b.phi
162166
frame_a.fx + frame_b.fx ~ 0
163167
frame_a.fy + frame_b.fy ~ 0
164168
frame_a.tau + frame_b.tau + r0[1] * frame_b.fy - r0[2] * frame_b.fx ~ 0
165169
e0[1] * frame_a.fx + e0[2] * frame_a.fy ~ f
166170
]
171+
if !iscut
172+
push!(eqs, frame_a.phi ~ frame_b.phi)
173+
end
167174

168175
if axisflange
169-
push!(eqs, connect(fixed.flange, support))
176+
append!(eqs, [
177+
connect(fixed, support)
178+
flange_a.s ~ s
179+
flange_a.f ~ f
180+
])
170181
else
171182
# actutation torque
172183
push!(eqs, f ~ 0)

test/test_PlanarMechanics.jl

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,3 +618,67 @@ sol = solve(prob, Rodas5P(autodiff=false))
618618
# plot(sol)
619619

620620
end
621+
622+
623+
# ==============================================================================
624+
## Planar Kinematic loop
625+
# ==============================================================================
626+
627+
import ModelingToolkitStandardLibrary.Mechanical.TranslationalModelica as Translational
628+
@testset "Planar Kinematic loop" begin
629+
@info "Testing Planar Kinematic loop"
630+
631+
@mtkmodel PlanarKinematicLoop begin
632+
@parameters begin
633+
radius = 0.02
634+
end
635+
@components begin
636+
fixed = Pl.Fixed()
637+
fixed1D = Translational.Fixed(s0=0)
638+
fixedTranslation1 = Pl.FixedTranslation(; r = [0, -0.5], radius)
639+
fixedTranslation2 = Pl.FixedTranslation(; r = [0, -0.5], radius)
640+
fixedTranslation3 = Pl.FixedTranslation(; r = [0, -0.6], radius)
641+
revolute1 = Pl.Revolute(; phi = asin(0.4/0.5/2), state_priority=100, radius)
642+
revolute3 = Pl.Revolute(; phi = -asin(0.4/0.5/2), radius)
643+
revolute2 = Pl.Revolute(; radius)
644+
revolute4 = Pl.Revolute(; phi = -0.69813170079773, w = 0, state_priority=100, radius)
645+
prismatic1 = Pl.Prismatic(r = [1, 0], s = 0.4, v = 0, axisflange=true, state_priority=10)
646+
springDamper1D = Translational.SpringDamper(c = 20, d = 4, s_rel0 = 0.4)
647+
body = Pl.Body(m = 1, I = 0.1, state_priority=10)
648+
end
649+
650+
@equations begin
651+
connect(fixedTranslation1.frame_a, revolute1.frame_b)
652+
connect(fixedTranslation2.frame_a, revolute3.frame_b)
653+
connect(revolute2.frame_a, fixedTranslation1.frame_b)
654+
connect(revolute2.frame_b, fixedTranslation2.frame_b)
655+
connect(fixedTranslation3.frame_a, revolute4.frame_b)
656+
connect(revolute1.frame_a, fixed.frame)
657+
connect(fixed1D.flange, springDamper1D.flange_a)
658+
connect(revolute4.frame_a, fixedTranslation1.frame_b)
659+
connect(body.frame_a, fixedTranslation3.frame_b)
660+
connect(prismatic1.frame_a, fixed.frame)
661+
connect(springDamper1D.flange_b, prismatic1.flange_a)
662+
connect(prismatic1.frame_b, revolute3.frame_a)
663+
end
664+
end
665+
666+
@named model = PlanarKinematicLoop()
667+
model = complete(model)
668+
ssys = structural_simplify(IRSystem(model))
669+
@test length(unknowns(ssys)) <= 6 # ideally 4
670+
display(sort(unknowns(ssys), by=string))
671+
672+
673+
guesses = ModelingToolkit.missing_variable_defaults(model)
674+
ps = parameters(model)
675+
initsys = generate_initializesystem(ssys)
676+
u0 = merge(Dict(guesses), ModelingToolkit.defaults(model))
677+
initprob = NonlinearLeastSquaresProblem(initsys, u0, [ps; t => 0.0])
678+
u0sol = solve(initprob)
679+
680+
681+
prob = ODEProblem(ssys, unknowns(ssys) .=> u0sol[unknowns(ssys)], (0.0, 5.0))
682+
sol = solve(prob, Rodas5P(), initializealg = ShampineCollocationInit())
683+
@test SciMLBase.successful_retcode(sol)
684+
end

0 commit comments

Comments
 (0)