Revolute joint where the rotation angle is computed from a length constraint (1 degree-of-freedom, no potential state). Joint where frame_b rotates around axis n which is fixed in frame_a.
The two frames coincide when \"phi + phi_offset = 0\", where
\"phi_offset\" is a parameter with a zero default
and \"phi\" is the rotation angle.

within Modelica.Mechanics.MultiBody.Joints.Internal;
model RevoluteWithLengthConstraint
  "Revolute joint where the rotation angle is computed from a length constraint (1 degree-of-freedom, no potential state)"

  extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames;
  Modelica.Mechanics.Rotational.Interfaces.Flange_a axis
    "1-dim. rotational flange that drives the joint"
  Modelica.Mechanics.Rotational.Interfaces.Flange_b bearing
    "1-dim. rotational flange of the drive bearing"

  Modelica.Blocks.Interfaces.RealInput position_a[3](each final quantity="Length", each final unit="m")
    "Position vector from frame_a to frame_a side of length constraint, resolved in frame_a of revolute joint"
  Modelica.Blocks.Interfaces.RealInput position_b[3](each final quantity="Length", each final unit="m")
    "Position vector from frame_b to frame_b side of length constraint, resolved in frame_b of revolute joint"

  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter SI.Position lengthConstraint(start=1)
    "Fixed length of length constraint";
  parameter Modelica.Mechanics.MultiBody.Types.Axis n={0,0,1}
    "Axis of rotation resolved in frame_a (= same as in frame_b)"
  parameter Modelica.Units.NonSI.Angle_deg phi_offset=0
    "Relative angle offset (angle = phi + from_deg(phi_offset))";
  parameter Modelica.Units.NonSI.Angle_deg phi_guess=0
    "Select the configuration such that at initial time |phi - from_deg(phi_guess)| is minimal";
  parameter SI.Distance cylinderLength=world.defaultJointLength
    "Length of cylinder representing the joint axis"
  parameter SI.Distance cylinderDiameter=world.defaultJointWidth
    "Diameter of cylinder representing the joint axis"
  input Types.Color cylinderColor=Modelica.Mechanics.MultiBody.Types.Defaults.JointColor
    "Color of cylinder representing the joint axis"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

  final parameter Boolean positiveBranch(fixed=false)
    "Based on phi_guess, selection of one of the two solutions of the non-linear constraint equation";
  final parameter Real e[3](each final unit="1")=Modelica.Math.Vectors.normalizeWithAssert(n)
    "Unit vector in direction of rotation axis, resolved in frame_a";

  SI.Angle phi "Rotation angle of revolute joint";
  Frames.Orientation R_rel
    "Relative orientation object from frame_a to frame_b";
  SI.Angle angle
    "= phi + from_deg(phi_offset) (relative rotation angle between frame_a and frame_b)";
  SI.Torque tau "= axis.tau (driving torque in the axis)";

protected
  SI.Position r_a[3]=position_a
    "Position vector from frame_a to frame_a side of length constraint, resolved in frame_a of revolute joint";
  SI.Position r_b[3]=position_b
    "Position vector from frame_b to frame_b side of length constraint, resolved in frame_b of revolute joint";
  Real e_r_a "Projection of r_a on e";
  Real e_r_b "Projection of r_b on e";
  Real A "Coefficient A of equation: A*cos(phi) + B*sin(phi) + C = 0";
  Real B "Coefficient B of equation: A*cos(phi) + B*sin(phi) + C = 0";
  Real C "Coefficient C of equation: A*cos(phi) + B*sin(phi) + C = 0";
  Real k1 "Constant of quadratic equation";
  Real k2 "Constant of quadratic equation";
  Real k1a(start=1);
  Real k1b;
  Real kcos_angle "= k1*cos(angle)";
  Real ksin_angle "= k1*sin(angle)";

  Visualizers.Advanced.Shape cylinder(
    shapeType="cylinder",
    color=cylinderColor,
    specularCoefficient=specularCoefficient,
    length=cylinderLength,
    width=cylinderDiameter,
    height=cylinderDiameter,
    lengthDirection=e,
    widthDirection={0,1,0},
    r_shape=-e*(cylinderLength/2),
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;

  function selectBranch
    "Determine branch which is closest to initial angle=0"
    extends Modelica.Icons.Function;
    input SI.Length L "Length of length constraint";
    input Real e[3](each final unit="1")
      "Unit vector along axis of rotation, resolved in frame_a (= same in frame_b)";
    input SI.Angle angle_guess
      "Select the configuration such that at initial time |angle-angle_guess| is minimal (angle=0: frame_a and frame_b coincide)";
    input SI.Position r_a[3]
      "Position vector from frame_a to frame_a side of length constraint, resolved in frame_a of revolute joint";
    input SI.Position r_b[3]
      "Position vector from frame_b to frame_b side of length constraint, resolved in frame_b of revolute joint";
    output Boolean positiveBranch "Branch of the initial solution";
  protected
    Real e_r_a "Projection of r_a on e";
    Real e_r_b "Projection of r_b on e";
    Real A "Coefficient A of equation: A*cos(phi) + B*sin(phi) + C = 0";
    Real B "Coefficient B of equation: A*cos(phi) + B*sin(phi) + C = 0";
    Real C "Coefficient C of equation: A*cos(phi) + B*sin(phi) + C = 0";
    Real k1 "Constant of quadratic equation";
    Real k2 "Constant of quadratic equation";
    Real k1a;
    Real k1b;
    Real kcos1 "k1*cos(angle1)";
    Real ksin1 "k1*sin(angle1)";
    Real kcos2 "k2*cos(angle2)";
    Real ksin2 "k2*sin(angle2)";
    SI.Angle angle1 "Solution 1 of nonlinear equation";
    SI.Angle angle2 "Solution 2 of nonlinear equation";
  algorithm
    /* The position vector r_rel from frame_a to frame_b of the length constraint
       element, resolved in frame_b of the revolute joint is given by
       (T_rel is the planar transformation matrix from frame_a to frame_b of
        the revolute joint):
          r_rel = r_b - T_rel*r_a
       The length constraint can therefore be formulated as:
          r_rel*r_rel = L*L
       with
          (r_b - T_rel*r_a)*(r_b - T_rel*r_a)
             = r_b*r_b - 2*r_b*T_rel*r_a + r_a*transpose(T_rel)*T_rel*r_a
             = r_b*r_b + r_a*r_a - 2*r_b*T_rel*r_a
       follows
          (1) 0 = r_a*r_a + r_b*r_b - 2*r_b*T_rel*r_a - L*L
       The vectors r_a, r_b and parameter L are NOT a function of
       the angle of the revolute joint. Since T_rel = T_rel(angle) is a function
       of the unknown angle of the revolute joint, this is a non-linear
       equation in this angle.
          T_rel = [e]*transpose([e]) + (identity(3) - [e]*transpose([e]))*cos(angle)
                  - skew(e)*sin(angle);
       with
          r_b*T_rel*r_a
             = r_b*(e*(e*r_a) + (r_a - e*(e*r_a))*cos(angle) - cross(e,r_a)*sin(angle)
             = (e*r_b)*(e*r_a) + (r_b*r_a - (e*r_b)*(e*r_a))*cos(angle) - r_b*cross(e,r_a)*sin(angle)
       follows for the constraint equation (1)
          (2) 0 = r_a*r_a + r_b*r_b - L*L
                  - 2*(e*r_b)*(e*r_a)
                  - 2*(r_b*r_a - (e*r_b)*(e*r_a))*cos(angle)
                  + 2*r_b*cross(e,r_a)*sin(angle)
       or
          (3) A*cos(angle) + B*sin(angle) + C = 0
       with
              A = -2*(r_b*r_a - (e*r_b)*(e*r_a))
              B = 2*r_b*cross(e,r_a)
              C = r_a*r_a + r_b*r_b - L*L - 2*(e*r_b)*(e*r_a)
       Equation (3) is solved by computing sin(angle) and cos(angle)
       independently from each other. This allows to compute
       angle in the range: -180 deg <= angle <= 180 deg
    */
    e_r_a := e*r_a;
    e_r_b := e*r_b;
    A := -2*(r_b*r_a - e_r_b*e_r_a);
    B := 2*r_b*cross(e, r_a);
    C := r_a*r_a + r_b*r_b - L*L - 2*e_r_b*e_r_a;
    k1 := A*A + B*B;
    k1a :=k1 - C*C;
    assert(k1a > 1e-10, "
Singular position of loop (either no or two analytic solutions;
the mechanism has lost one-degree-of freedom in this position).
Try first to use another Modelica.Mechanics.MultiBody.Joints.Assemblies.JointXXX component.
In most cases it is best that the joints outside of the JointXXX
component are revolute and NOT prismatic joints. If this also
lead to singular positions, it could be that this kinematic loop
cannot be solved analytically. In this case you have to build
up the loop with basic joints (NO aggregation JointXXX components)
and rely on dynamic state selection, i.e., during simulation
the states will be dynamically selected in such a way that in no
position a degree of freedom is lost.
"); k1b := max(k1a, 1.0e-12);
    k2 := sqrt(k1b);

    kcos1 := -A*C + B*k2;
    ksin1 := -B*C - A*k2;
    angle1 := Modelica.Math.atan2(ksin1, kcos1);

    kcos2 := -A*C - B*k2;
    ksin2 := -B*C + A*k2;
    angle2 := Modelica.Math.atan2(ksin2, kcos2);

    if abs(angle1 - angle_guess) <= abs(angle2 - angle_guess) then
      positiveBranch := true;
    else
      positiveBranch := false;
    end if;
  end selectBranch;
initial equation
  positiveBranch = selectBranch(lengthConstraint, e, Cv.from_deg(phi_offset
     + phi_guess), r_a, r_b);
equation
  Connections.branch(frame_a.R, frame_b.R);
  axis.tau = tau;
  axis.phi = phi;
  bearing.phi = 0;

  angle = Cv.from_deg(phi_offset) + phi;

  // transform kinematic quantities from frame_a to frame_b
  frame_b.r_0 = frame_a.r_0;

  R_rel = Frames.planarRotation(e, angle, der(angle));
  frame_b.R = Frames.absoluteRotation(frame_a.R, R_rel);

  // Force and torque balance
  zeros(3) = frame_a.f + Frames.resolve1(R_rel, frame_b.f);
  zeros(3) = frame_a.t + Frames.resolve1(R_rel, frame_b.t);

  // Compute rotation angle (details, see function "selectBranch")
  e_r_a = e*r_a;
  e_r_b = e*r_b;
  A = -2*(r_b*r_a - e_r_b*e_r_a);
  B = 2*r_b*cross(e, r_a);
  C = r_a*r_a + r_b*r_b - lengthConstraint*lengthConstraint - 2*e_r_b*e_r_a;
  k1 = A*A + B*B;
  k1a = k1 - C*C;

  assert(k1a > 1e-10, "
Singular position of loop (either no or two analytic solutions;
the mechanism has lost one-degree-of freedom in this position).
Try first to use another Modelica.Mechanics.MultiBody.Joints.Assemblies.JointXXX component.
In most cases it is best that the joints outside of the JointXXX
component are revolute and NOT prismatic joints. If this also
lead to singular positions, it could be that this kinematic loop
cannot be solved analytically. In this case you have to build
up the loop with basic joints (NO aggregation JointXXX components)
and rely on dynamic state selection, i.e., during simulation
the states will be dynamically selected in such a way that in no
position a degree of freedom is lost.
");

  k1b = Frames.Internal.maxWithoutEvent(k1a, 1.0e-12);
  k2 = sqrt(k1b);
  kcos_angle = -A*C + (if positiveBranch then B else -B)*k2;
  ksin_angle = -B*C + (if positiveBranch then -A else A)*k2;

  angle = Modelica.Math.atan2(ksin_angle, kcos_angle);
end RevoluteWithLengthConstraint;


Rolling constraint for wheel that is always perpendicular to x-y plane. Joint for a wheel rolling on the x-y plane of the world frame
intended for an idealized wheelset.
To meet this objective, the wheel always runs upright and enables no
slip in the longitudinal direction of the wheel/ground contact.

within Modelica.Mechanics.MultiBody.Joints.Internal;
model RollingConstraintVerticalWheel
 "Rolling constraint for wheel that is always perpendicular to x-y plane"
 import Modelica.Mechanics.MultiBody.Frames;

   Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
   "Frame fixed in wheel center point. x-Axis: upwards, y-axis: along wheel axis"

   parameter SI.Radius radius "Wheel radius";

   parameter Boolean lateralSlidingConstraint = true
   "= true, if lateral sliding constraint taken into account, = false if lateral force = 0 (needed to avoid overconstraining if two ideal rolling wheels are connect on one axis)"

   // Contact force
   SI.Force f_wheel_0[3]
   "Contact force acting on wheel, resolved in world frame";
   SI.Force f_lat "Contact force acting on wheel in lateral direction";
   SI.Force f_long
   "Contact force acting on wheel in longitudinal direction";
protected
    Real e_axis_0[3]
   "Unit vector along wheel axis, resolved in world frame";
    SI.Position rContact_0[3]
   "Distance vector from wheel center to contact point, resolved in world frame";

    // Coordinate system at contact point
    Real e_n_0[3]
   "Unit vector in normal direction of road at contact point, resolved in world frame";
    Real e_lat_0[3]
   "Unit vector in lateral direction of wheel at contact point, resolved in world frame";
    Real e_long_0[3]
   "Unit vector in longitudinal direction of wheel at contact point, resolved in world frame";

    // Slip velocities
    SI.Velocity v_0[3] "Velocity of wheel center, resolved in world frame";
    SI.AngularVelocity w_0[3]
   "Angular velocity of wheel, resolved in world frame";

    SI.Velocity vContact_0[3]
   "Velocity of wheel contact point, resolved in world frame";

    // Utility vectors
    Real aux[3];

equation
    // Coordinate system at contact point (e_long_0, e_lat_0, e_n_0)
    e_n_0    = {0,0,1};
    e_axis_0 = Frames.resolve1(frame_a.R, {0,1,0});
    aux      = cross(e_n_0, e_axis_0);
    e_long_0 = aux / Modelica.Math.Vectors.length(aux);
    e_lat_0  = cross(e_long_0, e_n_0);

    // Slip velocities
    rContact_0 = {0,0,-radius};
    v_0 = der(frame_a.r_0);
    w_0 = Frames.angularVelocity1(frame_a.R);
    vContact_0 = v_0 + cross(w_0, rContact_0);

    // Two non-holonomic constraint equations on velocity level (ideal rolling, no slippage)
    0 = vContact_0*e_long_0;
    if lateralSlidingConstraint then
       0 = vContact_0*e_lat_0;
       f_wheel_0 = f_lat*e_lat_0 + f_long*e_long_0;
    else
       0 = f_lat;
       f_wheel_0 = f_long*e_long_0;
    end if;

    // Force and torque balance at the wheel center
    zeros(3) = frame_a.f + Frames.resolve2(frame_a.R, f_wheel_0);
    zeros(3) = frame_a.t + Frames.resolve2(frame_a.R, cross(rContact_0, f_wheel_0));
</pre></blockquote>
</html>"));
end RollingConstraintVerticalWheel;


1D gearbox with arbitrary shaft directions and 3-dim. bearing frame (3D dynamic effects are taken into account provided world.driveTrainMechanics3D=true). This component is used to model a 1-dim. gearbox
with non-parallel axes (defined by parameters n_a, n_b).
A 3-dim. bearing frame is necessary to reflect the
correct support torque, as the axes of rotation of flange_a and
flange_b and the direction of the support torque vector
are different in general.

within Modelica.Mechanics.MultiBody.Parts;
model BevelGear1D
  "1D gearbox with arbitrary shaft directions and 3-dim. bearing frame (3D dynamic effects are taken into account provided world.driveTrainMechanics3D=true)"
  extends Modelica.Mechanics.Rotational.Interfaces.PartialTwoFlanges;

  parameter Real ratio(start=1) "Gear speed ratio";
  parameter Modelica.Mechanics.MultiBody.Types.Axis n_a={1,0,0}
    "Axis of rotation of flange_a, resolved in frame_a"
  parameter Modelica.Mechanics.MultiBody.Types.Axis n_b={1,0,0}
    "Axis of rotation of flange_b, resolved in frame_a"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a if world.driveTrainMechanics3D
    "Bearing frame"

protected
  outer World world;
  parameter Real e_a[3](each final unit="1")=
    Modelica.Math.Vectors.normalizeWithAssert(n_a)
    "Unit vector in direction of flange_a rotation axis";
  parameter Real e_b[3](each final unit="1")=
    Modelica.Math.Vectors.normalizeWithAssert(n_b)
    "Unit vector in direction of flange_b rotation axis";
  encapsulated model Housing
    import Modelica;
    input Modelica.Units.SI.Torque t[3];
    Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
  equation
    frame_a.f = zeros(3);
    frame_a.t = t;
  end Housing;
  Housing housing(t=-flange_a.tau*e_a - flange_b.tau*e_b) if world.driveTrainMechanics3D

equation
  flange_a.phi = ratio*flange_b.phi;
  0 = ratio*flange_a.tau + flange_b.tau;
  connect(housing.frame_a, frame_a)
end BevelGear1D;


Rigid body with mass, inertia tensor and one frame connector (12 potential states). Rigid body with mass and inertia tensor.
All parameter vectors have to be resolved in frame_a.
The inertia tensor has to be defined with respect to a
coordinate system that is parallel to frame_a with the
origin at the center of mass of the body.

within Modelica.Mechanics.MultiBody.Parts;
model Body
  "Rigid body with mass, inertia tensor and one frame connector (12 potential states)"

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

  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
    "Coordinate system fixed at body"
  parameter Boolean animation=true
    "= true, if animation shall be enabled (show cylinder and sphere)";
  parameter SI.Position r_CM[3](start={0,0,0})
    "Vector from frame_a to center of mass, resolved in frame_a";
  parameter SI.Mass m(min=0, start=1) "Mass of rigid body";
  parameter SI.Inertia I_11(min=0) = 0.001 "Element (1,1) of inertia tensor"
  parameter SI.Inertia I_22(min=0) = 0.001 "Element (2,2) of inertia tensor"
  parameter SI.Inertia I_33(min=0) = 0.001 "Element (3,3) of inertia tensor"
  parameter SI.Inertia I_21(min=-C.inf) = 0 "Element (2,1) of inertia tensor"
  parameter SI.Inertia I_31(min=-C.inf) = 0 "Element (3,1) of inertia tensor"
  parameter SI.Inertia I_32(min=-C.inf) = 0 "Element (3,2) of inertia tensor"

  SI.Position r_0[3](start={0,0,0}, each stateSelect=if enforceStates then
        StateSelect.always else StateSelect.avoid)
    "Position vector from origin of world frame to origin of frame_a"
  SI.Velocity v_0[3](start={0,0,0}, each stateSelect=if enforceStates then
        StateSelect.always else StateSelect.avoid)
    "Absolute velocity of frame_a, resolved in world frame (= der(r_0))"
  SI.Acceleration a_0[3](start={0,0,0})
    "Absolute acceleration of frame_a resolved in world frame (= der(v_0))"

  parameter Boolean angles_fixed=false
    "= true, if angles_start are used as initial values, else as guess values"
  parameter SI.Angle angles_start[3]={0,0,0}
    "Initial values of angles to rotate world frame around 'sequence_start' axes into frame_a"
  parameter Types.RotationSequence sequence_start={1,2,3}
    "Sequence of rotations to rotate world frame into frame_a at initial time"

  parameter Boolean w_0_fixed=false
    "= true, if w_0_start are used as initial values, else as guess values"
  parameter SI.AngularVelocity w_0_start[3]={0,0,0}
    "Initial or guess values of angular velocity of frame_a resolved in world frame"

  parameter Boolean z_0_fixed=false
    "= true, if z_0_start are used as initial values, else as guess values"
  parameter SI.AngularAcceleration z_0_start[3]={0,0,0}
    "Initial values of angular acceleration z_0 = der(w_0)"

  parameter SI.Diameter sphereDiameter=world.defaultBodyDiameter
    "Diameter of sphere"
  input Types.Color sphereColor=Modelica.Mechanics.MultiBody.Types.Defaults.BodyColor
    "Color of sphere"
  parameter SI.Diameter cylinderDiameter=sphereDiameter/Types.Defaults.BodyCylinderDiameterFraction
    "Diameter of cylinder"
  input Types.Color cylinderColor=sphereColor "Color of cylinder"
  input Types.SpecularCoefficient specularCoefficient=world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  parameter Boolean enforceStates=false
    "= true, if absolute variables of body object shall be used as states (StateSelect.always)"
  parameter Boolean useQuaternions=true
    "= true, if quaternions shall be used as potential states otherwise use 3 angles as potential states"
  parameter Types.RotationSequence sequence_angleStates={1,2,3}
    "Sequence of rotations to rotate world frame into frame_a around the 3 angles used as potential states"

  final parameter SI.Inertia I[3, 3]=[I_11, I_21, I_31; I_21, I_22, I_32;
      I_31, I_32, I_33] "Inertia tensor";
  final parameter Frames.Orientation R_start=
      Modelica.Mechanics.MultiBody.Frames.axesRotations(
        sequence_start,
        angles_start,
        zeros(3))
    "Orientation object from world frame to frame_a at initial time";

  SI.AngularVelocity w_a[3](
    start=Frames.resolve2(R_start, w_0_start),
    fixed=fill(w_0_fixed, 3),
    each stateSelect=if enforceStates then (if useQuaternions then
        StateSelect.always else StateSelect.never) else StateSelect.avoid)
    "Absolute angular velocity of frame_a resolved in frame_a";
  SI.AngularAcceleration z_a[3](start=Frames.resolve2(R_start, z_0_start),
      fixed=fill(z_0_fixed, 3))
    "Absolute angular acceleration of frame_a resolved in frame_a";
  SI.Acceleration g_0[3] "Gravity acceleration resolved in world frame";

protected
  outer Modelica.Mechanics.MultiBody.World world;

  // Declarations for quaternions (dummies, if quaternions are not used)
  parameter Frames.Quaternions.Orientation Q_start=Frames.to_Q(R_start)
    "Quaternion orientation object from world frame to frame_a at initial time";
  Frames.Quaternions.Orientation Q(start=Q_start, each stateSelect=if
        enforceStates then (if useQuaternions then StateSelect.prefer else
        StateSelect.never) else StateSelect.avoid)
    "Quaternion orientation object from world frame to frame_a (dummy value, if quaternions are not used as states)";

  // Declaration for 3 angles
  parameter SI.Angle phi_start[3]=if sequence_start[1] ==
      sequence_angleStates[1] and sequence_start[2] == sequence_angleStates[2]
       and sequence_start[3] == sequence_angleStates[3] then angles_start
       else Frames.axesRotationsAngles(R_start, sequence_angleStates)
    "Potential angle states at initial time";
  SI.Angle phi[3](start=phi_start, each stateSelect=if enforceStates then (
        if useQuaternions then StateSelect.never else StateSelect.always)
         else StateSelect.avoid)
    "Dummy or 3 angles to rotate world frame into frame_a of body";
  SI.AngularVelocity phi_d[3](each stateSelect=if enforceStates then (if
        useQuaternions then StateSelect.never else StateSelect.always) else
        StateSelect.avoid) "= der(phi)";
  SI.AngularAcceleration phi_dd[3] "= der(phi_d)";

  // Declarations for animation
  Visualizers.Advanced.Shape cylinder(
    shapeType="cylinder",
    color=cylinderColor,
    specularCoefficient=specularCoefficient,
    length=if Modelica.Math.Vectors.length(r_CM) > sphereDiameter/2 then
        Modelica.Math.Vectors.length(r_CM) - (if cylinderDiameter > 1.1*
        sphereDiameter then sphereDiameter/2 else 0) else 0,
    width=cylinderDiameter,
    height=cylinderDiameter,
    lengthDirection = to_unit1(r_CM),
    widthDirection={0,1,0},
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
  Visualizers.Advanced.Shape sphere(
    shapeType="sphere",
    color=sphereColor,
    specularCoefficient=specularCoefficient,
    length=sphereDiameter,
    width=sphereDiameter,
    height=sphereDiameter,
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    r_shape=r_CM - {1,0,0}*sphereDiameter/2,
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation and sphereDiameter >
    0;
initial equation
  if angles_fixed then
    // Initialize positional variables
    if not Connections.isRoot(frame_a.R) then
      // frame_a.R is computed somewhere else
      zeros(3) = Frames.Orientation.equalityConstraint(frame_a.R, R_start);
    elseif useQuaternions then
      // frame_a.R is computed from quaternions Q
      zeros(3) = Frames.Quaternions.Orientation.equalityConstraint(Q, Q_start);
    else
      // frame_a.R is computed from the 3 angles 'phi'
      phi = phi_start;
    end if;
  end if;

equation
  if enforceStates then
    Connections.root(frame_a.R);
  else
    Connections.potentialRoot(frame_a.R);
  end if;
  r_0 = frame_a.r_0;

  if not Connections.isRoot(frame_a.R) then
    // Body does not have states
    // Dummies
    Q = {0,0,0,1};
    phi = zeros(3);
    phi_d = zeros(3);
    phi_dd = zeros(3);
  elseif useQuaternions then
    // Use Quaternions as states (with dynamic state selection)
    frame_a.R = Frames.from_Q(Q, Frames.Quaternions.angularVelocity2(Q, der(Q)));
    {0} = Frames.Quaternions.orientationConstraint(Q);

    // Dummies
    phi = zeros(3);
    phi_d = zeros(3);
    phi_dd = zeros(3);
  else
    // Use Cardan angles as states
    phi_d = der(phi);
    phi_dd = der(phi_d);
    frame_a.R = Frames.axesRotations(
        sequence_angleStates,
        phi,
        phi_d);

    // Dummies
    Q = {0,0,0,1};
  end if;

  // gravity acceleration at center of mass resolved in world frame
  g_0 = world.gravityAcceleration(frame_a.r_0 + Frames.resolve1(frame_a.R,
    r_CM));

  // translational kinematic differential equations
  v_0 = der(frame_a.r_0);
  a_0 = der(v_0);

  // rotational kinematic differential equations
  w_a = Frames.angularVelocity2(frame_a.R);
  z_a = der(w_a);

  /* Newton/Euler equations with respect to center of mass
            a_CM = a_a + cross(z_a, r_CM) + cross(w_a, cross(w_a, r_CM));
            f_CM = m*(a_CM - g_a);
            t_CM = I*z_a + cross(w_a, I*w_a);
       frame_a.f = f_CM
       frame_a.t = t_CM + cross(r_CM, f_CM);
    Inserting the first three equations in the last two results in:
  */
  frame_a.f = m*(Frames.resolve2(frame_a.R, a_0 - g_0) + cross(z_a, r_CM) +
    cross(w_a, cross(w_a, r_CM)));
  frame_a.t = I*z_a + cross(w_a, I*w_a) + cross(r_CM, frame_a.f);
end Body;


Rigid body with box shape. Mass and animation properties are computed from box data and density (12 potential states). Rigid body with box shape.
The mass properties of the body (mass, center of mass,
inertia tensor) are computed
from the box data. Optionally, the box may be hollow.
The (outer) box shape is by default used in the animation.
The hollow part is not shown in the animation.
The two connector frames frame_a and frame_b
are always parallel to each other. Example of component
animation (note, that
the animation may be switched off via parameter animation = false):

within Modelica.Mechanics.MultiBody.Parts;
model BodyBox
  "Rigid body with box shape. Mass and animation properties are computed from box data and density (12 potential states)"

  import Modelica.Mechanics.MultiBody.Types;
  import Modelica.Math.Vectors.normalizeWithAssert;
  import Modelica.Units.Conversions.to_unit1;

  Interfaces.Frame_a frame_a
    "Coordinate system fixed to the component with one cut-force and cut-torque"
  Interfaces.Frame_b frame_b
    "Coordinate system fixed to the component with one cut-force and cut-torque"
  parameter Boolean animation=true
    "= true, if animation shall be enabled (show box between frame_a and frame_b)";
  parameter SI.Position r[3](start={0.1,0,0})
    "Vector from frame_a to frame_b resolved in frame_a";
  parameter SI.Position r_shape[3]={0,0,0}
    "Vector from frame_a to box origin, resolved in frame_a";
  parameter Modelica.Mechanics.MultiBody.Types.Axis lengthDirection=
     to_unit1(r - r_shape)
    "Vector in length direction of box, resolved in frame_a"
  parameter Modelica.Mechanics.MultiBody.Types.Axis widthDirection={0,1,0}
    "Vector in width direction of box, resolved in frame_a"
  parameter SI.Length length=Modelica.Math.Vectors.length(r - r_shape)
    "Length of box";
  parameter SI.Distance width=length/world.defaultWidthFraction
    "Width of box";
  parameter SI.Distance height=width "Height of box";
  parameter SI.Distance innerWidth=0
    "Width of inner box surface (0 <= innerWidth <= width)";
  parameter SI.Distance innerHeight=innerWidth
    "Height of inner box surface (0 <= innerHeight <= height)";
  parameter SI.Density density=7700
    "Density of cylinder (e.g., steel: 7700 .. 7900, wood : 400 .. 800)";
  input Modelica.Mechanics.MultiBody.Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.BodyColor
    "Color of box"
  input Types.SpecularCoefficient specularCoefficient=world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

  SI.Position r_0[3](start={0,0,0}, each stateSelect=if enforceStates then
        StateSelect.always else StateSelect.avoid)
    "Position vector from origin of world frame to origin of frame_a"
  SI.Velocity v_0[3](start={0,0,0}, each stateSelect=if enforceStates then
        StateSelect.always else StateSelect.avoid)
    "Absolute velocity of frame_a, resolved in world frame (= der(r_0))"
  SI.Acceleration a_0[3](start={0,0,0})
    "Absolute acceleration of frame_a resolved in world frame (= der(v_0))"

  parameter Boolean angles_fixed=false
    "= true, if angles_start are used as initial values, else as guess values"
  parameter SI.Angle angles_start[3]={0,0,0}
    "Initial values of angles to rotate world frame around 'sequence_start' axes into frame_a"
  parameter Types.RotationSequence sequence_start={1,2,3}
    "Sequence of rotations to rotate world frame into frame_a at initial time"

  parameter Boolean w_0_fixed=false
    "= true, if w_0_start are used as initial values, else as guess values"
  parameter SI.AngularVelocity w_0_start[3]={0,0,0}
    "Initial or guess values of angular velocity of frame_a resolved in world frame"

  parameter Boolean z_0_fixed=false
    "= true, if z_0_start are used as initial values, else as guess values"
  parameter SI.AngularAcceleration z_0_start[3]={0,0,0}
    "Initial values of angular acceleration z_0 = der(w_0)"

  parameter Boolean enforceStates=false
    "= true, if absolute variables of body object shall be used as states (StateSelect.always)"
  parameter Boolean useQuaternions=true
    "= true, if quaternions shall be used as potential states otherwise use 3 angles as potential states"
  parameter Types.RotationSequence sequence_angleStates={1,2,3}
    "Sequence of rotations to rotate world frame into frame_a around the 3 angles used as potential states"

  final parameter SI.Mass mo(min=0) = density*length*width*height
    "Mass of box without hole";
  final parameter SI.Mass mi(min=0) = density*length*innerWidth*innerHeight
    "Mass of hole of box";
  final parameter SI.Mass m(min=0) = mo - mi "Mass of box";
  final parameter Frames.Orientation R=Frames.from_nxy(r, widthDirection)
    "Orientation object from frame_a to coordinates system spanned by r and widthDirection";
  final parameter SI.Position r_CM[3]=r_shape +
      normalizeWithAssert(lengthDirection)*length/2
    "Position vector from origin of frame_a to center of mass, resolved in frame_a";
  final parameter SI.Inertia I[3, 3]=Frames.resolveDyade1(R, diagonal({mo*(
      width*width + height*height) - mi*(innerWidth*innerWidth + innerHeight*
      innerHeight),mo*(length*length + height*height) - mi*(length*length +
      innerHeight*innerHeight),mo*(length*length + width*width) - mi*(length*
      length + innerWidth*innerWidth)}/12))
    "Inertia tensor of body box with respect to center of mass, parallel to frame_a";
  Body body(
    animation=false,
    r_CM=r_CM,
    m=m,
    I_11=I[1, 1],
    I_22=I[2, 2],
    I_33=I[3, 3],
    I_21=I[2, 1],
    I_31=I[3, 1],
    I_32=I[3, 2],
    sequence_start=sequence_start,
    angles_fixed=angles_fixed,
    angles_start=angles_start,
    w_0_fixed=w_0_fixed,
    w_0_start=w_0_start,
    z_0_fixed=z_0_fixed,
    z_0_start=z_0_start,
    useQuaternions=useQuaternions,
    sequence_angleStates=sequence_angleStates,
    enforceStates=false)
  FixedTranslation frameTranslation(
    r=r,
    animation=animation,
    shapeType="box",
    r_shape=r_shape,
    lengthDirection=lengthDirection,
    widthDirection=widthDirection,
    length=length,
    width=width,
    height=height,
    color=color,
    specularCoefficient=specularCoefficient)

protected
  outer Modelica.Mechanics.MultiBody.World world;
equation
  r_0 = frame_a.r_0;
  v_0 = der(r_0);
  a_0 = der(v_0);

  assert(innerWidth <= width,
    "parameter innerWidth is greater than parameter width");
  assert(innerHeight <= height,
    "parameter innerHeight is greater than parameter height");
  connect(frameTranslation.frame_a, frame_a)
  connect(frameTranslation.frame_b, frame_b)
  connect(frame_a, body.frame_a)
end BodyBox;


Rigid body with cylinder shape. Mass and animation properties are computed from cylinder data and density (12 potential states). Rigid body with cylinder shape.
The mass properties of the body (mass, center of mass,
inertia tensor) are computed
from the cylinder data. Optionally, the cylinder may be hollow.
The cylinder shape is by default used in the animation.
The two connector frames frame_a and frame_b
are always parallel to each other. Example of component
animation (note, that
the animation may be switched off via parameter animation = false):

within Modelica.Mechanics.MultiBody.Parts;
model BodyCylinder
  "Rigid body with cylinder shape. Mass and animation properties are computed from cylinder data and density (12 potential states)"

  import Modelica.Units.NonSI;
  import Modelica.Mechanics.MultiBody.Types;
  import Modelica.Math.Vectors.normalizeWithAssert;
  import Modelica.Units.Conversions.to_unit1;
  import Modelica.Constants.pi;

  Interfaces.Frame_a frame_a
    "Coordinate system fixed to the component with one cut-force and cut-torque"
  Interfaces.Frame_b frame_b
    "Coordinate system fixed to the component with one cut-force and cut-torque"
  parameter Boolean animation=true
    "= true, if animation shall be enabled (show cylinder between frame_a and frame_b)";
  parameter SI.Position r[3](start={0.1,0,0})
    "Vector from frame_a to frame_b, resolved in frame_a";
  parameter SI.Position r_shape[3]={0,0,0}
    "Vector from frame_a to cylinder origin, resolved in frame_a";
  parameter Modelica.Mechanics.MultiBody.Types.Axis lengthDirection=
    to_unit1(r - r_shape)
    "Vector in length direction of cylinder, resolved in frame_a"
  parameter SI.Length length=Modelica.Math.Vectors.length(r - r_shape)
    "Length of cylinder";
  parameter SI.Distance diameter=length/world.defaultWidthFraction
    "Diameter of cylinder";
  parameter SI.Distance innerDiameter=0
    "Inner diameter of cylinder (0 <= innerDiameter <= Diameter)";
  parameter SI.Density density=7700
    "Density of cylinder (e.g., steel: 7700 .. 7900, wood : 400 .. 800)";
  input Modelica.Mechanics.MultiBody.Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.BodyColor
    "Color of cylinder"
  input Types.SpecularCoefficient specularCoefficient=world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

  SI.Position r_0[3](start={0,0,0}, each stateSelect=if enforceStates then
        StateSelect.always else StateSelect.avoid)
    "Position vector from origin of world frame to origin of frame_a"
  SI.Velocity v_0[3](start={0,0,0}, each stateSelect=if enforceStates then
        StateSelect.always else StateSelect.avoid)
    "Absolute velocity of frame_a, resolved in world frame (= der(r_0))"
  SI.Acceleration a_0[3](start={0,0,0})
    "Absolute acceleration of frame_a resolved in world frame (= der(v_0))"

  parameter Boolean angles_fixed=false
    "= true, if angles_start are used as initial values, else as guess values"
  parameter SI.Angle angles_start[3]={0,0,0}
    "Initial values of angles to rotate world frame around 'sequence_start' axes into frame_a"
  parameter Types.RotationSequence sequence_start={1,2,3}
    "Sequence of rotations to rotate world frame into frame_a at initial time"

  parameter Boolean w_0_fixed=false
    "= true, if w_0_start are used as initial values, else as guess values"
  parameter SI.AngularVelocity w_0_start[3]={0,0,0}
    "Initial or guess values of angular velocity of frame_a resolved in world frame"

  parameter Boolean z_0_fixed=false
    "= true, if z_0_start are used as initial values, else as guess values"
  parameter SI.AngularAcceleration z_0_start[3]={0,0,0}
    "Initial values of angular acceleration z_0 = der(w_0)"

  parameter Boolean enforceStates=false
    "= true, if absolute variables of body object shall be used as states (StateSelect.always)"
  parameter Boolean useQuaternions=true
    "= true, if quaternions shall be used as potential states otherwise use 3 angles as potential states"
  parameter Types.RotationSequence sequence_angleStates={1,2,3}
    "Sequence of rotations to rotate world frame into frame_a around the 3 angles used as potential states"

  final parameter SI.Distance radius=diameter/2 "Radius of cylinder";
  final parameter SI.Distance innerRadius=innerDiameter/2
    "Inner-Radius of cylinder";
  final parameter SI.Mass mo(min=0) = density*pi*length*radius*radius
    "Mass of cylinder without hole";
  final parameter SI.Mass mi(min=0) = density*pi*length*innerRadius*
    innerRadius "Mass of hole of cylinder";
  final parameter SI.Inertia I22=(mo*(length*length + 3*radius*radius) - mi*(
      length*length + 3*innerRadius*innerRadius))/12
    "Inertia with respect to axis through center of mass, perpendicular to cylinder axis";
  final parameter SI.Mass m(min=0) = mo - mi "Mass of cylinder";
  final parameter Frames.Orientation R=Frames.from_nxy(r, {0,1,0})
    "Orientation object from frame_a to frame spanned by cylinder axis and axis perpendicular to cylinder axis";
  final parameter SI.Position r_CM[3]=r_shape +
      normalizeWithAssert(lengthDirection)*length/2
    "Position vector from frame_a to center of mass, resolved in frame_a";
  final parameter SI.Inertia I[3, 3]=Frames.resolveDyade1(R, diagonal({(mo*
      radius*radius - mi*innerRadius*innerRadius)/2,I22,I22}))
    "Inertia tensor of cylinder with respect to center of mass, resolved in frame parallel to frame_a";

  Body body(
    r_CM=r_CM,
    m=m,
    I_11=I[1, 1],
    I_22=I[2, 2],
    I_33=I[3, 3],
    I_21=I[2, 1],
    I_31=I[3, 1],
    I_32=I[3, 2],
    animation=false,
    sequence_start=sequence_start,
    angles_fixed=angles_fixed,
    angles_start=angles_start,
    w_0_fixed=w_0_fixed,
    w_0_start=w_0_start,
    z_0_fixed=z_0_fixed,
    z_0_start=z_0_start,
    useQuaternions=useQuaternions,
    sequence_angleStates=sequence_angleStates,
    enforceStates=false)
  FixedTranslation frameTranslation(
    r=r,
    animation=animation,
    shapeType="pipecylinder",
    r_shape=r_shape,
    lengthDirection=lengthDirection,
    length=length,
    width=diameter,
    height=diameter,
    extra=innerDiameter/diameter,
    color=color,
    specularCoefficient=specularCoefficient,
    widthDirection={0,1,0})

protected
  outer Modelica.Mechanics.MultiBody.World world;
equation
  r_0 = frame_a.r_0;
  v_0 = der(r_0);
  a_0 = der(v_0);

  assert(innerDiameter < diameter,
    "parameter innerDiameter is greater than parameter diameter");
  connect(frameTranslation.frame_a, frame_a)
  connect(frameTranslation.frame_b, frame_b)
  connect(frame_a, body.frame_a)
end BodyCylinder;


Rigid body with mass, inertia tensor, different shapes for animation, and two frame connectors (12 potential states). Rigid body with mass and inertia tensor and two frame connectors.
All parameter vectors have to be resolved in frame_a.
The inertia tensor has to be defined with respect to a
coordinate system that is parallel to frame_a with the
origin at the center of mass of the body. The coordinate system frame_b
is always parallel to frame_a.

within Modelica.Mechanics.MultiBody.Parts;
model BodyShape
  "Rigid body with mass, inertia tensor, different shapes for animation, and two frame connectors (12 potential states)"

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

  Interfaces.Frame_a frame_a
    "Coordinate system fixed to the component with one cut-force and cut-torque"
  Interfaces.Frame_b frame_b
    "Coordinate system fixed to the component with one cut-force and cut-torque"

  parameter Boolean animation=true
    "= true, if animation shall be enabled (show shape between frame_a and frame_b and optionally a sphere at the center of mass)";
  parameter Boolean animateSphere=true
    "= true, if mass shall be animated as sphere provided animation=true";
  parameter SI.Position r[3](start={0,0,0})
    "Vector from frame_a to frame_b resolved in frame_a";
  parameter SI.Position r_CM[3](start={0,0,0})
    "Vector from frame_a to center of mass, resolved in frame_a";
  parameter SI.Mass m(min=0, start=1) "Mass of rigid body";
  parameter SI.Inertia I_11(min=0) = 0.001 "Element (1,1) of inertia tensor"
  parameter SI.Inertia I_22(min=0) = 0.001 "Element (2,2) of inertia tensor"
  parameter SI.Inertia I_33(min=0) = 0.001 "Element (3,3) of inertia tensor"
  parameter SI.Inertia I_21(min=-C.inf) = 0 "Element (2,1) of inertia tensor"
  parameter SI.Inertia I_31(min=-C.inf) = 0 "Element (3,1) of inertia tensor"
  parameter SI.Inertia I_32(min=-C.inf) = 0 "Element (3,2) of inertia tensor"

  SI.Position r_0[3](start={0,0,0}, each stateSelect=if enforceStates then
        StateSelect.always else StateSelect.avoid)
    "Position vector from origin of world frame to origin of frame_a"
  SI.Velocity v_0[3](start={0,0,0}, each stateSelect=if enforceStates then
        StateSelect.always else StateSelect.avoid)
    "Absolute velocity of frame_a, resolved in world frame (= der(r_0))"
  SI.Acceleration a_0[3](start={0,0,0})
    "Absolute acceleration of frame_a resolved in world frame (= der(v_0))"

  parameter Boolean angles_fixed=false
    "= true, if angles_start are used as initial values, else as guess values"
  parameter SI.Angle angles_start[3]={0,0,0}
    "Initial values of angles to rotate world frame around 'sequence_start' axes into frame_a"
  parameter Types.RotationSequence sequence_start={1,2,3}
    "Sequence of rotations to rotate world frame into frame_a at initial time"

  parameter Boolean w_0_fixed=false
    "= true, if w_0_start are used as initial values, else as guess values"
  parameter SI.AngularVelocity w_0_start[3]={0,0,0}
    "Initial or guess values of angular velocity of frame_a resolved in world frame"

  parameter Boolean z_0_fixed=false
    "= true, if z_0_start are used as initial values, else as guess values"
  parameter SI.AngularAcceleration z_0_start[3]={0,0,0}
    "Initial values of angular acceleration z_0 = der(w_0)"

  parameter Types.ShapeType shapeType="cylinder" "Type of shape"
  parameter SI.Position r_shape[3]={0,0,0}
    "Vector from frame_a to shape origin, resolved in frame_a"
  parameter Types.Axis lengthDirection = to_unit1(r - r_shape)
    "Vector in length direction of shape, resolved in frame_a"
  parameter Types.Axis widthDirection={0,1,0}
    "Vector in width direction of shape, resolved in frame_a"
  parameter SI.Length length=Modelica.Math.Vectors.length(r - r_shape)
    "Length of shape"
  parameter SI.Distance width=length/world.defaultWidthFraction
    "Width of shape"
  parameter SI.Distance height=width "Height of shape"
  parameter Types.ShapeExtra extra=0.0
    "Additional parameter depending on shapeType (see docu of Visualizers.Advanced.Shape)"
  input Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.BodyColor
    "Color of shape"
  parameter SI.Diameter sphereDiameter=2*width "Diameter of sphere"
  input Types.Color sphereColor=color "Color of sphere of mass"
  input Types.SpecularCoefficient specularCoefficient=world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  parameter Boolean enforceStates=false
    "= true, if absolute variables of body object shall be used as states (StateSelect.always)"
  parameter Boolean useQuaternions=true
    "= true, if quaternions shall be used as potential states otherwise use 3 angles as potential states"
  parameter Types.RotationSequence sequence_angleStates={1,2,3}
    "Sequence of rotations to rotate world frame into frame_a around the 3 angles used as potential states"

  FixedTranslation frameTranslation(r=r, animation=false)
  Body body(
    r_CM=r_CM,
    m=m,
    I_11=I_11,
    I_22=I_22,
    I_33=I_33,
    I_21=I_21,
    I_31=I_31,
    I_32=I_32,
    animation=false,
    sequence_start=sequence_start,
    angles_fixed=angles_fixed,
    angles_start=angles_start,
    w_0_fixed=w_0_fixed,
    w_0_start=w_0_start,
    z_0_fixed=z_0_fixed,
    z_0_start=z_0_start,
    useQuaternions=useQuaternions,
    sequence_angleStates=sequence_angleStates,
    enforceStates=false)
protected
  outer Modelica.Mechanics.MultiBody.World world;
  Visualizers.Advanced.Shape shape1(
    shapeType=shapeType,
    color=color,
    specularCoefficient=specularCoefficient,
    length=length,
    width=width,
    height=height,
    lengthDirection=lengthDirection,
    widthDirection=widthDirection,
    r_shape=r_shape,
    extra=extra,
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
  Visualizers.Advanced.Shape shape2(
    shapeType="sphere",
    color=sphereColor,
    specularCoefficient=specularCoefficient,
    length=sphereDiameter,
    width=sphereDiameter,
    height=sphereDiameter,
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    r_shape=r_CM - {1,0,0}*sphereDiameter/2,
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation and animateSphere;
equation
  r_0 = frame_a.r_0;
  v_0 = der(r_0);
  a_0 = der(v_0);
  connect(frame_a, frameTranslation.frame_a)
  connect(frame_b, frameTranslation.frame_b)
  connect(frame_a, body.frame_a)
end BodyShape;


Frame fixed in the world frame at a given position. Element consisting of a frame (frame_b) that is fixed in the world
frame at a given position defined by parameter vector r
(vector from origin of world frame to frame_b, resolved in the
world frame).

within Modelica.Mechanics.MultiBody.Parts;
model Fixed "Frame fixed in the world frame at a given position"
  import Modelica.Mechanics.MultiBody.Types;
  import Modelica.Units.Conversions.to_unit1;

  Interfaces.Frame_b frame_b "Coordinate system fixed in the world frame"

  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter SI.Position r[3]={0,0,0}
    "Position vector from world frame to frame_b, resolved in world frame";
  parameter Types.ShapeType shapeType="cylinder" "Type of shape"
  parameter SI.Position r_shape[3]={0,0,0}
    "Vector from world frame to shape origin, resolved in world frame"
  parameter Types.Axis lengthDirection = to_unit1(r - r_shape)
    "Vector in length direction of shape, resolved in world frame"
  parameter Types.Axis widthDirection={0,1,0}
    "Vector in width direction of shape, resolved in world frame"
  parameter SI.Length length=Modelica.Math.Vectors.length(r - r_shape)
    "Length of shape"
  parameter SI.Distance width=length/world.defaultWidthFraction
    "Width of shape"
  parameter SI.Distance height=width "Height of shape"
  parameter Types.ShapeExtra extra=0.0
    "Additional parameter for cone, pipe etc. (see docu of Visualizers.Advanced.Shape)"
  input Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.RodColor
    "Color of shape"
  input Types.SpecularCoefficient specularCoefficient=world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  outer Modelica.Mechanics.MultiBody.World world;
  Visualizers.Advanced.Shape shape(
    shapeType=shapeType,
    color=color,
    specularCoefficient=specularCoefficient,
    length=length,
    width=width,
    height=height,
    lengthDirection=lengthDirection,
    widthDirection=widthDirection,
    extra=extra,
    r_shape=r_shape,
    r=zeros(3),
    R=Frames.nullRotation()) if world.enableAnimation and animation;
equation
  Connections.root(frame_b.R);
  frame_b.r_0 = r;
  frame_b.R = Frames.nullRotation();
end Fixed;


Fixed translation followed by a fixed rotation of frame_b with respect to frame_a. Component for a fixed translation and fixed rotation of frame_b with respect
to frame_a, i.e., the relationship between connectors frame_a and frame_b
remains constant. There are several possibilities to define the
orientation of frame_b with respect to frame_a:

within Modelica.Mechanics.MultiBody.Parts;
model FixedRotation
  "Fixed translation followed by a fixed rotation of frame_b with respect to frame_a"

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

  Interfaces.Frame_a frame_a
    "Coordinate system fixed to the component with one cut-force and cut-torque"
  Interfaces.Frame_b frame_b
    "Coordinate system fixed to the component with one cut-force and cut-torque"

  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter SI.Position r[3]={0,0,0}
    "Vector from frame_a to frame_b resolved in frame_a";
  parameter Modelica.Mechanics.MultiBody.Types.RotationTypes rotationType=
      Modelica.Mechanics.MultiBody.Types.RotationTypes.RotationAxis
    "Type of rotation description"
  parameter Modelica.Mechanics.MultiBody.Types.Axis n={1,0,0}
    "Axis of rotation in frame_a (= same as in frame_b)"
  parameter Modelica.Units.NonSI.Angle_deg angle=0
    "Angle to rotate frame_a around axis n into frame_b"

  parameter Modelica.Mechanics.MultiBody.Types.Axis n_x={1,0,0}
    "Vector along x-axis of frame_b resolved in frame_a"
  parameter Modelica.Mechanics.MultiBody.Types.Axis n_y={0,1,0}
    "Vector along y-axis of frame_b resolved in frame_a"

  parameter Modelica.Mechanics.MultiBody.Types.RotationSequence sequence(
    min={1,1,1},
    max={3,3,3}) = {1,2,3} "Sequence of rotations"
  parameter Modelica.Units.NonSI.Angle_deg angles[3]={0,0,0}
    "Rotation angles around the axes defined in 'sequence'"
  parameter Modelica.Mechanics.MultiBody.Types.ShapeType shapeType="cylinder"
    "Type of shape"
  parameter SI.Position r_shape[3]={0,0,0}
    "Vector from frame_a to shape origin, resolved in frame_a"
  parameter Modelica.Mechanics.MultiBody.Types.Axis lengthDirection=
      to_unit1(r - r_shape)
    "Vector in length direction of shape, resolved in frame_a"
  parameter Modelica.Mechanics.MultiBody.Types.Axis widthDirection={0,1,0}
    "Vector in width direction of shape, resolved in frame_a"
  parameter SI.Length length=Modelica.Math.Vectors.length(r - r_shape)
    "Length of shape"
  parameter SI.Distance width=length/world.defaultWidthFraction
    "Width of shape"
  parameter SI.Distance height=width "Height of shape"
  parameter Modelica.Mechanics.MultiBody.Types.ShapeExtra extra=0.0
    "Additional parameter depending on shapeType (see docu of Visualizers.Advanced.Shape)"
  /*
  parameter Boolean checkTotalPower=false
    "= true, if total power flowing into this component shall be determined (must be zero)"
*/

  input Modelica.Mechanics.MultiBody.Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.RodColor
    "Color of shape"
  input Modelica.Mechanics.MultiBody.Types.SpecularCoefficient
    specularCoefficient=world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  final parameter Frames.Orientation R_rel=if rotationType == Types.RotationTypes.RotationAxis
       then Frames.planarRotation(
        Modelica.Math.Vectors.normalizeWithAssert(n),
        Cv.from_deg(angle),
        0) else if rotationType == Types.RotationTypes.TwoAxesVectors then
      Frames.from_nxy(n_x, n_y) else Frames.axesRotations(
        sequence,
        Cv.from_deg(angles),
        zeros(3)) "Fixed rotation object from frame_a to frame_b";
  /*
  SI.Power totalPower
    "Total power flowing into this element, if checkTotalPower=true (otherwise dummy)";
*/
protected
  outer Modelica.Mechanics.MultiBody.World world;

  /*
  parameter Frames.Orientation R_rel_inv=
      Frames.inverseRotation(R_rel)
*/
  parameter Frames.Orientation R_rel_inv=Frames.from_T(transpose(R_rel.T),
      zeros(3)) "Inverse of R_rel (rotate from frame_b to frame_a)";
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape shape(
    shapeType=shapeType,
    color=color,
    specularCoefficient=specularCoefficient,
    r_shape=r_shape,
    lengthDirection=lengthDirection,
    widthDirection=widthDirection,
    length=length,
    width=width,
    height=height,
    extra=extra,
    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 FixedRotation object is connected");

  /* Relationships between quantities of frame_a and frame_b */
  frame_b.r_0 = frame_a.r_0 + Frames.resolve1(frame_a.R, r);
  if Connections.rooted(frame_a.R) then
    frame_b.R = Frames.absoluteRotation(frame_a.R, R_rel);
    zeros(3) = frame_a.f + Frames.resolve1(R_rel, frame_b.f);
    zeros(3) = frame_a.t + Frames.resolve1(R_rel, frame_b.t) - cross(r,
      frame_a.f);
  else
    frame_a.R = Frames.absoluteRotation(frame_b.R, R_rel_inv);
    zeros(3) = frame_b.f + Frames.resolve1(R_rel_inv, frame_a.f);
    zeros(3) = frame_b.t + Frames.resolve1(R_rel_inv, frame_a.t) + cross(
      Frames.resolve1(R_rel_inv, r), frame_b.f);
  end if;

  /*
  if checkTotalPower then
    totalPower = frame_a.f*Frames.resolve2(frame_a.R, der(frame_a.r_0)) +
                 frame_b.f*Frames.resolve2(frame_b.R, der(frame_b.r_0)) +
                 frame_a.t*Frames.angularVelocity2(frame_a.R) +
                 frame_b.t*Frames.angularVelocity2(frame_b.R);
  else
    totalPower = 0;
  end if;
*/
end FixedRotation;


Fixed translation of frame_b with respect to frame_a. Component for a fixed translation of frame_b with respect
to frame_a, i.e., the relationship between connectors frame_a and frame_b
remains constant and frame_a is always parallel to frame_b.

within Modelica.Mechanics.MultiBody.Parts;
model FixedTranslation "Fixed translation of frame_b with respect to frame_a"
  import Modelica.Mechanics.MultiBody.Types;
  import Modelica.Units.Conversions.to_unit1;

  Interfaces.Frame_a frame_a
    "Coordinate system fixed to the component with one cut-force and cut-torque"
  Interfaces.Frame_b frame_b
    "Coordinate system fixed to the component with one cut-force and cut-torque"

  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter SI.Position r[3](start={0,0,0})
    "Vector from frame_a to frame_b resolved in frame_a";
  parameter Types.ShapeType shapeType="cylinder" "Type of shape"
  parameter SI.Position r_shape[3]={0,0,0}
    "Vector from frame_a to shape origin, resolved in frame_a"
  parameter Types.Axis lengthDirection = to_unit1(r - r_shape)
    "Vector in length direction of shape, resolved in frame_a"
  parameter Types.Axis widthDirection={0,1,0}
    "Vector in width direction of shape, resolved in frame_a"
  parameter SI.Length length=Modelica.Math.Vectors.length(r - r_shape)
    "Length of shape"
  parameter SI.Distance width=length/world.defaultWidthFraction
    "Width of shape"
  parameter SI.Distance height=width "Height of shape"
  parameter Types.ShapeExtra extra=0.0
    "Additional parameter depending on shapeType (see docu of Visualizers.Advanced.Shape)"
  input Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.RodColor
    "Color of shape"
  input Types.SpecularCoefficient specularCoefficient=world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  outer Modelica.Mechanics.MultiBody.World world;
  Visualizers.Advanced.Shape shape(
    shapeType=shapeType,
    color=color,
    specularCoefficient=specularCoefficient,
    r_shape=r_shape,
    lengthDirection=lengthDirection,
    widthDirection=widthDirection,
    length=length,
    width=width,
    height=height,
    extra=extra,
    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 FixedTranslation 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 FixedTranslation;


Propagate 1-dim. support torque to 3-dim. system (provided world.driveTrainMechanics3D=true). This component is used to acquire support torques from a 1-dim.-rotational
mechanical system (e.g., components from Modelica.Mechanics.Rotational)
and to propagate them to a carrier body.

within Modelica.Mechanics.MultiBody.Parts;
model Mounting1D
  "Propagate 1-dim. support torque to 3-dim. system (provided world.driveTrainMechanics3D=true)"
  parameter SI.Angle phi0=0 "Fixed offset angle of housing";
  parameter Modelica.Mechanics.MultiBody.Types.Axis n={1,0,0}
    "Axis of rotation = axis of support torque (resolved in frame_a)"
  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
    "(right) flange fixed in housing"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a if world.driveTrainMechanics3D
    "Frame in which housing is fixed (connector is removed, if world.driveTrainMechanics3D=false)"
protected
  outer Modelica.Mechanics.MultiBody.World world;

  encapsulated model Housing
    import Modelica;
    input Modelica.Units.SI.Torque t[3];
    Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
  equation
    frame_a.f = zeros(3);
    frame_a.t = t;
  end Housing;
  Housing housing(t=-n*flange_b.tau) if world.driveTrainMechanics3D
equation
  flange_b.phi = phi0;
  connect(housing.frame_a, frame_a)
end Mounting1D;


within Modelica.Mechanics.MultiBody;
package Parts "Rigid components such as bodies with mass and inertia and massless rods"
  extends Modelica.Icons.Package;
end Parts;


Rigid body where body rotation and inertia tensor is neglected (6 potential states). Rigid body where the inertia tensor is neglected.
This body is
solely defined by its mass.
By default, this component is visualized by a sphere that has
its center at frame_a. Note, that
the animation may be switched off via parameter animation = false.

within Modelica.Mechanics.MultiBody.Parts;
model PointMass
  "Rigid body where body rotation and inertia tensor is neglected (6 potential states)"

  import Modelica.Mechanics.MultiBody.Types;
  Interfaces.Frame_a frame_a
    "Coordinate system fixed at center of mass point"
  parameter Boolean animation=true
    "= true, if animation shall be enabled (show sphere)";
  parameter SI.Mass m(min=0) "Mass of mass point";
  input SI.Diameter sphereDiameter=world.defaultBodyDiameter
    "Diameter of sphere"
  input Types.Color sphereColor=Modelica.Mechanics.MultiBody.Types.Defaults.BodyColor
    "Color of sphere"
  input Types.SpecularCoefficient specularCoefficient=world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  parameter StateSelect stateSelect=StateSelect.avoid
    "Priority to use frame_a.r_0, v_0 (= der(frame_a.r_0)) as states"

  SI.Position r_0[3](start={0,0,0}, each stateSelect=stateSelect)
    "Position vector from origin of world frame to origin of frame_a, resolved in world frame"
  SI.Velocity v_0[3](start={0,0,0}, each stateSelect=stateSelect)
    "Absolute velocity of frame_a, resolved in world frame (= der(r_0))"
  SI.Acceleration a_0[3](start={0,0,0})
    "Absolute acceleration of frame_a resolved in world frame (= der(v_0))"

protected
  outer Modelica.Mechanics.MultiBody.World world;

  // Declarations for animation
  Visualizers.Advanced.Shape sphere(
    shapeType="sphere",
    color=sphereColor,
    specularCoefficient=specularCoefficient,
    length=sphereDiameter,
    width=sphereDiameter,
    height=sphereDiameter,
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    r_shape=-{1,0,0}*sphereDiameter/2,
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
equation
  // If any possible, do not use the connector as root
  Connections.potentialRoot(frame_a.R, 10000);

  if Connections.isRoot(frame_a.R) then
    assert(cardinality(frame_a) == 0, "
A Modelica.Mechanics.MultiBody.Parts.PointMass model is connected in
a way, so that no equations are present to compute frame_a.R
(the orientation object in the connector). Setting frame_a.R to
an arbitrary value in the PointMass model, might lead to a wrong
overall model, depending on how the PointMass model is used.
   You can avoid this message, by providing equations that
compute the orientation object, e.g., by using the
Modelica.Mechanics.MultiBody.Joints.FreeMotion joint.
   If a PointMass model is not connected at all, the
orientation object is set to a unit rotation. But this is
the only case where this is done.
"); frame_a.R = Frames.nullRotation();
  else
    frame_a.t = zeros(3);
  end if;

  // Newton equation: f = m*(a-g)
  r_0 = frame_a.r_0;
  v_0 = der(r_0);
  a_0 = der(v_0);
  frame_a.f = m*Frames.resolve2(frame_a.R, a_0 - world.gravityAcceleration(
    r_0));
end PointMass;


Ideal rolling wheel on flat surface z=0 (5 positional, 3 velocity degrees of freedom). A wheel rolling on the x-y plane of the world frame including
wheel mass and simple visualization.
The rolling contact is considered being ideal, i.e. there is no
slip between the wheel and the ground.
The wheel can not take off but it can incline toward the ground.
The frame frame_a is placed in the wheel center point and rotates
with the wheel itself. Therefore, a
rotational joint
with rotation axis n={0,1,0} should be used to
connect the wheel to a carrier.

within Modelica.Mechanics.MultiBody.Parts;
model RollingWheel
  "Ideal rolling wheel on flat surface z=0 (5 positional, 3 velocity degrees of freedom)"

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

  parameter SI.Radius radius "Radius of wheel";
  parameter SI.Mass m "Mass of wheel";
  parameter SI.Inertia I_axis "Inertia along the wheel axis";
  parameter SI.Inertia I_long "Inertia perpendicular to the wheel axis";
  parameter StateSelect stateSelect=StateSelect.always
    "Priority to use generalized coordinates as states"

  SI.Position x(
    start=0,
    fixed=true,
    stateSelect=stateSelect) "x-coordinate of wheel axis";

  SI.Position y(
    start=0,
    fixed=true,
    stateSelect=stateSelect) "y-coordinate of wheel axis";

  SI.Angle angles[3](
    start={0,0,0},
    each fixed=true,
    each stateSelect=stateSelect)
    "Angles to rotate world-frame in to frame_a around z-, y-, x-axis"

  SI.AngularVelocity der_angles[3](
    start={0,0,0},
    each fixed=true,
    each stateSelect=stateSelect) "Derivative of angles"

  parameter SI.Distance width=0.035 "Width of wheel"
  parameter Real hollowFraction=0.8
    "For ring-like visualization: wheel radius / inner hole radius; i.e. 1.0: completely hollow, 0.0: full disc"
  parameter Types.Color color={30,30,30} "Color of wheel"

  Modelica.Mechanics.MultiBody.Parts.Body body(
    final r_CM={0,0,0},
    final m=m,
    final I_11=I_long,
    final I_22=I_axis,
    final I_33=I_long,
    final I_21=0,
    final I_31=0,
    final I_32=0,
    animation=false)

  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
    "Frame fixed in wheel center point (y-axis: along wheel axis, z-axis: upwards)"
  Modelica.Mechanics.MultiBody.Joints.RollingWheel rollingWheel(
    radius=radius, stateSelect=StateSelect.avoid)
  Modelica.Mechanics.MultiBody.Visualizers.FixedShape fixedShape(
    final animation=animation,
    final r_shape={0,-width,0},
    final lengthDirection={0,1,0},
    final widthDirection={1,0,0},
    final length=2*width,
    final width=2*radius,
    final height=2*radius,
    final color=color,
    final extra=hollowFraction,
    final shapeType="pipe") if animation

equation
  rollingWheel.x = x;
  rollingWheel.y = y;
  rollingWheel.angles = angles;
  rollingWheel.der_angles = der_angles;

  connect(body.frame_a, frame_a)
  connect(rollingWheel.frame_a, frame_a)
  connect(fixedShape.frame_a, frame_a)
</pre></blockquote>
</html>"));
end RollingWheel;


Ideal rolling wheel set consisting of two ideal rolling wheels connected together by an axis. Two wheels are connected by an axis and can rotate around this axis.
The wheels are rolling on the x-y plane of the world frame.
The coordinate system attached to the center of the wheel axis (frameMiddle)
is constrained so that it is always parallel to the x-y plane.
If all generalized coordinates are zero, frameMiddle is parallel
to the world frame.

within Modelica.Mechanics.MultiBody.Parts;
model RollingWheelSet
  "Ideal rolling wheel set consisting of two ideal rolling wheels connected together by an axis"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frameMiddle
    "Frame fixed in middle of axis connecting both wheels (y-axis: along wheel axis, z-axis: upwards)"

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

  parameter SI.Radius R_wheel "Radius of one wheel";
  parameter SI.Mass m_wheel "Mass of one wheel";
  parameter SI.Inertia I_wheelAxis "Inertia along one wheel axis";
  parameter SI.Inertia I_wheelLong "Inertia perpendicular to one wheel axis";
  parameter SI.Distance track "Distance between the two wheels (= axle track)";
  parameter StateSelect stateSelect=StateSelect.always
    "Priority to use the generalized coordinates as states";

  SI.Position x(
    start=0,
    fixed=true,
    stateSelect=stateSelect) "x coordinate of center between wheels";
  SI.Position y(
    start=0,
    fixed=true,
    stateSelect=stateSelect) "y coordinate of center between wheels";
  SI.Angle phi(
    start=0,
    fixed=true,
    stateSelect=stateSelect) "Orientation angle of wheel axis along z-axis";
  SI.Angle theta1(
    start=0,
    fixed=true,
    stateSelect=stateSelect) "Angle of wheel 1";
  SI.Angle theta2(
    start=0,
    fixed=true,
    stateSelect=stateSelect) "Angle of wheel 2";
  SI.AngularVelocity der_theta1(
    start=0,
    fixed=true,
    stateSelect=stateSelect) "Derivative of theta 1";
  SI.AngularVelocity der_theta2(
    start=0,
    fixed=true,
    stateSelect=stateSelect) "Derivative of theta 2";

  parameter SI.Distance width_wheel=0.01 "Width of one wheel"
  parameter Real hollowFraction=0.8
    "For ring-like wheel visualization: wheel radius / inner hole radius; i.e. 1.0: completely hollow, 0.0: full disc"
  parameter Types.Color color={30,30,30} "Color of wheels"

  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame1
    "Frame fixed in center point of left wheel (y-axis: along wheel axis, z-axis: upwards)"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_b frame2
    "Frame fixed in center point of right wheel (y-axis: along wheel axis, z-axis: upwards)"
  Modelica.Mechanics.MultiBody.Parts.Body body2(
    final r_CM={0,0,0},
    final I_21=0,
    final I_31=0,
    final I_32=0,
    animation=false,
    final m=m_wheel,
    final I_11=I_wheelLong,
    final I_22=I_wheelAxis,
    final I_33=I_wheelLong)
  Modelica.Mechanics.MultiBody.Visualizers.FixedShape shape2(
    final animation=animation,
    final lengthDirection={0,1,0},
    final widthDirection={1,0,0},
    final color=color,
    final extra=hollowFraction,
    final shapeType="pipe",
    final r_shape={0,-width_wheel,0},
    final length=2*width_wheel,
    final width=2*R_wheel,
    final height=2*R_wheel) if animation
  Modelica.Mechanics.MultiBody.Parts.Body body1(
    final r_CM={0,0,0},
    final I_21=0,
    final I_31=0,
    final I_32=0,
    animation=false,
    final m=m_wheel,
    final I_11=I_wheelLong,
    final I_22=I_wheelAxis,
    final I_33=I_wheelLong)
  Modelica.Mechanics.MultiBody.Visualizers.FixedShape shape1(
    final animation=animation,
    final lengthDirection={0,1,0},
    final widthDirection={1,0,0},
    final color=color,
    final extra=hollowFraction,
    final shapeType="pipe",
    final r_shape={0,-width_wheel,0},
    final length=2*width_wheel,
    final width=2*R_wheel,
    final height=2*R_wheel) if animation
  Modelica.Mechanics.Rotational.Interfaces.Flange_a axis1
    "1-dim. rotational flange that drives the left wheel"
  Modelica.Mechanics.Rotational.Interfaces.Flange_a axis2
    "1-dim. rotational flange that drives the right wheel"
  Modelica.Mechanics.MultiBody.Joints.RollingWheelSet wheelSetJoint(
    animation=false,
    radius=R_wheel,
    track=track,
    stateSelect=StateSelect.default,
    x(fixed=false),
    y(fixed=false),
    phi(fixed=false),
    theta1(fixed=false),
    theta2(fixed=false),
    der_theta1(fixed=false),
    der_theta2(fixed=false))
  Modelica.Mechanics.Rotational.Interfaces.Flange_b support
    "Support of 1D axes"
equation
  wheelSetJoint.x = x;
  wheelSetJoint.y = y;
  wheelSetJoint.phi = phi;
  wheelSetJoint.theta1 = theta1;
  wheelSetJoint.theta2 = theta2;
  der_theta1 = der(theta1);
  der_theta2 = der(theta2);

  connect(body2.frame_a, frame2)
  connect(body1.frame_a, frame1)
  connect(shape1.frame_a, frame1)
  connect(shape2.frame_a, frame2)
  connect(wheelSetJoint.frame2, frame2)
  connect(wheelSetJoint.frame1, frame1)
  connect(wheelSetJoint.axis1, axis1)
  connect(wheelSetJoint.axis2, axis2)
  connect(wheelSetJoint.support, support)
  connect(wheelSetJoint.frameMiddle, frameMiddle)
</pre></blockquote>
</html>"));
end RollingWheelSet;


1D inertia attachable on 3-dim. bodies (3D dynamic effects are taken into account if world.driveTrainMechanics3D=true). This component is used to model the gyroscopic torques exerted by a 1-dim.
inertia (so called rotor) on its 3-dim. carrier body. Gyroscopic torques
appear, if the vector of the carrier body's angular velocity is not parallel
to the vector of the rotor's axis. The axis of rotation of the rotor is defined by
the parameter n, which has to be given in the local coordinate system
of frame_a. The default animation of this component is
shown in the figure below.

within Modelica.Mechanics.MultiBody.Parts;
model Rotor1D
  "1D inertia attachable on 3-dim. bodies (3D dynamic effects are taken into account if world.driveTrainMechanics3D=true)"

  parameter Boolean animation=true
    "= true, if animation shall be enabled (show rotor as cylinder)";
  parameter SI.Inertia J(min=0,start=1)
    "Moment of inertia of rotor around its axis of rotation";
  parameter Modelica.Mechanics.MultiBody.Types.Axis n={1,0,0}
    "Axis of rotation resolved in frame_a"
  parameter SI.Position r_center[3]=zeros(3)
    "Position vector from origin of frame_a to center of cylinder"
  parameter SI.Distance cylinderLength=2*world.defaultJointLength
    "Length of cylinder representing the rotor"
  parameter SI.Distance cylinderDiameter=2*world.defaultJointWidth
    "Diameter of cylinder representing the rotor"
  input Modelica.Mechanics.MultiBody.Types.Color cylinderColor=Modelica.Mechanics.MultiBody.Types.Defaults.RodColor
    "Color of cylinder representing the rotor"
  input Modelica.Mechanics.MultiBody.Types.SpecularCoefficient
    specularCoefficient=world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  parameter StateSelect stateSelect=StateSelect.default
    "Priority to use rotor angle (phi) and rotor speed (w) as states"
  parameter Boolean exact=true
    "= true, if exact calculations; false if influence of bearing on rotor acceleration is neglected to avoid an algebraic loop"

  SI.Angle phi(start=0, stateSelect=stateSelect)
    "Rotation angle of rotor with respect to frame_a (= flange_a.phi = flange_b.phi)";
  SI.AngularVelocity w(start=0, stateSelect=stateSelect)
    "Angular velocity of rotor with respect to frame_a";
  SI.AngularAcceleration a(start=0)
    "Angular acceleration of rotor with respect to frame_a";

  Modelica.Mechanics.Rotational.Interfaces.Flange_a flange_a
    "(left) driving flange (flange axis directed INTO cut plane)"
  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
    "(right) driven flange (flange axis directed OUT OF cut plane)"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a if world.driveTrainMechanics3D
    "Frame in which rotor housing is fixed (connector is removed, if world.driveTrainMechanics3D=false)"

  encapsulated model RotorWith3DEffects
    "1D inertia attachable on 3-dim. bodies (3D dynamic effects are taken into account)"

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

    parameter Boolean animation=true
      "= true, if animation shall be enabled (show rotor as cylinder)";
    parameter SI.Inertia J(min=0) = 1
      "Moment of inertia of rotor around its axis of rotation";
    parameter Types.Axis n={1,0,0} "Axis of rotation resolved in frame_a";
    parameter SI.Position r_center[3]=zeros(3)
      "Position vector from origin of frame_a to center of cylinder"
    parameter SI.Distance cylinderLength=2*world.defaultJointLength
      "Length of cylinder representing the rotor"
    parameter SI.Distance cylinderDiameter=2*world.defaultJointWidth
      "Diameter of cylinder representing the rotor"
    input Types.Color cylinderColor=Modelica.Mechanics.MultiBody.Types.Defaults.RodColor
      "Color of cylinder representing the rotor"
    input Types.SpecularCoefficient specularCoefficient=world.defaultSpecularCoefficient
      "Reflection of ambient light (= 0: light is completely absorbed)"
    parameter StateSelect stateSelect=StateSelect.default
      "Priority to use rotor angle (phi) and rotor speed (w) as states"
    parameter Boolean exact=true
      "= true, if exact calculations; false if influence of bearing on rotor acceleration is neglected to avoid an algebraic loop"

    SI.AngularVelocity w_a[3]
      "Angular velocity of frame_a, resolved in frame_a";
    SI.Angle phi(start=0, final stateSelect=stateSelect)
      "Rotation angle of rotor with respect to frame_a (= flange_a.phi = flange_b.phi)"

    SI.AngularVelocity w(start=0, stateSelect=stateSelect)
      "Angular velocity of rotor with respect to frame_a"
    SI.AngularAcceleration a(start=0)
      "Angular acceleration of rotor with respect to frame_a"

    Modelica.Mechanics.Rotational.Interfaces.Flange_a flange_a
      "(left) driving flange (flange axis directed INTO cut plane)"
    Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
      "(right) driven flange (flange axis directed OUT OF cut plane)"
    Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a
      "Frame in which rotor housing is fixed"

  protected
    outer Modelica.Mechanics.MultiBody.World world;
    parameter Real e[3](each final unit="1")=
      Modelica.Math.Vectors.normalizeWithAssert(n)
      "Unit vector in direction of rotor axis, resolved in frame_a";
    parameter SI.Inertia nJ[3]=J*e;
    Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape cylinder(
      shapeType="cylinder",
      color=cylinderColor,
      specularCoefficient=specularCoefficient,
      length=cylinderLength,
      width=cylinderDiameter,
      height=cylinderDiameter,
      lengthDirection=n,
      widthDirection={0,1,0},
      extra=1,
      r_shape=r_center - e*(cylinderLength/2),
      r=frame_a.r_0,
      R=Frames.absoluteRotation(frame_a.R, Frames.planarRotation(
              e,
              phi,
              0))) if world.enableAnimation and animation;
  equation
    phi = flange_a.phi;
    phi = flange_b.phi;
    w = der(phi);
    a = der(w);

    w_a = Modelica.Mechanics.MultiBody.Frames.angularVelocity2(frame_a.R);
    if exact then
      J*a = flange_a.tau + flange_b.tau - nJ*der(w_a);
    else
      J*a = flange_a.tau + flange_b.tau;
    end if;

    /* Reaction torque:
        t = n*(J*a - flange_a.tau - flange_b.tau) + cross(w_a, nJ*w)

     Since
        J*a = flange_a.tau + flange_b.tau - nJ*der(w_a);

     the reaction torque can be simplified to
        t = n*(- nJ*der(w_a)) + cross(w_a, nJ*w)

  */
    frame_a.f = zeros(3);
    frame_a.t = cross(w_a, nJ*w) - e*(nJ*der(w_a));
  end RotorWith3DEffects;

protected
  outer Modelica.Mechanics.MultiBody.World world;
  parameter Real e[3](each final unit="1")=
    Modelica.Math.Vectors.normalizeWithAssert(n)
    "Unit vector in direction of rotor axis, resolved in frame_a";
  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape cylinder(
    shapeType="cylinder",
    color=cylinderColor,
    specularCoefficient=specularCoefficient,
    length=cylinderLength,
    width=cylinderDiameter,
    height=cylinderDiameter,
    lengthDirection=n,
    widthDirection={0,1,0},
    extra=1,
    r_shape=r_center - e*(cylinderLength/2),
    r=zeros(3),
    R=Modelica.Mechanics.MultiBody.Frames.planarRotation(
          e,
          phi,
          0)) if world.enableAnimation and animation and not world.driveTrainMechanics3D;

  Modelica.Mechanics.Rotational.Components.Inertia inertia(J=J, stateSelect=
        StateSelect.never) if not world.driveTrainMechanics3D
  RotorWith3DEffects rotorWith3DEffects(
    animation=animation,
    J=J,
    n=n,
    r_center=r_center,
    cylinderLength=cylinderLength,
    cylinderDiameter=cylinderDiameter,
    cylinderColor=cylinderColor,
    specularCoefficient=specularCoefficient,
    exact=exact,
    stateSelect=StateSelect.never) if world.driveTrainMechanics3D
equation
  phi = flange_a.phi;
  w = der(phi);
  a = der(w);

  connect(inertia.flange_a, flange_a)
  connect(inertia.flange_b, flange_b)
  connect(rotorWith3DEffects.flange_b, flange_b)
  connect(rotorWith3DEffects.flange_a, flange_a)
  connect(rotorWith3DEffects.frame_a, frame_a)
end Rotor1D;


Measure absolute angles between frame connector and the world frame. This model determines the 3 angles to rotate the world frame
into frame_a along the axes defined by parameter sequence.
For example, if sequence = {3,1,2} then the world frame 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_a.
The 3 angles are returned in the range

within Modelica.Mechanics.MultiBody.Sensors;
model AbsoluteAngles
  "Measure absolute angles between frame connector and the world frame"
  extends Internal.PartialAbsoluteSensor;

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

equation
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
  angles = MultiBody.Frames.axesRotationsAngles(
    frame_a.R,
    sequence,
    guessAngle1);
end AbsoluteAngles;


Measure absolute angular velocity of frame connector. The absolute angular velocity of frame_a with respect to the
world frame is
determined and provided at the output signal connector w.

within Modelica.Mechanics.MultiBody.Sensors;
model AbsoluteAngularVelocity
  "Measure absolute angular velocity of frame connector"
  extends Internal.PartialAbsoluteSensor;

  Blocks.Interfaces.RealOutput w[3](
    each final quantity="AngularVelocity",
    each final unit="rad/s")
    "Absolute angular velocity vector of frame_a with respect to world frame, resolved in frame defined by resolveInFrame"

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

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

protected
  Internal.BasicAbsoluteAngularVelocity angularVelocity(
    resolveInFrame=resolveInFrame)
  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition if
    not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve)

equation
  connect(angularVelocity.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, angularVelocity.frame_resolve)
  connect(angularVelocity.w, w)
  connect(angularVelocity.frame_a, frame_a)
</pre></blockquote>
</html>"));
end AbsoluteAngularVelocity;


Measure absolute position vector of the origin of a frame connector. The absolute position vector of the origin of frame_a is
determined and provided at the output signal connector r.

within Modelica.Mechanics.MultiBody.Sensors;
model AbsolutePosition
  "Measure absolute position vector of the origin of a frame connector"
  extends Internal.PartialAbsoluteSensor;

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

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

protected
  Internal.BasicAbsolutePosition position(resolveInFrame=resolveInFrame)

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

equation
  connect(position.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, position.frame_resolve)
  connect(position.r, r)
  connect(position.frame_a, frame_a)
</pre></blockquote>
</html>"));
end AbsolutePosition;


Measure absolute kinematic quantities of frame connector. Absolute kinematic quantities of frame_a are
determined and provided at the conditional output signal connectors.
For example, if parameter \"get_r = true\", the connector
\"r\" is enabled and contains the absolute vector from the world frame
to the origin of frame_a. The following quantities can be provided
as output signals:

within Modelica.Mechanics.MultiBody.Sensors;
model AbsoluteSensor
  "Measure absolute kinematic quantities of frame connector"

  Blocks.Interfaces.RealOutput r[3](
    each final quantity="Length",
    each final unit="m") if get_r
    "Absolute position vector frame_a.r_0 resolved in frame defined by resolveInFrame"
  Blocks.Interfaces.RealOutput v[3](
    each final quantity="Velocity",
    each final unit="m/s") if get_v "Absolute velocity vector"
  Blocks.Interfaces.RealOutput a[3](
    each final quantity="Acceleration",
    each final unit="m/s2") if get_a "Absolute acceleration vector"
  Blocks.Interfaces.RealOutput angles[3](
    each final quantity="Angle",
    each final unit="rad",
    each displayUnit="deg") if get_angles
    "Angles to rotate world frame into frame_a via 'sequence'"
  Blocks.Interfaces.RealOutput w[3](
    each final quantity="AngularVelocity",
    each final unit="rad/s") if get_w "Absolute angular velocity vector"
  Blocks.Interfaces.RealOutput z[3](
    each final quantity="AngularAcceleration",
    each final unit="rad/s2") if get_z "Absolute angular acceleration vector"

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

  Interfaces.Frame_resolve frame_resolve if resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve
    "If resolveInFrame = Types.ResolveInFrameA.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.ResolveInFrameA resolveInFrame=
      Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_a
    "Frame in which vectors are resolved (world, frame_a, or frame_resolve)";
  parameter Boolean get_r=false
    "= true, to measure the absolute position vector of the origin of frame_a"
  parameter Boolean get_v=false
    "= true, to measure the absolute velocity of the origin of frame_a"
  parameter Boolean get_a=false
    "= true, to measure the absolute acceleration of the origin of frame_a"
  parameter Boolean get_w=false
    "= true, to measure the absolute angular velocity of frame_a"
  parameter Boolean get_z=false
    "= true, to measure the absolute angular acceleration of 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 world frame around axes sequence[1], sequence[2] and finally sequence[3] into frame_a"
  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 absolute arrow from world frame to frame_b"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  AbsolutePosition position(resolveInFrame=resolveInFrame) if get_r

protected
  AbsoluteVelocity velocity(resolveInFrame=resolveInFrame) if get_v
  Modelica.Mechanics.MultiBody.Sensors.AbsoluteAngles absoluteAngles(sequence=sequence, guessAngle1=guessAngle1) if get_angles
  AbsoluteAngularVelocity angularVelocity(resolveInFrame=resolveInFrame) if get_w

protected
  Blocks.Continuous.Der der1[3] if get_a
protected
  Blocks.Continuous.Der der2[3] if get_z

protected
  Modelica.Mechanics.MultiBody.Sensors.TransformAbsoluteVector transformVector_a(frame_r_in=Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.world, frame_r_out=resolveInFrame) if get_a
  Modelica.Mechanics.MultiBody.Sensors.TransformAbsoluteVector transformVector_z(frame_r_in=Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.world, frame_r_out=resolveInFrame) if get_z

protected
  outer Modelica.Mechanics.MultiBody.World world;

  Modelica.Mechanics.MultiBody.Visualizers.Advanced.Vector arrow(
    coordinates=frame_a.r_0,
    quantity=Types.VectorQuantity.RelativePosition,
    color=arrowColor,
    specularCoefficient=specularCoefficient) if world.enableAnimation and animation;

protected
  AbsoluteVelocity absoluteVelocity(resolveInFrame=Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.world) if get_a
  AbsoluteAngularVelocity absoluteAngularVelocity(resolveInFrame=Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.world) if
       get_z
  Modelica.Mechanics.MultiBody.Forces.Internal.ZeroForceAndTorque zeroForce1
  Modelica.Mechanics.MultiBody.Forces.Internal.ZeroForceAndTorque zeroForce2 if resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve
equation
  connect(zeroForce1.frame_a, frame_a)
  connect(absoluteAngles.angles, angles)
  connect(angularVelocity.frame_a, frame_a)
  connect(angularVelocity.w, w)
  connect(frame_resolve, position.frame_resolve)
  connect(frame_resolve,zeroForce2. frame_a)
  connect(angularVelocity.frame_resolve, frame_resolve)
  connect(transformVector_a.frame_a, frame_a)
  connect(transformVector_a.frame_resolve, frame_resolve)
  connect(transformVector_a.r_out, a)
  connect(der2.y, transformVector_z.r_in)
  connect(transformVector_z.r_out, z)
  connect(transformVector_z.frame_a, frame_a)
  connect(transformVector_z.frame_resolve, frame_resolve)
  connect(frame_a, position.frame_a)
  connect(absoluteAngles.frame_a, frame_a)
  connect(position.r, r)
  connect(velocity.frame_a, frame_a)
  connect(velocity.frame_resolve, frame_resolve)
  connect(velocity.v, v)
  connect(der1.y, transformVector_a.r_in)
  connect(absoluteVelocity.v, der1.u)
  connect(absoluteVelocity.frame_a, frame_a)
  connect(absoluteAngularVelocity.frame_a, frame_a)
  connect(absoluteAngularVelocity.w, der2.u)
v  = resolve2(frame_a.R, v0);

is returned, i.e., the derivative of the absolute distance from the
world frame to the origin of frame_a, resolved in frame_a.

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 the world
frame into frame_a along the axes defined by parameter sequence
are returned. For example, if sequence = {3,1,2} then the world frame 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_a.
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 absolute transformation matrix of frame_a
may be in a singular configuration with respect to \"sequence\", i.e.,
there is an infinite number of angle values leading to the same absolute
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 AbsoluteSensor;


Measure absolute velocity vector of origin of frame connector. The absolute velocity vector of the origin of frame_a is
determined and provided at the output signal connector v.

within Modelica.Mechanics.MultiBody.Sensors;
model AbsoluteVelocity
  "Measure absolute velocity vector of origin of frame connector"
  extends Internal.PartialAbsoluteSensor;

  Blocks.Interfaces.RealOutput v[3](
    each final quantity="Velocity",
    each final unit="m/s")
    "Absolute velocity vector resolved in frame defined by resolveInFrame"
  Modelica.Mechanics.MultiBody.Interfaces.Frame_resolve frame_resolve if
    resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve
    "Coordinate system in which output vector v is optionally resolved"

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

protected
  Internal.BasicAbsolutePosition position(
    resolveInFrame=Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.world)
  Blocks.Continuous.Der der1[3]
  Modelica.Mechanics.MultiBody.Sensors.TransformAbsoluteVector transformAbsoluteVector(frame_r_in=Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.world, frame_r_out=resolveInFrame)
  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition
  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition1 if not (
    resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve)
equation
  connect(position.r, der1.u)
  connect(position.frame_a, frame_a)
  connect(der1.y, transformAbsoluteVector.r_in)
  connect(transformAbsoluteVector.r_out, v)
  connect(zeroPosition.frame_resolve, position.frame_resolve)
  connect(transformAbsoluteVector.frame_a, frame_a)
  connect(transformAbsoluteVector.frame_resolve, zeroPosition1.frame_resolve)
  connect(transformAbsoluteVector.frame_resolve, frame_resolve)
v  = MultiBody.Frames.resolve2(frame_a.R, v0);
</pre></blockquote>
</html>"));
end AbsoluteVelocity;


Measure cut force vector. The cut-force acting between the two frames to which this
model is connected, is determined and 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;
model CutForce "Measure cut force vector"

  Modelica.Blocks.Interfaces.RealOutput force[3](each final quantity="Force", each final unit="N")
    "Cut force resolved in frame defined by resolveInFrame"

  parameter Boolean animation=true
    "= true, if animation shall be enabled (show arrow)";
  parameter Boolean positiveSign=true
    "= true, if force with positive sign is returned (= frame_a.f), otherwise with negative sign (= frame_b.f)";

  input Types.Color forceColor=Modelica.Mechanics.MultiBody.Types.Defaults.
      ForceColor "Color of force arrow"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

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

protected
  Visualizers.Advanced.Vector forceArrow(
    color=forceColor,
    specularCoefficient=specularCoefficient,
    R=frame_b.R,
    r=frame_b.r_0,
    headAtOrigin=true,
    quantity=Modelica.Mechanics.MultiBody.Types.VectorQuantity.Force,
    coordinates=-frame_a.f*(if positiveSign then +1 else -1)) if world.enableAnimation and animation;

  Internal.BasicCutForce cutForce(resolveInFrame=resolveInFrame, positiveSign=
        positiveSign)
  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition if
    not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve)
equation
  connect(cutForce.frame_a, frame_a)
  connect(cutForce.frame_b, frame_b)
  connect(cutForce.frame_resolve, frame_resolve)
  connect(cutForce.force, force)
  connect(zeroPosition.frame_resolve, cutForce.frame_resolve)
end CutForce;


Measure cut force and cut torque vector. The cut-force and cut-torque acting between the two frames to which this
model is connected, are determined and provided at the output signal connectors
force (= frame_a.f) and torque (= frame_a.t).
If parameter positiveSign =
false, the negative cut-force and cut-torque is provided
(= frame_b.f, frame_b.t).

within Modelica.Mechanics.MultiBody.Sensors;
model CutForceAndTorque "Measure cut force and cut torque vector"

  import Modelica.Mechanics.MultiBody.Types;

  Modelica.Blocks.Interfaces.RealOutput force[3](
    each final quantity="Force",
    each final unit="N")
    "Cut force resolved in frame defined by resolveInFrame"
  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 animation=true
    "= true, if animation shall be enabled (show force and torque arrow)";
  parameter Boolean positiveSign=true
    "= true, if force and torque with positive sign is returned (= frame_a.f/.t), otherwise with negative sign (= frame_b.f/.t)";
  input Types.Color forceColor=Modelica.Mechanics.MultiBody.Types.Defaults.ForceColor
    "Color of force arrow"
  input Types.Color torqueColor=Modelica.Mechanics.MultiBody.Types.Defaults.TorqueColor
    "Color of torque arrow"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

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

protected
  parameter Integer csign=if positiveSign then +1 else -1;
  Visualizers.Advanced.Vector forceArrow(
    color=forceColor,
    specularCoefficient=specularCoefficient,
    R=frame_b.R,
    r=frame_b.r_0,
    headAtOrigin=true,
    quantity=Modelica.Mechanics.MultiBody.Types.VectorQuantity.Force,
    coordinates=-frame_a.f*csign) if world.enableAnimation and animation;
  Visualizers.Advanced.Vector torqueArrow(
    color=torqueColor,
    specularCoefficient=specularCoefficient,
    quantity=Modelica.Mechanics.MultiBody.Types.VectorQuantity.Torque,
    R=frame_b.R,
    r=frame_b.r_0,
    headAtOrigin=true,
    twoHeadedArrow=true,
    coordinates=-frame_a.t*csign) if world.enableAnimation and animation;
  Internal.BasicCutForce cutForce(resolveInFrame=resolveInFrame, positiveSign=
        positiveSign)
  Internal.BasicCutTorque cutTorque(resolveInFrame=resolveInFrame, positiveSign=
       positiveSign)
  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition if
    not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve)
equation
  connect(cutForce.frame_a, frame_a)
  connect(cutForce.frame_b, cutTorque.frame_a)
  connect(cutTorque.frame_b, frame_b)
  connect(cutForce.force, force)
  connect(cutTorque.torque, torque)
  connect(zeroPosition.frame_resolve, cutTorque.frame_resolve)
  connect(zeroPosition.frame_resolve, cutForce.frame_resolve)
  connect(cutForce.frame_resolve, frame_resolve)
  connect(cutTorque.frame_resolve, frame_resolve)
end CutForceAndTorque;


Measure cut torque vector. The cut-torque acting between the two frames to which this
model is connected, is determined and provided at the output signal connector
torque (= frame_a.t). If parameter positiveSign =
false, the negative cut-torque is provided (= frame_b.t).

within Modelica.Mechanics.MultiBody.Sensors;
model CutTorque "Measure cut torque vector"

  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 animation=true
    "= true, if animation shall be enabled (show arrow)";
  parameter Boolean positiveSign=true
    "= true, if torque with positive sign is returned (= frame_a.t), otherwise with negative sign (= frame_b.t)";
  input Types.Color torqueColor=Modelica.Mechanics.MultiBody.Types.Defaults.TorqueColor
    "Color of torque arrow"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

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

protected
  Visualizers.Advanced.Vector torqueArrow(
    color=torqueColor,
    specularCoefficient=specularCoefficient,
    quantity=Modelica.Mechanics.MultiBody.Types.VectorQuantity.Torque,
    R=frame_b.R,
    r=frame_b.r_0,
    headAtOrigin=true,
    twoHeadedArrow=true,
    coordinates=-frame_a.t*(if positiveSign then +1 else -1)) if world.enableAnimation and animation;
  Internal.BasicCutTorque cutTorque(resolveInFrame=resolveInFrame, positiveSign=
       positiveSign)
  Modelica.Mechanics.MultiBody.Interfaces.ZeroPosition zeroPosition if
    not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameA.frame_resolve)
equation
  connect(cutTorque.frame_a, frame_a)
  connect(cutTorque.frame_b, frame_b)
  connect(cutTorque.torque, torque)
  connect(cutTorque.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, cutTorque.frame_resolve)
end CutTorque;