Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve inheritance of MultiBody constraints #4227

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions Modelica/Mechanics/MultiBody/Interfaces/PartialConstraint.mo
Original file line number Diff line number Diff line change
@@ -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="<html>
<p>
All <strong>elementary joints defined by constraints</strong> should inherit
from this base model, i.e., joints that are directly defined by constraint
equations between the two frames.
</p>
<p>
This partial model provides relative kinematic quantities <code>r_rel_a</code>
and <code>R_rel</code> between the two frame connectors <code>frame_a</code>
and <code>frame_b</code>, and basic equations constraining translational movement.
The inheriting class shall additionally provide corresponding equations
constraining rotational movement.
</p>
</html>
"));
end PartialConstraint;
1 change: 1 addition & 0 deletions Modelica/Mechanics/MultiBody/Interfaces/package.order
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ PartialTwoFrames
PartialTwoFramesDoubleSize
PartialOneFrame_a
PartialOneFrame_b
PartialConstraint
PartialElementaryJoint
PartialForce
LineForceBase
Expand Down
49 changes: 1 addition & 48 deletions Modelica/Mechanics/MultiBody/Joints/Constraints/Prismatic.mo
Original file line number Diff line number Diff line change
@@ -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)";
Expand All @@ -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",
Expand All @@ -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(
Expand Down
64 changes: 9 additions & 55 deletions Modelica/Mechanics/MultiBody/Joints/Constraints/Revolute.mo
Original file line number Diff line number Diff line change
@@ -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)";
Expand All @@ -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)
Expand All @@ -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(
Expand Down Expand Up @@ -137,7 +91,7 @@ equation
extent={{-150,110},{150,70}},
textColor={0,0,255},
textString="%name")}),
Documentation(info="<html>
Documentation(info="<html>
<p>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.</p>
<p>As a consequence of the formulation the relative kinematics between frame_a and frame_b cannot be initialized.</p>
<p>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.</p>
Expand Down
52 changes: 5 additions & 47 deletions Modelica/Mechanics/MultiBody/Joints/Constraints/Spherical.mo
Original file line number Diff line number Diff line change
@@ -1,29 +1,18 @@
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)"
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));

Expand All @@ -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(
Expand Down Expand Up @@ -155,7 +113,7 @@ equation
textColor={0,0,255},
textString="%name")}),
Documentation(info="<html>
<p>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.</p>
<p>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.</p>
<p>As a consequence of the formulation the relative kinematics between frame_a and frame_b cannot be initialized.</p>
<p>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.</p>
<p>In systems without closed loops the use of this implicit joint does not make sense or may even be disadvantageous.</p>
Expand Down
Loading