A 6 bar constraint problem

Hi there!

I am having a hard time getting a 6 bar construct to run in AnyBody.

In this model (any-file is attached) you can see 3 yellow bars, which represent rigid segments. The three red bars are segments which will be replaced by elastic segments later. In the later application I am going to apply a load on the bottom right point and we will see how the stiffness of the red elements will influence the movement in the XY plane of the yellow elements. For now I just want to use rigid segments to demonstrate the problem.

Choosing the joint types I obtained a configuration that mathematically has as much constraints as degrees of freedom. It loads just fine, but when I execute the Kinematics or InverseDynamics analysis I am receiving an error.

  1. InverseDynamics (Operation: Main.MyStudy.InverseDynamics):
    0.0) PreOperation (Operation: Main.MyStudy.InverseDynamics.PreOperation):
    0.0.0) InitialConditions (Operation: Main.MyStudy.InitialConditions):
    0.0.0) ...Design variables have been updated.
    0.0.1) ...Load-time positions have been re-established.
    WARNING(OBJ.MCH.KIN1) : C:/U..s/m..h/D..p/P..2/A..s/ASpringProblem6bar.any : MyStudy : Model is kinematically indeterminate : Position analysis failed : 41 independent constraints and 42 unknowns
    • attemps to continue (attempt no. 1)
      WARNING(OBJ.MCH.KIN1) : C:/U..s/m..h/D..p/P..2/A..s/ASpringProblem6bar.any : MyStudy : Model is kinematically indeterminate : Position analysis failed : 1 unsolvable constraint(s) found
  • attempt successfull, kinematic analysis continues.
    0.0.2) ...Kinematic analysis completed. The kinematic constraints have been resolved.
    0.0.3) ...Initial conditions are fully updated.
  1. Inverse dynamic analysis...
    WARNING(OBJ.MCH.MUS1) : C:/U..s/m..h/D..p/P..2/A..s/ASpringProblem6bar.any : MyStudy : The muscles in the model are not loaded due to kinetically over-constrained mechanical system.
    NOTICE(OBJ1) : C:/U..s/m..h/D..p/P..2/A..s/ASpringProblem6bar.any : MyStudy.InverseDynamics : No muscles in the model.
    WARNING(OBJ.MCH.DYN2) : C:/U..s/m..h/D..p/P..2/A..s/ASpringProblem6bar.any : MyStudy : Model contains redundant constraint reactions :
    List of redundant reactions:
    0: Main.MyModel.Jnts.BAR1left.Constraints.Reaction[1]

ERROR(OBJ1) : C:/U..s/m..h/D..p/P..2/A..s/ASpringProblem6bar.any : MyStudy.InverseDynamics : No solution found : There are fewer unknown forces (muscles and reactions) than dynamic equations.
9) ...Inverse dynamic analysis completed
Total simulation time: 0.339

Obviously AnyBody is choking up on a redundant reaction force. I can imagine this construct to work in real life, but I do not know how to ascertain the correct joint configuration for AnyBody (after several days of contemplation I can't figure this problem out...). To see how a working model would look like, you find attached the same geometry with 5 bars, working flawlessly.

Has anyone an idea how to figure out the needed joint types?

I really hope that someone of the AnyBody staff will have a look into this… (sorry for posting initially in the wrong thread :o)

Not being the most experienced in AnyScript, I can only guess that this might be solved by changing constraint types in the joints. :confused:

Maybe it is even an impossible problem to do in AnyBody, even though I am really positive that this construct would work in real life.

OK, so is anyone of the AnyBody staff looking into this?

Any answer would be appreciated…

Hi,

That problem can be done in AnyBody, it just needs the right approach. You have to remenber that in AnyBody the kinematic and kinetic can be decoupled. That means an AnyJoint can provide the kinematic constraint while the reaction forces are removed. You can also create custom joints with the AnyKinLinear and AnyKinRotational.

Let’s start from the 5 bars model that works fine. The problem is the 6th bar that adds redundant constraints when we consider rigid bodies. First slove the kinematic: when adding the Bar2 segment you can simply add revolute joint on the BOTTOM seg and one linear constraint to the LEFT seg like this:

AnyRevoluteJoint BAR2bottom = {
AnyRefFrame &ref1=…Segs.BAR2.bottom;
AnyRefFrame &ref2=…Segs.BOTTOM.bar2;
Constraints.Reaction.Type = {Off,Off,Off,Off,Off};
};

AnyKinEq BAR2left = {
MeasureOrganizer = {0};
AnyKinLinear Lin =
{
Ref = 0;
AnyRefFrame &ref1=…Segs.BAR2.left;
AnyRefFrame &ref2=…Segs.LEFT.bar2;
};
Reaction.Type = {Off};
};

That is kinematically correct, and it is safe in the way that even if the bar length is not exact it will still solve the kinematic.

Now for the forces, you will say that the BAR2Left is not a real joint and will not transfer correctly the forces. This is true.
The tric is to remove the reaction forces in the BAR1 and BAR2 joint (see the Reaction.Type = {Off}:wink: and replace them by AnyGeneralMuscles. The first purpose of doing this is to add reactions where the joints or linear constraints do not. The second is to avoid redundancy of the reaction forces. The joint reaction forces are infinite and have no cost in the system, therefore there is no rule to share the load when they are redundant. On the opposite the general muscle are part of the optimisation (lower muscle activity), that means the system will calculate a share with no problems (strength of the general muscle can be related to the stiffness of the connexion in real life).

I have attached a file with some of those changes. The general muscles still need to be added.

Best regards, Sylvain.

Thank you so much, Sylvain.
I have to say that the solution is not really obvious to me :o. I guess I have to learn A LOT more about AnyBody/AnyScript.:rolleyes:

Anyways, I still cannot get this to work. I added a muscle to the only joint with a AnyKinLinear measurement:

  AnyFolder Muscles = {
       
       AnyMuscleModel Model = {
          F0 = 1000;
        };
       
       AnyGeneralMuscle Joint1 = 
       {
         AnyKinMeasure &lin = ..Jnts.BAR2left;
         AnyMuscleModel &muscle = .Model;
       };  
       
     };//Muscles  

Obviously this is not sufficient, given that when InverseDynamic is executed AnyBody exclaims repeatedly:

ERROR(OBJ1) :   C:/U..s/m..h/D..p/P..2/A..s/ASpringProblem6barV2.any  :   MyStudy.InverseDynamics  :  No solution found :  There are fewer unknown forces (muscles and reactions) than dynamic equations.

I know that I am missing to constrain the joints BAR1top, BAR1left and BAR2bottom, but I don’t know how to do that.

To show you how this model will be used I added the elastic properties to the 5 bar model. I parted the RIGHT and BAR1 segment in two (RIGHTA/RIGHTB and BAR1A/BAR1B) to represent two dampers. When you run the attached ASpringProblem7bar.any you can see how the applied forces deform the initial structure.

In the attached ASpringProblem9bar.any I added the last damper (BAR2A/BAR2B) and the changes in constraints and muscle, but - as suspected from the simple model - it will not run properly.

Hi,

I think you should get the base model with 6 bars running first, before going on to more complex ones. If you take again the version i have uploaded, you just need to keep adding general muscle to the four joints of BAR1 and BAR2 (those are the four ones i have desactivated the reactions).

What you did is a good start but not sufficient. First thing is that the kinematic measure you are refering to is the joint rotation and not the linear between the two joint nodes. Change it to this:

AnyGeneralMuscle Joint1 =
{
AnyKinLinear lin = {
AnyRefNode &ref1 = …Segs.BAR2.left;
AnyRefNode &ref2 = …Segs.Left.bar2;
};

     AnyKinMeasureOrg RotY = {
       MeasureOrganizer = {1};
       AnyKinRotational Rot = {
         AnyRefNode &ref1 = ....Segs.BAR2.left;
         AnyRefNode &ref2 = ....Segs.Left.bar2;
       };
     };

     AnyMuscleModel &muscle = .Model;
   };

As you can see you also need to carry the axial rotation of the bar. Do that for all four joints and it should be fine. Maybe you’ll want to do it for the RIGHT bar joints as well, as it is supposed to be an elastic element connection also.

Best regards, Sylvain.

Hi Sylvain,

thanks for your reply. I agree to getting the simple model run first.

Change it to this:

AnyGeneralMuscle Joint1 =
{
AnyKinLinear lin = {
AnyRefNode &ref1 = ...Segs.BAR2.left;
AnyRefNode &ref2 = ...Segs.Left.bar2;
};

AnyKinMeasureOrg RotY = {
MeasureOrganizer = {1};
AnyKinRotational Rot = {
AnyRefNode &ref1 = ....Segs.BAR2.left;
AnyRefNode &ref2 = ....Segs.Left.bar2;
};
};

AnyMuscleModel &muscle = .Model;
};

I changed it and added the AnyKinRotational Type demanded by AnyBody. AnyBody then tells me that I can't have two measurements in a Muscle...

So I took out the linear measurement and added muscles to all four joints, as suggested.

 AnyFolder Muscles = {
      
      AnyMuscleModel Model = {
        F0 = 1000;
      };
          
      AnyGeneralMuscle Muscle1 = 
      {
        //                       AnyKinLinear lin = {
        //                         AnyRefNode &ref1 = ...Segs.BAR2.left;
        //                         AnyRefNode &ref2 = ...Segs.LEFT.bar2;
        //                       };              
        
        AnyKinMeasureOrg RotY = {
          MeasureOrganizer = {1};
          AnyKinRotational Rot = {
            Type = RotAxesAngles;
            AnyRefNode &ref1 = ....Segs.BAR2.left;
            AnyRefNode &ref2 = ....Segs.LEFT.bar2;
          };
        };
        AnyMuscleModel &muscle = .Model;
      };//Muscle1       
      
      AnyGeneralMuscle Muscle2 = 
      {      
        AnyKinMeasureOrg RotY = {
          MeasureOrganizer = {1};
          AnyKinRotational Rot = {
            Type = RotAxesAngles;
            AnyRefNode &ref1 = ....Segs.BAR2.bottom;
            AnyRefNode &ref2 = ....Segs.BOTTOM.bar2;
          };
        };
        AnyMuscleModel &muscle = .Model;
      };//Muscle2  
      
      AnyGeneralMuscle Muscle3 = 
      {      
        AnyKinMeasureOrg RotY = {
          MeasureOrganizer = {1};
          AnyKinRotational Rot = {
            Type = RotAxesAngles;
            AnyRefNode &ref1 = ....Segs.BAR1.top;
            AnyRefNode &ref2 = ....Segs.TOP.bar1;
          };
        };
        AnyMuscleModel &muscle = .Model;
      };//Muscle3  
      
      AnyGeneralMuscle Muscle4 = 
      {      
        AnyKinMeasureOrg RotY = {
          MeasureOrganizer = {1};
          AnyKinRotational Rot = {
            Type = RotAxesAngles;
            AnyRefNode &ref1 = ....Segs.BAR1.left;
            AnyRefNode &ref2 = ....Segs.LEFT.bar1;
          };
         };      
          AnyMuscleModel &muscle = .Model;
        };//Muscle4     
        
      };//Muscles 

Again, that does not work, because I have fewer reaction forces than dynamic equations:

ERROR(OBJ1) :   C:/Users/m..h/Desktop/ASpringProblem6bar.any  :   MyStudy.InverseDynamics  :  No solution found :  There are fewer unknown forces (muscles and reactions) than dynamic equations.

I attach the file with all changes for you.

To be honest I am not clear about what I am doing at this point. Do I have to make a muscle for every reaction force that you turned off (13 in total)? I guess I will see it clearer when the model works.

Yes it is true that a general muscle can contain only one kinematic measure. Sorry i wrote a little too fast an forget that fact.

The solution is to decompose the measures so that each general muscle contains only one component. To the muscle list you already have you can add a general muscle for each component of the linear mesure:

AnyGeneralMuscle Muscle5 =
{
AnyKinMeasureOrg LinX = {
MeasureOrganizer = {0};//first component (x)
AnyKinLinear lin = {
AnyRefNode &ref1 = …Segs.BAR2.left;
AnyRefNode &ref2 = …Segs.LEFT.bar2;
};
};
AnyMuscleModel &muscle = .Model;
};//Muscle5

And that goes for the linear measure of each elastic joint. I made those addition in the attached file, try the inverse dynamic analysis, it works now.

Best regards, Sylvain.

Thank you very much, Sylvain! :slight_smile:

I added the muscles to my 9 bar system with three dampers.
Additionally I added muscles for the x-rotation which were not included before.

Running this model I realized that the joint BAR2left has only one linear constraint.

  AnyKinEq BAR2left = {
    MeasureOrganizer = {0};
    AnyKinLinear Lin = 
    {
      Ref = 0;
      AnyRefFrame &ref1=...Segs.BAR2A.left;
      AnyRefFrame &ref2=...Segs.LEFT.bar2;
    };
    Reaction.Type = {Off};
  }; 

Indirectly the joint is also constrained by BAR2bottom, which leaves only LinY and RotZ free. When doing the kinematic simulation the bar "escapes" from its joint in Y direction (I attached the file).

Basically, this brings me right back to my initial problem. I need a rotational joint here, but adding a constraint or driver to LinY would over-constrain the system. Any other joint configuration leads me right back to the initial error code.

So the question still remains: Which joint configuration is valid to accomplish rotation in all joints around their Z axes? :confused:

Best regards,
Martin

The linear constraint solution for BAR2left works in a static model. But it is right that the joint will not stay in place if the structure moves. Your model is becoming quite complex now because you chose to represent the elastic red bars with rigid segments.

There is another different aproach using AnyKinPLine that should make it much simpler:
Just keep the three rigid elements as segments (TOP, LEFT, BOTTOM), and keep the joints Fix, TopLeft and BottomLeft as they are (standard, revolute and revolute).
Then you can replace each red segment by an AnyKinPLine. This is just a line between two point (no segment) so no need to had any joints. And it is also a linear kinematic measure so you can apply to it an AnyForce representing a push/pull stiffness similar to what you did in the 9 bars model.

Finaly you can add a driver to the two revolute joints with the ForceDep type, and it will be driven by the stiffness of the PLine.

I think that should do what you want.

Best regards, Sylvain.

Thank you, Sylvain!

The idea to use AnyKinPline makes the model simpler. :slight_smile:
I followed your idea with one exception: The force dependent drivers drive the length of the AnyKinPline (like in a real spring).

This works great with one or two elastic bars, but the insertion of the third bar gives me trouble (I attach the working 2 elastics and not working 3 elastics files).

Looking at the 3 bars/3 elastics system I have:
3 segments -> 18 dof
1 AnyStdJoint -> 6 constraints
2 AnyRevoluteJoint -> 10 constraints
3 Drivers for the elastic bars -> 3 constraints

With 19 constraints and 18 dof I have obviously an over-constrained system.
Logically I have to get rid of 1 constraint. Given that my conditions are (1) the fixed bar has to be fixed and (2) there are 3 elastic elements, I have to change one (or both) of the two revolute joints.

As I see it (with my limited experience), using either AnyCylindricalJoint or AnyUniversalJoint to fulfill the dof equation will cause the position of at least one segment to be indeterminate in the inverse dynamic simulation.

So, I am back at the initial problem… It seems obvious, but I just don’t know how to configure the joints to get it working. :frowning:

This is why you should apply the ForceDep drivers to the two joints. Then you are fine with the revolute joints and the balanced system (18 dof and 18 constraints).

The motion of the revolute joints is directly influenced by the stiffness and force of the springs, so it should work nicely, with two or three springs. Try it.

Best regards, Sylvain.

Thanks Sylvain.

I do not understand how the force in the springs influence the revolute joint position here. Given that this influence is rather complex, this is exactly what I want to get from the simulation.

I can imagine more ore less how the driver would have to look then (one for every revolute joint):

         
      AnyKinEqSimpleDriver Rev1 = {                          // this is the driver
          CType = {ForceDep};
          DriverPos = {0};
          DriverVel = {0};
          AnyKinMeasure &Rev= ..Jnts.TopLeft;                  // references to the revolute joint
          Reaction.Type = {Off};     
          AnyFunInterpol Function =                             // this function represents the stiffness of the springs
          {      
           T =    {    -3, -2.5, 2,   2.5,      3};
           Data = {{ 5000, 1000, 0, -1000,  -5000}*10};
           Type = PiecewiseLinear;
          };      
          AnyForce spring = {                                        // this should be the force on the revolute joint 
          AnyKinMeasure &ref1= ...ElasticBars.RIGHT;
          AnyKinMeasure &ref2= ...ElasticBars.BAR1;
          AnyKinMeasure &ref3= ...ElasticBars.BAR2;
          F = {.Function(ref1.Pos[0])[0]};
         };        
        }; // Rev1 Driver

Obviously my code does not work because of the AnyForce part:

          AnyForce spring = {                                        // this should be the force on the revolute joint 
          AnyKinMeasure &ref1= ...ElasticBars.RIGHT;
          AnyKinMeasure &ref2= ...ElasticBars.BAR1;
          AnyKinMeasure &ref3= ...ElasticBars.BAR2;
          F = {.Function(ref1.Pos[0])[0]};
         };      

IMHO I need some kind of combination of the three spring forces which works on the revolute joints, but I cannot find any information on how to do that.

Maybe I use the wrong driver? How can I add the influence of all three springs to each revolute joint?

You do not have to define yourself the influence of the spring on the joint. As you say it is complex, so it will be calculated by the Force Dependent solver.

The driver of the revolute joint should just say that it is force dependent. That means all the forces applied (here the elastic bars) to the segments creating the joint will be taken into account by the solver to calculate a motion of the joint. So the driver looks like this for each revolute:

AnyKinEqSimpleDriver Rev1 = {
CType = {ForceDep};
DriverPos = {0};
DriverVel = {0};
AnyKinMeasure &Rev= …Jnts.TopLeft;
Reaction.Type = {Off};
};

Then comes the force applied to the segments, you just add the stiffness to each of the elastic bars. So three times something like this:

AnyForce spring1 = {
AnyKinMeasure &ref1= …ElasticBars.RIGHT;
F = {Function(ref1.Pos[0])[0]};

      AnyFunInterpol Function = 
      {      
       T =    {    -3, -2.5, 2,   2.5,      3};
       Data = {{ 5000, 1000, 0, -1000,  -5000}*10};
       Type = PiecewiseLinear;
      };

};

And that should do it.

Best regards, Sylvain.

Hello Sylvain!

Finally I got it running!!!

I am attaching the working file for everyone to enjoy.

The main problem here (I think) was that I did not understand that a driver can work without the description of its dependency on a force. For example for our revolute joints here I would expect that I have to tell the drivers which torque at which rotation it has to apply on the joints.
Secondly I thought that a revolute joint needs a rotary measure (like torque) instead of a force in a linear measure.

Luckily I have now a working model that helps me understand better the properties and functions of drivers.

Hi Martin,

thanks you for sharing with the AnyBody community and thanks to Sylvain for helping to get it running :wink: