JointRRR

model JointRRR "Planar revolute - revolute - revolute joint aggregation (no constraints, no potential states)"
    import Modelica.Mechanics.MultiBody.Types;
    import Modelica.SIunits.Conversions.to_unit1;

    extends Interfaces.PartialTwoFramesDoubleSize;

    Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_ia "Coordinate system at origin of frame_a fixed at connecting rod of left and middle revolute joint"
        annotation (Placement(transformation(
            origin = {-80, 100},
            extent = {
                {-8, -8}, 
                {8, 8}},
            rotation = 90)));
    Modelica.Mechanics.MultiBody.Interfaces.Frame_b frame_ib "Coordinate system at origin of frame_b fixed at connecting rod of middle and right revolute joint"
        annotation (Placement(transformation(
            origin = {80, 100},
            extent = {
                {-8, 8}, 
                {8, -8}},
            rotation = 270)));
    Modelica.Mechanics.MultiBody.Interfaces.Frame_b frame_im "Coordinate system at origin of revolute joint in the middle fixed at connecting rod of middle and right revolute joint"
        annotation (Placement(transformation(
            origin = {0, 100},
            extent = {
                {8, -8}, 
                {-8, 8}},
            rotation = 270)));
    Modelica.Mechanics.Rotational.Interfaces.Flange_a axis "1-dim. rotational flange that drives the right revolute joint at frame_b"
        annotation (Placement(transformation(extent = {
            {105, 85}, 
            {95, 75}})));
    Modelica.Mechanics.Rotational.Interfaces.Flange_b bearing "1-dim. rotational flange of the drive bearing of the right revolute joint at frame_b"
        annotation (Placement(transformation(extent = {
            {95, 45}, 
            {105, 35}})));
    parameter Boolean animation = true "= true, if animation shall be enabled";
    parameter Modelica.Mechanics.MultiBody.Types.Axis n_a = {0, 0, 1} "Axes of revolute joints resolved in frame_a (all axes are parallel to each other)"
        annotation (Evaluate = true);
    final parameter Real n_b[3](each final unit = "1", each fixed = false, start = {0, 0, 1}) "Axis of revolute joint fixed and resolved in frame_b"
        annotation (Evaluate = true);
    parameter SI.Position rRod1_ia[3] = {1, 0, 0} "Vector from origin of frame_a to revolute joint in the middle, resolved in frame_ia"
        annotation (Evaluate = true);
    parameter SI.Position rRod2_ib[3] = {-1, 0, 0} "Vector from origin of frame_ib to revolute joint in the middle, resolved in frame_ib";
    parameter Cv.NonSIunits.Angle_deg phi_offset = 0 "Relative angle offset of revolute joint at frame_b (angle = phi(t) + from_deg(phi_offset))";
    parameter Cv.NonSIunits.Angle_deg phi_guess = 0 "Select the configuration such that at initial time |phi(t0) - from_deg(phi_guess)| is minimal";
    parameter SI.Distance cylinderLength = world.defaultJointLength "Length of cylinders representing the revolute joints"
        annotation (Dialog(
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    parameter SI.Distance cylinderDiameter = world.defaultJointWidth "Diameter of cylinders representing the revolute joints"
        annotation (Dialog(
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    input Types.Color cylinderColor = Modelica.Mechanics.MultiBody.Types.Defaults.JointColor "Color of cylinders representing the revolute joints"
        annotation (Dialog(
            colorSelector = true,
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    parameter SI.Diameter rodDiameter = 1.1 * cylinderDiameter "Diameter of the two rods connecting the revolute joints"
        annotation (Dialog(
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    input Types.Color rodColor = Modelica.Mechanics.MultiBody.Types.Defaults.RodColor "Color of the two rods connecting the revolute joint"
        annotation (Dialog(
            colorSelector = true,
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    input Types.SpecularCoefficient specularCoefficient = world.defaultSpecularCoefficient "Reflection of ambient light (= 0: light is completely absorbed)"
        annotation (Dialog(
            tab = "Animation",
            group = "if animation = true",
            enable = animation));
    parameter Boolean checkTotalPower = false "= true, if total power flowing into this component shall be determined (must be zero)"
        annotation (Dialog(tab = "Advanced"));
    final parameter Real e_a[3](each final unit = "1") = Modelica.Math.Vectors.normalizeWithAssert(n_a) "Unit vector along axes of rotations, resolved in frame_a";
    final parameter Real e_ia[3](each final unit = "1") = jointUSR.e2_ia "Unit vector along axes of rotations, resolved in frame_ia";
    final parameter Real e_b[3](each final unit = "1") = jointUSR.revolute.e "Unit vector along axes of rotations, resolved in frame_b, frame_ib and frame_im";
    SI.Power totalPower = jointUSR.totalPower "Total power flowing into this element, if checkTotalPower=true (otherwise dummy)";
    JointUSR jointUSR(animation = false, n1_a = n_a, n_b = n_b, phi_offset = phi_offset, rRod2_ib = rRod2_ib, showUniversalAxes = false, rRod1_ia = rRod1_ia, checkTotalPower = checkTotalPower, phi_guess = phi_guess) annotation (Placement(transformation(extent = {
        {-30, -20}, 
        {10, 20}})));
protected
    Visualizers.Advanced.Shape shape_rev1(shapeType = "cylinder", color = cylinderColor, specularCoefficient = specularCoefficient, length = cylinderLength, width = cylinderDiameter, height = cylinderDiameter, lengthDirection = e_a, widthDirection = {0, 1, 0}, r_shape = -e_a * (0.5 * cylinderLength), r = frame_a.r_0, R = frame_a.R) if world.enableAnimation and animation;
    Visualizers.Advanced.Shape shape_rev2(shapeType = "cylinder", color = cylinderColor, specularCoefficient = specularCoefficient, length = cylinderLength, width = cylinderDiameter, height = cylinderDiameter, lengthDirection = e_b, widthDirection = {0, 1, 0}, r_shape = -e_b * (0.5 * cylinderLength), r = frame_im.r_0, R = frame_im.R) if world.enableAnimation and animation;
    Visualizers.Advanced.Shape shape_rev3(shapeType = "cylinder", color = cylinderColor, specularCoefficient = specularCoefficient, length = cylinderLength, width = cylinderDiameter, height = cylinderDiameter, lengthDirection = e_b, widthDirection = {0, 1, 0}, r_shape = -e_b * (0.5 * cylinderLength), r = frame_b.r_0, R = frame_b.R) if world.enableAnimation and animation;
    Visualizers.Advanced.Shape shape_rod1(shapeType = "cylinder", color = rodColor, specularCoefficient = specularCoefficient, length = Modelica.Math.Vectors.length(rRod1_ia), width = rodDiameter, height = rodDiameter, lengthDirection = to_unit1(rRod1_ia), widthDirection = e_ia, r = frame_ia.r_0, R = frame_ia.R) if world.enableAnimation and animation;
    Visualizers.Advanced.Shape shape_rod2(shapeType = "cylinder", color = rodColor, specularCoefficient = specularCoefficient, length = Modelica.Math.Vectors.length(rRod2_ib), width = rodDiameter, height = rodDiameter, lengthDirection = to_unit1(rRod2_ib), widthDirection = e_b, r = frame_ib.r_0, R = frame_ib.R) if world.enableAnimation and animation;
initial equation
    n_b = Frames.resolve2(frame_b.R, Frames.resolve1(frame_a.R, n_a));
equation
    connect(jointUSR.axis,axis) annotation (Line(points = {
        {10, 16}, 
        {86, 16}, 
        {86, 80}, 
        {100, 80}}));
    connect(jointUSR.bearing,bearing) annotation (Line(points = {
        {10, 8}, 
        {94, 8}, 
        {94, 40}, 
        {100, 40}}));
    connect(jointUSR.frame_a,frame_a) annotation (Line(
        points = {
            {-30, 0}, 
            {-100, 0}},
        color = {95, 95, 95},
        thickness = 0.5));
    connect(jointUSR.frame_b,frame_b) annotation (Line(
        points = {
            {10, 0}, 
            {100, 0}},
        color = {95, 95, 95},
        thickness = 0.5));
    connect(jointUSR.frame_ia,frame_ia) annotation (Line(
        points = {
            {-26, 20}, 
            {-26, 70}, 
            {-80, 70}, 
            {-80, 100}},
        color = {95, 95, 95},
        thickness = 0.5));
    connect(jointUSR.frame_ib,frame_ib) annotation (Line(
        points = {
            {6, 20}, 
            {6, 50}, 
            {80, 50}, 
            {80, 100}},
        color = {95, 95, 95},
        thickness = 0.5));
    connect(jointUSR.frame_im,frame_im) annotation (Line(
        points = {
            {-10, 20}, 
            {-10, 70}, 
            {0, 70}, 
            {0, 100}},
        color = {95, 95, 95},
        thickness = 0.5));

    annotation (
        Documentation(info = "<html>\n<p>\nThis component consists of <strong>3 revolute</strong> joints with parallel\naxes of rotation that are connected together by two rods, see the default\nanimation in the following figure (the axes vectors are not part of the\ndefault animation):\n</p>\n\n<p>\n<img src=\"modelica://Modelica/Resources/Images/Mechanics/MultiBody/Joints/JointRRR.png\" alt=\"model Joints.Assemblies.JointRRR\">\n</p>\n\n<p>\nThis joint aggregation introduces neither constraints nor state variables and\nshould therefore be used in kinematic loops whenever possible to\navoid non-linear systems of equations. It is only meaningful to\nuse this component in <strong>planar loops</strong>. Basically, the position\nand orientation of the 3 revolute joints as well as of frame_ia, frame_ib, and\nframe_im are calculated by solving analytically a non-linear equation,\ngiven the position and orientation at frame_a and at frame_b.\n</p>\n<p>\nConnector <strong>frame_a</strong> is the \"left\" side of the first revolute joint\nwhereas <strong>frame_ia</strong> is the \"right side of this revolute joint, fixed in rod 1.\nConnector <strong>frame_b</strong> is the \"right\" side of the third revolute joint\nwhereas <strong>frame_ib</strong> is the \"left\" side of this revolute joint, fixed in rod 2.\nFinally, connector <strong>frame_im</strong> is the connector at the \"right\" side\nof the revolute joint in the middle, fixed in rod 2.\n</p>\n<p>\nThe easiest way to define the parameters of this joint is by moving the\nMultiBody system in a <strong>reference configuration</strong> where <strong>all frames</strong>\nof all components are <strong>parallel</strong> to each other (alternatively,\nat least frame_a, frame_ia, frame_im, frame_ib, frame_b of the JointRRR joint\nshould be parallel to each other when defining an instance of this\ncomponent).\n</p>\n<p>\nBasically, the JointRRR model consists internally of a universal -\nspherical - revolute joint aggregation (= JointUSR). In a planar\nloop this will behave as if 3 revolute joints with parallel axes\nare connected by rigid rods.\n</p>\n</html>"),
        Icon(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}},
                initialScale = 0.2),
            graphics = {
                Rectangle(
                    extent = {
                        {-90, 90}, 
                        {90, -90}},
                    lineColor = {255, 255, 255},
                    fillColor = {255, 255, 255},
                    fillPattern = FillPattern.Solid), 
                Text(
                    extent = {
                        {-140, -55}, 
                        {140, -80}},
                    lineColor = {0, 0, 255},
                    textString = "%name"), 
                Text(
                    extent = {
                        {36, 114}, 
                        {71, 92}},
                    lineColor = {128, 128, 128},
                    textString = "ib"), 
                Text(
                    extent = {
                        {-126, 115}, 
                        {-87, 90}},
                    lineColor = {128, 128, 128},
                    textString = "ia"), 
                Ellipse(
                    extent = {
                        {-100, 25}, 
                        {-50, -25}},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Ellipse(
                    extent = {
                        {-85, 10}, 
                        {-65, -10}},
                    fillPattern = FillPattern.Solid), 
                Ellipse(
                    extent = {
                        {50, 25}, 
                        {100, -25}},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Ellipse(
                    extent = {
                        {65, 10}, 
                        {85, -10}},
                    fillPattern = FillPattern.Solid), 
                Ellipse(
                    extent = {
                        {-26, 80}, 
                        {24, 30}},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Ellipse(
                    extent = {
                        {-10, 66}, 
                        {10, 46}},
                    fillPattern = FillPattern.Solid), 
                Polygon(
                    points = {
                        {-71, 9}, 
                        {-24, 45}, 
                        {-19, 39}, 
                        {-66, 3}, 
                        {-71, 9}},
                    fillPattern = FillPattern.Solid), 
                Polygon(
                    points = {
                        {54, 12}, 
                        {5, 47}, 
                        {10, 52}, 
                        {59, 18}, 
                        {54, 12}},
                    fillPattern = FillPattern.Solid), 
                Polygon(
                    points = {
                        {100, -4}, 
                        {83, -4}, 
                        {84, 3}, 
                        {100, 3}, 
                        {100, -4}},
                    fillPattern = FillPattern.Solid), 
                Line(
                    points = {
                        {80, 24}, 
                        {80, 80}, 
                        {80, 80}, 
                        {80, 100}},
                    color = {95, 95, 95},
                    thickness = 0.5), 
                Text(
                    extent = {
                        {-128, -29}, 
                        {136, -47}},
                    textString = "n_a=%n_a"), 
                Line(
                    points = {
                        {0, 57}, 
                        {0, 86}, 
                        {0, 86}, 
                        {0, 100}},
                    color = {95, 95, 95},
                    thickness = 0.5), 
                Text(
                    extent = {
                        {-46, 114}, 
                        {-7, 91}},
                    lineColor = {128, 128, 128},
                    textString = "im"), 
                Line(
                    points = {
                        {-80, 100}, 
                        {-80, 8}},
                    color = {95, 95, 95},
                    thickness = 0.5), 
                Line(
                    points = {
                        {80, 80}, 
                        {101, 80}},
                    color = {95, 95, 95},
                    thickness = 0.5), 
                Line(
                    points = {
                        {100, 40}, 
                        {93, 40}, 
                        {93, 3}},
                    color = {95, 95, 95},
                    thickness = 0.5)}));
end JointRRR;