Skip to content

Commit 33856e3

Browse files
Merge pull request #138 from ModiaSim/gh_sensorResultElement
Add result element SensorResult
2 parents ded1184 + ff32b43 commit 33856e3

File tree

12 files changed

+192
-21
lines changed

12 files changed

+192
-21
lines changed

docs/src/Components/ResultElements.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
CurrentModule = Modia3D.Composition
55
```
66

7+
## SensorResult
8+
9+
```@docs
10+
SensorResult
11+
```
12+
713
## ContactResult
814

915
```@docs

docs/src/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ julia -JModia3D_sysimage.so (otherwise)
9696

9797
### Forthcoming version
9898

99+
- Add Result Element SensorResult
99100
- Enable kinematic chain flipping for structure variable systems
100101
- Avoid function code generation for linear stiffness and damping in SpringDamperPtP and Bushing
101102

src/Composition/ResultElements/ContactResult.jl

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -111,19 +111,17 @@ function evaluateResultElement(model::Modia.InstantiatedModel{F,TimeType}, scene
111111
torqueVector = SVector{3,F}(0, 0, 0)
112112
end
113113

114-
if Modia.storeResults(model)
115-
Modia.copy_w_segmented_value_to_result(model, result.penetrationResultIndex, penetration)
116-
Modia.copy_w_segmented_value_to_result(model, result.penetrationVelocityResultIndex, penetrationVelocity)
117-
Modia.copy_w_segmented_value_to_result(model, result.tangentialVelocityResultIndex, tangentialVelocity)
118-
Modia.copy_w_segmented_value_to_result(model, result.angularVelocityResultIndex, angularVelocity)
119-
Modia.copy_w_segmented_value_to_result(model, result.normalForceResultIndex, normalForce)
120-
Modia.copy_w_segmented_value_to_result(model, result.tangentialForceResultIndex, tangentialForce)
121-
Modia.copy_w_segmented_value_to_result(model, result.torqueResultIndex, torque)
122-
Modia.copy_w_segmented_value_to_result(model, result.positionVectorResultIndex, positionVector)
123-
Modia.copy_w_segmented_value_to_result(model, result.normalVectorResultIndex, normalVector)
124-
Modia.copy_w_segmented_value_to_result(model, result.forceVectorResultIndex, forceVector)
125-
Modia.copy_w_segmented_value_to_result(model, result.torqueVectorResultIndex, torqueVector)
126-
end
114+
Modia.copy_w_segmented_value_to_result(model, result.penetrationResultIndex, penetration)
115+
Modia.copy_w_segmented_value_to_result(model, result.penetrationVelocityResultIndex, penetrationVelocity)
116+
Modia.copy_w_segmented_value_to_result(model, result.tangentialVelocityResultIndex, tangentialVelocity)
117+
Modia.copy_w_segmented_value_to_result(model, result.angularVelocityResultIndex, angularVelocity)
118+
Modia.copy_w_segmented_value_to_result(model, result.normalForceResultIndex, normalForce)
119+
Modia.copy_w_segmented_value_to_result(model, result.tangentialForceResultIndex, tangentialForce)
120+
Modia.copy_w_segmented_value_to_result(model, result.torqueResultIndex, torque)
121+
Modia.copy_w_segmented_value_to_result(model, result.positionVectorResultIndex, positionVector)
122+
Modia.copy_w_segmented_value_to_result(model, result.normalVectorResultIndex, normalVector)
123+
Modia.copy_w_segmented_value_to_result(model, result.forceVectorResultIndex, forceVector)
124+
Modia.copy_w_segmented_value_to_result(model, result.torqueVectorResultIndex, torqueVector)
127125

128126
return nothing
129127
end
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
2+
"""
3+
result = SensorResult(; object, objectOrigin, objectCoordinateRef, objectObserveRef)
4+
5+
Return a `result` providing kinematic measurements of
6+
`object::`[`Object3D`](@ref) relative to
7+
`objectOrigin::`[`Object3D`](@ref), resolved in coordinates of
8+
`objectCoordinateRef::`[`Object3D`](@ref) and observed in
9+
`objectObserveRef::`[`Object3D`](@ref).
10+
11+
In case of `objectOrigin` is undefined, world is used as sensor
12+
origin, i.e. results are absolute measurements. In case of
13+
`objectCoordinateRef` is undefined, `objectOrigin` is used as coordinate
14+
reference frame. In case of `objectObserveRef = nothing`,
15+
`objectCoordinateRef` is used as observer reference frame (so that
16+
velocity and acceleration results are consistent time derivatives of
17+
position results).
18+
19+
# Results
20+
- `translation` is the position vector from `objectOrigin` to `object`.
21+
- `velocity` is the translational velocity vector from `objectOrigin` to `object`, observed in `objectObserveRef`.
22+
- `acceleration` is the translational acceleration vector from `objectOrigin` to `object`, observed in `objectObserveRef`.
23+
- `rotation` contains the [Cardan (Tait–Bryan) angles](https://en.wikipedia.org/wiki/Euler_angles#Chained_rotations_equivalence) (rotation sequence x-y-z) from `objectOrigin` to `object`.
24+
- `angularVelocity` is the rotational velocity vector from `objectOrigin` to `object`.
25+
- `angularAcceleration` is the rotational acceleration vector from `objectOrigin` to `object`, observed in `objectObserveRef`.
26+
- `distance` is the point-to-point distance between `objectOrigin` and `object`.
27+
- `distanceVelocity` is the point-to-point velocity between `objectOrigin` and `object`.
28+
- `distanceAcceleration` is the point-to-point acceleration between `objectOrigin` and `object`.
29+
"""
30+
mutable struct SensorResult{F <: Modia3D.VarFloatType} <: Modia3D.AbstractResultElement
31+
32+
path::String
33+
34+
object::Object3D{F}
35+
objectOrigin::Union{Object3D{F}, Nothing}
36+
objectCoordinateRef::Union{Object3D{F}, Nothing}
37+
objectObserveRef::Union{Object3D{F}, Nothing}
38+
39+
translationResultIndex::Int
40+
velocityResultIndex::Int
41+
accelerationResultIndex::Int
42+
rotationResultIndex::Int
43+
angularVelocityResultIndex::Int
44+
angularAccelerationResultIndex::Int
45+
distanceResultIndex::Int
46+
distanceVelocityResultIndex::Int
47+
distanceAccelerationResultIndex::Int
48+
49+
function SensorResult{F}(; path::String = "",
50+
object::Object3D{F},
51+
objectOrigin::Union{Object3D{F}, Nothing}=nothing,
52+
objectCoordinateRef::Union{Object3D{F}, Nothing}=objectOrigin,
53+
objectObserveRef::Union{Object3D{F}, Nothing}=objectCoordinateRef ) where F <: Modia3D.VarFloatType
54+
return new(path, object, objectOrigin, objectCoordinateRef, objectObserveRef)
55+
end
56+
end
57+
SensorResult(; kwargs...) = SensorResult{Float64}(; kwargs...)
58+
59+
60+
function initializeResultElement(model::Modia.InstantiatedModel{F,TimeType}, result::SensorResult{F}) where {F <: Modia3D.VarFloatType, TimeType <: AbstractFloat}
61+
result.object.computeAcceleration = true
62+
if (!isnothing(result.objectOrigin))
63+
result.objectOrigin.computeAcceleration = true
64+
end
65+
if (!isnothing(result.objectObserveRef))
66+
result.objectObserveRef.computeAcceleration = true
67+
end
68+
69+
result.translationResultIndex = Modia.new_w_segmented_variable!(model, result.path*".translation" , SVector{3,F}(0, 0, 0), "m")
70+
result.velocityResultIndex = Modia.new_w_segmented_variable!(model, result.path*".velocity" , SVector{3,F}(0, 0, 0), "m/s")
71+
result.accelerationResultIndex = Modia.new_w_segmented_variable!(model, result.path*".acceleration" , SVector{3,F}(0, 0, 0), "m/s^2")
72+
result.rotationResultIndex = Modia.new_w_segmented_variable!(model, result.path*".rotation" , SVector{3,F}(0, 0, 0), "rad")
73+
result.angularVelocityResultIndex = Modia.new_w_segmented_variable!(model, result.path*".angularVelocity" , SVector{3,F}(0, 0, 0), "rad/s")
74+
result.angularAccelerationResultIndex = Modia.new_w_segmented_variable!(model, result.path*".angularAcceleration" , SVector{3,F}(0, 0, 0), "rad/s^2")
75+
result.distanceResultIndex = Modia.new_w_segmented_variable!(model, result.path*".distance" , F(0) , "m")
76+
result.distanceVelocityResultIndex = Modia.new_w_segmented_variable!(model, result.path*".distanceVelocity" , F(0) , "m/s")
77+
result.distanceAccelerationResultIndex = Modia.new_w_segmented_variable!(model, result.path*".distanceAcceleration" , F(0) , "m/s^2")
78+
79+
return nothing
80+
end
81+
82+
function evaluateResultElement(model::Modia.InstantiatedModel{F,TimeType}, scene::Modia3D.Composition.Scene{F}, result::SensorResult{F}, time::TimeType) where {F <: Modia3D.VarFloatType, TimeType <: AbstractFloat}
83+
84+
translation = measFramePosition(result.object; frameOrig=result.objectOrigin, frameCoord=result.objectCoordinateRef)
85+
velocity = measFrameTransVelocity(result.object; frameOrig=result.objectOrigin, frameCoord=result.objectCoordinateRef, frameObsrv=result.objectObserveRef)
86+
acceleration = measFrameTransAcceleration(result.object; frameOrig=result.objectOrigin, frameCoord=result.objectCoordinateRef, frameObsrv=result.objectObserveRef)
87+
rotationMatrix = measFrameRotation(result.object; frameOrig=result.objectOrigin)
88+
rotation = rot123fromR(rotationMatrix)
89+
angularVelocity = measFrameRotVelocity(result.object; frameOrig=result.objectOrigin, frameCoord=result.objectCoordinateRef)
90+
angularAcceleration = measFrameRotAcceleration(result.object; frameOrig=result.objectOrigin, frameCoord=result.objectCoordinateRef, frameObsrv=result.objectObserveRef)
91+
(distance, dir) = measFrameDistance(result.object; frameOrig=result.objectOrigin)
92+
distanceVelocity = measFrameDistVelocity(result.object; frameOrig=result.objectOrigin)
93+
distanceAcceleration = measFrameDistAcceleration(result.object; frameOrig=result.objectOrigin)
94+
95+
Modia.copy_w_segmented_value_to_result(model, result.translationResultIndex, translation)
96+
Modia.copy_w_segmented_value_to_result(model, result.velocityResultIndex, velocity)
97+
Modia.copy_w_segmented_value_to_result(model, result.accelerationResultIndex, acceleration)
98+
Modia.copy_w_segmented_value_to_result(model, result.rotationResultIndex, rotation)
99+
Modia.copy_w_segmented_value_to_result(model, result.angularVelocityResultIndex, angularVelocity)
100+
Modia.copy_w_segmented_value_to_result(model, result.angularAccelerationResultIndex, angularAcceleration)
101+
Modia.copy_w_segmented_value_to_result(model, result.distanceResultIndex, distance)
102+
Modia.copy_w_segmented_value_to_result(model, result.distanceVelocityResultIndex, distanceVelocity)
103+
Modia.copy_w_segmented_value_to_result(model, result.distanceAccelerationResultIndex, distanceAcceleration)
104+
105+
return nothing
106+
end
107+
108+
function terminateResultElement(result::SensorResult{F}) where F <: Modia3D.VarFloatType
109+
return nothing
110+
end

src/Composition/_module.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ include("scene.jl") # must be included after superObjects.jl
117117
include(joinpath("joints", "joints.jl"))
118118
include(joinpath("joints", "changeJointState.jl"))
119119

120+
include(joinpath("ResultElements", "SensorResult.jl"))
120121
include(joinpath("ResultElements", "ContactResult.jl"))
121122
include("sensors.jl")
122123
include("frameMeasurements.jl")

src/Composition/dynamics.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,8 +551,10 @@ function computeGeneralizedForces!(mbs::MultibodyData{F,TimeType}, qdd_hidden::V
551551
end
552552

553553
elseif leq_mode == -2
554-
# Compute only terms needed at a communication point (currently: Only visualization + export animation)
554+
# Compute only terms needed at a communication point (user-defined Object3D r/R_abs, result elements, visualization/animation export)
555555
TimerOutputs.@timeit instantiatedModel.timer "Modia3D_3" begin
556+
# Compute kinematics (yields absolute accelerations for result elements)
557+
TimerOutputs.@timeit instantiatedModel.timer "Modia3D_3 computePositionsVelocitiesAccelerations!" computePositionsVelocitiesAccelerations!(mbs, tree, time)
556558
# objects can have interactionManner
557559
if scene.options.useOptimizedStructure
558560
for obj in scene.pureResultObject3Ds

src/Composition/frameMeasurements.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ If `frameObsrv` is omitted `wd` is observed in world frame.
132132
function measFrameRotAcceleration(frameMeas::Object3D{F}; frameOrig::Union{Object3D{F}, Nothing}=nothing, frameCoord::Union{Object3D{F}, Nothing}=nothing, frameObsrv::Union{Object3D{F}, Nothing}=nothing) where F <: Modia3D.VarFloatType
133133
wd_OrigMeas = frameMeas.R_abs' * copy(frameMeas.z) # World_wd_WorldMeas := R_MeasWorld^T * Meas_wd_WorldMeas
134134
if !isnothing(frameOrig)
135-
wd_OrigMeas = wd_OrigMeas - (frame.Orig.R_abs' * frameOrig.z) # World_wd_OrigMeas := World_wd_WorldMeas - R_OrigWorld^T * Orig_wd_WorldOrig
135+
wd_OrigMeas = wd_OrigMeas - (frameOrig.R_abs' * frameOrig.z) # World_wd_OrigMeas := World_wd_WorldMeas - R_OrigWorld^T * Orig_wd_WorldOrig
136136
end
137137
if !isnothing(frameObsrv)
138138
w_OrigMeas = measFrameRotVelocity(frameMeas; frameOrig=frameOrig)

src/ModiaInterface/_module.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export Revolute, RevoluteWithFlange
1919
export Prismatic, PrismaticWithFlange
2020
export singularRem, FreeMotion, change_rotSequenceInNextIteration!
2121
export WorldForce, WorldTorque, Bushing, SpringDamperPtP, PolygonalContactModel
22-
export ContactResult
22+
export SensorResult, ContactResult
2323
export FreeMotion2
2424

2525
export ModelActions, ActionAttach, ActionRelease, ActionReleaseAndAttach, ActionDelete, EventAfterPeriod, ActionWait, ActionFlipChain

src/ModiaInterface/model3D.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ WorldTorque( ; kwargs...) = Par(; _constructor = :(Modia3D.Composition.
3030
Bushing( ; kwargs...) = Par(; _constructor = :(Modia3D.Composition.Bushing{FloatType}) , _path = true, kwargs...)
3131
SpringDamperPtP( ; kwargs...) = Par(; _constructor = :(Modia3D.Composition.SpringDamperPtP{FloatType}) , _path = true, kwargs...)
3232
PolygonalContactModel(; kwargs...) = Par(; _constructor = :(Modia3D.Composition.PolygonalContactModel{FloatType}), _path = true, kwargs...)
33+
SensorResult( ; kwargs...) = Par(; _constructor = :(Modia3D.Composition.SensorResult{FloatType}) , _path = true, kwargs...)
3334
ContactResult( ; kwargs...) = Par(; _constructor = :(Modia3D.Composition.ContactResult{FloatType}) , _path = true, kwargs...)
3435

3536
MassPropertiesFromShape() = Par(; _constructor = :(Modia3D.Shapes.MassPropertiesFromShape{FloatType}))

test/ForceElements/BoxBushing.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ BoxBushing = Model3D(
3030
visualMaterial=:(visualMaterial))),
3131
force = Bushing(obj1=:world, obj2=:box,
3232
springForceLaw=[fc, 100.0, 200.0], damperForceLaw=[1.0, fd, 4.0],
33-
rotSpringForceLaw=[5.0, 10.0, mc], rotDamperForceLaw=[0.1, md, 0.4], largeAngles=largeAngles)
33+
rotSpringForceLaw=[5.0, 10.0, mc], rotDamperForceLaw=[0.1, md, 0.4], largeAngles=largeAngles),
34+
result = SensorResult(object=:box)
3435
)
3536

3637
boxBushing = @instantiateModel(BoxBushing, unitless=true, logCode=true)
@@ -45,9 +46,10 @@ end
4546
simulate!(boxBushing, stopTime=stopTime, dtmax=dtmax, log=true, requiredFinalStates=requiredFinalStates)
4647

4748
@usingModiaPlot
48-
plot(boxBushing, ["box.translation", "box.velocity", "box.rotation", "box.angularVelocity"], figure=1)
49-
plot(boxBushing, ["force.translation", "force.velocity", "force.rotation", "force.rotationVelocity"], figure=2)
50-
plot(boxBushing, ["force.springForce", "force.damperForce", "force.forceVector"], figure=3)
51-
plot(boxBushing, ["force.springTorque", "force.damperTorque", "force.torque", "force.torqueVector"], figure=4)
49+
plot(boxBushing, ["result.translation", "result.velocity", "result.acceleration"], figure=1)
50+
plot(boxBushing, ["result.rotation", "result.angularVelocity", "result.angularAcceleration"], figure=2)
51+
plot(boxBushing, ["force.translation", "force.velocity", "force.rotation", "force.rotationVelocity"], figure=3)
52+
plot(boxBushing, ["force.springForce", "force.damperForce", "force.forceVector"], figure=4)
53+
plot(boxBushing, ["force.springTorque", "force.damperTorque", "force.torque", "force.torqueVector"], figure=5)
5254

5355
end

0 commit comments

Comments
 (0)