From 5cf6683bdb3feb2e8d8c1cc15d53ad6cabe25598 Mon Sep 17 00:00:00 2001 From: Jakub Tobolar Date: Wed, 3 Feb 2021 15:00:43 +0100 Subject: [PATCH 1/3] Add base class for constraints --- .../MultiBody/Interfaces/PartialConstraint.mo | 73 +++++++++++++++++++ .../MultiBody/Interfaces/package.order | 1 + 2 files changed, 74 insertions(+) create mode 100644 Modelica/Mechanics/MultiBody/Interfaces/PartialConstraint.mo diff --git a/Modelica/Mechanics/MultiBody/Interfaces/PartialConstraint.mo b/Modelica/Mechanics/MultiBody/Interfaces/PartialConstraint.mo new file mode 100644 index 0000000000..40e501ab13 --- /dev/null +++ b/Modelica/Mechanics/MultiBody/Interfaces/PartialConstraint.mo @@ -0,0 +1,73 @@ +within Modelica.Mechanics.MultiBody.Interfaces; +partial model PartialConstraint + "Base model for elementary constraints" + extends PartialTwoFrames; + + parameter Boolean x_locked=true + "= true, if constraint force in x-direction, resolved in frame_a" + annotation (Dialog(group="Constrain translational motion"), choices(checkBox=true)); + parameter Boolean y_locked=true + "= true, if constraint force in y-direction, resolved in frame_a" + annotation (Dialog(group="Constrain translational motion"), choices(checkBox=true)); + parameter Boolean z_locked=true + "= true, if constraint force in z-direction, resolved in frame_a" + annotation (Dialog(group="Constrain translational motion"), choices(checkBox=true)); + +protected + SI.Position r_rel_a[3] + "Position vector from origin of frame_a to origin of frame_b, resolved in frame_a"; + Frames.Orientation R_rel + "Relative orientation object from frame_a to frame_b"; + SI.InstantaneousPower P "Instantaneous power"; + +equation + // Determine relative position and orientation + r_rel_a = Frames.resolve2(frame_a.R, frame_b.r_0 - frame_a.r_0); + R_rel = Frames.relativeRotation(frame_a.R, frame_b.R); + + // Constraint equations concerning translations + if x_locked then + r_rel_a[1]=0; + else + frame_a.f[1]=0; + end if; + + if y_locked then + r_rel_a[2]=0; + else + frame_a.f[2]=0; + end if; + + if z_locked then + r_rel_a[3]=0; + else + frame_a.f[3]=0; + end if; + + // Force and torque balance + zeros(3) = frame_a.f + Frames.resolve1(R_rel, frame_b.f); + zeros(3) = frame_a.t + Frames.resolve1(R_rel, frame_b.t) - cross(r_rel_a, frame_a.f); + // - cross(r_rel_a, frame_a.f) gives the same result like cross(r_rel_a, Frames.resolve1(R_rel, frame_b.f)) + + // Instantaneous power + P = frame_a.t * Frames.angularVelocity2(frame_a.R) + + frame_b.t * Frames.angularVelocity2(frame_b.R) + + frame_a.f * Frames.resolve2(frame_a.R, der(frame_a.r_0)) + + frame_b.f * Frames.resolve2(frame_b.R, der(frame_b.r_0)); + + annotation (Documentation(info=" +

+All elementary joints defined by constraints should inherit +from this base model, i.e., joints that are directly defined by constraint +equations between the two frames. +

+

+This partial model provides relative kinematic quantities r_rel_a +and R_rel between the two frame connectors frame_a +and frame_b, and basic equations constraining translational movement. +The inheriting class shall additionally provide corresponding equations +constraining rotational movement. +

+ +")); +end PartialConstraint; diff --git a/Modelica/Mechanics/MultiBody/Interfaces/package.order b/Modelica/Mechanics/MultiBody/Interfaces/package.order index f90accb778..dcac74b4ba 100644 --- a/Modelica/Mechanics/MultiBody/Interfaces/package.order +++ b/Modelica/Mechanics/MultiBody/Interfaces/package.order @@ -8,6 +8,7 @@ PartialTwoFrames PartialTwoFramesDoubleSize PartialOneFrame_a PartialOneFrame_b +PartialConstraint PartialElementaryJoint PartialForce LineForceBase From 2a1bcbe7467a4487791853488b9275becabb756e Mon Sep 17 00:00:00 2001 From: Jakub Tobolar Date: Wed, 3 Feb 2021 15:03:51 +0100 Subject: [PATCH 2/3] Inherit from PartialConstraint --- .../MultiBody/Joints/Constraints/Prismatic.mo | 49 +------------- .../MultiBody/Joints/Constraints/Revolute.mo | 64 +++---------------- .../MultiBody/Joints/Constraints/Spherical.mo | 52 ++------------- .../MultiBody/Joints/Constraints/Universal.mo | 54 ++-------------- 4 files changed, 21 insertions(+), 198 deletions(-) diff --git a/Modelica/Mechanics/MultiBody/Joints/Constraints/Prismatic.mo b/Modelica/Mechanics/MultiBody/Joints/Constraints/Prismatic.mo index 3092c9e80d..ef1f30b2b8 100644 --- a/Modelica/Mechanics/MultiBody/Joints/Constraints/Prismatic.mo +++ b/Modelica/Mechanics/MultiBody/Joints/Constraints/Prismatic.mo @@ -1,17 +1,7 @@ within Modelica.Mechanics.MultiBody.Joints.Constraints; model Prismatic "Prismatic cut-joint and translational directions may be constrained or released" - extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames; - - parameter Boolean x_locked=true - "= true: constraint force in x-direction, resolved in frame_a" - annotation (Dialog(group="Constraints"),choices(checkBox=true)); - parameter Boolean y_locked=true - "= true: constraint force in y-direction, resolved in frame_a" - annotation (Dialog(group="Constraints"),choices(checkBox=true)); - parameter Boolean z_locked=true - "= true: constraint force in z-direction, resolved in frame_a" - annotation (Dialog(group="Constraints"),choices(checkBox=true)); + extends Modelica.Mechanics.MultiBody.Interfaces.PartialConstraint; parameter Boolean animation=true "= true, if animation shall be enabled (show sphere)"; @@ -25,13 +15,6 @@ model Prismatic "Reflection of ambient light (= 0: light is completely absorbed)" annotation (Dialog(group="if animation = true", enable=animation)); -protected - Frames.Orientation R_rel - "Dummy or relative orientation object from frame_a to frame_b"; - SI.Position r_rel_a[3] - "Position vector from origin of frame_a to origin of frame_b, resolved in frame_a"; - SI.InstantaneousPower P; - public Visualizers.Advanced.Shape sphere( shapeType="sphere", @@ -46,40 +29,10 @@ public r=frame_a.r_0, R=frame_a.R) if world.enableAnimation and animation; equation - // Determine relative position vector resolved in frame_a - R_rel = Frames.relativeRotation(frame_a.R, frame_b.R); - r_rel_a = Frames.resolve2(frame_a.R, frame_b.r_0 - frame_a.r_0); - // Constraint equations concerning rotations // Same logic as for overdetermined connection graph loops to get good residuals. zeros(3)=Modelica.Mechanics.MultiBody.Frames.Orientation.equalityConstraint(frame_a.R, frame_b.R); - // Constraint equations concerning translations - if x_locked then - r_rel_a[1]=0; - else - frame_a.f[1]=0; - end if; - - if y_locked then - r_rel_a[2]=0; - else - frame_a.f[2]=0; - end if; - - if z_locked then - r_rel_a[3]=0; - else - frame_a.f[3]=0; - end if; - - zeros(3) = frame_a.t + Frames.resolve1(R_rel, frame_b.t) + cross(r_rel_a, - Frames.resolve1(R_rel, frame_b.f)); - zeros(3) = Frames.resolve1(R_rel, frame_b.f) + frame_a.f; - P = frame_a.t*Frames.angularVelocity2(frame_a.R) + frame_b.t* - Frames.angularVelocity2(frame_b.R) + frame_b.f*Frames.resolve2(frame_b.R, - der(frame_b.r_0)) + frame_a.f*Frames.resolve2(frame_a.R, der(frame_a.r_0)); - annotation ( defaultComponentName="constraint", Icon(coordinateSystem( diff --git a/Modelica/Mechanics/MultiBody/Joints/Constraints/Revolute.mo b/Modelica/Mechanics/MultiBody/Joints/Constraints/Revolute.mo index cc3bad276a..5b9f929126 100644 --- a/Modelica/Mechanics/MultiBody/Joints/Constraints/Revolute.mo +++ b/Modelica/Mechanics/MultiBody/Joints/Constraints/Revolute.mo @@ -1,17 +1,7 @@ within Modelica.Mechanics.MultiBody.Joints.Constraints; model Revolute "Revolute cut-joint and translational directions may be constrained or released" - extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames; - - parameter Boolean x_locked=true - "= true: constraint force in x-direction, resolved in frame_a" - annotation (Dialog(group="Constraints in translational motion"),choices(checkBox=true)); - parameter Boolean y_locked=true - "= true: constraint force in y-direction, resolved in frame_a" - annotation (Dialog(group="Constraints in translational motion"),choices(checkBox=true)); - parameter Boolean z_locked=true - "= true: constraint force in z-direction, resolved in frame_a" - annotation (Dialog(group="Constraints in translational motion"),choices(checkBox=true)); + extends Modelica.Mechanics.MultiBody.Interfaces.PartialConstraint; parameter Boolean animation=true "= true, if animation shall be enabled (show sphere)"; @@ -30,21 +20,15 @@ model Revolute annotation (Dialog(group="if animation = true", enable=animation)); protected - Frames.Orientation R_rel - "Dummy or relative orientation object from frame_a to frame_b"; - SI.Position r_rel_a[3] - "Position vector from origin of frame_a to origin of frame_b, resolved in frame_a"; - SI.InstantaneousPower P; - parameter Real e[3](each final unit="1")=Modelica.Math.Vectors.normalizeWithAssert( - n) + parameter Real e[3](each final unit="1")=Modelica.Math.Vectors.normalizeWithAssert(n) "Unit vector in direction of rotation axis, resolved in frame_a (= same as in frame_b)"; - parameter Real nnx_a[3](each final unit="1")=if abs(e[1]) > 0.1 then {0,1,0} else (if abs(e[2]) - > 0.1 then {0,0,1} else {1,0,0}) + parameter Real nnx_a[3](each final unit="1")= + if abs(e[1]) > 0.1 then {0,1,0} else (if abs(e[2]) > 0.1 then {0,0,1} else {1,0,0}) "Arbitrary vector that is not aligned with rotation axis n" annotation (Evaluate=true); - parameter Real ey_a[3](each final unit="1")=Modelica.Math.Vectors.normalizeWithAssert( - cross(e, nnx_a)) + parameter Real ey_a[3](each final unit="1")= + Modelica.Math.Vectors.normalizeWithAssert(cross(e, nnx_a)) "Unit vector orthogonal to axis n of revolute joint, resolved in frame_a" annotation (Evaluate=true); parameter Real ex_a[3](each final unit="1")=cross(ey_a, e) @@ -65,43 +49,13 @@ public R=frame_a.R) if world.enableAnimation and animation; equation - // Determine relative position vector resolved in frame_a - R_rel = Frames.relativeRotation(frame_a.R, frame_b.R); - r_rel_a = Frames.resolve2(frame_a.R, frame_b.r_0 - frame_a.r_0); - - // Constraint equations concerning translations - if x_locked then - r_rel_a[1]=0; - else - frame_a.f[1]=0; - end if; - - if y_locked then - r_rel_a[2]=0; - else - frame_a.f[2]=0; - end if; - - if z_locked then - r_rel_a[3]=0; - else - frame_a.f[3]=0; - end if; - // Constraint equations concerning rotations 0 = ex_a*R_rel.T*e; 0 = ey_a*R_rel.T*e; frame_a.t*n=0; - zeros(3) = frame_a.f + Frames.resolve1(R_rel, frame_b.f); - zeros(3) = frame_a.t + Frames.resolve1(R_rel, frame_b.t) - cross(r_rel_a, - frame_a.f); - P = frame_a.t*Frames.angularVelocity2(frame_a.R) + frame_b.t* - Frames.angularVelocity2(frame_b.R) + Frames.resolve1(frame_b.R, frame_b.f) - *der(frame_b.r_0) + Frames.resolve1(frame_a.R, frame_a.f)*der(frame_a.r_0); - - annotation ( defaultComponentName="constraint", - Icon(coordinateSystem( + annotation ( defaultComponentName="constraint", + Icon(coordinateSystem( preserveAspectRatio=true, extent={{-100,-100},{100,100}}), graphics={ Text( @@ -137,7 +91,7 @@ equation extent={{-150,110},{150,70}}, textColor={0,0,255}, textString="%name")}), - Documentation(info=" + Documentation(info="

This model does not use explicit variables e.g. state variables in order to describe the relative motion of frame_b with respect to frame_a, but defines kinematic constraints between the frame_a and frame_b. The forces and torques at both frames are then evaluated in such a way that the constraints are satisfied. Sometimes this type of formulation is also called an implicit joint in literature.

As a consequence of the formulation the relative kinematics between frame_a and frame_b cannot be initialized.

In particular in complex multibody systems with closed loops this may help to simplify the system of non-linear equations. Please compare the translation log using the classical joint formulation and the alternative formulation used here in order to check whether this fact applies to the particular system under consideration.

diff --git a/Modelica/Mechanics/MultiBody/Joints/Constraints/Spherical.mo b/Modelica/Mechanics/MultiBody/Joints/Constraints/Spherical.mo index 83e7b39270..e8f3309e8f 100644 --- a/Modelica/Mechanics/MultiBody/Joints/Constraints/Spherical.mo +++ b/Modelica/Mechanics/MultiBody/Joints/Constraints/Spherical.mo @@ -1,18 +1,7 @@ within Modelica.Mechanics.MultiBody.Joints.Constraints; model Spherical "Spherical cut joint and translational directions may be constrained or released" - extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames; - import MBS = Modelica.Mechanics.MultiBody; - - parameter Boolean x_locked=true - "= true: constraint force in x-direction, resolved in frame_a" - annotation (Dialog(group="Constraints"), choices(checkBox=true)); - parameter Boolean y_locked=true - "= true: constraint force in y-direction, resolved in frame_a" - annotation (Dialog(group="Constraints"), choices(checkBox=true)); - parameter Boolean z_locked=true - "= true: constraint force in z-direction, resolved in frame_a" - annotation (Dialog(group="Constraints"), choices(checkBox=true)); + extends Modelica.Mechanics.MultiBody.Interfaces.PartialConstraint; parameter Boolean animation=true "= true, if animation shall be enabled (show sphere)" @@ -20,10 +9,10 @@ model Spherical parameter SI.Distance sphereDiameter=world.defaultJointLength /3 "Diameter of sphere representing the spherical joint" annotation (Dialog(group="Animation", enable=animation)); - input MBS.Types.Color sphereColor=MBS.Types.Defaults.JointColor + input Types.Color sphereColor=Types.Defaults.JointColor "Color of sphere representing the spherical joint" annotation (Dialog(colorSelector=true, group="Animation", enable=animation)); - input MBS.Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient + input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient "Reflection of ambient light (= 0: light is completely absorbed)" annotation (Dialog(group="Animation", enable=animation)); @@ -39,42 +28,11 @@ model Spherical r_shape={-0.5,0,0}*sphereDiameter, r=frame_a.r_0, R=frame_a.R) if world.enableAnimation and animation; -protected - MBS.Frames.Orientation R_rel - "Dummy or relative orientation object from frame_a to frame_b"; - SI.Position r_rel_a[3] - "Position vector from origin of frame_a to origin of frame_b, resolved in frame_a"; - SI.InstantaneousPower P; equation - // Determine relative position vector resolved in frame_a - R_rel = MBS.Frames.relativeRotation(frame_a.R, frame_b.R); - r_rel_a = MBS.Frames.resolve2(frame_a.R, frame_b.r_0 - frame_a.r_0); - - // Constraint equations concerning translation - if x_locked then - r_rel_a[1]=0; - else - frame_a.f[1]=0; - end if; - - if y_locked then - r_rel_a[2]=0; - else - frame_a.f[2]=0; - end if; - - if z_locked then - r_rel_a[3]=0; - else - frame_a.f[3]=0; - end if; - //frame_a.t = zeros(3); frame_b.t = zeros(3); - frame_b.f = -MBS.Frames.resolve2(R_rel, frame_a.f); - zeros(3) = frame_a.t + MBS.Frames.resolve1(R_rel, frame_b.t) - cross(r_rel_a, frame_a.f); - P= frame_a.t*MBS.Frames.angularVelocity2(frame_a.R)+frame_b.t*MBS.Frames.angularVelocity2(frame_b.R) + MBS.Frames.resolve1(frame_b.R,frame_b.f)*der(frame_b.r_0)+MBS.Frames.resolve1(frame_a.R,frame_a.f)*der(frame_a.r_0); + annotation ( defaultComponentName="constraint", Icon(coordinateSystem( @@ -155,7 +113,7 @@ equation textColor={0,0,255}, textString="%name")}), Documentation(info=" -

This model does not use explicit variables e.g. state variables in order to describe the relative motion of frame_b with to respect to frame_a, but defines kinematic constraints between the frame_a and frame_b. The forces and torques at both frames are then evaluated in such a way that the constraints are satisfied. Sometimes this type of formulation is also called an implicit joint in literature.

+

This model does not use explicit variables e.g. state variables in order to describe the relative motion of frame_b with respect to frame_a, but defines kinematic constraints between the frame_a and frame_b. The forces and torques at both frames are then evaluated in such a way that the constraints are satisfied. Sometimes this type of formulation is also called an implicit joint in literature.

As a consequence of the formulation the relative kinematics between frame_a and frame_b cannot be initialized.

In particular in complex multibody systems with closed loops this may help to simplify the system of non-linear equations. Please compare the translation log using the classical joint formulation and the alternative formulation used here in order to check whether this fact applies to the particular system under consideration.

In systems without closed loops the use of this implicit joint does not make sense or may even be disadvantageous.

diff --git a/Modelica/Mechanics/MultiBody/Joints/Constraints/Universal.mo b/Modelica/Mechanics/MultiBody/Joints/Constraints/Universal.mo index 9dce558fb0..d94762d634 100644 --- a/Modelica/Mechanics/MultiBody/Joints/Constraints/Universal.mo +++ b/Modelica/Mechanics/MultiBody/Joints/Constraints/Universal.mo @@ -1,68 +1,30 @@ within Modelica.Mechanics.MultiBody.Joints.Constraints; model Universal "Universal cut-joint and translational directions may be constrained or released" - extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames; - import MBS = Modelica.Mechanics.MultiBody; + extends Modelica.Mechanics.MultiBody.Interfaces.PartialConstraint; - parameter MBS.Types.Axis n_a={1,0,0} + parameter Types.Axis n_a={1,0,0} "Axis of revolute joint 1 resolved in frame_a" annotation (Evaluate=true); - parameter MBS.Types.Axis n_b={0,1,0} + parameter Types.Axis n_b={0,1,0} "Axis of revolute joint 2 resolved in frame_b" annotation (Evaluate=true); - parameter Boolean x_locked=true - "= true: constraint force in x-direction, resolved in frame_a" - annotation (Dialog(group="Constraints in translational motion"), choices(checkBox=true)); - parameter Boolean y_locked=true - "= true: constraint force in y-direction, resolved in frame_a" - annotation (Dialog(group="Constraints in translational motion"), choices(checkBox=true)); - parameter Boolean z_locked=true - "= true: constraint force in z-direction, resolved in frame_a" - annotation (Dialog(group="Constraints in translational motion"), choices(checkBox=true)); - parameter Boolean animation=true "= true, if animation shall be enabled (show sphere)" annotation (Dialog(group="Animation")); parameter SI.Distance sphereDiameter=world.defaultJointLength /3 "Diameter of sphere representing the spherical joint" annotation (Dialog(group="Animation", enable=animation)); - input MBS.Types.Color sphereColor=MBS.Types.Defaults.JointColor + input Types.Color sphereColor=Types.Defaults.JointColor "Color of sphere representing the spherical joint" annotation (Dialog(colorSelector=true, group="Animation", enable=animation)); - input MBS.Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient + input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient "Reflection of ambient light (= 0: light is completely absorbed)" annotation (Dialog(group="Animation", enable=animation)); protected - MBS.Frames.Orientation R_rel - "Dummy or relative orientation object from frame_a to frame_b"; Real w_rel[3]; - SI.Position r_rel_a[3] - "Position vector from origin of frame_a to origin of frame_b, resolved in frame_a"; - SI.InstantaneousPower P; equation - // Determine relative position vector resolved in frame_a - R_rel = MBS.Frames.relativeRotation(frame_a.R, frame_b.R); - w_rel = MBS.Frames.angularVelocity1(R_rel); - r_rel_a = MBS.Frames.resolve2(frame_a.R, frame_b.r_0 - frame_a.r_0); - - // Constraint equations concerning translations - if x_locked then - r_rel_a[1]=0; - else - frame_a.f[1]=0; - end if; - - if y_locked then - r_rel_a[2]=0; - else - frame_a.f[2]=0; - end if; - - if z_locked then - r_rel_a[3]=0; - else - frame_a.f[3]=0; - end if; + w_rel = Frames.angularVelocity1(R_rel); // Constraint equations concerning rotations frame_a.t*n_a=0; @@ -70,10 +32,6 @@ equation n_b*R_rel.T*n_a=0; assert(abs(n_a*n_b) < Modelica.Constants.eps, "The two axes that constitute the Constraints.Universal joint must be different"); - zeros(3)=frame_a.f + MBS.Frames.resolve1(R_rel, frame_b.f); - zeros(3) = frame_a.t+MBS.Frames.resolve1(R_rel, frame_b.t)- cross(r_rel_a, frame_a.f); - P = frame_a.t*MBS.Frames.angularVelocity2(frame_a.R)+frame_b.t*MBS.Frames.angularVelocity2(frame_b.R) + MBS.Frames.resolve1(frame_b.R,frame_b.f)*der(frame_b.r_0)+MBS.Frames.resolve1(frame_a.R,frame_a.f)*der(frame_a.r_0); - annotation ( defaultComponentName="constraint", Icon(coordinateSystem( From 38ec62b20cbc893c16e7e3db242b7e5e9fd64c7e Mon Sep 17 00:00:00 2001 From: tobolar Date: Wed, 3 Feb 2021 15:51:42 +0100 Subject: [PATCH 3/3] Use frame transformation function for constraint --- .../Mechanics/MultiBody/Joints/Constraints/Universal.mo | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modelica/Mechanics/MultiBody/Joints/Constraints/Universal.mo b/Modelica/Mechanics/MultiBody/Joints/Constraints/Universal.mo index d94762d634..829a213a22 100644 --- a/Modelica/Mechanics/MultiBody/Joints/Constraints/Universal.mo +++ b/Modelica/Mechanics/MultiBody/Joints/Constraints/Universal.mo @@ -27,9 +27,9 @@ equation w_rel = Frames.angularVelocity1(R_rel); // Constraint equations concerning rotations - frame_a.t*n_a=0; - frame_b.t*n_b=0; - n_b*R_rel.T*n_a=0; + frame_a.t * n_a = 0; + frame_b.t * n_b = 0; + n_b * Frames.resolve2(R_rel, n_a) = 0; // Constraint: R_rel shall assure orthogonality of n_a and n_b assert(abs(n_a*n_b) < Modelica.Constants.eps, "The two axes that constitute the Constraints.Universal joint must be different"); annotation (