Measure the distance between the origins of two frame connectors. The distance between the origins of frame_a
and of frame_b are determined and provided at the
output signal connector distance. This
distance is always positive. Derivatives of this
signal can be easily obtained by connecting the
block
Modelica.Blocks.Continuous.Der
to \"distance\" (this block performs analytic differentiation
of the input signal using the der(…) operator).

within Modelica.Mechanics.MultiBody.Sensors;
model Distance
  "Measure the distance between the origins of two frame connectors"

  import Modelica.Mechanics.MultiBody.Frames;
  import Modelica.Mechanics.MultiBody.Types;

  extends Interfaces.PartialTwoFrames;
  extends Modelica.Icons.RectangularSensor;
  Modelica.Blocks.Interfaces.RealOutput distance
    "Distance between the origin of frame_a and the origin of frame_b"

  parameter Boolean animation=true
    "= true, if animation shall be enabled (show arrow)";
  input Types.Color arrowColor=Modelica.Mechanics.MultiBody.Types.Defaults.SensorColor
    "Color of relative arrow from frame_a to frame_b"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  input SI.Position s_small(min=sqrt(Modelica.Constants.small))=1e-10
    "Prevent zero-division if distance between frame_a and frame_b is zero"
protected
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Vector arrow(
    r=frame_a.r_0,
    coordinates=frame_b.r_0 - frame_a.r_0,
    quantity=Types.VectorQuantity.RelativePosition,
    color=arrowColor,
    specularCoefficient=specularCoefficient) if world.enableAnimation and animation;

protected
  SI.Position r_rel_0[3] = frame_b.r_0 - frame_a.r_0
    "Position vector from frame_a to frame_b resolved in world frame";
  SI.Area L2 = r_rel_0*r_rel_0;
  SI.Area s_small2 = s_small^2;
equation
  frame_a.f = zeros(3);
  frame_b.f = zeros(3);
  frame_a.t = zeros(3);
  frame_b.t = zeros(3);

  distance =  smooth(1,if noEvent(L2 > s_small2) then sqrt(L2) else L2/(2*s_small)*(3-L2/s_small2));
end Distance;


Sensors to measure variables

within Modelica.Mechanics.MultiBody;
package Sensors "Sensors to measure variables"
  extends Modelica.Icons.SensorsPackage;
end Sensors;


Measure power flowing from frame_a to frame_b. This component provides the power flowing from frame_a to frame_b
as output signal power.

within Modelica.Mechanics.MultiBody.Sensors;
model Power "Measure power flowing from frame_a to frame_b"
  extends Modelica.Icons.RoundSensor;

  extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames;
  Modelica.Blocks.Interfaces.RealOutput power(quantity="Power",unit="W")
    "Power at frame_a as output signal"

equation
  Connections.branch(frame_a.R, frame_b.R);
  frame_a.r_0 = frame_b.r_0;
  frame_a.R = frame_b.R;
  zeros(3) = frame_a.f + frame_b.f;
  zeros(3) = frame_a.t + frame_b.t;
  power = frame_a.f*Frames.resolve2(frame_a.R, der(frame_a.r_0))
     + frame_a.t*Frames.angularVelocity2(frame_a.R);
end Power;


Measure relative angles between two frame connectors. This model determines the 3 angles to rotate frame_a
into frame_b along the axes defined by parameter sequence.
For example, if sequence = {3,1,2} then frame_a is
rotated around angles[1] along the z-axis, afterwards it is rotated
around angles[2] along the x-axis, and finally it is rotated around
angles[3] along the y-axis and is then identical to frame_b.
The 3 angles are returned in the range

within Modelica.Mechanics.MultiBody.Sensors;
model RelativeAngles "Measure relative angles between two frame connectors"
  extends Internal.PartialRelativeSensor
  extends Modelica.Icons.RoundSensor;

  Modelica.Blocks.Interfaces.RealOutput angles[3](
    each final quantity="Angle",
    each final unit="rad",
    each displayUnit="deg")
    "Angles to rotate frame_a into frame_b via 'sequence'"
  parameter MultiBody.Types.RotationSequence sequence(
    min={1,1,1},
    max={3,3,3})={1,2,3}
    "Angles are returned to rotate frame_a around axes sequence[1], sequence[2] and finally sequence[3] into frame_b"
  parameter SI.Angle guessAngle1=0
    "Select angles[1] such that abs(angles[1] - guessAngle1) is a minimum";
  Modelica.Mechanics.MultiBody.Frames.Orientation R_rel
    "Relative orientation object from frame_a to frame_b";

equation
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
  frame_b.f = zeros(3);
  frame_b.t = zeros(3);
  R_rel = Modelica.Mechanics.MultiBody.Frames.relativeRotation(frame_a.R, frame_b.R);
  angles = MultiBody.Frames.axesRotationsAngles(
    R_rel,
    sequence,
    guessAngle1);
end RelativeAngles;


Measure relative angular velocity between two frame connectors. The relative angular velocity between frame_a and frame_b is
determined and provided at the output signal connector w_rel.

within Modelica.Mechanics.MultiBody.Sensors;
model RelativeAngularVelocity
  "Measure relative angular velocity between two frame connectors"
  extends Internal.PartialRelativeSensor;

  Blocks.Interfaces.RealOutput w_rel[3](
    each final quantity="AngularVelocity",
    each final unit = "rad/s")
    "Relative angular velocity vector between frame_a and frame_b resolved in frame defined by resolveInFrame"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve if resolveInFrame ==
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve
    "Coordinate system in which w_rel is optionally resolved"

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_a
    "Frame in which output vector w_rel shall be resolved (world, frame_a, frame_b, or frame_resolve)";

protected
  Internal.BasicRelativeAngularVelocity relativeAngularVelocity(
    resolveInFrame=resolveInFrame)
  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition if
    not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve)

equation
  connect(relativeAngularVelocity.frame_a, frame_a)
  connect(relativeAngularVelocity.frame_b, frame_b)
  connect(relativeAngularVelocity.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, relativeAngularVelocity.frame_resolve)
  connect(relativeAngularVelocity.w_rel, w_rel)

// Angular velocity resolved in frame_a
w_rel = MultiBody.Frames.angularVelocity1(R_rel);
</pre></blockquote>
</html>"));
end RelativeAngularVelocity;


Measure relative position vector between the origins of two frame connectors. The relative position vector between the origins of frame_a and frame_b are
determined and provided at the output signal connector r_rel.

within Modelica.Mechanics.MultiBody.Sensors;
model RelativePosition
  "Measure relative position vector between the origins of two frame connectors"
  extends Internal.PartialRelativeSensor;

  Blocks.Interfaces.RealOutput r_rel[3](
    each final quantity="Length",
    each final unit="m")
    "Relative position vector resolved in frame defined by resolveInFrame"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve if resolveInFrame ==
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve
    "Coordinate system in which r_rel is optionally resolved"

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_a
    "Frame in which output vector r_rel shall be resolved (world, frame_a, frame_b, or frame_resolve)";

protected
  Internal.BasicRelativePosition relativePosition(resolveInFrame=resolveInFrame)

  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition if
    not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve)

equation
  connect(relativePosition.frame_a, frame_a)
  connect(relativePosition.frame_b, frame_b)
  connect(relativePosition.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, relativePosition.frame_resolve)
  connect(relativePosition.r_rel, r_rel)
</pre></blockquote>
</html>"));
end RelativePosition;


Measure relative kinematic quantities between two frame connectors. Relative kinematic quantities between frame_a and frame_b are
determined and provided at the conditional output signal connectors.
For example, if parameter \"get_r_rel = true\", the connector
\"r_rel\" is enabled and contains the relative vector from
frame_a to frame_b. The following quantities can be provided
as output signals:

within Modelica.Mechanics.MultiBody.Sensors;
model RelativeSensor
  "Measure relative kinematic quantities between two frame connectors"

  extends Modelica.Mechanics.MultiBody.Sensors.Internal.PartialRelativeSensor;

  Interfaces.Frame_resolve frame_resolve if
        resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve or
        resolveInFrameAfterDifferentiation == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve
    "If resolveInFrame = Types.ResolveInFrameAB.frame_resolve, the output signals are resolved in this frame"

  parameter Boolean animation=true
    "= true, if animation shall be enabled (show arrow)";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB
    resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_a
    "Frame in which vectors are resolved before differentiation (world, frame_a, frame_b, or frame_resolve)";
  parameter Boolean get_r_rel=false
    "= true, to measure the relative position vector from the origin of frame_a to frame_b"
  parameter Boolean get_v_rel=false
    "= true, to measure the relative velocity of the origin of frame_b with respect to frame_a"
  parameter Boolean get_a_rel=false
    "= true, to measure the relative acceleration of the origin of frame_b with respect to frame_a"
  parameter Boolean get_w_rel=false
    "= true, to measure the relative angular velocity of frame_b with respect to frame_a"
  parameter Boolean get_z_rel=false
    "= true, to measure the relative angular acceleration of frame_b with respect to frame_a"
  parameter Boolean get_angles=false
    "= true, to measure the 3 rotation angles"
  parameter Types.RotationSequence sequence(
    min={1,1,1},
    max={3,3,3}) = {1,2,3}
    "If get_angles=true: Angles are returned to rotate frame_a around axes sequence[1], sequence[2] and finally sequence[3] into frame_b"
  parameter SI.Angle guessAngle1=0
    "If get_angles=true: Select angles[1] such that abs(angles[1] - guessAngle1) is a minimum"

  input Types.Color arrowColor=Modelica.Mechanics.MultiBody.Types.Defaults.SensorColor
    "Color of relative arrow from frame_a to frame_b"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB
    resolveInFrameAfterDifferentiation = resolveInFrame
    "Frame in which vectors are resolved after differentiation (world, frame_a, frame_b, or frame_resolve)"

  Blocks.Interfaces.RealOutput r_rel[3](each final quantity="Length", each final
            unit="m") if get_r_rel
    "Relative position vector frame_b.r_0 - frame_a.r_0 resolved in frame defined by resolveInFrame"
  Blocks.Interfaces.RealOutput v_rel[3](each final quantity="Velocity", each final
            unit="m/s") if get_v_rel "Relative velocity vector"
  Blocks.Interfaces.RealOutput a_rel[3](each final quantity="Acceleration",
      each final unit="m/s2") if get_a_rel "Relative acceleration vector"
  Blocks.Interfaces.RealOutput angles[3](
    each final quantity="Angle",
    each final unit="rad",
    each displayUnit="deg") if get_angles
    "Angles to rotate frame_a into frame_b via 'sequence'"
  Blocks.Interfaces.RealOutput w_rel[3](each final quantity="AngularVelocity",
      each final unit="rad/s") if get_w_rel "Relative angular velocity vector"
  Blocks.Interfaces.RealOutput z_rel[3](each final quantity="AngularAcceleration",
      each final unit="rad/s2") if get_z_rel
    "Relative angular acceleration vector"

protected
  RelativePosition relativePosition(resolveInFrame=resolveInFrame)
    if get_r_rel or get_v_rel or get_a_rel

protected
  Blocks.Continuous.Der der1[3] if get_v_rel or get_a_rel
  Blocks.Continuous.Der der2[3] if get_a_rel
  Modelica.Mechanics.MultiBody.Sensors.RelativeAngles relativeAngles(sequence=sequence, guessAngle1=guessAngle1) if get_angles
  RelativeAngularVelocity relativeAngularVelocity(resolveInFrame=resolveInFrame) if get_w_rel or get_z_rel

protected
  Blocks.Continuous.Der der3[3] if get_z_rel
  Modelica.Mechanics.MultiBody.Forces.Internal.ZeroForceAndTorque zeroForce1
  Modelica.Mechanics.MultiBody.Forces.Internal.ZeroForceAndTorque zeroForce2
  Modelica.Mechanics.MultiBody.Forces.Internal.ZeroForceAndTorque zeroForce3 if resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve

protected
  Modelica.Mechanics.MultiBody.Sensors.TransformRelativeVector transformVector_v_rel(frame_r_in=resolveInFrame, frame_r_out=resolveInFrameAfterDifferentiation) if get_v_rel
  Modelica.Mechanics.MultiBody.Sensors.TransformRelativeVector transformVector_a_rel(frame_r_in=resolveInFrame, frame_r_out=resolveInFrameAfterDifferentiation) if get_a_rel
  Modelica.Mechanics.MultiBody.Sensors.TransformRelativeVector transformVector_z_rel(frame_r_in=resolveInFrame, frame_r_out=resolveInFrameAfterDifferentiation) if get_z_rel

protected
  outer Modelica.Mechanics.MultiBody.World world;

  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Vector arrow(
    r=frame_a.r_0,
    coordinates=frame_b.r_0 - frame_a.r_0,
    quantity=Types.VectorQuantity.RelativePosition,
    color=arrowColor,
    specularCoefficient=specularCoefficient) if world.enableAnimation and animation;
equation
  connect(relativePosition.frame_a, frame_a)
  connect(relativePosition.frame_b, frame_b)
  connect(relativePosition.r_rel, r_rel)
  connect(zeroForce1.frame_a, frame_a)
  connect(zeroForce2.frame_a, frame_b)
  connect(relativePosition.r_rel, der1.u)
  connect(der2.u, der1.y)
  connect(relativeAngles.frame_a, frame_a)
  connect(relativeAngles.frame_b, frame_b)
  connect(relativeAngles.angles, angles)
  connect(relativeAngularVelocity.frame_b, frame_b)
  connect(relativeAngularVelocity.frame_a, frame_a)
  connect(relativeAngularVelocity.w_rel, w_rel)
  connect(relativeAngularVelocity.w_rel, der3.u)
  connect(der1.y, transformVector_v_rel.r_in)
  connect(transformVector_v_rel.r_out, v_rel)
  connect(transformVector_v_rel.frame_a, frame_a)
  connect(transformVector_v_rel.frame_b, frame_b)
  connect(transformVector_v_rel.frame_resolve, frame_resolve)
  connect(frame_resolve, relativePosition.frame_resolve)
  connect(frame_resolve, zeroForce3.frame_a)
  connect(relativeAngularVelocity.frame_resolve, frame_resolve)
  connect(der2.y, transformVector_a_rel.r_in)
  connect(transformVector_a_rel.frame_a, frame_a)
  connect(transformVector_a_rel.frame_b, frame_b)
  connect(transformVector_a_rel.frame_resolve, frame_resolve)
  connect(transformVector_a_rel.r_out, a_rel)
  connect(der3.y, transformVector_z_rel.r_in)
  connect(transformVector_z_rel.r_out, z_rel)
  connect(transformVector_z_rel.frame_a, frame_a)
  connect(transformVector_z_rel.frame_b, frame_b)
  connect(transformVector_z_rel.frame_resolve, frame_resolve)
v_rel = der(r_rel);

is returned (r_rel = resolve2(frame_b.R, frame_b.r_0 - frame_a.r0)), i.e.,
the derivative of the relative distance from frame_a to frame_b,
resolved in frame_b. If
resolveInFrameAfterDifferentiation = Types.ResolveInFrameAB.world, then
v_rel is additionally transformed to:

v_rel = resolve1(frame_b.R, der(r_rel))

The cut-force and the cut-torque in frame_resolve are
always zero, whether frame_resolve is connected or not.

If get_angles = true, the 3 angles to rotate frame_a
into frame_b along the axes defined by parameter sequence
are returned. For example, if sequence = {3,1,2} then frame_a is
rotated around angles[1] along the z-axis, afterwards it is rotated
around angles[2] along the x-axis, and finally it is rotated around
angles[3] along the y-axis and is then identical to frame_b.
The 3 angles are returned in the range

-π <= angles[i] <= π

There are two solutions for \"angles[1]\" in this range.
Via parameter guessAngle1 (default = 0) the
returned solution is selected such that |angles[1] - guessAngle1| is
minimal. The relative transformation matrix between frame_a and
frame_b may be in a singular configuration with respect to \"sequence\", i.e.,
there is an infinite number of angle values leading to the same relative
transformation matrix. In this case, the returned solution is
selected by setting angles[1] = guessAngle1. Then angles[2]
and angles[3] can be uniquely determined in the above range.

The parameter sequence has the restriction that
only values 1,2,3 can be used and that sequence[1] ≠ sequence[2]
and sequence[2] ≠ sequence[3]. Often used values are:

sequence = {1,2,3}  // Cardan or Tait-Bryan angle sequence
         = {3,1,3}  // Euler angle sequence
         = {3,2,1}

"));
end RelativeSensor;


Measure relative velocity vector between the origins of two frame connectors. The relative velocity vector between the origins of frame_a and of frame_b are
determined and provided at the output signal connector v_rel.
This vector is defined as:

within Modelica.Mechanics.MultiBody.Sensors;
model RelativeVelocity
  "Measure relative velocity vector between the origins of two frame connectors"
  extends Internal.PartialRelativeSensor;
  Modelica.Blocks.Interfaces.RealOutput v_rel[3](
    each final quantity="Velocity",
    each final unit = "m/s")
    "Relative velocity vector resolved in frame defined by resolveInFrame"

  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve if resolveInFrame ==
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve
    "Coordinate system in which v_rel is optionally resolved"

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB
    resolveInFrame=
  Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_a
    "Frame in which output vector v_rel shall be resolved (world, frame_a, frame_b, or frame_resolve)";

protected
  RelativePosition relativePosition(resolveInFrame=Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_a)
  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition if
    not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve)
  Modelica.Blocks.Continuous.Der der_r_rel[3]
  Modelica.Mechanics.MultiBody.Sensors.TransformRelativeVector transformRelativeVector(frame_r_in=Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_a, frame_r_out=resolveInFrame)
equation
  connect(relativePosition.frame_a, frame_a)
  connect(relativePosition.frame_b, frame_b)
  connect(relativePosition.r_rel, der_r_rel.u)
  connect(der_r_rel.y, transformRelativeVector.r_in)
  connect(transformRelativeVector.r_out, v_rel)
  connect(transformRelativeVector.frame_a, frame_a)
  connect(transformRelativeVector.frame_b, frame_b)
  connect(transformRelativeVector.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, transformRelativeVector.frame_resolve)
v_rel = der(r_rel);

Via parameter resolveInFrame it is defined, in which frame
the velocity vector is resolved:

resolveInFrame =
Types.ResolveInFrameAB.	Meaning

world
    Resolve vector in world frame

frame_a
    Resolve vector in frame_a

frame_b
    Resolve vector in frame_b

frame_resolve
    Resolve vector in frame_resolve

If resolveInFrame = Types.ResolveInFrameAB.frame_resolve, the conditional connector
\"frame_resolve\" is enabled and v_rel is resolved in the frame, to
which frame_resolve is connected. Note, if this connector is enabled, it must
be connected.

Example

If resolveInFrame = Types.ResolveInFrameAB.frame_b, the output vector is
computed as:

r_rel   = MultiBody.Frames.resolve2(frame_a.R, frame_b.r_0 - frame_a.r_0);
v_rel_a = der(r_rel);
v_rel   = MultiBody.Frames.resolveRelative(frame_a.R, frame_b.R, v_rel_a);

"));
end RelativeVelocity;


Transform absolute vector in to another frame. The input vector \"Real r_in[3]\" is assumed to be an absolute kinematic quantity
of frame_a that is defined to be resolved in the frame defined
with parameter \"frame_r_in\". This model resolves vector r_in in the
coordinate system defined with parameter \"frame_r_out\" and returns the
transformed output vector as \"Real r_out[3]\";

within Modelica.Mechanics.MultiBody.Sensors;
model TransformAbsoluteVector "Transform absolute vector in to another frame"
  extends Modelica.Icons.RoundSensor;

  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
    "Coordinate system from which absolute kinematic quantities are measured"

  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve if
   (frame_r_in  == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve) or
   (frame_r_out == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve)
    "Coordinate system in which r_in or r_out is optionally resolved"

  Blocks.Interfaces.RealInput r_in[3]
    "Input vector resolved in frame defined by frame_r_in"
  Blocks.Interfaces.RealOutput r_out[3]
    "Input vector r_in resolved in frame defined by frame_r_out"

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameA frame_r_in=
  Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_a
    "Frame in which vector r_in is resolved (world, frame_a, or frame_resolve)";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameA frame_r_out=
                  frame_r_in
    "Frame in which vector r_in shall be resolved and provided as r_out (world, frame_a, or frame_resolve)";

protected
  Internal.BasicTransformAbsoluteVector basicTransformVector(frame_r_in=
        frame_r_in, frame_r_out=frame_r_out)
  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition if
    not (frame_r_in == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve or
         frame_r_out == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve)

equation
  connect(basicTransformVector.frame_a, frame_a)
  connect(basicTransformVector.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, basicTransformVector.frame_resolve)
  connect(basicTransformVector.r_out, r_out)
  connect(basicTransformVector.r_in, r_in)
end TransformAbsoluteVector;


Transform relative vector in to another frame. The input vector \"Real r_in[3]\" is assumed to be a relative kinematic quantity
between frame_a and frame_b
that is defined to be resolved in the frame defined
with parameter \"frame_r_in\". This model resolves vector r_in in the
coordinate system defined with parameter \"frame_r_out\" and returns the
transformed output vector as \"Real r_out[3]\";

within Modelica.Mechanics.MultiBody.Sensors;
model TransformRelativeVector "Transform relative vector in to another frame"
  extends Internal.PartialRelativeSensor;

  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve if
   (frame_r_in  == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve) or
   (frame_r_out == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve)
    "Coordinate system in which r_in or r_out is optionally resolved"

  Blocks.Interfaces.RealInput r_in[3]
    "Input vector resolved in frame defined by frame_r_in"
  Blocks.Interfaces.RealOutput r_out[3]
    "Input vector r_in resolved in frame defined by frame_r_out"

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB frame_r_in=
  Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_a
    "Frame in which vector r_in is resolved (world, frame_a, frame_b, or frame_resolve)";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB frame_r_out=
                  frame_r_in
    "Frame in which vector r_in shall be resolved and provided as r_out (world, frame_a, frame_b, or frame_resolve)";

protected
  Modelica.Mechanics.MultiBody.Sensors.Internal.BasicTransformRelativeVector basicTransformVector(frame_r_in=frame_r_in, frame_r_out=frame_r_out)
  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition if
    not (frame_r_in == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve or
         frame_r_out == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve)

equation
  connect(basicTransformVector.frame_a, frame_a)
  connect(basicTransformVector.frame_b, frame_b)
  connect(basicTransformVector.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, basicTransformVector.frame_resolve)
  connect(basicTransformVector.r_out, r_out)
  connect(basicTransformVector.r_in, r_in)
end TransformRelativeVector;


Basic sensor to measure absolute angular velocity. This basic sensor is aimed to be used within advanced sensors where
the absolute angular velocity of frame_a should be determined.
This vector is provided at the output signal connector w.

within Modelica.Mechanics.MultiBody.Sensors.Internal;
model BasicAbsoluteAngularVelocity "Basic sensor to measure absolute angular velocity"
  import Modelica.Mechanics.MultiBody.Frames;
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameA;

  extends Modelica.Mechanics.MultiBody.Sensors.Internal.PartialAbsoluteBaseSensor;
  Modelica.Blocks.Interfaces.RealOutput w[3](each final quantity="AngularVelocity",each final unit = "rad/s")
    "Absolute angular velocity vector"
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameA
    resolveInFrame=
  Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_a
    "Frame in which output vector w is resolved (world, frame_a, or frame_resolve)";

equation
   if resolveInFrame == ResolveInFrameA.world then
      w = Frames.angularVelocity1(frame_a.R);
   elseif resolveInFrame == ResolveInFrameA.frame_a then
      w = Frames.angularVelocity2(frame_a.R);
   elseif resolveInFrame == ResolveInFrameA.frame_resolve then
      w = Frames.resolve2(frame_resolve.R, Frames.angularVelocity1(frame_a.R));
   else
      assert(false, "Wrong value for parameter resolveInFrame");
      w = zeros(3);
   end if;
</pre></blockquote>
</html>"));
end BasicAbsoluteAngularVelocity;


Basic sensor to measure absolute position vector. This basic sensor is aimed to be used within advanced sensors where
the absolute position vector of the origin of frame_a should be determined.
This vector is provided at the output signal connector r.

within Modelica.Mechanics.MultiBody.Sensors.Internal;
model BasicAbsolutePosition
  "Basic sensor to measure absolute position vector"
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameA;
  extends Modelica.Mechanics.MultiBody.Sensors.Internal.PartialAbsoluteBaseSensor;
  Modelica.Blocks.Interfaces.RealOutput r[3](
    each final quantity="Length", each final unit = "m")
    "Absolute position vector frame_a.r_0 resolved in frame defined by resolveInFrame"

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameA resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_a
    "Frame in which output vector r is resolved (world, frame_a, or frame_resolve)";

equation
  if resolveInFrame == ResolveInFrameA.world then
    r = frame_a.r_0;
  elseif resolveInFrame == ResolveInFrameA.frame_a then
    r = Frames.resolve2(frame_a.R, frame_a.r_0);
  elseif resolveInFrame == ResolveInFrameA.frame_resolve then
    r = Frames.resolve2(frame_resolve.R, frame_a.r_0);
  else
    assert(false, "Wrong value for parameter resolveInFrame");
    r = zeros(3);
  end if;
</pre></blockquote>
</html>"));
end BasicAbsolutePosition;


Basic sensor to measure cut force vector (frame_resolve must be connected). This basic sensor is aimed to be used within advanced sensors where
the cut-force acting between the two frames is determined to which this
model is connected.
This cut-force is provided at the output signal connector
force (= frame_a.f). If parameter positiveSign =
false, the negative cut-force is provided (= frame_b.f).

within Modelica.Mechanics.MultiBody.Sensors.Internal;
model BasicCutForce
  "Basic sensor to measure cut force vector (frame_resolve must be connected)"
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameA;
  import Modelica.Mechanics.MultiBody.Frames;
  extends Modelica.Mechanics.MultiBody.Sensors.Internal.PartialCutForceBaseSensor;

  Modelica.Blocks.Interfaces.RealOutput force[3](each final quantity="Force", each final unit="N")
    "Cut force resolved in frame defined by resolveInFrame"
  parameter Boolean positiveSign=true
    "= true, if force with positive sign is returned (= frame_a.f), otherwise with negative sign (= frame_b.f)";
protected
  parameter Integer csign=if positiveSign then +1 else -1;
equation
  if resolveInFrame == ResolveInFrameA.world then
    force = Frames.resolve1(frame_a.R, frame_a.f)*csign;
  elseif resolveInFrame == ResolveInFrameA.frame_a then
    force = frame_a.f*csign;
  elseif resolveInFrame == ResolveInFrameA.frame_resolve then
    force = Frames.resolveRelative(frame_a.f, frame_a.R, frame_resolve.R)*csign;
  else
    assert(false,"Wrong value for parameter resolveInFrame");
    force = zeros(3);
  end if;
end BasicCutForce;


Basic sensor to measure cut torque vector (frame_resolve must be connected). This basic sensor is aimed to be used within advanced sensors where
the cut-torque acting between the two frames is determined to which this
model is connected.
This cut-torque is provided at the output signal connector
torque (= frame_a.f). If parameter positiveSign =
false, the negative cut-torque is provided (= frame_b.f).

within Modelica.Mechanics.MultiBody.Sensors.Internal;
model BasicCutTorque
  "Basic sensor to measure cut torque vector (frame_resolve must be connected)"

  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameA;
  import Modelica.Mechanics.MultiBody.Frames;

  extends Modelica.Mechanics.MultiBody.Sensors.Internal.PartialCutForceBaseSensor;
  Modelica.Blocks.Interfaces.RealOutput torque[3](each final quantity="Torque", each final unit=
        "N.m") "Cut torque resolved in frame defined by resolveInFrame"

  parameter Boolean positiveSign=true
    "= true, if torque with positive sign is returned (= frame_a.t), otherwise with negative sign (= frame_b.t)";

protected
  parameter Integer csign=if positiveSign then +1 else -1;
equation
   if resolveInFrame == ResolveInFrameA.world then
      torque = Frames.resolve1(frame_a.R, frame_a.t)*csign;
   elseif resolveInFrame == ResolveInFrameA.frame_a then
      torque = frame_a.t*csign;
   elseif resolveInFrame == ResolveInFrameA.frame_resolve then
      torque = Frames.resolveRelative(frame_a.t, frame_a.R, frame_resolve.R)*csign;
   else
      assert(false,"Wrong value for parameter resolveInFrame");
      torque = zeros(3);
   end if;
end BasicCutTorque;


Basic sensor to measure relative angular velocity. This basic sensor is aimed to be used within advanced sensors where
the relative angular velocity between frame_a and frame_b should be determined.
This vector is provided at the output signal connector w_rel.

within Modelica.Mechanics.MultiBody.Sensors.Internal;
model BasicRelativeAngularVelocity "Basic sensor to measure relative angular velocity"
  import Modelica.Mechanics.MultiBody.Frames;
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB;

  extends Modelica.Mechanics.MultiBody.Sensors.Internal.PartialRelativeBaseSensor;
  Modelica.Blocks.Interfaces.RealOutput w_rel[3](each final quantity="AngularVelocity",each final unit = "rad/s")
    "Relative angular velocity vector"
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB
    resolveInFrame=
  Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_a
    "Frame in which output vector w_rel is resolved (world, frame_a, frame_b, or frame_resolve)";

protected
  Modelica.Mechanics.MultiBody.Frames.Orientation R_rel
    "Relative orientation object from frame_a to frame_b";
equation
   R_rel = Frames.relativeRotation(frame_a.R, frame_b.R);
   if resolveInFrame == ResolveInFrameAB.frame_a then
      w_rel = Frames.angularVelocity1(R_rel);
   elseif resolveInFrame == ResolveInFrameAB.frame_b then
      w_rel = Frames.angularVelocity2(R_rel);
   elseif resolveInFrame == ResolveInFrameAB.world then
      w_rel = Frames.resolve1(frame_a.R, Frames.angularVelocity1(R_rel));
   elseif resolveInFrame == ResolveInFrameAB.frame_resolve then
      w_rel = Frames.resolveRelative(Frames.angularVelocity1(R_rel), frame_a.R, frame_resolve.R);
   else
      assert(false, "Wrong value for parameter resolveInFrame");
      w_rel = zeros(3);
   end if;

// Angular velocity resolved in frame_a
w_rel = MultiBody.Frames.angularVelocity1(R_rel);
</pre></blockquote>
</html>"));
end BasicRelativeAngularVelocity;


Basic sensor to measure relative position vector. This basic sensor is aimed to be used within advanced sensors where
the relative position vector between the origins of frame_a and frame_b should be determined.
This vector is provided at the output signal connector r_rel.

within Modelica.Mechanics.MultiBody.Sensors.Internal;
model BasicRelativePosition
  "Basic sensor to measure relative position vector"
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB;
  extends Modelica.Mechanics.MultiBody.Sensors.Internal.PartialRelativeBaseSensor;
  Modelica.Blocks.Interfaces.RealOutput r_rel[3](each final quantity="Length", each final
            unit = "m")
    "Relative position vector frame_b.r_0 - frame_a.r_0 resolved in frame defined by resolveInFrame"

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB
    resolveInFrame=
  Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_a
    "Frame in which output vector r_rel is resolved (world, frame_a, frame_b, or frame_resolve)";

equation
   if resolveInFrame == ResolveInFrameAB.frame_a then
      r_rel = Frames.resolve2(frame_a.R, frame_b.r_0 - frame_a.r_0);
   elseif resolveInFrame == ResolveInFrameAB.frame_b then
      r_rel = Frames.resolve2(frame_b.R, frame_b.r_0 - frame_a.r_0);
   elseif resolveInFrame == ResolveInFrameAB.world then
      r_rel = frame_b.r_0 - frame_a.r_0;
   elseif resolveInFrame == ResolveInFrameAB.frame_resolve then
      r_rel = Frames.resolve2(frame_resolve.R, frame_b.r_0 - frame_a.r_0);
   else
      assert(false, "Wrong value for parameter resolveInFrame");
      r_rel = zeros(3);
   end if;
</pre></blockquote>
</html>"));
end BasicRelativePosition;


Transform absolute vector into another frame. This basic sensor transforms an absolute vector r_in,
resolved in frame defined by frame_r_in,
into another frame specified by frame_r_out.
This output vector is provided at the output signal connector r_out.

within Modelica.Mechanics.MultiBody.Sensors.Internal;
model BasicTransformAbsoluteVector
  "Transform absolute vector into another frame"
  import Modelica.Mechanics.MultiBody.Frames;
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameA;

  extends Modelica.Icons.RoundSensor;

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameA frame_r_in=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_a
    "Frame in which vector r_in is resolved (world, frame_a, or frame_resolve)";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameA frame_r_out=
    frame_r_in
    "Frame in which vector r_out (= r_in in other frame) is resolved (world, frame_a, or frame_resolve)";

  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
    "Coordinate system from which absolute kinematic quantities are measured"

  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve
    "Coordinate system in which vector is optionally resolved"

  Blocks.Interfaces.RealInput r_in[3]
    "Input vector resolved in frame defined by frame_r_in"
  Blocks.Interfaces.RealOutput r_out[3]
    "Input vector r_in resolved in frame defined by frame_r_out"

protected
  Modelica.Mechanics.MultiBody.Frames.Orientation R1
    "Orientation object from world frame to frame in which r_in is resolved";
equation
  assert(cardinality(frame_a) > 0, "Connector frame_a must be connected at least once");
  assert(cardinality(frame_resolve) == 1, "Connector frame_resolve must be connected exactly once");
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
  frame_resolve.f = zeros(3);
  frame_resolve.t = zeros(3);

  if frame_r_out == frame_r_in then
    r_out = r_in;
    R1 = Frames.nullRotation();
  else
    if frame_r_in == ResolveInFrameA.world then
      R1 = Frames.nullRotation();
    elseif frame_r_in == ResolveInFrameA.frame_a then
      R1 = frame_a.R;
    elseif frame_r_in == ResolveInFrameA.frame_resolve then
      R1 = frame_resolve.R;
    else
      assert(false, "Wrong value for parameter frame_r_in");
      R1 = Frames.nullRotation();
    end if;

    if frame_r_out == ResolveInFrameA.world then
      r_out = Frames.resolve1(R1, r_in);
    elseif frame_r_out == ResolveInFrameA.frame_a then
      r_out = Frames.resolveRelative(r_in, R1, frame_a.R);
    elseif frame_r_out == ResolveInFrameA.frame_resolve then
      r_out = Frames.resolveRelative(r_in, R1, frame_resolve.R);
    else
      assert(false, "Wrong value for parameter frame_r_out");
      r_out = zeros(3);
    end if;
  end if;
end BasicTransformAbsoluteVector;


Transform relative vector into another frame. This basic sensor transforms a relative vector r_in,
resolved in frame defined by frame_r_in,
into another frame specified by frame_r_out.
This output vector is provided at the output signal connector r_out.

within Modelica.Mechanics.MultiBody.Sensors.Internal;
model BasicTransformRelativeVector
  "Transform relative vector into another frame"
  import Modelica.Mechanics.MultiBody.Frames;
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB;
  extends Modelica.Mechanics.MultiBody.Sensors.Internal.PartialRelativeBaseSensor;
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB frame_r_in=
  Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_a
    "Frame in which vector r_in is resolved (world, frame_a, frame_b, or frame_resolve)";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB frame_r_out=
    frame_r_in
    "Frame in which vector r_out (= r_in in other frame) is resolved (world, frame_a, frame_b, or frame_resolve)";

  Blocks.Interfaces.RealInput r_in[3]
    "Input vector resolved in frame defined by frame_r_in"
  Blocks.Interfaces.RealOutput r_out[3]
    "Input vector r_in resolved in frame defined by frame_r_out"

protected
  Modelica.Mechanics.MultiBody.Frames.Orientation R1
    "Orientation object from world frame to frame in which r_in is resolved";
equation
   if frame_r_out == frame_r_in then
      r_out = r_in;
      R1 = Frames.nullRotation();
   else
      if frame_r_in == ResolveInFrameAB.world then
         R1 = Frames.nullRotation();
      elseif frame_r_in == ResolveInFrameAB.frame_a then
         R1 = frame_a.R;
      elseif frame_r_in == ResolveInFrameAB.frame_b then
         R1 = frame_b.R;
      else
         R1 = frame_resolve.R;
      end if;

      if frame_r_out == ResolveInFrameAB.world then
         r_out = Frames.resolve1(R1, r_in);
      elseif frame_r_out == ResolveInFrameAB.frame_a then
         r_out = Frames.resolveRelative(r_in, R1, frame_a.R);
      elseif frame_r_out == ResolveInFrameAB.frame_b then
         r_out = Frames.resolveRelative(r_in, R1, frame_b.R);
      else
         r_out = Frames.resolveRelative(r_in, R1, frame_resolve.R);
      end if;
   end if;
end BasicTransformRelativeVector;


within Modelica.Mechanics.MultiBody.Sensors;
package Internal "Internal package, should not be used by user"
  extends Modelica.Icons.InternalPackage;
end Internal;


Base class for absolute sensor models defined by equations (frame_resolve must be connected exactly once). Partial base class for absolute sensor models defined by equations.
The connector frame_resolve is always enabled and must be connected exactly once.

within Modelica.Mechanics.MultiBody.Sensors.Internal;
model PartialAbsoluteBaseSensor
  "Base class for absolute sensor models defined by equations (frame_resolve must be connected exactly once)"
  extends Modelica.Icons.RoundSensor;

  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
    "Coordinate system from which kinematic quantities are measured"

  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve
    "Coordinate system in which output vector(s) is optionally resolved"

equation
  assert(cardinality(frame_a) > 0, "Connector frame_a must be connected at least once");
  assert(cardinality(frame_resolve) == 1, "Connector frame_resolve must be connected exactly once");
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
  frame_resolve.f = zeros(3);
  frame_resolve.t = zeros(3);
end PartialAbsoluteBaseSensor;


Base class for absolute sensor models. This is a base class of a 3-dim. mechanical component with one frame
frame_a in order to measure an absolute quantity of this
connector.
This partial class can be used for sensors defined either by components or by equations.

within Modelica.Mechanics.MultiBody.Sensors.Internal;
partial model PartialAbsoluteSensor "Base class for absolute sensor models"
  extends Modelica.Icons.RoundSensor;

  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
    "Coordinate system a of which the absolute kinematic quantities are measured"

equation
  assert(cardinality(frame_a) > 0, "Connector frame_a must be connected at least once");
end PartialAbsoluteSensor;


within Modelica.Mechanics.MultiBody.Sensors.Internal;
partial model PartialCutForceBaseSensor
  "Base class to measure cut force and/or torque between two frames, defined by equations (frame_resolve must be connected exactly once)"

  extends Modelica.Icons.RoundSensor;
  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
    "Coordinate system a"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_b frame_b
    "Coordinate system b"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve
    "The output vector is optionally resolved in this frame (cut-force/-torque are set to zero)"

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameA resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_a
    "Frame in which output vector is resolved (world, frame_a, or frame_resolve)";

protected
  outer Modelica.Mechanics.MultiBody.World world;
equation
  Connections.branch(frame_a.R, frame_b.R);
  assert(cardinality(frame_a) > 0,
    "Connector frame_a of cut-force/-torque sensor object is not connected");
  assert(cardinality(frame_b) > 0,
    "Connector frame_b of cut-force/-torque sensor object is not connected");

  // frame_a and frame_b are identical
  frame_a.r_0 = frame_b.r_0;
  frame_a.R = frame_b.R;

  // force and torque balance
  zeros(3) = frame_a.f + frame_b.f;
  zeros(3) = frame_a.t + frame_b.t;
  frame_resolve.f = zeros(3);
  frame_resolve.t = zeros(3);
end PartialCutForceBaseSensor;


within Modelica.Mechanics.MultiBody.Sensors.Internal;
partial model PartialCutForceSensor
  "Base class to measure cut force and/or torque between two frames, defined by components"

  extends Modelica.Icons.RoundSensor;
  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
    "Coordinate system a"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_b frame_b
    "Coordinate system b"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve if
         resolveInFrame==Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve
    "Output vectors are optionally resolved in this frame (cut-force/-torque are set to zero)"

  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameA resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_a
    "Frame in which output vector(s) is/are resolved (world, frame_a, or frame_resolve)";

protected
  outer Modelica.Mechanics.MultiBody.World world;
equation
  assert(cardinality(frame_a) > 0,
    "Connector frame_a of cut-force/-torque sensor object is not connected");
  assert(cardinality(frame_b) > 0,
    "Connector frame_b of cut-force/-torque sensor object is not connected");
end PartialCutForceSensor;


Base class for relative sensor models defined by equations (frame_resolve must be connected exactly once). Partial base class for relative sensor models defined by equations.
The connector frame_resolve is always enabled and must be connected exactly once.

within Modelica.Mechanics.MultiBody.Sensors.Internal;
model PartialRelativeBaseSensor
  "Base class for relative sensor models defined by equations (frame_resolve must be connected exactly once)"
  extends Modelica.Icons.RoundSensor;

  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
    "Coordinate system a (measurement is between frame_a and frame_b)"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_b frame_b
    "Coordinate system b (measurement is between frame_a and frame_b)"

  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve
    "Coordinate system in which vector is optionally resolved"

equation
  assert(cardinality(frame_a) > 0, "Connector frame_a must be connected at least once");
  assert(cardinality(frame_b) > 0, "Connector frame_b must be connected at least once");
  assert(cardinality(frame_resolve) == 1, "Connector frame_resolve must be connected exactly once");
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
  frame_b.f = zeros(3);
  frame_b.t = zeros(3);
  frame_resolve.f = zeros(3);
  frame_resolve.t = zeros(3);
end PartialRelativeBaseSensor;


Base class for relative sensor models. This is a base class of a 3-dim. mechanical component with two frames
frame_a and frame_b
in order to measure a relative quantity between these two connectors.
This partial class can be used for sensors defined either by components or by equations.

within Modelica.Mechanics.MultiBody.Sensors.Internal;
partial model PartialRelativeSensor
  "Base class for relative sensor models"
  extends Modelica.Icons.RoundSensor;

  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
    "Coordinate system a"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_b frame_b
    "Coordinate system b"

equation
  assert(cardinality(frame_a) > 0, "Connector frame_a must be connected at least once");
  assert(cardinality(frame_b) > 0, "Connector frame_b must be connected at least once");
end PartialRelativeSensor;


within Modelica.Mechanics.MultiBody;
package Types "Constants and types with choices, especially to build menus"
  extends Modelica.Icons.TypesPackage;
end Types;


Type of shape (box, sphere, cylinder, pipecylinder, cone, pipe, beam, gearwheel, spring, <external shape>). Type ShapeType is used to define the shape of the
visual object as parameter String. Usually, \"shapeType\" is used
as instance name. The following
values for shapeType are possible, e.g., shapeType=\"box\":

within Modelica.Mechanics.MultiBody.Types;
type ShapeType = Modelica.Icons.TypeString
  "Type of shape (box, sphere, cylinder, pipecylinder, cone, pipe, beam, gearwheel, spring, <external shape>)"


within Modelica.Mechanics.MultiBody.Types;
package Defaults "Default settings of the MultiBody library via constants"
  extends Modelica.Icons.Package;

  // Color defaults
  constant Types.Color BodyColor={0,128,255} "Default color for body shapes that have mass (light blue)";
  constant Types.Color RodColor={155,155,155} "Default color for massless rod shapes (grey)";
  constant Types.Color JointColor={255,0,0} "Default color for elementary joints (red)";
  constant Types.Color ForceColor={0,128,0} "Default color for force arrow (dark green)";
  constant Types.Color TorqueColor={0,128,0} "Default color for torque arrow (dark green)";
  constant Types.Color SpringColor={0,0,255} "Default color for a spring (blue)";
  constant Types.Color SensorColor={255,255,0} "Default color for sensors (yellow)";
  constant Types.Color FrameColor={0,0,0} "Default color for frame axes and labels (black)";
  constant Types.Color ArrowColor={0,0,255} "Default color for arrows and double arrows (blue)";

  // Arrow and frame defaults
  constant Real FrameHeadLengthFraction=5.0
    "Frame arrow head length / arrow diameter";
  constant Real FrameHeadWidthFraction=3.0
    "Frame arrow head width / arrow diameter";
  constant Real FrameLabelHeightFraction=3.0
    "Height of frame label / arrow diameter";
  constant Real ArrowHeadLengthFraction=4.0
    "Arrow head length / arrow diameter";
  constant Real ArrowHeadWidthFraction=3.0
    "Arrow head width / arrow diameter";

  // Other defaults
  constant Real BodyCylinderDiameterFraction=3
    "Default for body cylinder diameter as a fraction of body sphere diameter";
  constant Real JointRodDiameterFraction=2
    "Default for rod diameter as a fraction of joint sphere diameter attached to rod";

  /*
  constant Real N_to_m(unit="N/m") = 1000
    "Default force arrow scaling (length = force/N_to_m_default)";
  constant Real Nm_to_m(unit="N.m/m") = 1000
    "Default torque arrow scaling (length = torque/Nm_to_m_default)";
*/
end Defaults;


Visualizing an arrow with dynamically varying size in frame_a. Model FixedArrow defines an arrow that is
shown at the location of its frame_a.

within Modelica.Mechanics.MultiBody.Visualizers;
model FixedArrow
  "Visualizing an arrow with dynamically varying size in frame_a"

  import Modelica.Mechanics.MultiBody.Types;
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialVisualizer;
  parameter Boolean animation=true "= true, if animation shall be enabled";
  input SI.Position r_tail[3]={0,0,0}
    "Vector from frame_a to arrow tail, resolved in frame_a"
  input Types.Axis n={1,0,0} "Vector in arrow direction, resolved in frame_a"
  input SI.Length length=0.1 "Length of complete arrow"
  input Types.Color color={0,0,255} "Color of arrow"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  parameter Types.VectorQuantity quantity=Types.VectorQuantity.RelativePosition
    "Kind of physical quantity represented by the vector"
  input Boolean headAtOrigin=false "= true, if the vector is pointing towards the origin of vector frame"
protected
  Visualizers.Advanced.Vector arrowLine(
    color=color,
    specularCoefficient=specularCoefficient,
    coordinates=n*length,
    quantity=quantity,
    headAtOrigin=headAtOrigin,
    r=frame_a.r_0 + Modelica.Mechanics.MultiBody.Frames.TransformationMatrices.resolve1(frame_a.R.T, r_tail),
    R=frame_a.R) if world.enableAnimation and animation;
equation
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
end FixedArrow;


Visualizing a coordinate system including axes labels (visualization data may vary dynamically). Model FixedFrame visualizes the three axes of
its coordinate system frame_a together with appropriate axes
labels. A typical example is shown in the following figure:

within Modelica.Mechanics.MultiBody.Visualizers;
model FixedFrame
  "Visualizing a coordinate system including axes labels (visualization data may vary dynamically)"

  import Modelica.Mechanics.MultiBody.Types;
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialVisualizer;
  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter Boolean showLabels=true "= true, if labels shall be shown"
  input SI.Distance length=0.5 "Length of axes arrows"
  input SI.Distance diameter=length/world.defaultFrameDiameterFraction
    "Diameter of axes arrows"
  input Types.Color color_x=Modelica.Mechanics.MultiBody.Types.Defaults.
      FrameColor "Color of x-arrow"
  input Types.Color color_y=color_x "Color of y-arrow"
  input Types.Color color_z=color_x "Color of z-arrow"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
protected
  parameter Boolean animation2 = world.enableAnimation and animation;
  parameter Boolean showLabels2= world.enableAnimation and animation and showLabels;

  // Parameters to define axes
  SI.Length headLength=min(length, diameter*Types.Defaults.FrameHeadLengthFraction);
  SI.Length headWidth=diameter*Types.Defaults.FrameHeadWidthFraction;
  SI.Length lineLength=max(0, length - headLength);
  SI.Length lineWidth=diameter;

  // Parameters to define axes labels
  SI.Length scaledLabel=Modelica.Mechanics.MultiBody.Types.Defaults.FrameLabelHeightFraction*diameter;
  SI.Length labelStart=1.05*length;

  // x-axis
  Visualizers.Advanced.Shape x_arrowLine(
    shapeType="cylinder",
    length=lineLength,
    width=lineWidth,
    height=lineWidth,
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    color=color_x,
    specularCoefficient=specularCoefficient,
    r=frame_a.r_0,
    R=frame_a.R) if animation2;
  Visualizers.Advanced.Shape x_arrowHead(
    shapeType="cone",
    length=headLength,
    width=headWidth,
    height=headWidth,
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    color=color_x,
    specularCoefficient=specularCoefficient,
    r=frame_a.r_0 + Frames.resolve1(frame_a.R, {lineLength,0,0}),
    R=frame_a.R) if animation2;
  Visualizers.Internal.Lines x_label(
    lines=scaledLabel*{[0,0; 1,1],[0,1; 1,0]},
    diameter=diameter,
    color=color_x,
    specularCoefficient=specularCoefficient,
    r_lines={labelStart,0,0},
    n_x={1,0,0},
    n_y={0,1,0},
    r=frame_a.r_0,
    R=frame_a.R) if showLabels2;

  // y-axis
  Visualizers.Advanced.Shape y_arrowLine(
    shapeType="cylinder",
    length=lineLength,
    width=lineWidth,
    height=lineWidth,
    lengthDirection={0,1,0},
    widthDirection={1,0,0},
    color=color_y,
    specularCoefficient=specularCoefficient,
    r=frame_a.r_0,
    R=frame_a.R) if animation2;
  Visualizers.Advanced.Shape y_arrowHead(
    shapeType="cone",
    length=headLength,
    width=headWidth,
    height=headWidth,
    lengthDirection={0,1,0},
    widthDirection={1,0,0},
    color=color_y,
    specularCoefficient=specularCoefficient,
    r=frame_a.r_0 + Frames.resolve1(frame_a.R, {0,lineLength,0}),
    R=frame_a.R) if animation2;
  Visualizers.Internal.Lines y_label(
    lines=scaledLabel*{[0,0; 1,1.5],[0,1.5; 0.5,0.75]},
    diameter=diameter,
    color=color_y,
    specularCoefficient=specularCoefficient,
    r_lines={0,labelStart,0},
    n_x={0,1,0},
    n_y={-1,0,0},
    r=frame_a.r_0,
    R=frame_a.R) if showLabels2;

  // z-axis
  Visualizers.Advanced.Shape z_arrowLine(
    shapeType="cylinder",
    length=lineLength,
    width=lineWidth,
    height=lineWidth,
    lengthDirection={0,0,1},
    widthDirection={0,1,0},
    color=color_z,
    specularCoefficient=specularCoefficient,
    r=frame_a.r_0,
    R=frame_a.R) if animation2;
  Visualizers.Advanced.Shape z_arrowHead(
    shapeType="cone",
    length=headLength,
    width=headWidth,
    height=headWidth,
    lengthDirection={0,0,1},
    widthDirection={0,1,0},
    color=color_z,
    specularCoefficient=specularCoefficient,
    r=frame_a.r_0 + Frames.resolve1(frame_a.R, {0,0,lineLength}),
    R=frame_a.R) if animation2;
  Visualizers.Internal.Lines z_label(
    lines=scaledLabel*{[0,0; 1,0],[0,1; 1,1],[0,1; 1,0]},
    diameter=diameter,
    color=color_z,
    specularCoefficient=specularCoefficient,
    r_lines={0,0,labelStart},
    n_x={0,0,1},
    n_y={0,1,0},
    r=frame_a.r_0,
    R=frame_a.R) if showLabels2;
equation
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
end FixedFrame;


Visualizing an elementary shape with dynamically varying shape attributes (has one frame connector). Model FixedShape defines a visual shape that is
shown at the location of its frame_a.
All describing data such as size and color can vary dynamically by
providing appropriate expressions in the input fields of the
parameter menu. The only exception is parameter shapeType
that cannot be changed during simulation.
The following shapes are currently supported via
parameter shapeType (e.g., shapeType=\"box\"):

within Modelica.Mechanics.MultiBody.Visualizers;
model FixedShape
  "Visualizing an elementary shape with dynamically varying shape attributes (has one frame connector)"
  import Modelica.Mechanics.MultiBody.Types;
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialVisualizer;

  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter Types.ShapeType shapeType="box" "Type of shape"
  input SI.Position r_shape[3]={0,0,0}
    "Vector from frame_a to shape origin, resolved in frame_a"
  input Types.Axis lengthDirection={1,0,0}
    "Vector in length direction of shape, resolved in frame_a"
  input Types.Axis widthDirection={0,1,0}
    "Vector in width direction of shape, resolved in frame_a"
  input SI.Distance length(start=1) "Length of shape"
  input SI.Distance width(start=0.1) "Width of shape"
  input SI.Distance height(start=0.1) "Height of shape"
  input Modelica.Mechanics.MultiBody.Types.Color color={0,128,255}
    "Color of shape"
  input Types.ShapeExtra extra=0.0
    "Additional data for cylinder, cone, pipe, gearwheel and spring"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  Advanced.Shape vis(
    shapeType=shapeType,
    r_shape=r_shape,
    lengthDirection=lengthDirection,
    widthDirection=widthDirection,
    length=length,
    width=width,
    height=height,
    color=color,
    extra=extra,
    specularCoefficient=specularCoefficient,
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
equation
  // No forces and torques
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
end FixedShape;


Visualizing an elementary shape with dynamically varying shape attributes (has two frame connectors). Model FixedShape2 defines a visual shape that is
shown at the location of its frame_a. This model is identical
to FixedShape with the only difference that an
additional frame_b is present which is parallel to frame_a.
This makes it more convenient to connect several visual
shapes together when building up more complex visual
objects. All describing data such as size and color can vary dynamically by
providing appropriate expressions in the input fields of the
parameter menu. The only exception is parameter shapeType
that cannot be changed during simulation.
The following shapes are currently supported via
parameter shapeType (e.g., shapeType=\"box\"):

within Modelica.Mechanics.MultiBody.Visualizers;
model FixedShape2
  "Visualizing an elementary shape with dynamically varying shape attributes (has two frame connectors)"

  import Modelica.Mechanics.MultiBody.Frames;
  import Modelica.Mechanics.MultiBody.Types;
  import Modelica.Units.Conversions.to_unit1;

  Interfaces.Frame_a frame_a
    "Coordinate system a (all shape definition vectors are resolved in this frame)"
  Interfaces.Frame_b frame_b "Coordinate system b"

  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter Types.ShapeType shapeType="box" "Type of shape"
  input SI.Position r[3]={1,0,0}
    "Vector from frame_a to frame_b resolved in frame_a";
  input SI.Position r_shape[3]={0,0,0}
    "Vector from frame_a to shape origin, resolved in frame_a"
  input Types.Axis lengthDirection = to_unit1(r - r_shape)
    "Vector in length direction of shape, resolved in frame_a"
  input Types.Axis widthDirection={0,1,0}
    "Vector in width direction of shape, resolved in frame_a"
  input SI.Length length=Modelica.Math.Vectors.length(
                                       r - r_shape) "Length of shape"
  input SI.Distance width=0.1 "Width of shape"
  input SI.Distance height=width "Height of shape"
  input Types.ShapeExtra extra=0.0
    "Additional data for cylinder, cone, pipe, gearwheel and spring"
  input Types.Color color={0,128,255} "Color of shape"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  outer MultiBody.World world;
  Advanced.Shape shape(
    shapeType=shapeType,
    r_shape=r_shape,
    lengthDirection=lengthDirection,
    widthDirection=widthDirection,
    length=length,
    width=width,
    height=height,
    extra=extra,
    color=color,
    specularCoefficient = specularCoefficient,
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
equation
  Connections.branch(frame_a.R, frame_b.R);
  assert(cardinality(frame_a) > 0 or cardinality(frame_b) > 0, "Neither connector frame_a nor frame_b of
MultiBody.Visualizers.FixedShape2 object is connected");

  frame_b.r_0 = frame_a.r_0 + Frames.resolve1(frame_a.R, r);
  frame_b.R = frame_a.R;

  /* Force and torque balance */
  zeros(3) = frame_a.f + frame_b.f;
  zeros(3) = frame_a.t + frame_b.t + cross(r, frame_b.f);
end FixedShape2;


within Modelica.Mechanics.MultiBody;
package Visualizers "3-dimensional visual objects used for animation"
  extends Modelica.Icons.Package;
end Visualizers;


Visualizing a pipe with scalar field quantities along the pipe axis. This replaceable function defines a particular color map.

within Modelica.Mechanics.MultiBody.Visualizers;
model PipeWithScalarField
  "Visualizing a pipe with scalar field quantities along the pipe axis"
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialVisualizer;

  parameter Boolean animation=true "= true, if animation shall be enabled";

  parameter SI.Radius rOuter "Outer radius of pipe"
  parameter SI.Length length "Length of pipe"

  parameter Real xsi[:](each min=0, each max=1)= Modelica.Math.Vectors.relNodePositions(12)
    "Vector of relative positions along the pipe with x[1] = 0, x[end] = 1"
  input Real T[size(xsi,1)]
    "Vector of values at positions xsi*length (will be visualized by color)"
  parameter Real T_min "Minimum value of T that corresponds to colorMap[1,:]"
  parameter Real T_max
    "Maximum value of T that corresponds to colorMap[end,:]"
  replaceable function colorMap =
    Modelica.Mechanics.MultiBody.Visualizers.Colors.ColorMaps.jet constrainedby Modelica.Mechanics.MultiBody.Interfaces.partialColorMap
    "Function defining the color map"

  parameter Integer n_colors=64 "Number of colors in the colorMap"
  parameter Types.SpecularCoefficient specularCoefficient = 0.7
    "Reflection of ambient light (= 0: light is completely absorbed)"
  parameter Real transparency=0
    "Transparency of shape: 0 (= opaque) ... 1 (= fully transparent)"

  parameter Integer n_rOuter=30 "Number of points along outer radius"
  parameter Integer n_length=20 "Number of points along length"

protected
  Advanced.PipeWithScalarField pipe(redeclare function colorMap = colorMap,
         rOuter=rOuter,
         length=length,
         xsi=xsi,
         T=T,
         T_min=T_min,
         T_max=T_max,
         n_colors=n_colors,
         n_rOuter=n_rOuter,
         n_length=n_length,
         specularCoefficient=specularCoefficient,
         transparency=transparency,
         R=frame_a.R,
         r_0=frame_a.r_0) if world.enableAnimation and animation
equation
  // No forces and torques
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);

",
        revisions="

 July 2010 by Martin Otter

       Adapted to the new Surface model.

 July 2005 by Dirk Zimmer (practical training at DLR)

       First version to visualize a multi-level tyre wheel model.

"));
end PipeWithScalarField;


Visualizing a planar rectangular surface. This model visualizes a planar rectangle. The center of the rectangle is located at
connector frame_a (visualized by the red coordinate system in the figure below).
The figure below shows two rectangles of the same parameters

within Modelica.Mechanics.MultiBody.Visualizers;
model Rectangle "Visualizing a planar rectangular surface"
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialVisualizer;

  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter MultiBody.Types.Axis direction_u={1,0,0}
    "Vector along u-axis of rectangle resolved in frame_a"
  parameter MultiBody.Types.Axis direction_v={0,1,0}
    "Vector along v-axis of rectangle resolved in frame_a"

  parameter SI.Distance length_u=3 "Length of rectangle in direction u"
  parameter SI.Distance length_v=1 "Length of rectangle in direction v"
  parameter Integer nu(min=2)=3 "Number of points in direction u"
  parameter Integer nv(min=2)=2 "Number of points in direction v"

  parameter Boolean wireframe=false
    "= true: 3D model will be displayed without faces"
  input Modelica.Mechanics.MultiBody.Types.RealColor color={0,128,255}
    "Color of surface"
  input Types.SpecularCoefficient specularCoefficient = 0.7
    "Reflection of ambient light (= 0: light is completely absorbed)"
  input Real transparency=0
    "Transparency of shape: 0 (= opaque) ... 1 (= fully transparent)"

protected
  Advanced.Surface surface(
    final multiColoredSurface=false,
    final wireframe=wireframe,
    final color=color,
    final specularCoefficient=specularCoefficient,
    final transparency=transparency,
    final R=Modelica.Mechanics.MultiBody.Frames.absoluteRotation(
        frame_a.R,Modelica.Mechanics.MultiBody.Frames.from_nxy(direction_u, direction_v)),
    final r_0=frame_a.r_0,
    final nu=nu,
    final nv=nv,
    redeclare function surfaceCharacteristic = Advanced.SurfaceCharacteristics.rectangle (
      lu=length_u, lv=length_v)) if world.enableAnimation and animation
  Modelica.Mechanics.MultiBody.Forces.Internal.ZeroForceAndTorque zeroForceAndTorque

equation
  connect(frame_a, zeroForceAndTorque.frame_a)
end Rectangle;


Visualizing an arrow with dynamically varying size in frame_a based on input signal. Model SignalArrow defines an arrow that is dynamically visualized
at the location where its frame_a is attached. The
vector from the tail to the head of the arrow,
resolved in frame_a, is defined via the signal vector of
the connector r_head (Real r_head[3]):

within Modelica.Mechanics.MultiBody.Visualizers;
model SignalArrow
  "Visualizing an arrow with dynamically varying size in frame_a based on input signal"

  import Modelica.Mechanics.MultiBody.Types;

  extends Modelica.Mechanics.MultiBody.Interfaces.PartialVisualizer;
  parameter Boolean animation=true "= true, if animation shall be enabled";
  input SI.Position r_tail[3]={0,0,0}
    "Vector from frame_a to arrow tail, resolved in frame_a"
  input Types.Color color={0,0,255} "Color of arrow"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  parameter Types.VectorQuantity quantity=Types.VectorQuantity.RelativePosition
    "Kind of physical quantity represented by the vector"
  input Boolean headAtOrigin=false "= true, if the vector is pointing towards the origin of vector frame"

  Modelica.Blocks.Interfaces.RealInput r_head[3]
    "Vector resolved in frame_a"

protected
  Visualizers.Advanced.Vector arrow(
    R=frame_a.R,
    r=frame_a.r_0 + Modelica.Mechanics.MultiBody.Frames.TransformationMatrices.resolve1(frame_a.R.T, r_tail),
    coordinates=r_head,
    color=color,
    quantity=quantity,
    headAtOrigin=headAtOrigin,
    specularCoefficient=specularCoefficient) if world.enableAnimation and animation;
equation
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
end SignalArrow;


Visualizing a torus. Model Torus visualizes a torus. The center of the torus is located at
connector frame_a (visualized by the red coordinate system in the figure below).
The left image below shows a torus with <var>R</var> = 0.5 m and
<var>r</var> = 0.2 m.
The right images below shows the torus with the additional parameter
settings:

within Modelica.Mechanics.MultiBody.Visualizers;
model Torus "Visualizing a torus"
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialVisualizer;

  parameter Boolean animation=true "= true, if animation shall be enabled";

  parameter SI.Radius R=0.5 "Major radius (distance from center of torus to center of tube)"
  parameter SI.Radius r=0.1 "Minor radius (radius of tube)"
  parameter SI.Angle opening=0 "Opening angle of torus"
  parameter SI.Angle startAngle=-3.1415926535898
    "Start angle of torus slice"
  parameter SI.Angle stopAngle=3.1415926535898
    "End angle of torus slice"
  parameter Boolean wireframe=false
    "= true: 3D model will be displayed without faces"
  input Modelica.Mechanics.MultiBody.Types.RealColor color={0,128,255}
    "Color of surface"
  input Types.SpecularCoefficient specularCoefficient = 0.7
    "Reflection of ambient light (= 0: light is completely absorbed)"
  input Real transparency=0
    "Transparency of shape: 0 (= opaque) ... 1 (= fully transparent)"
  parameter Integer n_R=40 "Number of points along major radius R"
  parameter Integer n_r=20 "Number of points along minor radius r"

protected
  Advanced.Surface surface(
    redeclare function surfaceCharacteristic =
      Modelica.Mechanics.MultiBody.Visualizers.Advanced.SurfaceCharacteristics.torus (
        R=R,
        r=r,
        opening=opening,
        startAngle=startAngle,
        stopAngle=stopAngle),
        nu=n_R,
        nv=n_r,
        multiColoredSurface=false,
        wireframe=wireframe,
        color=color,
        specularCoefficient=specularCoefficient,
        transparency=transparency,
        R=frame_a.R,
        r_0=frame_a.r_0) if world.enableAnimation and animation
equation
  // No forces and torques
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
end Torus;


Visualizing a voluminous wheel.

within Modelica.Mechanics.MultiBody.Visualizers;
model VoluminousWheel "Visualizing a voluminous wheel"
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialVisualizer;

  parameter Boolean animation=true "= true, if animation shall be enabled";

  parameter SI.Radius rTire=0.25 "Radius of the tire";
  parameter SI.Radius rRim= 0.14 "Radius of the rim";
  parameter SI.Radius width=0.25 "Width of the tire";
  parameter SI.Radius rCurvature=0.30 "Radius of the tire's cross section";

  parameter Modelica.Mechanics.MultiBody.Types.RealColor color={64,64,64}
    "Color of tire"
  parameter Types.SpecularCoefficient specularCoefficient = 0.5
    "Reflection of ambient light (= 0: light is completely absorbed)"
  parameter Integer n_rTire=40 "Number of points along rTire"
  parameter Integer n_rCurvature=20 "Number of points along rCurvature"

protected
  parameter SI.Radius rw = (width/2);
  parameter SI.Radius rCurvature2 = if rCurvature > rw then rCurvature else rw;
  final parameter Real kw = rw/rCurvature2 "Regularized width ratio (0...1)";
  parameter SI.Radius h =     sqrt(1 - kw*kw) * rCurvature2;
  parameter SI.Length ri =  rTire-rCurvature2;
  parameter SI.Radius rRim2 = if rRim < 0 then 0 else if rRim > ri+h then ri+h else rRim;

    Visualizers.Advanced.Shape pipe(
    shapeType="pipe",
    color=color,
    length=width,
    width=2*(ri + h),
    height=2*(ri + h),
    lengthDirection={0,1,0},
    widthDirection={0,0,1},
    extra=(rRim2)/(ri + h),
    r=frame_a.r_0,
    r_shape=-{0,1,0}*(width/2),
    R=frame_a.R,
    specularCoefficient=specularCoefficient) if world.enableAnimation and animation

    Visualizers.Advanced.Surface torus(
    redeclare function surfaceCharacteristic = Modelica.Mechanics.MultiBody.Visualizers.Advanced.SurfaceCharacteristics.torus (
        R=ri,
        r=rCurvature2,
        opening=Modelica.Constants.pi - Modelica.Math.asin(kw)),
    nu=n_rTire,
    nv=n_rCurvature,
    multiColoredSurface=false,
    wireframe=false,
    color=color,
    specularCoefficient=specularCoefficient,
    transparency=0,
    R=frame_a.R,
    r_0=frame_a.r_0) if world.enableAnimation and animation

equation
  // No forces and torques
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
end VoluminousWheel;


Visualizing an arrow with variable size. Model Arrow defines an arrow that is dynamically
visualized at the defined location (see variables below).
If you want an arrow representing something that is not a relative position, use
Vector instead.

within Modelica.Mechanics.MultiBody.Visualizers.Advanced;
model Arrow
  "Visualizing an arrow with variable size"

  import Modelica.Mechanics.MultiBody.Types;
  import Modelica.Mechanics.MultiBody.Frames;
  import T = Modelica.Mechanics.MultiBody.Frames.TransformationMatrices;

  input Frames.Orientation R=Frames.nullRotation()
    "Orientation object to rotate the world frame into the arrow frame"
  input SI.Position r[3]={0,0,0}
    "Position vector from origin of world frame to origin of arrow frame, resolved in world frame"
  input SI.Position r_tail[3]={0,0,0}
    "Position vector from origin of arrow frame to arrow tail, resolved in arrow frame"
  input Real r_head[3]={0,0,0}
    "Vector from arrow tail to the head of the arrow, resolved in arrow frame"
  input Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.ArrowColor
    "Color of arrow"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Material property describing the reflecting of ambient light (= 0 means, that light is completely absorbed)"
  parameter Types.VectorQuantity quantity=Types.VectorQuantity.RelativePosition
    "Kind of physical quantity represented by the vector"
  input Boolean headAtOrigin=false "= true, if the vector is pointing towards the origin of vector frame"
protected
  outer Modelica.Mechanics.MultiBody.World world;
  SI.Position rvisobj[3] = r + T.resolve1(R.T, r_tail);
  Visualizers.Advanced.Vector arrowLine(
    coordinates=r_head,
    color=color,
    specularCoefficient=specularCoefficient,
    r=rvisobj,
    quantity=quantity,
    headAtOrigin=headAtOrigin,
    R=R) if world.enableAnimation;

Variable color is an Integer vector with 3 elements,
{r, g, b}, and specifies the color of the shape.
{r, g, b} are the "red", "green" and "blue" color parts.
Note, r, g and b are given in the range 0 … 255.
The predefined type
MultiBody.Types.Color
contains a menu definition of the colors used in the MultiBody
library together with a color editor.

"),
    Icon(coordinateSystem(preserveAspectRatio=true, extent={{-100,-100},{
            100,100}}), graphics={
        Rectangle(
          extent={{-100,28},{20,-28}},
          lineColor={128,128,128},
          fillColor={128,128,128},
          fillPattern=FillPattern.Solid),
        Polygon(
          points={{20,60},{100,0},{20,-60},{20,60}},
          lineColor={128,128,128},
          fillColor={128,128,128},
          fillPattern=FillPattern.Solid),
        Text(
          extent={{-150,105},{150,65}},
          textString="%name",
          textColor={0,0,255})}));
end Arrow;


Visualizing a double arrow with variable size. Model DoubleArrow defines a double arrow that is dynamically
visualized at the defined location (see variables below).
Nonetheless, visualizing physical vectors by means of
Vector
can be better option in many cases.

within Modelica.Mechanics.MultiBody.Visualizers.Advanced;
model DoubleArrow
  "Visualizing a double arrow with variable size"

  import Modelica.Mechanics.MultiBody.Types;
  import Modelica.Mechanics.MultiBody.Frames;
  import T = Modelica.Mechanics.MultiBody.Frames.TransformationMatrices;

  input Frames.Orientation R=Frames.nullRotation()
    "Orientation object to rotate the world frame into the arrow frame"
  input SI.Position r[3]={0,0,0}
    "Position vector from origin of world frame to origin of arrow frame, resolved in world frame"
  input SI.Position r_tail[3]={0,0,0}
    "Position vector from origin of arrow frame to double arrow tail, resolved in arrow frame"
  input Real r_head[3]={0,0,0}
    "Vector from double arrow tail to the head of the double arrow, resolved in arrow frame"
  input Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.ArrowColor
    "Color of double arrow"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Material property describing the reflecting of ambient light (= 0 means, that light is completely absorbed)"
  parameter Types.VectorQuantity quantity=Types.VectorQuantity.Torque
    "Kind of physical quantity represented by the vector";
  input Boolean headAtOrigin=true "= true, if the vector is pointing towards the origin of vector frame"
protected
  outer Modelica.Mechanics.MultiBody.World world;
  SI.Position rvisobj[3] = r + T.resolve1(R.T, r_tail);
  Visualizers.Advanced.Vector arrowLine(
    coordinates=r_head,
    color=color,
    specularCoefficient=specularCoefficient,
    r=rvisobj,
    quantity=quantity,
    headAtOrigin=headAtOrigin,
    twoHeadedArrow=true,
    R=R) if world.enableAnimation;
end DoubleArrow;


within Modelica.Mechanics.MultiBody.Visualizers;
package Advanced "Visualizers that require basic knowledge about Modelica in order to use them"

  extends Modelica.Icons.Package;
end Advanced;


Visualizing a pipe with a scalar field. This replaceable function defines a particular color map.

within Modelica.Mechanics.MultiBody.Visualizers.Advanced;
model PipeWithScalarField "Visualizing a pipe with a scalar field"
  input Frames.Orientation R=Frames.nullRotation()
    "Orientation object to rotate the world frame into the surface frame"
  input SI.Position r_0[3]={0,0,0}
    "Position vector from origin of world frame to origin of surface frame, resolved in world frame"

  parameter SI.Radius rOuter "Outer radius of pipe"
  parameter SI.Length length "Length of pipe"
  parameter Integer n_rOuter=30 "Number of points along outer radius"
  parameter Integer n_length=10 "Number of points along length"
  parameter Types.SpecularCoefficient specularCoefficient = 0.7
    "Reflection of ambient light (= 0: light is completely absorbed)"
  parameter Real transparency=0
    "Transparency of shape: 0 (= opaque) ... 1 (= fully transparent)"

  parameter Real xsi[:](each min=0,each max=1)= Modelica.Math.Vectors.relNodePositions(12)
    "Vector of relative positions along the pipe with x[1] = 0, x[end] = 1"
  input Real T[size(xsi,1)]
    "Vector of values at positions xsi*length (will be visualized by color)"
  parameter Real T_min
    "Minimum value of T that corresponds to colorMap[1,:]"
  parameter Real T_max
    "Maximum value of T that corresponds to colorMap[end,:]"
  parameter Integer n_colors=64 "Number of colors in the colorMap"
  replaceable function colorMap =
    Modelica.Mechanics.MultiBody.Visualizers.Colors.ColorMaps.jet constrainedby Modelica.Mechanics.MultiBody.Interfaces.partialColorMap
    "Function defining the color map"
protected
  parameter Real colorMapData[n_colors,3] = colorMap(n_colors)
  Surface surface(
    R=R,
    r_0=r_0,
    nu=n_length,
    nv=n_rOuter,
    wireframe=false,
    multiColoredSurface=true,
    specularCoefficient=specularCoefficient,
    transparency=transparency,
    redeclare function surfaceCharacteristic =
        Modelica.Mechanics.MultiBody.Visualizers.Advanced.SurfaceCharacteristics.pipeWithScalarField (
         rOuter=rOuter,
         length=length,
         xsi=xsi,
         T=T,
         T_min=T_min,
         T_max=T_max,
         colorMap=colorMapData))

"));
end PipeWithScalarField;


Visualizing an elementary object with variable size; all data have to be set as modifiers (see info layer). Model Shape defines a visual shape that is
shown at the location of its reference coordinate system, called
'object frame' below. All describing variables such
as size and color can vary dynamically (with the only exception
of parameter shapeType). The default equations in the
declarations should be modified by providing appropriate modifier
equations. Model Shape is usually used as a basic building block to
implement simpler to use graphical components.

within Modelica.Mechanics.MultiBody.Visualizers.Advanced;
model Shape
  "Visualizing an elementary object with variable size; all data have to be set as modifiers (see info layer)"

  extends ModelicaServices.Animation.Shape;
  extends Modelica.Utilities.Internal.PartialModelicaServices.Animation.PartialShape;
</pre></blockquote>
</html>"));
end Shape;


Visualizing a moveable, parameterized surface; the surface characteristic is provided by a function. Model Surface defines a moveable, parametrized surface in 3-dim. space
that is used for animation. This object is specified by:

within Modelica.Mechanics.MultiBody.Visualizers.Advanced;
model Surface
  "Visualizing a moveable, parameterized surface; the surface characteristic is provided by a function"
  extends Modelica.Mechanics.MultiBody.Icons.Surface;
  extends Modelica.Utilities.Internal.PartialModelicaServices.Animation.PartialSurface;
  extends ModelicaServices.Animation.Surface;
end Surface;


Visualizing a vector quantity (force, torque, etc.). Model Vector defines an arrow that dynamically
visualizes a physical vector of selected quantity at the defined
location (see variables below). Thus, the arrow length does not represent
a physical length (except, of course, for quantity = RelativePosition),
but a different 3-dimensional quantity
(such as force, torque, speed, …), defined by
MultiBody.Types.VectorQuantity.

That allows the vectors of similar quantities to be scaled appropriately during post-processing.
This is useful even for RelativePosition, and in that case to disable or
exaggerate the relative positions.

within Modelica.Mechanics.MultiBody.Visualizers.Advanced;
model Vector "Visualizing a vector quantity (force, torque, etc.)"

  extends ModelicaServices.Animation.Vector;
  extends Modelica.Utilities.Internal.PartialModelicaServices.Animation.PartialVector;

Variable color is an Integer vector with 3 elements,
{r, g, b}, and specifies the color of the shape.
{r, g, b} are the "red", "green" and "blue" color parts.
Note, r, g and b are given in the range 0 … 255.
The predefined type
MultiBody.Types.Color
contains a menu definition of the colors used in the MultiBody
library together with a color editor.

"),
    Icon(coordinateSystem(preserveAspectRatio=true, extent={{-100,-100},{
            100,100}}), graphics={
        Polygon(
          points={{20,60},{100,0},{20,-60},{20,60}},
          fillColor={60,120,180},
          fillPattern=FillPattern.Solid,
          pattern=LinePattern.None),
        Text(
          extent={{-150,105},{150,65}},
          textString="%name",
          textColor={0,0,255}),
        Rectangle(
          extent={{-100,-28},{20,28}},
          fillColor={60,120,180},
          fillPattern=FillPattern.Solid,
          pattern=LinePattern.None,
          lineColor={0,0,0}),
        Rectangle(
          extent={{-100,-8},{20,-20}},
          fillColor={46,94,140},
          fillPattern=FillPattern.Solid,
          pattern=LinePattern.None,
          lineColor={0,0,0}),
        Rectangle(
          extent={{-100,-20},{20,-28}},
          fillColor={26,53,80},
          fillPattern=FillPattern.Solid,
          pattern=LinePattern.None,
          lineColor={0,0,0}),
        Polygon(
          points={{20,-20},{100,0},{20,-48},{20,-20}},
          fillColor={46,93,140},
          fillPattern=FillPattern.Solid,
          pattern=LinePattern.None,
          lineColor={0,0,0}),
        Polygon(
          points={{20,-60},{100,0},{20,-48},{20,-60}},
          fillColor={26,53,80},
          fillPattern=FillPattern.Solid,
          pattern=LinePattern.None,
          lineColor={0,0,0}),
        Rectangle(
          extent={{-100,26},{20,4}},
          fillColor={73,147,220},
          fillPattern=FillPattern.Solid,
          pattern=LinePattern.None),
        Rectangle(
          extent={{-100,22},{20,14}},
          fillColor={85,170,255},
          fillPattern=FillPattern.Solid,
          pattern=LinePattern.None),
        Polygon(
          points={{20,56},{100,0},{20,18},{20,56}},
          fillColor={72,149,220},
          fillPattern=FillPattern.Solid,
          pattern=LinePattern.None,
          lineColor={0,0,0}),
        Polygon(
          points={{20,48},{100,0},{20,36},{20,48}},
          fillColor={85,170,255},
          fillPattern=FillPattern.Solid,
          pattern=LinePattern.None,
          lineColor={0,0,0})}));
end Vector;


within Modelica.Mechanics.MultiBody.Visualizers.Advanced;
package SurfaceCharacteristics "Functions returning surface descriptions"
    extends Modelica.Icons.FunctionsPackage;
end SurfaceCharacteristics;


Library of functions operating on color

within Modelica.Mechanics.MultiBody.Visualizers;
package Colors "Library of functions operating on color"
  extends Modelica.Icons.FunctionsPackage;

This definition is also available as type
Modelica.Mechanics.MultiBody.Types.RealColor.

"));
end Colors;


within Modelica.Mechanics.MultiBody.Visualizers.Colors;
package ColorMaps "Library of functions returning color maps"
  extends Modelica.Icons.FunctionsPackage;
end ColorMaps;


Visualizing a set of lines as cylinders (e.g., used to display characters). With model FixedLines a set of lines is defined
that are located relatively to frame_a. Every line
is represented by a cylinder. This allows to define simple shaped
3-dimensional characters. An example is shown in the
following figure:

within Modelica.Mechanics.MultiBody.Visualizers.Internal;
model FixedLines
  "Visualizing a set of lines as cylinders (e.g., used to display characters)"

  import Modelica.Mechanics.MultiBody;
  import Modelica.Mechanics.MultiBody.Types;
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialVisualizer;

  parameter Boolean animation=true "= true, if animation shall be enabled";
  input Real scale(min=0) = 1
    "The 'lines' are visualized 'scale' times bigger"
  input SI.Position lines[:,2,2]={[0,0; 1,1],[0,1; 1,0]}
    "List of start and end points of cylinders resolved along n_x and n_y"
  input SI.Distance diameter(min=0) = 0.05
    "Diameter of the cylinders defined by lines"
  input SI.Position r_lines[3]={0,0,0}
    "Position vector from origin of frame_a to the origin of the 'lines' frame, resolved in frame_a"
  input Real n_x[3](each final unit="1")={1,0,0}
    "Vector in direction of x-axis of 'lines' frame, resolved in frame_a."
  input Real n_y[3](each final unit="1")={0,1,0}
    "Vector in direction of y-axis of 'lines' frame, resolved in frame_a."
  input MultiBody.Types.Color color={0,128,255} "Color of cylinders"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  Lines x_label(
    lines=scale*lines,
    diameter=scale*diameter,
    color=color,
    specularCoefficient = specularCoefficient,
    r_lines=r_lines,
    n_x=n_x,
    n_y=n_y,
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
equation
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
end FixedLines;


Visualizing a set of lines as cylinders with variable size, e.g., used to display characters (no Frame connector). With model Lines a set of dynamic lines is defined
that are located relatively to frame_a. Every line
is represented by a cylinder. This allows, e.g., to define simple shaped
3-dimensional characters. Note, if the lines are fixed relatively to frame_a,
it is more convenient to use model Visualizers.Internal.FixedLines.
An example for dynamic lines is shown in the following figure:

within Modelica.Mechanics.MultiBody.Visualizers.Internal;
model Lines
  "Visualizing a set of lines as cylinders with variable size, e.g., used to display characters (no Frame connector)"

  import Modelica.Mechanics.MultiBody;
  import Modelica.Mechanics.MultiBody.Types;
  import Modelica.Mechanics.MultiBody.Frames;
  import T = Modelica.Mechanics.MultiBody.Frames.TransformationMatrices;
  input Modelica.Mechanics.MultiBody.Frames.Orientation R=Frames.nullRotation()
    "Orientation object to rotate the world frame into the object frame"
  input SI.Position r[3]={0,0,0}
    "Position vector from origin of world frame to origin of object frame, resolved in world frame"
  input SI.Position r_lines[3]={0,0,0}
    "Position vector from origin of object frame to the origin of 'lines' frame, resolved in object frame"
  input Real n_x[3](each final unit="1")={1,0,0}
    "Vector in direction of x-axis of 'lines' frame, resolved in object frame"
  input Real n_y[3](each final unit="1")={0,1,0}
    "Vector in direction of y-axis of 'lines' frame, resolved in object frame"
  input SI.Position lines[:, 2, 2]=zeros(0, 2, 2)
    "List of start and end points of cylinders resolved in an x-y frame defined by n_x, n_y, e.g., {[0,0;1,1], [0,1;1,0], [2,0; 3,1]}"
  input SI.Length diameter(min=0) = 0.05
    "Diameter of the cylinders defined by lines"
  input Modelica.Mechanics.MultiBody.Types.Color color={0,128,255}
    "Color of cylinders"
  input Types.SpecularCoefficient specularCoefficient = 0.7
    "Reflection of ambient light (= 0: light is completely absorbed)"
protected
  parameter Integer n=size(lines, 1) "Number of cylinders";
  T.Orientation R_rel=T.from_nxy(n_x, n_y);
  T.Orientation R_lines=T.absoluteRotation(R.T, R_rel);
  SI.Position r_abs[3]=r + T.resolve1(R.T, r_lines);
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape cylinders[n](
    each shapeType="cylinder",
    lengthDirection={T.resolve1(R_rel, vector([lines[i, 2, :] - lines[i, 1, :]; 0])) for i in 1:n},
    length={Modelica.Math.Vectors.length(lines[i, 2, :] - lines[i, 1, :]) for i in 1:n},
    r={r_abs + T.resolve1(R_lines, vector([lines[i, 1, :]; 0])) for i in 1:n},
    each width=diameter,
    each height=diameter,
    each widthDirection={0,1,0},
    each color=color,
    each R=R,
    each specularCoefficient=specularCoefficient);

end Lines;


within Modelica.Mechanics.MultiBody.Visualizers;
package Internal "Makeshift visualizers for display of three-dimensional fonts using cylinders"

  extends Modelica.Icons.InternalPackage;
end Internal;


within Modelica.Mechanics;
package Rotational "Library to model 1-dimensional, rotational mechanical systems"
  extends Modelica.Icons.Package;
end Rotational;


Signal adaptor for a Rotational flange with torque as output and angle, speed, and optionally acceleration as inputs (especially useful for FMUs). Flange flange is forced to move relative to flange support with a predefined motion
according to the input signal u

within Modelica.Mechanics.Rotational.Components;
model AngleToTorqueAdaptor
  "Signal adaptor for a Rotational flange with torque as output and angle, speed, and optionally acceleration as inputs (especially useful for FMUs)"
  parameter Boolean use_w=true
    "= true, enable the input connector w (angular velocity)"
  parameter Boolean use_a=true
    "= true, enable the input connector a (angular acceleration)"
  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange
  Modelica.Blocks.Interfaces.RealInput phi(unit="rad")
    "Angle to drive the flange"
  Modelica.Blocks.Interfaces.RealInput w(unit="rad/s") if use_w or use_a
    "Speed to drive the flange (w=der(phi) required)"
  Modelica.Blocks.Interfaces.RealInput a(unit="rad/s2") if use_a
    "Angular acceleration to drive the flange (a = der(w) required)"
  Modelica.Blocks.Interfaces.RealOutput tau(unit="N.m")
    "Torque needed to drive the flange according to phi, w, a"

protected
  Modelica.Mechanics.Rotational.Sources.Move move if use_a
  Modelica.Blocks.Routing.Multiplex3 multiplex3 if use_a
  Modelica.Mechanics.Rotational.Sensors.TorqueSensor torqueSensor

  Modelica.Blocks.Routing.Multiplex2 multiplex2 if use_w and not use_a
  Move_phi move_phi if not use_w and not use_a
  Move_w move_w if use_w and not use_a

  model Move_phi "Forced movement of a flange according to an angle signal"
    extends Modelica.Mechanics.Rotational.Interfaces.PartialElementaryOneFlangeAndSupport2;

    Modelica.Blocks.Interfaces.RealInput phi(
      final quantity="Angle",
      final unit="rad",
      displayUnit="deg") "Rotation angle of flange with respect to support"
  equation
    phi = flange.phi - phi_support;
  end Move_phi;

  model Move_w
    "Forced movement of a flange according to an angle and speed signal"
    extends Modelica.Mechanics.Rotational.Interfaces.PartialElementaryOneFlangeAndSupport2;

    SI.Angle phi
      "Rotation angle of flange with respect to support";
    Modelica.Blocks.Interfaces.RealInput u[2]
      "Angle and angular velocity of flange with respect to support as input signals"
  protected
    function position
      extends Modelica.Icons.Function;
      input Real q_qd[2] "Required values for position and speed";
      input Real dummy
        "Just to have one input signal that should be differentiated to avoid possible problems in the Modelica tool (is not used)";
      output Real q;
    algorithm
      q := q_qd[1];
    end position;

    function position_der
      extends Modelica.Icons.Function;
      input Real q_qd[2] "Required values for position and speed";
      input Real dummy
        "Just to have one input signal that should be differentiated to avoid possible problems in the Modelica tool (is not used)";
      input Real dummy_der;
      output Real qd;
    algorithm
      qd := q_qd[2];
    end position_der;
  equation
    phi = flange.phi - phi_support;
    phi = position(u, time);
  end Move_w;
equation
  connect(multiplex3.y, move.u)
  connect(phi, multiplex3.u1[1])
  connect(w, multiplex3.u2[1])
  connect(a, multiplex3.u3[1])
  connect(flange, torqueSensor.flange_b)
  connect(move.flange, torqueSensor.flange_a)
  connect(torqueSensor.tau, tau)
  connect(multiplex2.y, move_w.u)
  connect(phi, multiplex2.u1[1])
  connect(w, multiplex2.u2[1])
  connect(move_w.flange, torqueSensor.flange_a)
  connect(phi, move_phi.phi)
  connect(move_phi.flange, torqueSensor.flange_a)
end AngleToTorqueAdaptor;


Coulomb friction in bearings. This element describes Coulomb friction in bearings,
i.e., a frictional torque acting between a flange and the housing.
The positive sliding friction torque \"tau\" has to be defined
by table \"tau_pos\" as function of the absolute angular velocity \"w\".
E.g.

within Modelica.Mechanics.Rotational.Components;
model BearingFriction "Coulomb friction in bearings"
  extends Modelica.Mechanics.Rotational.Interfaces.PartialElementaryTwoFlangesAndSupport2;

  import Modelica.Blocks.Types.{ExternalCombiTable1D, Extrapolation, Smoothness};
  import Modelica.Blocks.Tables.Internal.{getTable1DValue, getTable1DValueNoDer, getTable1DValueNoDer2};

  parameter Real tau_pos[:, 2]=[0, 1]
    "Positive sliding friction characteristic [N.m] as function of w [rad/s] (w>=0)";
  parameter Smoothness smoothness = Smoothness.LinearSegments
    "Smoothness of interpolation in tau_pos table";
  parameter Real peak(final min=1) = 1
    "Peak for maximum friction torque at w==0 (tau0_max = peak*tau_pos[1,2])";

  extends Rotational.Interfaces.PartialFriction;
  extends
    Modelica.Thermal.HeatTransfer.Interfaces.PartialElementaryConditionalHeatPortWithoutT;

  SI.Angle phi
    "Angle between shaft flanges (flange_a, flange_b) and support";
  SI.Torque tau "Friction torque";
  SI.AngularVelocity w "Absolute angular velocity of flange_a and flange_b";
  SI.AngularAcceleration a
    "Absolute angular acceleration of flange_a and flange_b";

protected
  final parameter ExternalCombiTable1D tableID = ExternalCombiTable1D(
    tableName="NoName",
    fileName="NoName",
    table=tau_pos,
    columns={2},
    smoothness=smoothness,
    extrapolation=Extrapolation.LastTwoPoints,
    verboseRead=false) "External table object for sliding friction coefficient";

  Real table_signs[2]
    "Signs for sliding friction coefficient table interpolation: [sign for w, sign for tau]";

equation
  assert(size(tau_pos, 1) > 0 and size(tau_pos, 2) > 0, "Parameter tau_pos is an empty matrix");

  // Constant auxiliary variables
  tau0 =
    if     smoothness == Smoothness.ConstantSegments then getTable1DValueNoDer(tableID, 1, 0)
    elseif smoothness == Smoothness.LinearSegments   then getTable1DValueNoDer2(tableID, 1, 0)
    else                                                  getTable1DValue(tableID, 1, 0);
  tau0_max = peak*tau0;
  free = false;

  phi = flange_a.phi - phi_support;
  flange_b.phi = flange_a.phi;

  // Angular velocity and angular acceleration of flanges
  w = der(phi);
  a = der(w);
  w_relfric = w;
  a_relfric = a;

  // Friction torque
  flange_a.tau + flange_b.tau - tau = 0;

  // Friction torque
  table_signs =
    if     startForward         then { 1, 1}
    elseif startBackward        then {-1,-1}
    elseif pre(mode) == Forward then { 1, 1}
    else                             {-1,-1};
  tau = if locked then sa*unitTorque else table_signs[2]*(
    if     smoothness == Smoothness.ConstantSegments then getTable1DValueNoDer(tableID, 1, table_signs[1]*w)
    elseif smoothness == Smoothness.LinearSegments   then getTable1DValueNoDer2(tableID, 1, table_signs[1]*w)
    else                                                  getTable1DValue(tableID, 1, table_signs[1]*w));
  lossPower = tau*w_relfric;
end BearingFriction;