Motor inertia and gearbox model for r3 joints 4,5,6. The elasticity and damping in the gearboxes of the outermost
three joints of the robot is neglected.
Default values for all parameters are given for joint 4.

within Modelica.Mechanics.MultiBody.Examples.Systems.RobotR3.Utilities;
model GearType2 "Motor inertia and gearbox model for r3 joints 4,5,6"
  extends Modelica.Mechanics.Rotational.Icons.Gearbox;
  extends Modelica.Mechanics.Rotational.Interfaces.PartialTwoFlanges;

  parameter Real i=-99 "Gear ratio";
  parameter SI.Torque Rv0=21.8 "Viscous friction torque at zero velocity";
  parameter Real Rv1(unit="N.m.s/rad")=9.8
    "Viscous friction coefficient (R=Rv0+Rv1*abs(qd))";
  parameter Real peak=(26.7/21.8)
    "Maximum static friction torque is peak*Rv0 (peak >= 1)";

  constant SI.AngularVelocity unitAngularVelocity = 1;
  constant SI.Torque unitTorque = 1;
  Modelica.Mechanics.Rotational.Components.IdealGear gear(
    ratio=i, useSupport=false)
  Modelica.Mechanics.Rotational.Components.BearingFriction bearingFriction(
    tau_pos=[0,
         Rv0/unitTorque; 1, (Rv0 + Rv1*unitAngularVelocity)/unitTorque], peak=peak,
    useSupport=false)
equation
  connect(gear.flange_b, bearingFriction.flange_a)
  connect(bearingFriction.flange_b, flange_b)
  connect(gear.flange_a, flange_a)
end GearType2;


Model of the mechanical part of the r3 robot (without animation). This model contains the mechanical components of the r3 robot
(multibody system).

within Modelica.Mechanics.MultiBody.Examples.Systems.RobotR3.Utilities;
model MechanicalStructure
  "Model of the mechanical part of the r3 robot (without animation)"
  import Modelica.Units.Conversions.to_unit1;

  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter SI.Mass mLoad(min=0)=15 "Mass of load";
  parameter SI.Position rLoad[3]={0,0.25,0}
    "Distance from last flange to load mass";
  parameter SI.Acceleration g=9.81 "Gravity acceleration";
  SI.Angle q[6] "Joint angles";
  SI.AngularVelocity qd[6] "Joint speeds";
  SI.AngularAcceleration qdd[6] "Joint accelerations";
  SI.Torque tau[6] "Joint driving torques";
  //r0={0,0.351,0},

  Modelica.Mechanics.Rotational.Interfaces.Flange_a axis1
  Modelica.Mechanics.Rotational.Interfaces.Flange_a axis2
  Modelica.Mechanics.Rotational.Interfaces.Flange_a axis3
  Modelica.Mechanics.Rotational.Interfaces.Flange_a axis4
  Modelica.Mechanics.Rotational.Interfaces.Flange_a axis5
  Modelica.Mechanics.Rotational.Interfaces.Flange_a axis6
  inner Modelica.Mechanics.MultiBody.World world(
    g=(g)*Modelica.Math.Vectors.length(({0,-1,0})),
    n={0,-1,0},
    animateWorld=false,
    animateGravity=false,
    enableAnimation=animation)
  Modelica.Mechanics.MultiBody.Joints.Revolute r1(
    n={0,1,0},
    useAxisFlange=true,
    animation=animation)
  Modelica.Mechanics.MultiBody.Joints.Revolute r2(
    n={1,0,0},
    useAxisFlange=true,
    animation=animation)
  Modelica.Mechanics.MultiBody.Joints.Revolute r3(
    n={1,0,0},
    useAxisFlange=true,
    animation=animation)
  Modelica.Mechanics.MultiBody.Joints.Revolute r4(
    n={0,1,0},
    useAxisFlange=true,
    animation=animation)
  Modelica.Mechanics.MultiBody.Joints.Revolute r5(
    n={1,0,0},
    useAxisFlange=true,
    animation=animation)
  Modelica.Mechanics.MultiBody.Joints.Revolute r6(
    n={0,1,0},
    useAxisFlange=true,
    animation=animation)
  Modelica.Mechanics.MultiBody.Parts.BodyShape b0(
    r={0,0.351,0},
    shapeType="modelica://Modelica/Resources/Data/Shapes/RobotR3/b0.dxf",
    r_shape={0,0,0},
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    length=0.225,
    width=0.3,
    height=0.3,
    color={0,0,255},
    animation=animation,
    animateSphere=false,
    r_CM={0,0,0},
    m=1)
  Modelica.Mechanics.MultiBody.Parts.BodyShape b1(
    r={0,0.324,0.3},
    I_22=1.16,
    shapeType="modelica://Modelica/Resources/Data/Shapes/RobotR3/b1.dxf",
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    length=0.25,
    width=0.15,
    height=0.2,
    animation=animation,
    animateSphere=false,
    color={255,0,0},
    r_CM={0,0,0},
    m=1)
  Modelica.Mechanics.MultiBody.Parts.BodyShape b2(
    r={0,0.65,0},
    r_CM={0.172,0.205,0},
    m=56.5,
    I_11=2.58,
    I_22=0.64,
    I_33=2.73,
    I_21=-0.46,
    shapeType="modelica://Modelica/Resources/Data/Shapes/RobotR3/b2.dxf",
    r_shape={0,0,0},
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    length=0.5,
    width=0.2,
    height=0.15,
    animation=animation,
    animateSphere=false,
    color={255,178,0})
  Modelica.Mechanics.MultiBody.Parts.BodyShape b3(
    r={0,0.414,-0.155},
    r_CM={0.064,-0.034,0},
    m=26.4,
    I_11=0.279,
    I_22=0.245,
    I_33=0.413,
    I_21=-0.070,
    shapeType="modelica://Modelica/Resources/Data/Shapes/RobotR3/b3.dxf",
    r_shape={0,0,0},
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    length=0.15,
    width=0.15,
    height=0.15,
    animation=animation,
    animateSphere=false,
    color={255,0,0})
  Modelica.Mechanics.MultiBody.Parts.BodyShape b4(
    r={0,0.186,0},
    r_CM={0,0,0},
    m=28.7,
    I_11=1.67,
    I_22=0.081,
    I_33=1.67,
    shapeType="modelica://Modelica/Resources/Data/Shapes/RobotR3/b4.dxf",
    r_shape={0,0,0},
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    length=0.73,
    width=0.1,
    height=0.1,
    animation=animation,
    animateSphere=false,
    color={255,178,0})
  Modelica.Mechanics.MultiBody.Parts.BodyShape b5(
    r={0,0.125,0},
    r_CM={0,0,0},
    m=5.2,
    I_11=1.25,
    I_22=0.81,
    I_33=1.53,
    shapeType="modelica://Modelica/Resources/Data/Shapes/RobotR3/b5.dxf",
    r_shape={0,0,0},
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    length=0.225,
    width=0.075,
    height=0.1,
    animation=animation,
    animateSphere=false,
    color={0,0,255})
  Modelica.Mechanics.MultiBody.Parts.BodyShape b6(
    r={0,0,0},
    r_CM={0.05,0.05,0.05},
    m=0.5,
    shapeType="modelica://Modelica/Resources/Data/Shapes/RobotR3/b6.dxf",
    r_shape={0,0,0},
    lengthDirection={1,0,0},
    widthDirection={0,1,0},
    animation=animation,
    animateSphere=false,
    color={0,0,255})
  Modelica.Mechanics.MultiBody.Parts.BodyShape load(
    r={0,0,0},
    r_CM=rLoad,
    m=mLoad,
    r_shape={0,0,0},
    widthDirection={1,0,0},
    width=0.05,
    height=0.05,
    color={255,0,0},
    lengthDirection = to_unit1(rLoad),
    length=Modelica.Math.Vectors.length(rLoad),
    animation=animation)
equation
  q = {r1.phi,r2.phi,r3.phi,r4.phi,r5.phi,r6.phi};
  qd = der(q);
  qdd = der(qd);
  tau = {r1.tau, r2.tau, r3.tau, r4.tau, r5.tau, r6.tau};

  connect(load.frame_a, b6.frame_b)
  connect(world.frame_b, b0.frame_a)
  connect(b0.frame_b, r1.frame_a)
  connect(b1.frame_b, r2.frame_a)
  connect(r1.frame_b, b1.frame_a)
  connect(r2.frame_b, b2.frame_a)
  connect(b2.frame_b, r3.frame_a)
  connect(r2.axis, axis2)
  connect(r1.axis, axis1)
  connect(r3.frame_b, b3.frame_a)
  connect(b3.frame_b, r4.frame_a)
  connect(r3.axis, axis3)
  connect(r4.axis, axis4)
  connect(r4.frame_b, b4.frame_a)
  connect(b4.frame_b, r5.frame_a)
  connect(r5.axis, axis5)
  connect(r5.frame_b, b5.frame_a)
  connect(b5.frame_b, r6.frame_a)
  connect(r6.axis, axis6)
  connect(r6.frame_b, b6.frame_a)
end MechanicalStructure;


Motor model including current controller of r3 motors. Default values are given for the motor of joint 1.
The input of the motor is the desired current
(the actual current is proportional to the torque
produced by the motor).

within Modelica.Mechanics.MultiBody.Examples.Systems.RobotR3.Utilities;
model Motor "Motor model including current controller of r3 motors"
  extends Electrical.Machines.Icons.Machine;
  parameter SI.Inertia J(min=0)=0.0013 "Moment of inertia of motor";
  parameter Real k=1.1616 "Gain of motor";
  parameter Real w=4590 "Time constant of motor";
  parameter Real D=0.6 "Damping constant of motor";
  parameter SI.AngularVelocity w_max=315 "Maximum speed of motor";
  parameter SI.Current i_max=9 "Maximum current of motor";

  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_motor
  Modelica.Electrical.Analog.Sources.SignalVoltage Vs
  Modelica.Electrical.Analog.Ideal.IdealOpAmp power
  Modelica.Electrical.Analog.Ideal.IdealOpAmp diff
  Electrical.Analog.Basic.RotationalEMF emf(k=k, useSupport=false)
  Modelica.Electrical.Analog.Basic.Inductor La(L=(250/(2*D*w)))
  Modelica.Electrical.Analog.Basic.Resistor Ra(R=250)
  Modelica.Electrical.Analog.Basic.Resistor Rd2(R=100)
  Modelica.Electrical.Analog.Basic.Capacitor C(C=0.004*D/w)
  Modelica.Electrical.Analog.Ideal.IdealOpAmp OpI
  Modelica.Electrical.Analog.Basic.Resistor Ri(R=10)
  Modelica.Electrical.Analog.Basic.Resistor Rd1(R=100)
  Modelica.Electrical.Analog.Basic.Resistor Rp1(R=200)
  Modelica.Electrical.Analog.Basic.Resistor Rp2(R=50)
  Modelica.Electrical.Analog.Basic.Resistor Rd4(R=100)
  Modelica.Electrical.Analog.Sources.SignalVoltage hall2
  Modelica.Electrical.Analog.Basic.Resistor Rd3(R=100)
  Modelica.Electrical.Analog.Basic.Ground g1
  Modelica.Electrical.Analog.Basic.Ground g2
  Modelica.Electrical.Analog.Basic.Ground g3
  Modelica.Electrical.Analog.Sensors.CurrentSensor hall1
  Modelica.Electrical.Analog.Basic.Ground g4
  Modelica.Electrical.Analog.Basic.Ground g5
  Modelica.Mechanics.Rotational.Sensors.AngleSensor phi
  Modelica.Mechanics.Rotational.Sensors.SpeedSensor speed
  Modelica.Mechanics.Rotational.Components.Inertia Jmotor(
                                               J=J)
  Modelica.Mechanics.MultiBody.Examples.Systems.RobotR3.Utilities.AxisControlBus axisControlBus
  Blocks.Math.Gain convert1(k(unit="V/A")=1)
  Blocks.Math.Gain convert2(k(unit="V/A")=1)
initial equation
  // initialize motor in steady state
  der(C.v) = 0;
  der(La.i) = 0;

equation
  connect(La.n, emf.p)
  connect(Ra.n, La.p)
  connect(Rd2.n, diff.n1)
  connect(C.n, OpI.p2)
  connect(OpI.p2, power.p1)
  connect(Vs.p, Rd2.p)
  connect(diff.n1, Rd1.p)
  connect(Rd1.n, diff.p2)
  connect(diff.p2, Ri.p)
  connect(Ri.n, OpI.n1)
  connect(OpI.n1, C.p)
  connect(power.n1, Rp1.p)
  connect(power.p2, Rp1.n)
  connect(Rp1.p, Rp2.p)
  connect(power.p2, Ra.p)
  connect(Rd3.p, hall2.p)
  connect(Rd3.n, diff.p1)
  connect(Rd3.n, Rd4.p)
  connect(Vs.n, g1.p)
  connect(g2.p, hall2.n)
  connect(Rd4.n, g3.p)
  connect(g3.p, OpI.p1)
  connect(g5.p, Rp2.n)
  connect(emf.n, hall1.p)
  connect(hall1.n, g4.p)
  connect(emf.flange, phi.flange)
  connect(emf.flange, speed.flange)
  connect(OpI.n2, power.n2)
  connect(OpI.p1, OpI.n2)
  connect(OpI.p1, diff.n2)
  connect(Jmotor.flange_b, flange_motor)
  connect(phi.phi, axisControlBus.motorAngle)
  connect(speed.w, axisControlBus.motorSpeed)
  connect(hall1.i, axisControlBus.current)
  connect(hall1.i, convert1.u)
  connect(convert1.y, hall2.v)
  connect(convert2.u, axisControlBus.current_ref)
  connect(convert2.y, Vs.v)
  connect(emf.flange, Jmotor.flange_a)
end Motor;


Utility classes for robot examples

within Modelica.Mechanics.MultiBody.Examples.Systems.RobotR3;
package Utilities "Utility classes for robot examples"
  extends Modelica.Icons.UtilitiesPackage;
end Utilities;


Generate reference angles for fastest kinematic movement. Given

within Modelica.Mechanics.MultiBody.Examples.Systems.RobotR3.Utilities;
model PathPlanning1
  "Generate reference angles for fastest kinematic movement"
  extends Blocks.Icons.Block;

  parameter Modelica.Units.NonSI.Angle_deg angleBegDeg = 0 "Start angle";
  parameter Modelica.Units.NonSI.Angle_deg angleEndDeg = 1 "End angle";
  parameter SI.AngularVelocity speedMax = 3 "Maximum axis speed";
  parameter SI.AngularAcceleration accMax = 2.5 "Maximum axis acceleration";
  parameter SI.Time startTime=0 "Start time of movement";
  parameter SI.Time swingTime=0.5
    "Additional time after reference motion is in rest before simulation is stopped";
  final parameter SI.Angle angleBeg=Cv.from_deg(angleBegDeg) "Start angles";
  final parameter SI.Angle angleEnd=Cv.from_deg(angleEndDeg) "End angles";
  ControlBus controlBus
  Modelica.Blocks.Sources.KinematicPTP2 path(
    q_end={angleEnd},
    qd_max={speedMax},
    qdd_max={accMax},
    startTime=startTime,
    q_begin={angleBeg})
  PathToAxisControlBus pathToAxis1(final nAxis=1, final axisUsed=1)

  Blocks.Logical.TerminateSimulation terminateSimulation(condition=time >= path.endTime
         + swingTime)
equation
  connect(path.q, pathToAxis1.q)
  connect(path.qd, pathToAxis1.qd)
  connect(path.qdd, pathToAxis1.qdd)
  connect(path.moving, pathToAxis1.moving)
  connect(pathToAxis1.axisControlBus, controlBus.axisControlBus1)
end PathPlanning1;


within Modelica.Mechanics.MultiBody.Examples.Systems.RobotR3.Utilities;
model PathPlanning6
  "Generate reference angles for fastest kinematic movement"
  extends Blocks.Icons.Block;

  parameter Integer naxis=6 "Number of driven axis";
  parameter Modelica.Units.NonSI.Angle_deg angleBegDeg[naxis] = zeros(naxis)
    "Start angles";
  parameter Modelica.Units.NonSI.Angle_deg angleEndDeg[naxis] = ones(naxis)
    "End angles";
  parameter SI.AngularVelocity speedMax[naxis]=fill(3, naxis)
    "Maximum axis speed";
  parameter SI.AngularAcceleration accMax[naxis]=fill(2.5, naxis)
    "Maximum axis acceleration";
  parameter SI.Time startTime=0 "Start time of movement";
  parameter SI.Time swingTime=0.5
    "Additional time after reference motion is in rest before simulation is stopped";
  final parameter SI.Angle angleBeg[:]=Cv.from_deg(angleBegDeg)
    "Start angles";
  final parameter SI.Angle angleEnd[:]=Cv.from_deg(angleEndDeg)
    "End angles";
  ControlBus controlBus
  Modelica.Blocks.Sources.KinematicPTP2 path(
    q_end=angleEnd,
    qd_max=speedMax,
    qdd_max=accMax,
    startTime=startTime,
    q_begin=angleBeg)
  PathToAxisControlBus pathToAxis1(nAxis=naxis, axisUsed=1)
  PathToAxisControlBus pathToAxis2(nAxis=naxis, axisUsed=2)
  PathToAxisControlBus pathToAxis3(nAxis=naxis, axisUsed=3)
  PathToAxisControlBus pathToAxis4(nAxis=naxis, axisUsed=4)
  PathToAxisControlBus pathToAxis5(nAxis=naxis, axisUsed=5)
  PathToAxisControlBus pathToAxis6(nAxis=naxis, axisUsed=6)

  Blocks.Logical.TerminateSimulation terminateSimulation(condition=time >= path.endTime
         + swingTime)
equation
  connect(path.q, pathToAxis1.q)
  connect(path.qd, pathToAxis1.qd)
  connect(path.qdd, pathToAxis1.qdd)
  connect(path.moving, pathToAxis1.moving)
  connect(path.q, pathToAxis2.q)
  connect(path.qd, pathToAxis2.qd)
  connect(path.qdd, pathToAxis2.qdd)
  connect(path.moving, pathToAxis2.moving)
  connect(path.q, pathToAxis3.q)
  connect(path.qd, pathToAxis3.qd)
  connect(path.qdd, pathToAxis3.qdd)
  connect(path.moving, pathToAxis3.moving)
  connect(path.q, pathToAxis4.q)
  connect(path.qd, pathToAxis4.qd)
  connect(path.qdd, pathToAxis4.qdd)
  connect(path.moving, pathToAxis4.moving)
  connect(path.q, pathToAxis5.q)
  connect(path.qd, pathToAxis5.qd)
  connect(path.qdd, pathToAxis5.qdd)
  connect(path.moving, pathToAxis5.moving)
  connect(path.q, pathToAxis6.q)
  connect(path.qd, pathToAxis6.qd)
  connect(path.qdd, pathToAxis6.qdd)
  connect(path.moving, pathToAxis6.moving)
  connect(pathToAxis1.axisControlBus, controlBus.axisControlBus1)
  connect(pathToAxis2.axisControlBus, controlBus.axisControlBus2)
  connect(pathToAxis3.axisControlBus, controlBus.axisControlBus3)
  connect(pathToAxis4.axisControlBus, controlBus.axisControlBus4)
  connect(pathToAxis5.axisControlBus, controlBus.axisControlBus5)
  connect(pathToAxis6.axisControlBus, controlBus.axisControlBus6)
end PathPlanning6;


Map path planning to one axis control bus. This model stores the 4 reference variables q, qd, qdd, moving from the path planning on the axis control bus.

within Modelica.Mechanics.MultiBody.Examples.Systems.RobotR3.Utilities;
model PathToAxisControlBus "Map path planning to one axis control bus"
  extends Modelica.Blocks.Icons.Block;

  parameter Integer nAxis=6 "Number of driven axis";
  parameter Integer axisUsed=1
    "Map path planning of axisUsed to axisControlBus";
  Blocks.Interfaces.RealInput q[nAxis]
  Blocks.Interfaces.RealInput qd[nAxis]
  Blocks.Interfaces.RealInput qdd[nAxis]
  AxisControlBus axisControlBus
  Blocks.Routing.RealPassThrough q_axisUsed
  Blocks.Routing.RealPassThrough qd_axisUsed
  Blocks.Routing.RealPassThrough qdd_axisUsed
  Blocks.Interfaces.BooleanInput moving[nAxis]
  Blocks.Routing.BooleanPassThrough motion_ref_axisUsed
equation
  connect(q_axisUsed.u, q[axisUsed])
  connect(qd_axisUsed.u, qd[axisUsed])
  connect(qdd_axisUsed.u, qdd[axisUsed])
  connect(motion_ref_axisUsed.u, moving[axisUsed])
  connect(motion_ref_axisUsed.y, axisControlBus.motion_ref)
  connect(qdd_axisUsed.y, axisControlBus.acceleration_ref)
  connect(qd_axisUsed.y, axisControlBus.speed_ref)
  connect(q_axisUsed.y, axisControlBus.angle_ref)
end PathToAxisControlBus;


Linear (velocity dependent) damper. Linear damper acting as line force between frame_a and frame_b.
A force f is exerted on the origin of frame_b and with opposite sign
on the origin of frame_a along the line from the origin of frame_a to the origin
of frame_b according to the equation:

within Modelica.Mechanics.MultiBody.Forces;
model Damper "Linear (velocity dependent) damper"
  import Modelica.Mechanics.MultiBody.Types;
  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter SI.TranslationalDampingConstant d(final min=0, start = 0)
    "Damping constant";
  parameter SI.Distance length_a=world.defaultForceLength
    "Length of cylinder at frame_a side"
  input SI.Diameter diameter_a=world.defaultForceWidth
    "Diameter of cylinder at frame_a side"
  input SI.Diameter diameter_b=0.6*diameter_a
    "Diameter of cylinder at frame_b side"
  input Types.Color color_a={100,100,100} "Color at frame_a"
  input Types.Color color_b={155,155,155} "Color at frame_b"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  extends Interfaces.PartialLineForce;
  extends Modelica.Thermal.HeatTransfer.Interfaces.PartialElementaryConditionalHeatPort(
     final T=293.15);
protected
  SI.Position r0_b[3]=e_a*noEvent(min(length_a, s));
  Visualizers.Advanced.Shape shape_a(
    shapeType="cylinder",
    color=color_a,
    specularCoefficient=specularCoefficient,
    length=noEvent(min(length_a, s)),
    width=diameter_a,
    height=diameter_a,
    lengthDirection=e_a,
    widthDirection={0,1,0},
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
  Visualizers.Advanced.Shape shape_b(
    shapeType="cylinder",
    color=color_b,
    specularCoefficient=specularCoefficient,
    length=noEvent(max(s - length_a, 0)),
    width=diameter_b,
    height=diameter_b,
    lengthDirection=e_a,
    widthDirection={0,1,0},
    r_shape=r0_b,
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
equation
  f = d*der(s);
  lossPower = f*der(s);

where \"d\" is a parameter, \"s\" is the
distance between the origin of frame_a and the origin of frame_b
and der(s) is the time derivative of \"s\".

In the following figure a typical animation is shown
where a mass is hanging on a damper.

"),
    Icon(coordinateSystem(
        preserveAspectRatio=true,
        extent={{-100,-100},{100,100}}), graphics={
        Line(points={{-101,0},{-60,0}}),
        Line(points={{-60,-30},{-60,30}}),
        Line(points={{-60,-30},{60,-30}}),
        Line(points={{-60,30},{60,30}}),
        Rectangle(
          extent={{-60,30},{30,-30}},
          fillColor={192,192,192},
          fillPattern=FillPattern.Solid),
        Line(points={{30,0},{100,0}}),
        Text(
          extent={{-150,90},{150,50}},
          textString="%name",
          textColor={0,0,255}),
        Text(extent={{-150,-50},{150,-80}}, textString="d=%d"),
        Line(visible=useHeatPort,
          points={{-100,-99},{-100,-25},{-10,-25}},
          color={191,0,0},
          pattern=LinePattern.Dot)}));
end Damper;


Force acting between two frames, defined by 3 input signals and resolved in frame world, frame_a, frame_b or frame_resolve. The 3 signals of the force connector are interpreted
as the x-, y- and z-coordinates of a force acting at the frame
connector to which frame_b of this component is attached.
Via parameter resolveInFrame it is defined, in which frame these
coordinates shall be resolved:

within Modelica.Mechanics.MultiBody.Forces;
model Force
  "Force acting between two frames, defined by 3 input signals and resolved in frame world, frame_a, frame_b or frame_resolve"
  import Modelica.Units.Conversions.to_unit1;
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames;
  Interfaces.Frame_resolve frame_resolve if
       resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve
    "The input signals are optionally resolved in this frame"
  Modelica.Blocks.Interfaces.RealInput force[3](each final quantity="Force", each final unit="N")
    "x-, y-, z-coordinates of force resolved in frame defined by resolveInFrame"
  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB
    resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_b
    "Frame in which input force is resolved (1: world, 2: frame_a, 3: frame_b, 4: frame_resolve)";
  input SI.Diameter connectionLineDiameter=world.defaultArrowDiameter
    "Diameter of line connecting frame_a and frame_b"
  input Types.Color forceColor=Modelica.Mechanics.MultiBody.Types.Defaults.ForceColor
    "Color of force arrow"
  input Types.Color connectionLineColor=Modelica.Mechanics.MultiBody.Types.Defaults.SensorColor
    "Color of line connecting frame_a and frame_b"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  Visualizers.Advanced.Vector forceArrow(
    color=forceColor,
    specularCoefficient=specularCoefficient,
    quantity=Modelica.Mechanics.MultiBody.Types.VectorQuantity.Force,
    R=frame_b.R,
    r=frame_b.r_0,
    coordinates=-frame_b.f,
    headAtOrigin=true) if world.enableAnimation and animation;
  Visualizers.Advanced.Shape connectionLine(
    shapeType="cylinder",
    lengthDirection = to_unit1(basicForce.r_0),
    widthDirection={0,1,0},
    length=Modelica.Math.Vectors.length(basicForce.r_0),
    width=connectionLineDiameter,
    height=connectionLineDiameter,
    color=connectionLineColor,
    specularCoefficient=specularCoefficient,
    r=frame_a.r_0) if world.enableAnimation and animation;

public
  Internal.BasicForce basicForce(resolveInFrame=resolveInFrame)
protected
  MultiBody.Interfaces.ZeroPosition zeroPosition if
       not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve)
equation
  connect(basicForce.frame_a, frame_a)
  connect(basicForce.frame_b, frame_b)
  connect(force, basicForce.force)
  connect(basicForce.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, basicForce.frame_resolve)
end Force;


Force and torque acting between two frames, defined by 3+3 input signals and resolved in frame world, frame_a, frame_b or frame_resolve. The 3 signals of the force connector and the
3 signals of the torque connector
are interpreted
as the x-, y- and z-coordinates of a force and of a
torque acting at the frame
connector to which frame_b of this component is attached.
Via parameter resolveInFrame it is defined, in which frame these
coordinates shall be resolved:

within Modelica.Mechanics.MultiBody.Forces;
model ForceAndTorque
  "Force and torque acting between two frames, defined by 3+3 input signals and resolved in frame world, frame_a, frame_b or frame_resolve"

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

  extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames;

  Blocks.Interfaces.RealInput force[3](each final quantity="Force", each final unit="N")
    "x-, y-, z-coordinates of force resolved in frame defined by resolveInFrame"
  Blocks.Interfaces.RealInput torque[3](each final quantity="Torque", each final unit="N.m")
    "x-, y-, z-coordinates of torque resolved in frame defined by resolveInFrame"
  Interfaces.Frame_resolve frame_resolve if
       resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve
    "The input signals are optionally resolved in this frame"

  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB
    resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_b
    "Frame in which input force and torque are resolved (1: world, 2: frame_a, 3: frame_b, 4: frame_resolve)";
  input SI.Diameter connectionLineDiameter=world.defaultArrowDiameter
    "Diameter of line connecting frame_a and frame_b"
  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.Color connectionLineColor=Modelica.Mechanics.MultiBody.Types.Defaults.SensorColor
    "Color of line connecting frame_a and frame_b"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  Visualizers.Advanced.Vector forceArrow(
    color=forceColor,
    specularCoefficient=specularCoefficient,
    quantity=Modelica.Mechanics.MultiBody.Types.VectorQuantity.Force,
    R=frame_b.R,
    r=frame_b.r_0,
    headAtOrigin=true,
    coordinates=-frame_b.f) 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_b.t) if world.enableAnimation and animation;
  Visualizers.Advanced.Shape connectionLine(
    shapeType="cylinder",
    lengthDirection = to_unit1(basicForce.r_0),
    widthDirection={0,1,0},
    length=Modelica.Math.Vectors.length(basicForce.r_0),
    width=connectionLineDiameter,
    height=connectionLineDiameter,
    color=connectionLineColor,
    specularCoefficient=specularCoefficient,
    r=frame_a.r_0) if world.enableAnimation and animation;

public
  Internal.BasicForce basicForce(resolveInFrame=resolveInFrame)
  Internal.BasicTorque basicTorque(resolveInFrame=resolveInFrame)
protected
  Interfaces.ZeroPosition zeroPosition if
       not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve)
equation
  connect(basicForce.frame_a, frame_a)
  connect(basicForce.frame_b, frame_b)
  connect(basicTorque.frame_b, frame_b)
  connect(basicTorque.frame_a, frame_a)
  connect(basicForce.force, force)
  connect(basicTorque.torque, torque)
  connect(basicTorque.frame_resolve, frame_resolve)
  connect(basicForce.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, basicTorque.frame_resolve)
  connect(zeroPosition.frame_resolve, basicForce.frame_resolve)
end ForceAndTorque;


General line force component with an optional point mass on the connection line. This component is used to exert a line force
between the origin of frame_a and the origin of frame_b
by attaching components of the 1-dimensional translational
mechanical library of Modelica (Modelica.Mechanics.Translational)
between the two flange connectors flange_a and
flange_b. Optionally, there is a point mass on the line
connecting the origin of frame_a and the origin of frame_b.
This point mass approximates the mass of the force element.
The distance of the point mass from frame_a as a fraction of the
distance between frame_a and frame_b is defined via
parameter lengthFraction (default is 0.5, i.e., the point
mass is in the middle of the line).

within Modelica.Mechanics.MultiBody.Forces;
model LineForceWithMass "General line force component with an optional point mass on the connection line"
  import Modelica.Mechanics.MultiBody.Types;
  extends Interfaces.LineForceBase;

  Modelica.Mechanics.Translational.Interfaces.Flange_a flange_b
    "1-dim. translational flange (connect force of Translational library between flange_a and flange_b)"
  Modelica.Mechanics.Translational.Interfaces.Flange_b flange_a
    "1-dim. translational flange (connect force of Translational library between flange_a and flange_b)"

  parameter Boolean animateLine=true
    "= true, if a line shape between frame_a and frame_b shall be visualized";
  parameter Boolean animateMass=true
    "= true, if point mass shall be visualized as sphere provided m > 0";
  parameter SI.Mass m(min=0)=0
    "Mass of point mass on the connection line between the origin of frame_a and the origin of frame_b";
  parameter Real lengthFraction(
    unit="1",
    min=0,
    max=1) = 0.5
    "Location of point mass with respect to frame_a as a fraction of the distance from frame_a to frame_b";
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  parameter Types.ShapeType lineShapeType="cylinder"
    "Type of shape visualizing the line from frame_a to frame_b"
  input SI.Length lineShapeWidth=world.defaultArrowDiameter "Width of shape"
  input SI.Length lineShapeHeight=lineShapeWidth "Height of shape"
  parameter Types.ShapeExtra lineShapeExtra=0.0 "Extra parameter for shape"
  input Types.Color lineShapeColor=Modelica.Mechanics.MultiBody.Types.Defaults.SensorColor
    "Color of line shape"
  input Real massDiameter=world.defaultBodyDiameter
    "Diameter of point mass sphere"
  input Types.Color massColor=Modelica.Mechanics.MultiBody.Types.Defaults.BodyColor
    "Color of point mass"

protected
  SI.Force fa "Force from flange_a";
  SI.Force fb "Force from flange_b";
  SI.Position r_CM_0[3](each stateSelect=StateSelect.avoid)
    "Position vector from world frame to point mass, resolved in world frame";
  SI.Velocity v_CM_0[3](each stateSelect=StateSelect.avoid)
    "First derivative of r_CM_0";
  SI.Acceleration ag_CM_0[3] "der(v_CM_0) - gravityAcceleration";

  Visualizers.Advanced.Shape lineShape(
    shapeType=lineShapeType,
    color=lineShapeColor,
    specularCoefficient=specularCoefficient,
    length=length,
    width=lineShapeWidth,
    height=lineShapeHeight,
    lengthDirection=e_rel_0,
    widthDirection=Frames.resolve1(frame_a.R, {0,1,0}),
    extra=lineShapeExtra,
    r=frame_a.r_0) if world.enableAnimation and animateLine;

  Visualizers.Advanced.Shape massShape(
    shapeType="sphere",
    color=massColor,
    specularCoefficient=specularCoefficient,
    length=massDiameter,
    width=massDiameter,
    height=massDiameter,
    lengthDirection=e_rel_0,
    widthDirection={0,1,0},
    r_shape=e_rel_0*(length*lengthFraction - massDiameter/2),
    r=frame_a.r_0) if world.enableAnimation and animateMass and m > 0;

equation
  flange_a.s = 0;
  flange_b.s = length;

  // Determine translational flange forces
  if cardinality(flange_a) > 0 and cardinality(flange_b) > 0 then
    fa = flange_a.f;
    fb = flange_b.f;
  elseif cardinality(flange_a) > 0 and cardinality(flange_b) == 0 then
    fa = flange_a.f;
    fb = -fa;
  elseif cardinality(flange_a) == 0 and cardinality(flange_b) > 0 then
    fa = -fb;
    fb = flange_b.f;
  else
    fa = 0;
    fb = 0;
  end if;

  /* Force and torque balance of point mass
     - Kinematics for center of mass CM of point mass including gravity
       r_CM_0 = frame_a.r0 + r_rel_CM_0;
       v_CM_0 = der(r_CM_0);
       ag_CM_0 = der(v_CM_0) - world.gravityAcceleration(r_CM_0);
     - Power balance for the connection line
       (f1=force on frame_a side, f2=force on frame_b side, h=lengthFraction)
       0 = f1*va - m*ag_CM*(va+(vb-va)*h) + f2*vb
         = (f1 - m*ag_CM*(1-h))*va + (f2 - m*ag_CM*h)*vb
       since va and vb are completely independent from other
       the parenthesis must vanish:
         f1 := m*ag_CM*(1-h)
         f2 := m*ag_CM*h
     - Force balance on frame_a and frame_b finally results in
         0 = frame_a.f + e_rel_a*fa - f1_a
         0 = frame_b.f + e_rel_b*fb - f2_b
       and therefore
         frame_a.f = -e_rel_a*fa + m*ag_CM_a*(1-h)
         frame_b.f = -e_rel_b*fb + m*ag_CM_b*h
  */
  if m > 0 then
    r_CM_0 = frame_a.r_0 + r_rel_0*lengthFraction;
    v_CM_0 = der(r_CM_0);
    ag_CM_0 = der(v_CM_0) - world.gravityAcceleration(r_CM_0);
    frame_a.f = Frames.resolve2(frame_a.R, (m*(1 - lengthFraction))*ag_CM_0 - e_rel_0*fa);
    frame_b.f = Frames.resolve2(frame_b.R, (m*lengthFraction)*ag_CM_0 - e_rel_0*fb);
  else
    r_CM_0 = zeros(3);
    v_CM_0 = zeros(3);
    ag_CM_0 = zeros(3);
    frame_a.f = -Frames.resolve2(frame_a.R, e_rel_0*fa);
    frame_b.f = -Frames.resolve2(frame_b.R, e_rel_0*fb);
  end if;
end LineForceWithMass;


General line force component with two optional point masses on the connection line. This component is used to exert a line force
between the origin of frame_a and the origin of frame_b
by attaching components of the 1-dimensional translational
mechanical library of Modelica (Modelica.Mechanics.Translational)
between the two flange connectors flange_a and
flange_b. Optionally, there are two point masses on the line
connecting the origin of frame_a and the origin of frame_b.
These point masses approximate the masses of the force element.
The locations of the two point masses are defined by their
(fixed) distances of L_a relative to frame_a and of L_b relative
to frame_b, respectively.

within Modelica.Mechanics.MultiBody.Forces;
model LineForceWithTwoMasses
  "General line force component with two optional point masses on the connection line"
  import Modelica.Mechanics.MultiBody.Types;
  extends Interfaces.LineForceBase;

  Modelica.Mechanics.Translational.Interfaces.Flange_a flange_b
    "1-dim. translational flange (connect force of Translational library between flange_a and flange_b)"
  Modelica.Mechanics.Translational.Interfaces.Flange_b flange_a
    "1-dim. translational flange (connect force of Translational library between flange_a and flange_b)"
  parameter Boolean animate=true "= true, if animation shall be enabled";
  parameter Boolean animateMasses=true
    "= true, if point masses shall be visualized provided animate=true and m_a, m_b > 0";
  parameter SI.Mass m_a(min=0)=0
    "Mass of point mass a on the connection line between the origin of frame_a and the origin of frame_b";
  parameter SI.Mass m_b(min=0)=0
    "Mass of point mass b on the connection line between the origin of frame_a and the origin of frame_b";
  parameter SI.Position L_a=0
    "Distance between point mass a and frame_a (positive, if in direction of frame_b)";
  parameter SI.Position L_b=L_a
    "Distance between point mass b and frame_b (positive, if in direction of frame_a)";
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  input SI.Diameter cylinderDiameter_a=world.defaultForceWidth
    "Diameter of cylinder at frame_a"
  parameter SI.Length cylinderLength_a=2*L_a "Length of cylinder at frame_a"
  input Types.Color color_a={155,155,155} "Color of cylinder at frame_a"
  input Real diameterFraction=0.8
    "Diameter of cylinder at frame_b with respect to diameter of cylinder at frame_a"
  parameter SI.Length cylinderLength_b=2*L_b "Length of cylinder at frame_b"
  input Types.Color color_b={100,100,100} "Color of cylinder at frame_b"
  input Real massDiameterFaction=1.7
    "Diameter of point mass spheres with respect to cylinderDiameter_a"
  input Types.Color massColor=Modelica.Mechanics.MultiBody.Types.Defaults.BodyColor
    "Color of point masses"

protected
  SI.Force fa "Force from flange_a";
  SI.Force fb "Force from flange_b";
  SI.Position r_CM1_0[3](each stateSelect=StateSelect.avoid)
    "Position vector from world frame to point mass 1, resolved in world frame";
  SI.Position r_CM2_0[3](each stateSelect=StateSelect.avoid)
    "Position vector from world frame to point mass 2, resolved in world frame";
  SI.Velocity v_CM1_0[3](each stateSelect=StateSelect.avoid)
    "der(r_CM_1_0) - velocity of point mass 1";
  SI.Velocity v_CM2_0[3](each stateSelect=StateSelect.avoid)
    "der(r_CM_2_0) - velocity of point mass 2";
  SI.Acceleration ag_CM1_0[3] "der(v_CM1_0) - gravityAcceleration(r_CM1_0)";
  SI.Acceleration ag_CM2_0[3] "der(v_CM2_0) - gravityAcceleration(r_CM2_0)";
  SI.Force aux1_0[3] "Auxiliary force 1";
  SI.Force aux2_0[3] "Auxiliary force 2";

  input SI.Length cylinderDiameter_b=cylinderDiameter_a*diameterFraction;
  input SI.Length massDiameter=cylinderDiameter_a*massDiameterFaction;
  parameter Boolean animateMasses2=world.enableAnimation and animate and animateMasses and m_a > 0 and m_b > 0;
  Visualizers.Advanced.Shape cylinder_a(
    shapeType="cylinder",
    color=color_a,
    specularCoefficient=specularCoefficient,
    length=cylinderLength_a,
    width=cylinderDiameter_a,
    height=cylinderDiameter_a,
    lengthDirection=e_rel_0,
    widthDirection={0,1,0},
    r=frame_a.r_0) if world.enableAnimation and animate;

  Visualizers.Advanced.Shape cylinder_b(
    shapeType="cylinder",
    color=color_b,
    specularCoefficient=specularCoefficient,
    length=cylinderLength_b,
    width=cylinderDiameter_b,
    height=cylinderDiameter_b,
    lengthDirection=-e_rel_0,
    widthDirection={0,1,0},
    r=frame_b.r_0) if world.enableAnimation and animate;

  Visualizers.Advanced.Shape sphere_a(
    shapeType="sphere",
    color=massColor,
    specularCoefficient=specularCoefficient,
    length=massDiameter,
    width=massDiameter,
    height=massDiameter,
    lengthDirection=e_rel_0,
    widthDirection={0,1,0},
    r_shape=e_rel_0*(L_a - massDiameter/2),
    r=frame_a.r_0) if animateMasses2;

  Visualizers.Advanced.Shape sphere_b(
    shapeType="sphere",
    color=massColor,
    specularCoefficient=specularCoefficient,
    length=massDiameter,
    width=massDiameter,
    height=massDiameter,
    lengthDirection=-e_rel_0,
    widthDirection={0,1,0},
    r_shape=-e_rel_0*(L_b - massDiameter/2),
    r=frame_b.r_0) if animateMasses2;

equation
  flange_a.s = 0;
  flange_b.s = length;

  // Determine translational flange forces
  if cardinality(flange_a) > 0 and cardinality(flange_b) > 0 then
    fa = flange_a.f;
    fb = flange_b.f;
  elseif cardinality(flange_a) > 0 and cardinality(flange_b) == 0 then
    fa = flange_a.f;
    fb = -fa;
  elseif cardinality(flange_a) == 0 and cardinality(flange_b) > 0 then
    fa = -fb;
    fb = flange_b.f;
  else
    fa = 0;
    fb = 0;
  end if;

  /* Force and torque balance of the two point masses
     - Kinematics for center of masses CM1, CM2 of point masses including gravity
       (L = length, va = der(frame_a.r_0), vb = der(frame_b.r_0))
       r_CM1_0 = frame_a.r_0 + e_rel_0*L_a;
       r_CM2_0 = frame_b.r_0 - e_rel_0*L_b;
       v_CM1_0 = der(r_CM1_0);
       v_CM2_0 = der(r_CM2_0);
       ag_CM1_0 = der(v_CM1_0) - world.gravityAcceleration(r_CM1_0);
       ag_CM2_0 = der(v_CM2_0) - world.gravityAcceleration(r_CM2_0);
       der(e_rel_0) = der(r_rel_0/sqrt(r_rel_0*r_rel_0))
                    = 1/L*(I - e_rel_0*e_rel_0')*der(r_rel_0)
                    = 1/L*(I - e_rel_0*e_rel_0')*(vb - va)
       v_CM1_0 = va + L_a/L*(I - e_rel_0*e_rel_0')*(vb - va)
       v_CM2_0 = vb - L_b/L*(I - e_rel_0*e_rel_0')*(vb - va)
     - Power balance for the connection line
       (f1=force on frame_a side, f2=force on frame_b side)
       0 = f1*va - m_a*ag_CM1*v_CM1 + f2*vb - m_b*ag_CM2*v_CM2
         = f1*va - m_a*ag_CM1*(va + L_a/L*(I - e_rel*e_rel')*(vb - va)) +
           f2*vb - m_b*ag_CM2*(vb - L_b/L*(I - e_rel*e_rel')*(vb - va))
         = (f1 - m_a*ag_CM1*(I - L_a/L*(I - e_rel*e_rel'))
               - m_b*ag_CM2*(L_b/L*(I - e_rel*e_rel')))*va +
           (f2 - m_b*ag_CM2*(I - L_b/L*(I - e_rel_0*e_rel_0'))
               - m_a*ag_CM1*(L_a/L*(I - e_rel*e_rel')))*vb
         = va*(f1 - m_a*ag_CM1 +
               (m_a*ag_CM1*L_a/L - m_b*ag_CM2*L_b/L)*(I - e_rel*e_rel')) +
           vb*(f2 - m_b*ag_CM2 +
               (m_b*ag_CM2*L_b/L - m_a*ag_CM1*L_a/L)*(I - e_rel*e_rel'))
       since va and vb are completely independent from other
       the parenthesis must vanish:
         f1 := m_a*ag_CM1 - (m_a*ag_CM1*L_a/L - m_b*ag_CM2*L_b/L)*(I - e_rel*e_rel')
         f2 := m_b*ag_CM2 + (m_a*ag_CM1*L_a/L - m_b*ag_CM2*L_b/L)*(I - e_rel*e_rel')
       or
         aux1 := ag_CM1*(m_a*L_a/L) - ag_CM2*(m_b*L_b/L);
         aux2 := aux1 - (aux1'*e_rel)*e_rel
         f1 := m_a*ag_CM1 - aux2
         f2 := m_b*ag_CM2 + aux2
     - Force balance on frame_a and frame_b finally results in
         0 = frame_a.f + e_rel_a*fa - f1_a
         0 = frame_b.f + e_rel_b*fb - f2_b
       and therefore
         frame_a.f = -e_rel_a*fa + m_a*ag_CM1 - aux2
         frame_b.f = -e_rel_b*fb + m_b*ag_CM2 + aux2
  */
  if m_a > 0 or m_b > 0 then
    r_CM1_0 = frame_a.r_0 + e_rel_0*L_a;
    r_CM2_0 = frame_b.r_0 - e_rel_0*L_b;
    v_CM1_0 = der(r_CM1_0);
    v_CM2_0 = der(r_CM2_0);
    ag_CM1_0 = der(v_CM1_0) - world.gravityAcceleration(r_CM1_0);
    ag_CM2_0 = der(v_CM2_0) - world.gravityAcceleration(r_CM2_0);
    aux1_0 = ag_CM1_0*(m_a*L_a/length) - ag_CM2_0*(m_b*L_b/length);
    aux2_0 = aux1_0 - (aux1_0*e_rel_0)*e_rel_0;
    frame_a.f = Frames.resolve2(frame_a.R, m_a*ag_CM1_0 - aux2_0 - e_rel_0*fa);
    frame_b.f = Frames.resolve2(frame_b.R, m_b*ag_CM2_0 + aux2_0 - e_rel_0*fb);
  else
    r_CM1_0 = zeros(3);
    r_CM2_0 = zeros(3);
    v_CM1_0 = zeros(3);
    v_CM2_0 = zeros(3);
    ag_CM1_0 = zeros(3);
    ag_CM2_0 = zeros(3);
    aux1_0 = zeros(3);
    aux2_0 = zeros(3);
    frame_a.f = -Frames.resolve2(frame_a.R, e_rel_0*fa);
    frame_b.f = -Frames.resolve2(frame_b.R, e_rel_0*fb);
  end if;
end LineForceWithTwoMasses;


within Modelica.Mechanics.MultiBody;
package Forces "Components that exert forces and/or torques between frames"
  extends Modelica.Icons.SourcesPackage;
end Forces;


Linear translational spring with optional mass. Linear spring acting as line force between frame_a and frame_b.
A force f is exerted on the origin of frame_b and with opposite sign
on the origin of frame_a along the line from the origin of frame_a to the origin
of frame_b according to the equation:

within Modelica.Mechanics.MultiBody.Forces;
model Spring "Linear translational spring with optional mass"
  import Modelica.Mechanics.MultiBody.Types;
  extends Interfaces.PartialTwoFrames;
  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter Boolean showMass=true
    "= true, if point mass shall be visualized as sphere if animation=true and m>0";

  parameter SI.TranslationalSpringConstant c(final min=0) "Spring constant";
  parameter SI.Length s_unstretched=0 "Unstretched spring length";
  parameter SI.Mass m(min=0)=0
    "Spring mass located on the connection line between the origin of frame_a and the origin of frame_b";
  parameter Real lengthFraction(
    min=0,
    max=1) = 0.5
    "Location of spring mass with respect to frame_a as a fraction of the distance from frame_a to frame_b (=0: at frame_a; =1: at frame_b)";
  input SI.Distance width=world.defaultForceWidth "Width of spring"
  input SI.Distance coilWidth=width/10 "Width of spring coil"
  parameter Integer numberOfWindings=5 "Number of spring windings"
  input Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.SpringColor
    "Color of spring"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  input SI.Diameter massDiameter=max(0, (width - 2*coilWidth)*0.9)
    "Diameter of mass point sphere"
  input Types.Color massColor=Modelica.Mechanics.MultiBody.Types.Defaults.BodyColor
    "Color of mass point"
  parameter SI.Distance s_small=1e-10
    "Prevent zero-division if distance between frame_a and frame_b is zero"
  parameter Boolean fixedRotationAtFrame_a=false
    "= true, if rotation frame_a.R is fixed (to directly connect line forces)"
  parameter Boolean fixedRotationAtFrame_b=false
    "= true, if rotation frame_b.R is fixed (to directly connect line forces)"

  SI.Position r_rel_a[3]
    "Position vector from origin of frame_a to origin of frame_b, resolved in frame_a";
  Real e_a[3](each final unit="1")
    "Unit vector on the line connecting the origin of frame_a with the origin of frame_b resolved in frame_a (directed from frame_a to frame_b)";
  SI.Force f
    "Line force acting on frame_a and on frame_b (positive, if acting on frame_b and directed from frame_a to frame_b)";
  SI.Distance length
    "Distance between the origin of frame_a and the origin of frame_b";
  SI.Position s
    "(Guarded) distance between the origin of frame_a and the origin of frame_b (>= s_small))";
  SI.Position r_rel_0[3]
    "Position vector from frame_a to frame_b resolved in world frame";
  Real e_rel_0[3](each final unit="1")
    "Unit vector in direction from frame_a to frame_b, resolved in world frame";

  Forces.LineForceWithMass lineForce(
    animateLine=animation,
    animateMass=showMass,
    m=m,
    lengthFraction=lengthFraction,
    lineShapeType="spring",
    lineShapeHeight=coilWidth*2,
    lineShapeWidth=width,
    lineShapeExtra=numberOfWindings,
    lineShapeColor=color,
    specularCoefficient=specularCoefficient,
    massDiameter=massDiameter,
    massColor=massColor,
    s_small=s_small,
    fixedRotationAtFrame_a=fixedRotationAtFrame_a,
    fixedRotationAtFrame_b=fixedRotationAtFrame_b)
  Modelica.Mechanics.Translational.Components.Spring spring(
     s_rel0=s_unstretched,
     c=c)

equation
  // Results
  r_rel_a = Frames.resolve2(frame_a.R, r_rel_0);
  e_a = r_rel_a/s;
  f = spring.f;
  length = lineForce.length;
  s = lineForce.s;
  r_rel_0 = lineForce.r_rel_0;
  e_rel_0 = lineForce.e_rel_0;

  connect(lineForce.frame_a, frame_a)
  connect(lineForce.frame_b, frame_b)
  connect(spring.flange_b, lineForce.flange_b)
  connect(spring.flange_a, lineForce.flange_a)

where \"c\" and \"s_unstretched\" are parameters and \"s\" is the
distance between the origin of frame_a and the origin of frame_b.

Optionally, the mass of the spring is taken into account by a
point mass located on the line between frame_a and frame_b
(default: middle of the line). If the spring mass is zero, the
additional equations to handle the mass are removed.

In the following figure a typical animation of the
spring is shown. The blue sphere in the middle of the
spring characterizes the location of the point mass.

"));
end Spring;


Linear spring and linear damper in parallel. Linear spring and linear damper
in parallel acting as line force between frame_a and frame_b.
A force f is exerted on the origin of frame_b and with opposite sign
on the origin of frame_a along the line from the origin of frame_a to the origin
of frame_b according to the equation:

within Modelica.Mechanics.MultiBody.Forces;
model SpringDamperParallel "Linear spring and linear damper in parallel"
  import Modelica.Mechanics.MultiBody.Types;
  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter SI.TranslationalSpringConstant c(final min=0) "Spring constant";
  parameter SI.Length s_unstretched=0 "Unstretched spring length";
  parameter SI.TranslationalDampingConstant d(final min=0) = 0
    "Damping constant";
  parameter SI.Distance length_a=world.defaultForceLength
    "Length of damper cylinder at frame_a side"
  input SI.Diameter diameter_a=world.defaultForceWidth
    "Diameter of damper cylinder at frame_a side"
  input SI.Diameter diameter_b=0.6*diameter_a
    "Diameter of damper cylinder at frame_b side"
  input Types.Color color_a={100,100,100} "Color of damper cylinder at frame_a"
  input Types.Color color_b={155,155,155} "Color of damper cylinder at frame_b"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  input SI.Distance width=world.defaultForceWidth "Width of spring"
  input SI.Distance coilWidth=width/10 "Width of spring coil"
  parameter Integer numberOfWindings=5 "Number of spring windings"
  input Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.SpringColor
    "Color of spring"
  extends Interfaces.PartialLineForce;
  extends Modelica.Thermal.HeatTransfer.Interfaces.PartialElementaryConditionalHeatPort(
     final T=293.15);

protected
  SI.Force f_d "Damping force";
  Visualizers.Advanced.Shape shape_a(
    shapeType="cylinder",
    color=color_a,
    specularCoefficient=specularCoefficient,
    length=noEvent(min(length_a, s)),
    width=diameter_a,
    height=diameter_a,
    lengthDirection=e_a,
    widthDirection={0,1,0},
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
  Visualizers.Advanced.Shape shape_b(
    shapeType="cylinder",
    color=color_b,
    specularCoefficient=specularCoefficient,
    length=noEvent(max(s - length_a, 0)),
    width=diameter_b,
    height=diameter_b,
    lengthDirection=e_a,
    widthDirection={0,1,0},
    r_shape=e_a*noEvent(min(length_a, s)),
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
  Visualizers.Advanced.Shape shape(
    shapeType="spring",
    color=color,
    specularCoefficient=specularCoefficient,
    length=s,
    width=width,
    height=coilWidth*2,
    lengthDirection=e_a,
    widthDirection={0,1,0},
    extra=numberOfWindings,
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
equation
  f_d = d*der(s);
  f = c*(s - s_unstretched) + f_d;
  lossPower = f_d*der(s);

where \"c\", \"s_unstretched\" and \"d\" are parameters, \"s\" is the
distance between the origin of frame_a and the origin of frame_b
and der(s) is the time derivative of s.

"),
         Icon(coordinateSystem(
        preserveAspectRatio=true,
        extent={{-100,-100},{100,100}}), graphics={
        Text(
          extent={{-150,120},{150,80}},
          textString="%name",
          textColor={0,0,255}),
        Line(points={{-80,40},{-60,40},{-45,10},{-15,70},{15,10},{45,70},{60,
              40},{80,40}}),
        Line(points={{-80,40},{-80,-40}}),
        Line(points={{-80,-40},{80,-40}}),
        Rectangle(
          extent={{-50,-14},{40,-66}},
          fillColor={192,192,192},
          fillPattern=FillPattern.Solid),
        Line(points={{-50,-14},{68,-14}}),
        Line(points={{-50,-66},{70,-66}}),
        Line(points={{80,40},{80,-40}}),
        Line(points={{-100,0},{-80,0}}),
        Line(points={{80,0},{100,0}}),
        Text(
          extent={{-150,-105},{150,-135}},
          textString="d=%d"),
        Line(
          visible=useHeatPort,
          points={{-100,-110},{-100,-60},{0,-60}},
          color={191,0,0},
          pattern=LinePattern.Dot),
        Text(
          extent={{-150,-70},{150,-100}},
          textString="c=%c")}));
end SpringDamperParallel;


Linear spring and linear damper in series connection. Linear spring and linear damper in series connection
acting as line force between frame_a and frame_b:

within Modelica.Mechanics.MultiBody.Forces;
model SpringDamperSeries
  "Linear spring and linear damper in series connection"
  import Modelica.Mechanics.MultiBody.Types;
  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter SI.TranslationalSpringConstant c(final min=0) "Spring constant";
  parameter SI.Length s_unstretched=0 "Unstretched spring length";
  parameter SI.TranslationalDampingConstant d(final min=0) = 0
    "Damping constant";
  parameter SI.Length s_damper_start=0 "Initial length of damper";
  SI.Position s_damper(start=s_damper_start, fixed=true)
    "Actual length of damper (frame_a - damper - spring - frame_b)";
  parameter SI.Distance length_a=world.defaultForceLength
    "Length of damper cylinder at frame_a side"
  input SI.Diameter diameter_a=world.defaultForceWidth
    "Diameter of damper cylinder at frame_a side"
  input SI.Diameter diameter_b=0.6*diameter_a
    "Diameter of damper cylinder at damper-spring side"
  input Types.Color color_a={100,100,100} "Color of damper cylinder at frame_a"
  input Types.Color color_b={155,155,155} "Color of damper cylinder at damper-spring frame"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"
  input SI.Distance width=world.defaultForceWidth "Width of spring"
  input SI.Distance coilWidth=width/10 "Width of spring coil"
  parameter Integer numberOfWindings=5 "Number of spring windings"
  input Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.SpringColor
    "Color of spring"
  extends Interfaces.PartialLineForce;
  extends Modelica.Thermal.HeatTransfer.Interfaces.PartialElementaryConditionalHeatPort(
     final T=293.15);

protected
  Visualizers.Advanced.Shape shape_a(
    shapeType="cylinder",
    color=color_a,
    specularCoefficient=specularCoefficient,
    length=noEvent(min(length_a, s_damper)),
    width=diameter_a,
    height=diameter_a,
    lengthDirection=e_a,
    widthDirection={0,1,0},
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
  Visualizers.Advanced.Shape shape_b(
    shapeType="cylinder",
    color=color_b,
    specularCoefficient=specularCoefficient,
    length=noEvent(max(s_damper - length_a, 0)),
    width=diameter_b,
    height=diameter_b,
    lengthDirection=e_a,
    widthDirection={0,1,0},
    r_shape=e_a*noEvent(min(length_a, s_damper)),
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
  Visualizers.Advanced.Shape shape(
    shapeType="spring",
    color=color,
    specularCoefficient=specularCoefficient,
    length=s - s_damper,
    width=width,
    height=coilWidth*2,
    lengthDirection=e_a,
    widthDirection={0,1,0},
    extra=numberOfWindings,
    r_shape=e_a*s_damper,
    r=frame_a.r_0,
    R=frame_a.R) if world.enableAnimation and animation;
equation
  f = c*(s - s_unstretched - s_damper);
  d*der(s_damper) = f;
  lossPower = f*der(s_damper);
f = d*der(s_damper);

where \"c\", \"s_unstretched\" and \"d\" are parameters, \"s\" is the
distance between the origin of frame_a and the origin of frame_b.
\"s_damper\" is the length of the damper (= an internal state of this
force element) and der(s_damper) is the time derivative of s_damper.

"),
         Icon(coordinateSystem(
        preserveAspectRatio=true,
        extent={{-100,-100},{100,100}}), graphics={
        Line(points={{-100,0},{-15,0}}),
        Rectangle(
          extent={{-60,30},{-30,-30}},
          fillColor={192,192,192},
          fillPattern=FillPattern.Solid),
        Line(points={{-60,-30},{-15,-30}}),
        Line(points={{-60,30},{-15,30}}),
        Line(points={{-15,0},{-5,0},{5,-30},{25,30},{45,-30},{65,30},{75,0},{
              100,0}}),
        Text(
          extent={{-150,90},{150,50}},
          textString="%name",
          textColor={0,0,255}),
        Text(
          extent={{-150,-35},{150,-65}},
          textString="c=%c"),
        Line(visible=useHeatPort,
          points={{-100,-99},{-100,-24},{-45,-24}},
          color={191,0,0},
          pattern=LinePattern.Dot),
        Text(
          extent={{-150,-70},{150,-100}},
          textString="d=%d")}));
end SpringDamperSeries;


Torque acting between two frames, defined by 3 input signals and resolved in frame world, frame_a, frame_b or frame_resolve. The 3 signals of the torque connector are interpreted
as the x-, y- and z-coordinates of a torque acting at the frame
connector to which frame_b of this component is attached.
Via parameter resolveInFrame it is defined, in which frame these
coordinates shall be resolved:

within Modelica.Mechanics.MultiBody.Forces;
model Torque
  "Torque acting between two frames, defined by 3 input signals and resolved in frame world, frame_a, frame_b or frame_resolve"
  import Modelica.Units.Conversions.to_unit1;
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames;
  Interfaces.Frame_resolve frame_resolve if
       resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve
    "The input signals are optionally resolved in this frame"

  Modelica.Blocks.Interfaces.RealInput torque[3](each final quantity="Torque", each final unit="N.m")
    "x-, y-, z-coordinates of torque resolved in frame defined by resolveInFrame"
  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB
    resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_b
    "Frame in which input force is resolved (1: world, 2: frame_a, 3: frame_b, 4: frame_resolve)";
  input SI.Diameter connectionLineDiameter=world.defaultArrowDiameter
    "Diameter of line connecting frame_a and frame_b"
  input Types.Color torqueColor=Modelica.Mechanics.MultiBody.Types.Defaults.TorqueColor
    "Color of torque arrow"
  input Types.Color connectionLineColor=Modelica.Mechanics.MultiBody.Types.Defaults.SensorColor
    "Color of line connecting frame_a and frame_b"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  Visualizers.Advanced.Vector torqueArrow(
    color=torqueColor,
    specularCoefficient=specularCoefficient,
    R=frame_b.R,
    r=frame_b.r_0,
    quantity=Modelica.Mechanics.MultiBody.Types.VectorQuantity.Torque,
    headAtOrigin=true,
    twoHeadedArrow=true,
    coordinates=-frame_b.t) if world.enableAnimation and animation;
  Visualizers.Advanced.Shape connectionLine(
    shapeType="cylinder",
    lengthDirection = to_unit1(basicTorque.r_0),
    widthDirection={0,1,0},
    length=Modelica.Math.Vectors.length(basicTorque.r_0),
    width=connectionLineDiameter,
    height=connectionLineDiameter,
    color=connectionLineColor,
    specularCoefficient=specularCoefficient,
    r=frame_a.r_0) if world.enableAnimation and animation;

public
  Internal.BasicTorque basicTorque(resolveInFrame=resolveInFrame)
protected
  Interfaces.ZeroPosition zeroPosition if
       not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_resolve)
equation
  connect(basicTorque.frame_a, frame_a)
  connect(basicTorque.frame_b, frame_b)
  connect(basicTorque.torque, torque)
  connect(basicTorque.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, basicTorque.frame_resolve)
end Torque;


External force acting at frame_b, defined by 3 input signals and resolved in frame world, frame_b or frame_resolve. The 3 signals of the force connector are interpreted
as the x-, y- and z-coordinates of a force acting at the frame
connector to which frame_b of this component is attached.
Via parameter resolveInFrame it is defined, in which frame these
coordinates shall be resolved:

within Modelica.Mechanics.MultiBody.Forces;
model WorldForce
  "External force acting at frame_b, defined by 3 input signals and resolved in frame world, frame_b or frame_resolve"

  extends Interfaces.PartialOneFrame_b;
  Interfaces.Frame_resolve frame_resolve if
       resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.frame_resolve
    "The input signals are optionally resolved in this frame"
  Modelica.Blocks.Interfaces.RealInput force[3](each final quantity="Force", each final unit="N")
    "x-, y-, z-coordinates of force resolved in frame defined by resolveInFrame"
  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameB resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.world
    "Frame in which input force is resolved (1: world, 2: frame_b, 3: frame_resolve)";
  input Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.ForceColor
    "Color of arrow"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  Visualizers.Advanced.Vector arrow(
    color=color,
    specularCoefficient=specularCoefficient,
    R=frame_b.R,
    r=frame_b.r_0,
    headAtOrigin=true,
    quantity=Modelica.Mechanics.MultiBody.Types.VectorQuantity.Force,
    coordinates=-frame_b.f) if world.enableAnimation and animation;

public
  Internal.BasicWorldForce basicWorldForce(resolveInFrame=resolveInFrame)
protected
  Interfaces.ZeroPosition zeroPosition if
       not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.frame_resolve)
equation
  connect(basicWorldForce.frame_b, frame_b)
  connect(basicWorldForce.force, force)
  connect(basicWorldForce.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, basicWorldForce.frame_resolve)
end WorldForce;


External force and torque acting at frame_b, defined by 3+3 input signals and resolved in frame world, frame_b or in frame_resolve. The 3 signals of the force and torque
connector are interpreted
as the x-, y- and z-coordinates of a force and
torque acting at the frame
connector to which frame_b of this component is attached.
Via parameter resolveInFrame it is defined, in which frame these
coordinates shall be resolved:

within Modelica.Mechanics.MultiBody.Forces;
model WorldForceAndTorque
  "External force and torque acting at frame_b, defined by 3+3 input signals and resolved in frame world, frame_b or in frame_resolve"

  import Modelica.Mechanics.MultiBody.Types;
  extends Interfaces.PartialOneFrame_b;
  Interfaces.Frame_resolve frame_resolve if
       resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.frame_resolve
    "The input signals are optionally resolved in this frame"
  Blocks.Interfaces.RealInput force[3](each final quantity="Force", each final unit=
                   "N")
    "x-, y-, z-coordinates of force resolved in frame defined by resolveInFrame"
  Blocks.Interfaces.RealInput torque[3](each final quantity="Torque", each final unit=
                   "N.m")
    "x-, y-, z-coordinates of torque resolved in frame defined by resolveInFrame"

  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameB resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.world
    "Frame in which input force and torque are resolved (1: world, 2: frame_b, 3: frame_resolve)";

  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)"

protected
  Visualizers.Advanced.Vector forceArrow(
    color=forceColor,
    specularCoefficient=specularCoefficient,
    quantity=Modelica.Mechanics.MultiBody.Types.VectorQuantity.Force,
    R=frame_b.R,
    r=frame_b.r_0,
    coordinates=-frame_b.f,
    headAtOrigin=true) 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,
    coordinates=-frame_b.t,
    twoHeadedArrow=true,
    headAtOrigin=true) if world.enableAnimation and animation;
public
  Internal.BasicWorldForce basicWorldForce(resolveInFrame=resolveInFrame)
  Internal.BasicWorldTorque basicWorldTorque(resolveInFrame=resolveInFrame)
protected
  Interfaces.ZeroPosition zeroPosition if
       not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.frame_resolve)
equation
  connect(basicWorldForce.frame_b, frame_b)
  connect(basicWorldForce.force, force)
  connect(basicWorldTorque.frame_b, frame_b)
  connect(basicWorldTorque.torque, torque)
  connect(basicWorldForce.frame_resolve, frame_resolve)
  connect(basicWorldTorque.frame_resolve, frame_resolve)
  connect(zeroPosition.frame_resolve, basicWorldTorque.frame_resolve)
  connect(zeroPosition.frame_resolve, basicWorldForce.frame_resolve)
end WorldForceAndTorque;


External torque acting at frame_b, defined by 3 input signals and resolved in frame world, frame_b or frame_resolve. The 3 signals of the torque connector are interpreted
as the x-, y- and z-coordinates of a torque acting at the frame
connector to which frame_b of this component is attached.
Via parameter resolveInFrame it is defined, in which frame these
coordinates shall be resolved:

within Modelica.Mechanics.MultiBody.Forces;
model WorldTorque
  "External torque acting at frame_b, defined by 3 input signals and resolved in frame world, frame_b or frame_resolve"

  extends Interfaces.PartialOneFrame_b;

  Interfaces.Frame_resolve frame_resolve if
       resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.frame_resolve
    "The input signals are optionally resolved in this frame"
  Modelica.Blocks.Interfaces.RealInput torque[3](each final quantity="Torque", each final unit="N.m")
    "x-, y-, z-coordinates of torque resolved in frame defined by resolveInFrame"
  parameter Boolean animation=true "= true, if animation shall be enabled";
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameB resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.world
    "Frame in which input torque is resolved (1: world, 2: frame_b, 3: frame_resolve)";
  input Types.Color color=Modelica.Mechanics.MultiBody.Types.Defaults.TorqueColor
    "Color of arrow"
  input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient
    "Reflection of ambient light (= 0: light is completely absorbed)"

protected
  Visualizers.Advanced.Vector arrow(
    color=color,
    specularCoefficient=specularCoefficient,
    R=frame_b.R,
    r=frame_b.r_0,
    quantity=Modelica.Mechanics.MultiBody.Types.VectorQuantity.Torque,
    headAtOrigin=true,
    twoHeadedArrow=true,
    coordinates=-frame_b.t) if world.enableAnimation and animation;
public
  Internal.BasicWorldTorque basicWorldTorque(resolveInFrame=resolveInFrame)
protected
  Interfaces.ZeroPosition zeroPosition if
       not (resolveInFrame == Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.frame_resolve)
equation
  connect(basicWorldTorque.frame_b, frame_b)
  connect(basicWorldTorque.torque, torque)
  connect(frame_resolve, basicWorldTorque.frame_resolve)
  connect(zeroPosition.frame_resolve, basicWorldTorque.frame_resolve)
end WorldTorque;


Force acting between two frames, defined by 3 input signals. The 3 signals of the force connector are interpreted
as the x-, y- and z-coordinates of a force acting at the frame
connector to which frame_b of this component is attached.
Via parameter resolveInFrame it is defined, in which frame these
coordinates shall be resolved:

within Modelica.Mechanics.MultiBody.Forces.Internal;
model BasicForce
  "Force acting between two frames, defined by 3 input signals"
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames;
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB;
  Interfaces.Frame_resolve frame_resolve
    "The input signals are optionally resolved in this frame"
  Modelica.Blocks.Interfaces.RealInput force[3](each final quantity="Force", each final unit="N")
    "x-, y-, z-coordinates of force resolved in frame defined by resolveInFrame"
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB
    resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_b
    "Frame in which force is resolved (1: world, 2: frame_a, 3: frame_b, 4: frame_resolve)";

  SI.Position r_0[3]
    "Position vector from origin of frame_a to origin of frame_b resolved in world frame";
  SI.Force f_b_0[3] "frame_b.f resolved in world frame";

equation
  assert(cardinality(frame_resolve) > 0, "Connector frame_resolve must be connected at least once and frame_resolve.r_0/.R must be set");
  frame_resolve.f = zeros(3);
  frame_resolve.t = zeros(3);

   if resolveInFrame == ResolveInFrameAB.frame_a then
      f_b_0     = -Frames.resolve1(frame_a.R, force);
      frame_b.f =  Frames.resolve2(frame_b.R, f_b_0);
   elseif resolveInFrame == ResolveInFrameAB.frame_b then
      f_b_0     = -Frames.resolve1(frame_b.R, force);
      frame_b.f = -force;
   elseif resolveInFrame == ResolveInFrameAB.world then
      f_b_0     = -force;
      frame_b.f =  Frames.resolve2(frame_b.R, f_b_0);
   elseif resolveInFrame == ResolveInFrameAB.frame_resolve then
      f_b_0     = -Frames.resolve1(frame_resolve.R, force);
      frame_b.f = Frames.resolve2(frame_b.R, f_b_0);
   else
      assert(false, "Wrong value for parameter resolveInFrame");
      f_b_0     = zeros(3);
      frame_b.f = zeros(3);
   end if;
   frame_b.t = zeros(3);

   // Force and torque balance
   r_0 = frame_b.r_0 - frame_a.r_0;
   zeros(3) = frame_a.f + Frames.resolve2(frame_a.R, f_b_0);
   zeros(3) = frame_a.t + Frames.resolve2(frame_a.R, cross(r_0, f_b_0));
end BasicForce;


Torque acting between two frames, defined by 3 input signals. The 3 signals of the torque connector are interpreted
as the x-, y- and z-coordinates of a torque acting at the frame
connector to which frame_b of this component is attached.
Via parameter resolveInFrame it is defined, in which frame these
coordinates shall be resolved:

within Modelica.Mechanics.MultiBody.Forces.Internal;
model BasicTorque
  "Torque acting between two frames, defined by 3 input signals"
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB;
  extends Modelica.Mechanics.MultiBody.Interfaces.PartialTwoFrames;
  Interfaces.Frame_resolve frame_resolve
    "The input signals are optionally resolved in this frame"

  Modelica.Blocks.Interfaces.RealInput torque[3](each final quantity="Torque", each final unit="N.m")
    "x-, y-, z-coordinates of torque resolved in frame defined by resolveInFrame"
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB
    resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameAB.frame_b
    "Frame in which torque is resolved (1: world, 2: frame_a, 3: frame_b, 4: frame_resolve)";

  SI.Position r_0[3]
    "Position vector from origin of frame_a to origin of frame_b resolved in world frame";
  SI.Torque t_b_0[3] "frame_b.t resolved in world frame";

equation
  assert(cardinality(frame_resolve) > 0, "Connector frame_resolve must be connected at least once and frame_resolve.r_0/.R must be set");
  frame_resolve.f = zeros(3);
  frame_resolve.t = zeros(3);

  r_0 = frame_b.r_0 - frame_a.r_0;
  frame_a.f = zeros(3);
  frame_b.f = zeros(3);

   if resolveInFrame == ResolveInFrameAB.frame_a then
      t_b_0     = -Frames.resolve1(frame_a.R, torque);
      frame_b.t =  Frames.resolve2(frame_b.R, t_b_0);
   elseif resolveInFrame == ResolveInFrameAB.frame_b then
      t_b_0     = -Frames.resolve1(frame_b.R, torque);
      frame_b.t = -torque;
   elseif resolveInFrame == ResolveInFrameAB.world then
      t_b_0     = -torque;
      frame_b.t =  Frames.resolve2(frame_b.R, t_b_0);
   elseif resolveInFrame == ResolveInFrameAB.frame_resolve then
      t_b_0     = -Frames.resolve1(frame_resolve.R, torque);
      frame_b.t =  Frames.resolve2(frame_b.R, t_b_0);
   else
      assert(false, "Wrong value for parameter resolveInFrame");
      t_b_0     = zeros(3);
      frame_b.t = zeros(3);
   end if;

   // torque balance
   zeros(3) = frame_a.t + Frames.resolve2(frame_a.R, t_b_0);
end BasicTorque;


External force acting at frame_b, defined by 3 input signals. The 3 signals of the force connector are interpreted
as the x-, y- and z-coordinates of a force acting at the frame
connector to which this component is attached.
Via parameter resolveInFrame it is defined, in which frame these
coordinates shall be resolved:

within Modelica.Mechanics.MultiBody.Forces.Internal;
model BasicWorldForce
  "External force acting at frame_b, defined by 3 input signals"
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameB;
  extends Interfaces.PartialOneFrame_b;
  Interfaces.Frame_resolve frame_resolve
    "The input signals are optionally resolved in this frame"

  Modelica.Blocks.Interfaces.RealInput force[3](each final quantity="Force", each final unit="N")
    "x-, y-, z-coordinates of force resolved in frame defined by resolveInFrame"
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameB
    resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.world
    "Frame in which force is resolved (1: world, 2: frame_b, 3: frame_resolve)";

equation
   assert(cardinality(frame_resolve) > 0, "Connector frame_resolve must be connected at least once and frame_resolve.r_0/.R must be set");
   frame_resolve.f = zeros(3);
   frame_resolve.t = zeros(3);

   if resolveInFrame == ResolveInFrameB.world then
      frame_b.f = -Frames.resolve2(frame_b.R, force);
   elseif resolveInFrame == ResolveInFrameB.frame_b then
      frame_b.f = -force;
   elseif resolveInFrame == ResolveInFrameB.frame_resolve then
      frame_b.f = -Frames.resolveRelative(force, frame_resolve.R, frame_b.R);
   else
      assert(false, "Wrong value for parameter resolveInFrame");
      frame_b.f = zeros(3);
   end if;
   frame_b.t = zeros(3);
end BasicWorldForce;


External torque acting at frame_b, defined by 3 input signals. The 3 signals of the torque connector are interpreted
as the x-, y- and z-coordinates of a torque acting at the frame
connector to which this component is attached.
Via parameter resolveInFrame it is defined, in which frame these
coordinates shall be resolved:

within Modelica.Mechanics.MultiBody.Forces.Internal;
model BasicWorldTorque
  "External torque acting at frame_b, defined by 3 input signals"
  import Modelica.Mechanics.MultiBody.Types.ResolveInFrameB;
  extends Interfaces.PartialOneFrame_b;
  Interfaces.Frame_resolve frame_resolve
    "The input signals are optionally resolved in this frame"

  Modelica.Blocks.Interfaces.RealInput torque[3](each final quantity="Torque", each final unit="N.m")
    "x-, y-, z-coordinates of torque resolved in frame defined by resolveInFrame"
  parameter Modelica.Mechanics.MultiBody.Types.ResolveInFrameB
    resolveInFrame=
    Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.world
    "Frame in which torque is resolved (1: world, 2: frame_b, 3: frame_resolve)";

equation
   assert(cardinality(frame_resolve) > 0, "Connector frame_resolve must be connected at least once and frame_resolve.r_0/.R must be set");
   frame_resolve.f = zeros(3);
   frame_resolve.t = zeros(3);

   if resolveInFrame == ResolveInFrameB.world then
      frame_b.t = -Frames.resolve2(frame_b.R, torque);
   elseif resolveInFrame == ResolveInFrameB.frame_b then
      frame_b.t = -torque;
   elseif resolveInFrame == ResolveInFrameB.frame_resolve then
      frame_b.t = -Frames.resolveRelative(torque, frame_resolve.R, frame_b.R);
   else
      assert(false, "Wrong value for parameter resolveInFrame");
      frame_b.t = zeros(3);
   end if;
   frame_b.f = zeros(3);
end BasicWorldTorque;


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


Set force and torque to zero. Set force and torque vectors on frame connector frame_a to zero.

within Modelica.Mechanics.MultiBody.Forces.Internal;
model ZeroForceAndTorque "Set force and torque to zero"
   extends Modelica.Blocks.Icons.Block;
  Interfaces.Frame_a frame_a
equation
  frame_a.f = zeros(3);
  frame_a.t = zeros(3);
end ZeroForceAndTorque;


within Modelica.Mechanics.MultiBody.Frames;
record Orientation
  "Orientation object defining rotation from a frame 1 into a frame 2"

  extends Modelica.Icons.Record;
  Real T[3, 3] "Transformation matrix from world frame to local frame";
  SI.AngularVelocity w[3]
    "Absolute angular velocity of local frame, resolved in local frame";

  encapsulated function equalityConstraint
    "Return the constraint residues to express that two frames have the same orientation"

    import Modelica;
    import Modelica.Mechanics.MultiBody.Frames;
    extends Modelica.Icons.Function;
    input Frames.Orientation R1
      "Orientation object to rotate frame 0 into frame 1";
    input Frames.Orientation R2
      "Orientation object to rotate frame 0 into frame 2";
    output Real residue[3]
      "The rotation angles around x-, y-, and z-axis of frame 1 to rotate frame 1 into frame 2 for a small rotation (should be zero)";
  algorithm
    residue := {
       Modelica.Math.atan2(cross(R1.T[1, :], R1.T[2, :])*R2.T[2, :],R1.T[1,:]*R2.T[1,:]),
       Modelica.Math.atan2(-cross(R1.T[1, :],R1.T[2, :])*R2.T[1, :],R1.T[2,:]*R2.T[2,:]),
       Modelica.Math.atan2(R1.T[2, :]*R2.T[1, :],R1.T[3,:]*R2.T[3,:])};

Description

The function call Orientation.equalityConstrain(R1,R2) returns the Real residue vector
with 3 elements. This vector has zero elements if orientation objects R1 and R2 are identical
(= describe the same orientation). The residue vector is determined by computing the relative
orientation object between R1 and R2 and using the outer-diagonal elements of this matrix to
formulate the residue in such a way that only identical orientation objects lead to a zero residue vector.

"));
  end equalityConstraint;
end Orientation;


within Modelica.Mechanics.MultiBody;
package Frames "Functions to transform rotational frame quantities"

  extends Modelica.Icons.Package;
      Return the constraints between the variables of an orientation object

      (shall be zero).

w1 = angularVelocity1(R);
      Return angular velocity resolved in frame 1 from
          orientation object R.

w2 = angularVelocity2(R);
      Return angular velocity resolved in frame 2 from
          orientation object R.

v1 = resolve1(R,v2);
      Transform vector v2 from frame 2 to frame 1.

v2 = resolve2(R,v1);
      Transform vector v1 from frame 1 to frame 2.

v2 = resolveRelative(v1,R1,R2);
      Transform vector v1 from frame 1 to frame 2
          using absolute orientation objects R1 of frame 1 and R2 of frame 2.

D1 = resolveDyade1(R,D2);
      Transform second order tensor D2 from frame 2 to frame 1.

D2 = resolveDyade2(R,D1);
      Transform second order tensor D1 from frame 1 to frame 2.

R = nullRotation()
      Return orientation object R that does not rotate a frame.

R_inv = inverseRotation(R);
      Return inverse orientation object.

R_rel = relativeRotation(R1,R2);
      Return relative orientation object from two absolute
          orientation objects.

R2 = absoluteRotation(R1,R_rel);
      Return absolute orientation object from another
          absolute
 and a relative orientation object.

R = planarRotation(e, angle, der_angle);
      Return orientation object of a planar rotation.

angle = planarRotationAngle(e, v1, v2);
      Return angle of a planar rotation, given the rotation axis

        and the representations of a vector in frame 1 and frame 2.

R = axisRotation(axis, angle, der_angle);
      Return orientation object R to rotate around angle along axis of frame 1.

R = axesRotations(sequence, angles, der_angles);
      Return rotation object to rotate in sequence around 3 axes. Example:

          R = axesRotations({1,2,3},{pi/2,pi/4,-pi}, zeros(3));

angles = axesRotationsAngles(R, sequence);
      Return the 3 angles to rotate in sequence around 3 axes to

          construct the given orientation object.

phi = smallRotation(R);
      Return rotation angles phi valid for a small rotation R.

R = from_nxy(n_x, n_y);
      Return orientation object from n_x and n_y vectors.

R = from_nxz(n_x, n_z);
      Return orientation object from n_x and n_z vectors.

R = from_T(T,w);
      Return orientation object R from transformation matrix T and
          its angular velocity w.

R = from_T2(T,der(T));
      Return orientation object R from transformation matrix T and
          its derivative der(T).

R = from_T_inv(T_inv,w);
      Return orientation object R from inverse transformation matrix T_inv and
          its angular velocity w.

R = from_Q(Q,w);
      Return orientation object R from quaternion orientation object Q
          and its angular velocity w.

T = to_T(R);
      Return transformation matrix T from orientation object R.

T_inv = to_T_inv(R);
      Return inverse transformation matrix T_inv from orientation object R.

Q = to_Q(R);
      Return quaternion orientation object Q from orientation object R.

exy = to_exy(R);
      Return [e_x, e_y] matrix of an orientation object R,

          with e_x and e_y vectors of frame 2, resolved in frame 1.

L = length(n_x);
      Return length L of a vector n_x.

e_x = normalize(n_x);
      Return normalized vector e_x of n_x such that length of e_x is one.

e = axis(i);
      Return unit vector e directed along axis i

Quaternions
      Package with functions to transform rotational frame quantities based
          on quaternions (also called Euler parameters).

TransformationMatrices
      Package with functions to transform rotational frame quantities based
          on transformation matrices.

"), Icon(graphics={
        Line(points={{-2,-18},{80,-60}}, color={95,95,95}),
        Line(points={{-2,-18},{-2,80}}, color={95,95,95}),
        Line(points={{-78,-56},{-2,-18}}, color={95,95,95})}));
end Frames;


within Modelica.Mechanics.MultiBody.Frames;
package Internal "Internal definitions that may be removed or changed (do not use)"
  extends Modelica.Icons.InternalPackage;
end Internal;


within Modelica.Mechanics.MultiBody.Frames;
package Quaternions "Functions to transform rotational frame quantities based on quaternions (also called Euler parameters)"
  extends Modelica.Icons.FunctionsPackage;
      Return the constraints between the variables of a quaternion object

      (shall be zero).

w1 = angularVelocity1(Q, der_Q);
      Return angular velocity resolved in frame 1 from
          quaternion object Q
 and its derivative der_Q.

w2 = angularVelocity2(Q, der_Q);
      Return angular velocity resolved in frame 2 from
          quaternion object Q
 and its derivative der_Q.

v1 = resolve1(Q,v2);
      Transform vector v2 from frame 2 to frame 1.

v2 = resolve2(Q,v1);
      Transform vector v1 from frame 1 to frame 2.

[v1,w1] = multipleResolve1(Q, [v2,w2]);
      Transform several vectors from frame 2 to frame 1.

[v2,w2] = multipleResolve2(Q, [v1,w1]);
      Transform several vectors from frame 1 to frame 2.

Q = nullRotation()
      Return quaternion object R that does not rotate a frame.

Q_inv = inverseRotation(Q);
      Return inverse quaternion object.

Q_rel = relativeRotation(Q1,Q2);
      Return relative quaternion object from two absolute
          quaternion objects.

Q2 = absoluteRotation(Q1,Q_rel);
      Return absolute quaternion object from another
          absolute
 and a relative quaternion object.

Q = planarRotation(e, angle);
      Return quaternion object of a planar rotation.

phi = smallRotation(Q);
      Return rotation angles phi valid for a small rotation.

Q = from_T(T);
      Return quaternion object Q from transformation matrix T.

Q = from_T_inv(T_inv);
      Return quaternion object Q from inverse transformation matrix T_inv.

T = to_T(Q);
      Return transformation matrix T from quaternion object Q.

T_inv = to_T_inv(Q);
      Return inverse transformation matrix T_inv from quaternion object Q.

"));
end Quaternions;


within Modelica.Mechanics.MultiBody.Frames.TransformationMatrices;
type Orientation
  "Orientation type defining rotation from a frame 1 into a frame 2 with a transformation matrix"

  extends Internal.TransformationMatrix;

  encapsulated function equalityConstraint
    "Return the constraint residues to express that two frames have the same orientation"

    import Modelica;
    import Modelica.Mechanics.MultiBody.Frames.TransformationMatrices;
    extends Modelica.Icons.Function;
    input TransformationMatrices.Orientation T1
      "Orientation object to rotate frame 0 into frame 1";
    input TransformationMatrices.Orientation T2
      "Orientation object to rotate frame 0 into frame 2";
    output Real residue[3]
      "The rotation angles around x-, y-, and z-axis of frame 1 to rotate frame 1 into frame 2 for a small rotation (should be zero)";
  algorithm
    residue := {
      cross(T1[1, :], T1[2, :]) * T2[2, :],
      -cross(T1[1, :], T1[2, :]) * T2[1, :],
      T1[2, :]*T2[1, :]};

Description

This function returns the Real residue vector with 3 elements.
This vector has zero elements if transformation matrices T1 and T2 are identical,
i.e. they describe the same orientation. The residue vector is determined by computing the relative
transformation matrix between T1 and T2 and using the outer-diagonal elements of this matrix to
formulate the residue in such a way that only identical orientation objects lead to a zero residue vector.

"));
  end equalityConstraint;
end Orientation;


Functions for transformation matrices

within Modelica.Mechanics.MultiBody.Frames;
package TransformationMatrices "Functions for transformation matrices"
  extends Modelica.Icons.FunctionsPackage;
      Return the constraints between the variables of an orientation object

      (shall be zero).

w1 = angularVelocity1(T, der_T);
      Return angular velocity resolved in frame 1 from
          orientation object T
 and its derivative der_T.

w2 = angularVelocity2(T, der_T);
      Return angular velocity resolved in frame 2 from
          orientation object T
 and its derivative der_T.

v1 = resolve1(T,v2);
      Transform vector v2 from frame 2 to frame 1.

v2 = resolve2(T,v1);
      Transform vector v1 from frame 1 to frame 2.

[v1,w1] = multipleResolve1(T, [v2,w2]);
      Transform several vectors from frame 2 to frame 1.

[v2,w2] = multipleResolve2(T, [v1,w1]);
      Transform several vectors from frame 1 to frame 2.

D1 = resolveDyade1(T,D2);
      Transform second order tensor D2 from frame 2 to frame 1.

D2 = resolveDyade2(T,D1);
      Transform second order tensor D1 from frame 1 to frame 2.

T= nullRotation()
      Return orientation object T that does not rotate a frame.

T_inv = inverseRotation(T);
      Return inverse orientation object.

T_rel = relativeRotation(T1,T2);
      Return relative orientation object from two absolute
          orientation objects.

T2 = absoluteRotation(T1,T_rel);
      Return absolute orientation object from another
          absolute
 and a relative orientation object.

T = planarRotation(e, angle);
      Return orientation object of a planar rotation.

angle = planarRotationAngle(e, v1, v2);
      Return angle of a planar rotation, given the rotation axis

        and the representations of a vector in frame 1 and frame 2.

T = axisRotation(i, angle);
      Return orientation object T for rotation around axis i of frame 1.

T = axesRotations(sequence, angles);
      Return rotation object to rotate in sequence around 3 axes. Example:

          T = axesRotations({1,2,3},{90,45,-90});

angles = axesRotationsAngles(T, sequence);
      Return the 3 angles to rotate in sequence around 3 axes to

          construct the given orientation object.

phi = smallRotation(T);
      Return rotation angles phi valid for a small rotation.

T = from_nxy(n_x, n_y);
      Return orientation object from n_x and n_y vectors.

T = from_nxz(n_x, n_z);
      Return orientation object from n_x and n_z vectors.

R = from_T(T);
      Return orientation object R from transformation matrix T.

R = from_T_inv(T_inv);
      Return orientation object R from inverse transformation matrix T_inv.

T = from_Q(Q);
      Return orientation object T from quaternion orientation object Q.

T = to_T(R);
      Return transformation matrix T from orientation object R.

T_inv = to_T_inv(R);
      Return inverse transformation matrix T_inv from orientation object R.

Q = to_Q(T);
      Return quaternion orientation object Q from orientation object T.

exy = to_exy(T);
      Return [e_x, e_y] matrix of an orientation object T,

          with e_x and e_y vectors of frame 2, resolved in frame 1.

"));
end TransformationMatrices;


Icons for MultiBody package

within Modelica.Mechanics.MultiBody;
package Icons "Icons for MultiBody package"
  extends Modelica.Icons.IconsPackage;
end Icons;


Surface icon. This icon is designed for a parametrized surface model.

within Modelica.Mechanics.MultiBody.Icons;
model Surface "Surface icon"
end Surface;


Adaptor to allow direct connections to the sub-connectors of FlangeWithBearing. Adaptor object to make a more visible connection to the flange and frame
subconnectors of a
FlangeWithBearing
connector.

within Modelica.Mechanics.MultiBody.Interfaces;
model FlangeWithBearingAdaptor
  "Adaptor to allow direct connections to the sub-connectors of FlangeWithBearing"
  parameter Boolean includeBearingConnector=false
    "= true, if bearing frame connector is present, otherwise not present";

  Modelica.Mechanics.MultiBody.Interfaces.FlangeWithBearing flangeAndFrame(includeBearingConnector=includeBearingConnector) "Compound connector consisting of 1-dim. rotational flange and 3-dim. frame mounting"
  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange
    "1-dim. rotational flange"
  Frame_a frame if includeBearingConnector
    "3-dim. frame in which the 1-dim. shaft is mounted"

equation
  connect(flange, flangeAndFrame.flange)
  connect(frame, flangeAndFrame.bearingFrame)
end FlangeWithBearingAdaptor;


Base model for line force elements. All line force elements should be based on this base model.
This model defines frame_a and frame_b and computes the (guarded) relative
distance s. An assertion is raised if the relative
distance length became smaller as parameter s_small.

within Modelica.Mechanics.MultiBody.Interfaces;
partial model LineForceBase "Base model for line force elements"
  extends PartialTwoFrames;
  parameter SI.Distance s_small=1e-10
    "Prevent zero-division if distance between frame_a and frame_b is zero"
  parameter Boolean fixedRotationAtFrame_a=false
    "= true, if rotation frame_a.R is fixed (to directly connect line forces)"
  parameter Boolean fixedRotationAtFrame_b=false
    "= true, if rotation frame_b.R is fixed (to directly connect line forces)"

  SI.Distance length
    "Distance between the origin of frame_a and the origin of frame_b";
  SI.Position s
    "(Guarded) distance between the origin of frame_a and the origin of frame_b (>= s_small))";
  SI.Position r_rel_0[3]
    "Position vector from frame_a to frame_b resolved in world frame";
  Real e_rel_0[3](each final unit="1")
    "Unit vector in direction from frame_a to frame_b, resolved in world frame";
equation
  assert(noEvent(length > s_small), "
The distance between the origin of frame_a and the origin of frame_b
of a line force component became smaller as parameter s_small
(= a small number, defined in the \"Advanced\" menu). The distance is
set to s_small, although it is smaller, to avoid a division by zero
when computing the direction of the line force. Possible reasons
for this situation:
- At initial time the distance may already be zero: Change the initial
  positions of the bodies connected by this element.
- Hardware stops are not modeled or are modeled not stiff enough.
  Include stops, e.g., stiff springs, or increase the stiffness
  if already present.
- Another error in your model may lead to unrealistically large forces
  and torques that would in reality destroy the stops.
- The flange_b connector might be defined by a pre-defined motion,
  e.g., with Modelica.Mechanics.Translational.Position and the
  predefined flange_b.s is zero or negative.
");

  // Determine relative position vector between the two frames
  r_rel_0 = frame_b.r_0 - frame_a.r_0;
  length = Modelica.Math.Vectors.length(r_rel_0);
  s = Frames.Internal.maxWithoutEvent(length, s_small);
  e_rel_0 = r_rel_0/s;

  // Additional equations, if direct connections of line forces
  if fixedRotationAtFrame_a then
    Connections.root(frame_a.R);
    frame_a.R = Frames.nullRotation();
  else
    frame_a.t = zeros(3);
  end if;

  if fixedRotationAtFrame_b then
    Connections.root(frame_b.R);
    frame_b.R = Frames.nullRotation();
  else
    frame_b.t = zeros(3);
  end if;
end LineForceBase;


within Modelica.Mechanics.MultiBody;
package Interfaces "Connectors and partial models for 3-dim. mechanical components"

  extends Modelica.Icons.InterfacesPackage;
end Interfaces;


within Modelica.Mechanics.MultiBody.Interfaces;
partial model PartialAbsoluteSensor
  "Base model to measure an absolute frame variable"
  extends Modelica.Icons.RoundSensor;
  parameter Integer n_out = 1 "Number of output signals";
  Interfaces.Frame_a frame_a "Coordinate system from which absolute quantities are provided as output signals"

  Modelica.Blocks.Interfaces.RealOutput y[n_out]
    "Measured data as signal vector"
protected
  outer Modelica.Mechanics.MultiBody.World world;

equation
  assert(cardinality(frame_a) > 0,
    "Connector frame_a of absolute sensor object is not connected");
end PartialAbsoluteSensor;


Base model for elementary joints (has two frames + outer world + assert to guarantee that the joint is connected). All elementary joints should inherit from this base model, i.e.,
joints that are directly defined by equations, provided they compute
either the rotation object of frame_b from the rotation object of frame_a
and from relative quantities (or vice versa), or there is a constraint
equation between the rotation objects of the two frames.
In other cases, a joint object should inherit from
Interfaces.PartialTwoFrames (e.g., joint Spherical, because there
is no constraint between the rotation objects of frame_a and frame_b
or joint Cylindrical because it is not an elementary joint).

within Modelica.Mechanics.MultiBody.Interfaces;
partial model PartialElementaryJoint
  "Base model for elementary joints (has two frames + outer world + assert to guarantee that the joint is connected)"

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

protected
  outer Modelica.Mechanics.MultiBody.World world;
equation
  Connections.branch(frame_a.R, frame_b.R);
  assert(cardinality(frame_a) > 0,
    "Connector frame_a of joint object is not connected");
  assert(cardinality(frame_b) > 0,
    "Connector frame_b of joint object is not connected");
end PartialElementaryJoint;


Base model for force elements (provide frame_b.f and frame_b.t in subclasses). All 3-dimensional force and torque elements
should be based on this superclass.
This model defines frame_a and frame_b, computes the relative
translation and rotation between the two frames and calculates
the cut-force and cut-torque at frame_a by a force and torque
balance from the cut-force and cut-torque at frame_b.
As a result, in a subclass, only the relationship between
the cut-force and cut-torque at frame_b has to be defined as
a function of the following relative quantities:

within Modelica.Mechanics.MultiBody.Interfaces;
partial model PartialForce
  "Base model for force elements (provide frame_b.f and frame_b.t in subclasses)"
  extends PartialTwoFrames;
  SI.Position r_rel_b[3]
    "Position vector from origin of frame_a to origin of frame_b, resolved in frame_b";
equation
  // Determine relative position vector between frame_a and frame_b
  r_rel_b = Frames.resolve2(frame_b.R, frame_b.r_0 - frame_a.r_0);

  // Force and torque balance between frame_a and frame_b
  zeros(3) = frame_a.f + Frames.resolveRelative(frame_b.f, frame_b.R, frame_a.R);
  zeros(3) = frame_a.t + Frames.resolveRelative(frame_b.t + cross(r_rel_b, frame_b.f), frame_b.R, frame_a.R);
end Constant_x_Force;

Note, that frame_b.f and frame_b.t are flow variables and therefore
the negative value of frame_b.f and frame_b.t is acting at the part
to which this force element is connected.

"));
end PartialForce;


Base model for massless line force elements. All massless line force elements should be based on this base model.
This model defines frame_a and frame_b, computes the (guarded) relative
distance s and provides the force and torque
balance of the cut-forces and cut-torques at frame_a and
frame_b, respectively. In sub-models, only the line force f,
acting at frame_b on the line from frame_a to frame_b, as a function
of the relative distance s and its derivative der(s)
has to be defined. Example:

within Modelica.Mechanics.MultiBody.Interfaces;
partial model PartialLineForce "Base model for massless line force elements"
  extends LineForceBase;

  SI.Position r_rel_a[3]
    "Position vector from origin of frame_a to origin of frame_b, resolved in frame_a";
  Real e_a[3](each final unit="1")
    "Unit vector on the line connecting the origin of frame_a with the origin of frame_b resolved in frame_a (directed from frame_a to frame_b)";
  SI.Force f
    "Line force acting on frame_a and on frame_b (positive, if acting on frame_b and directed from frame_a to frame_b)";
equation
  // Determine relative position vector between the two frames
  r_rel_a = Frames.resolve2(frame_a.R, r_rel_0);
  e_a = r_rel_a/s;

  // Determine forces and torques at frame_a and frame_b
  frame_a.f = -e_a*f;
  frame_b.f = -Frames.resolve2(Frames.relativeRotation(frame_a.R, frame_b.R), frame_a.f);
end Spring;

"),
         Icon(coordinateSystem(preserveAspectRatio=true, extent={{-100,-100},
            {100,100}}), graphics={
        Ellipse(visible=fixedRotationAtFrame_a, extent={{-70,30},{-130,-30}}, lineColor={255,0,0}),
        Text(visible=fixedRotationAtFrame_a,
          extent={{-62,50},{-140,30}},
          textColor={255,0,0},
          textString="R=0"),
        Ellipse(visible=fixedRotationAtFrame_b, extent={{70,30},{130,-30}}, lineColor={255,0,0}),
        Text(visible=fixedRotationAtFrame_b,
          extent={{62,50},{140,30}},
          textColor={255,0,0},
          textString="R=0")}));
end PartialLineForce;


Base model for components providing one frame_a connector + outer world + assert to guarantee that the component is connected. This partial model provides one frame_a connector, access to the world
object and an assert to check that the frame_a connector is connected.
Therefore, inherit from this partial model if the frame_a connector is
needed and if this connector should be connected for a correct model.

within Modelica.Mechanics.MultiBody.Interfaces;
partial model PartialOneFrame_a
  "Base model for components providing one frame_a connector + outer world + assert to guarantee that the component is connected"

  Interfaces.Frame_a frame_a "Coordinate system fixed to the component with one cut-force and cut-torque"
protected
  outer Modelica.Mechanics.MultiBody.World world;
equation
  assert(cardinality(frame_a) > 0,
    "Connector frame_a of component is not connected");
end PartialOneFrame_a;