Skip to content

Commit 68b91eb

Browse files
Merge pull request #50 from ModiaSim/gh_extendForceElementFunctionality
Extend force element functionality
2 parents 8d78a7f + d5fa3ea commit 68b91eb

File tree

6 files changed

+140
-37
lines changed

6 files changed

+140
-37
lines changed

src/Composition/ForceElements/Bushing.jl

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,36 @@
11

22
"""
3-
force = Bushing(; obj1, obj2, stiffness, damping)
3+
force = Bushing(; obj1, obj2,
4+
nominalForce = Modia3D.ZeroVector3D,
5+
stiffness = Modia3D.ZeroVector3D,
6+
damping = Modia3D.ZeroVector3D )
47
58
Return a `force` acting as bushing between `obj1::`[`Object3D`](@ref) and
6-
`obj2::`[`Object3D`](@ref). Vectors `stiffness` and `damping` define the
7-
stiffness resp. damping values in x, y and z direction of `obj1`. The
8-
orientation of `obj2` does not influence the resulting forces.
9+
`obj2::`[`Object3D`](@ref). Vectors `stiffness`, `damping` and
10+
`nominalForce` define the stiffness, damping and nominal force values in
11+
x, y and z direction of `obj1`. The orientation of `obj2` does not
12+
influence the resulting forces.
913
"""
1014
mutable struct Bushing <: Modia3D.AbstractForceElement
1115

12-
obj1::Modia3D.AbstractObject3D
13-
obj2::Modia3D.AbstractObject3D
16+
obj1::Object3D
17+
obj2::Object3D
1418

19+
nominalForce::SVector{3,Float64}
1520
stiffness::SVector{3,Float64}
1621
damping::SVector{3,Float64}
1722

18-
function Bushing(; obj1::Modia3D.AbstractObject3D,
19-
obj2::Modia3D.AbstractObject3D,
23+
function Bushing(; obj1::Object3D,
24+
obj2::Object3D,
25+
nominalForce::AbstractVector = Modia3D.ZeroVector3D,
2026
stiffness::AbstractVector = Modia3D.ZeroVector3D,
21-
damping::AbstractVector = Modia3D.ZeroVector3D)
27+
damping::AbstractVector = Modia3D.ZeroVector3D)
2228

23-
stiff = Modia3D.convertAndStripUnit(SVector{3,Float64}, u"N/m" , stiffness)
24-
damp = Modia3D.convertAndStripUnit(SVector{3,Float64}, u"N*s/m", damping)
29+
nomForce = Modia3D.convertAndStripUnit(SVector{3,Float64}, u"N" , nominalForce)
30+
stiff = Modia3D.convertAndStripUnit(SVector{3,Float64}, u"N/m" , stiffness)
31+
damp = Modia3D.convertAndStripUnit(SVector{3,Float64}, u"N*s/m", damping)
2532

26-
return new(obj1, obj2, stiff, damp)
33+
return new(obj1, obj2, nomForce, stiff, damp)
2734

2835
end
2936
end
@@ -38,7 +45,9 @@ end
3845
function evaluateForceElement(force::Bushing)
3946
r12 = measFramePosition(force.obj2; frameOrig=force.obj1, frameCoord=force.obj1)
4047
v12 = measFrameTransVelocity(force.obj2; frameOrig=force.obj1, frameCoord=force.obj1, frameObsrv=force.obj1)
41-
f12 = force.stiffness .* r12 + force.damping .* v12
48+
49+
f12 = force.stiffness .* r12 + force.damping .* v12 + force.nominalForce
50+
4251
applyFrameForcePair!(force.obj2, force.obj1, f12; frameCoord=force.obj1)
4352
return nothing
4453
end

src/Composition/ForceElements/SpringDamperPtP.jl

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,58 @@
11

22
"""
3-
force = SpringDamperPtP(; obj1, obj2, stiffness, damping)
3+
force = SpringDamperPtP(; obj1, obj2,
4+
nominalLength = 0.0,
5+
nominalForce = 0.0,
6+
springForceLaw = 0.0,
7+
damperForceLaw = 0.0 )
48
59
Return a `force` acting as point-to-point parallel spring-damper between
6-
`obj1::`[`Object3D`](@ref) and `obj2::`[`Object3D`](@ref). Values
7-
`stiffness` and `damping` define the stiffness resp. damping coefficient.
10+
`obj1::`[`Object3D`](@ref) and `obj2::`[`Object3D`](@ref).
11+
12+
# Arguments
13+
14+
- `nominalLength` defines the nominal length, i.e. the distance between
15+
`obj1` and `obj2` where the deflection of the spring is zero.
16+
- `nominalForce` defines the nominal force, i.e. the force that acts when
17+
spring and damper forces are zero. Positive values represent tension.
18+
- `springForceLaw` defines the force law of the spring:
19+
A `Float64` value represents a linear stiffness coefficient.
20+
An univariate `Function` is used to compute the spring force dependent
21+
of its deflection. Positive values represent tension.
22+
- `damperForceLaw` defines the force law of the damper:
23+
A `Float64` value represents a linear damping coefficient.
24+
An univariate `Function` is used to compute the damper force dependent
25+
of its deflection velocity. Positive values represent expansion.
826
"""
927
mutable struct SpringDamperPtP <: Modia3D.AbstractForceElement
1028

11-
obj1::Modia3D.AbstractObject3D
12-
obj2::Modia3D.AbstractObject3D
13-
14-
stiffness::Float64
15-
damping::Float64
29+
obj1::Object3D
30+
obj2::Object3D
1631

17-
function SpringDamperPtP(; obj1::Modia3D.AbstractObject3D,
18-
obj2::Modia3D.AbstractObject3D,
19-
stiffness::Float64 = 0.0,
20-
damping::Float64 = 0.0)
32+
nominalLength::Float64
33+
nominalForce::Float64
34+
springForceFunction::Function
35+
damperForceFunction::Function
2136

22-
stiff = Modia3D.convertAndStripUnit(Float64, u"N/m" , stiffness)
23-
damp = Modia3D.convertAndStripUnit(Float64, u"N*s/m", damping)
37+
function SpringDamperPtP(; obj1::Object3D,
38+
obj2::Object3D,
39+
nominalLength::Float64 = 0.0,
40+
nominalForce::Float64 = 0.0,
41+
springForceLaw::Union{Float64, Function} = 0.0,
42+
damperForceLaw::Union{Float64, Function} = 0.0 )
2443

25-
return new(obj1, obj2, stiff, damp)
44+
nomLength = Modia3D.convertAndStripUnit(Float64, u"m", nominalLength)
45+
nomForce = Modia3D.convertAndStripUnit(Float64, u"N", nominalForce)
46+
if (typeof(springForceLaw) == Float64)
47+
stiffness = Modia3D.convertAndStripUnit(Float64, u"N/m", springForceLaw)
48+
springForceLaw = eval(:(fc(pos) = $stiffness * pos))
49+
end
50+
if (typeof(damperForceLaw) == Float64)
51+
damping = Modia3D.convertAndStripUnit(Float64, u"N*s/m", damperForceLaw)
52+
damperForceLaw = eval(:(fd(vel) = $damping * vel))
53+
end
2654

55+
return new(obj1, obj2, nomLength, nomForce, springForceLaw, damperForceLaw)
2756
end
2857
end
2958

@@ -37,8 +66,12 @@ end
3766
function evaluateForceElement(force::SpringDamperPtP)
3867
(pos, norm) = measFrameDistance(force.obj2; frameOrig=force.obj1)
3968
vel = measFrameDistVelocity(force.obj2; frameOrig=force.obj1)
40-
frc = force.stiffness * pos + force.damping * vel
41-
f12 = frc * norm
69+
70+
defl = pos - force.nominalLength
71+
fc = force.springForceFunction(defl)
72+
fd = force.damperForceFunction(vel)
73+
f12 = (fc + fd + force.nominalForce) * norm
74+
4275
applyFrameForcePair!(force.obj2, force.obj1, f12; frameCoord=force.obj1)
4376
end
4477

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
module BoxNonLinearSpringDamperPtP
2+
3+
using ModiaLang
4+
5+
import Modia3D
6+
using Modia3D.ModiaInterface
7+
8+
interpolatedForceLaws = false
9+
l0 = 0.1
10+
f0 = 5.0
11+
fc(x) = sign(x) * 100.0 * abs(x)^1.2
12+
fd(v) = sign(v) * 2.0 * abs(v)^0.8
13+
if (interpolatedForceLaws)
14+
using Interpolations
15+
xc = -1.0:0.1:1.0
16+
yc = [fc(x) for x in xc]
17+
fc(x) = CubicSplineInterpolation(xc, yc)(x)
18+
xd = -10.0:0.1:10.0
19+
yd = [fd(x) for x in xd]
20+
fd(v) = LinearInterpolation(xd, yd)(v)
21+
end
22+
23+
SpringDamper = Model(
24+
Length = 0.1,
25+
Mass = 1.0,
26+
IMoment = 0.1,
27+
visualMaterial = VisualMaterial(color="IndianRed1", transparency=0.5),
28+
world = Object3D(feature=Scene(gravityField=UniformGravityField(g=9.81, n=[0, 0, -1]), nominalLength=:Length)),
29+
worldFrame = Object3D(parent=:world,
30+
feature=Visual(shape=CoordinateSystem(length=:Length))),
31+
box = Object3D(feature=Solid(shape=Box(lengthX=:Length, lengthY=:Length, lengthZ=:Length),
32+
massProperties=MassProperties(; mass=:Mass, Ixx=:IMoment, Iyy=:IMoment, Izz=:IMoment),
33+
visualMaterial=:(visualMaterial))),
34+
boxCornerFrame = Object3D(parent=:box,
35+
feature=Visual(shape=CoordinateSystem(length=:(Length/2))),
36+
translation=:[Length/2, Length/2, Length/2]),
37+
joint = FreeMotion(obj1=:world, obj2=:box),
38+
force = SpringDamperPtP(obj1=:world, obj2=:boxCornerFrame, nominalLength=l0, nominalForce=f0, springForceLaw=fc, damperForceLaw=fd)
39+
)
40+
41+
springDamper = @instantiateModel(buildModia3D(SpringDamper), aliasReduction=false, unitless=true)
42+
43+
stopTime = 5.0
44+
dtmax = 0.1
45+
if (interpolatedForceLaws)
46+
requiredFinalStates = [-0.018609840194419268, -0.018610063010666804, -0.22128548799442815, 0.3091309586280587, 0.3091307182143652, 0.019491580480008697, -0.01289771100508473, 0.012897263597266288, 8.547830805609731e-5, -0.24873244248570697, 0.2487317559006742, 6.865934996471178e-7]
47+
else
48+
requiredFinalStates = [-0.021471022585945587, -0.021471338063312084, -0.22257979374805176, 0.3258966598257503, 0.3258956068893249, 0.007390650203910464, -0.014365742162847027, 0.014364567804398353, 0.00010407183716342378, -0.2720750966146867, 0.27207423475429426, 8.60986118342952e-7]
49+
end
50+
simulate!(springDamper, stopTime=stopTime, dtmax=dtmax, log=true, requiredFinalStates=requiredFinalStates)
51+
52+
@usingModiaPlot
53+
plot(springDamper, ["joint.r", "joint.v", "joint.rot", "joint.w"], figure=1)
54+
55+
end
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,21 @@ using Modia3D.ModiaInterface
88
SpringDamper = Model(
99
Length = 0.1,
1010
Mass = 1.0,
11+
IMoment = 0.1,
1112
Stiffness = 100.0,
1213
Damping = 2.0,
1314
visualMaterial = VisualMaterial(color="IndianRed1", transparency=0.5),
1415
world = Object3D(feature=Scene(gravityField=UniformGravityField(g=9.81, n=[0, 0, -1]), nominalLength=:Length)),
1516
worldFrame = Object3D(parent=:world,
1617
feature=Visual(shape=CoordinateSystem(length=:Length))),
1718
box = Object3D(feature=Solid(shape=Box(lengthX=:Length, lengthY=:Length, lengthZ=:Length),
18-
massProperties=MassProperties(; mass=1.0, Ixx=0.1, Iyy=0.1, Izz=0.1),
19+
massProperties=MassProperties(; mass=:Mass, Ixx=:IMoment, Iyy=:IMoment, Izz=:IMoment),
1920
visualMaterial=:(visualMaterial))),
2021
boxCornerFrame = Object3D(parent=:box,
2122
feature=Visual(shape=CoordinateSystem(length=:(Length/2))),
2223
translation=:[Length/2, Length/2, Length/2]),
2324
joint = FreeMotion(obj1=:world, obj2=:box),
24-
force = SpringDamperPtP(obj1=:world, obj2=:boxCornerFrame, stiffness=:Stiffness, damping=:Damping)
25+
force = SpringDamperPtP(obj1=:world, obj2=:boxCornerFrame, springForceLaw=:Stiffness, damperForceLaw=:Damping)
2526
)
2627

2728
springDamper = @instantiateModel(buildModia3D(SpringDamper), aliasReduction=false, unitless=true)
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,25 @@ using Modia3D.ModiaInterface
88
Oscillator = Model(
99
Length = 0.1,
1010
Mass = 1.0,
11+
nomForce = 0.5,
1112
Stiffness = 100.0,
1213
Damping = 2.0,
1314
visualMaterial = VisualMaterial(color="IndianRed1", transparency=0.5),
1415
world = Object3D(feature=Scene(gravityField=UniformGravityField(g=9.81, n=[0, 0, -1]), nominalLength=:Length)),
1516
worldFrame = Object3D(parent=:world,
1617
feature=Visual(shape=CoordinateSystem(length=:Length))),
1718
oscillator = Object3D(feature=Solid(shape=Box(lengthX=:Length, lengthY=:Length, lengthZ=:Length),
18-
massProperties=MassProperties(; mass=1.0, Ixx=0.1, Iyy=0.1, Izz=0.1),
19+
massProperties=MassProperties(; mass=:Mass, Ixx=0.1, Iyy=0.1, Izz=0.1),
1920
visualMaterial=:(visualMaterial))),
2021
joint = Prismatic(obj1=:world, obj2=:oscillator, axis=3, s=Var(init=0.0), v=Var(init=0.0)),
21-
force = Bushing(obj1=:world, obj2=:oscillator, stiffness=:[0.0, 0.0, Stiffness], damping=:[0.0, 0.0, Damping])
22+
force = Bushing(obj1=:world, obj2=:oscillator, nominalForce=:[0.0, 0.0, nomForce], stiffness=:[0.0, 0.0, Stiffness], damping=:[0.0, 0.0, Damping])
2223
)
2324

2425
oscillator = @instantiateModel(buildModia3D(Oscillator), aliasReduction=false, unitless=true)
2526

2627
stopTime = 5.0
2728
dtmax = 0.1
28-
requiredFinalStates = [0.0032763240987720987, -0.09755848695453585]
29+
requiredFinalStates = [0.0034429013089251376, -0.10253096819858225]
2930
simulate!(oscillator, stopTime=stopTime, dtmax=dtmax, log=true, requiredFinalStates=requiredFinalStates)
3031

3132
@usingModiaPlot

test/includeTests.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ Test.@testset "Basic" begin
99
include(joinpath("Basic", "PendulumWithParameterizedDamper.jl"))
1010
include(joinpath("Basic", "PendulumWithSpring.jl"))
1111
include(joinpath("Basic", "DoublePendulumWithDampers.jl"))
12-
include(joinpath("Basic", "HarmonicOscillator.jl"))
13-
include(joinpath("Basic", "BoxSpringDamperPtP.jl"))
1412
include(joinpath("Basic", "BoxPlanarMotion.jl"))
1513
include(joinpath("Basic", "ShaftFreeMotion.jl"))
1614
include(joinpath("Basic", "ShaftFreeMotionAdaptiveRotSequence.jl"))
@@ -20,6 +18,12 @@ Test.@testset "Basic" begin
2018
end
2119
end
2220

21+
Test.@testset "Force Elements" begin
22+
include(joinpath("ForceElements", "HarmonicOscillator.jl"))
23+
include(joinpath("ForceElements", "BoxSpringDamperPtP.jl"))
24+
include(joinpath("ForceElements", "BoxNonLinearSpringDamperPtP.jl"))
25+
end
26+
2327
Test.@testset "Robot" begin
2428
include(joinpath("Robot", "ServoWithRamp.jl"))
2529
include(joinpath("Robot", "ServoWithRampAndPrismatic.jl"))

0 commit comments

Comments
 (0)