AnyBody™ Tutorials
Lesson 3: Kinematics

So far we have added a revolving segment - a hand wheel - to the standing model. In this lesson we shall deal with the kinematics in the sense that we are hooking the hand up to the handles on the wheel. Thiswill make the arms move with the wheel as it turns and it is a convenient and simple way of realizing what would otherwise be a rather complex movement.

Before we begin it is worth noticing that we did a successful kinematic analysis at the end of the preceding lesson. This shows us that the model is kinematically determinate, so there is a balance between joint degrees of freedom and constraints in the model. So now that we wish to add constraints by hooking the hands up to the handles we must remove a similar number of the existing constraints. Otherwise the model will have redundant and mutually incompatible kinematic constraints and refuse to move or even assemble.

The model's arms are currently driven by:

  • three joint angles in the shoulder (the gleno-humeral joint)
  • one joint angle in the elbow
  • one pronation angle of the forearm
  • two joint angles in the wrist

If we attach a hand to a handle by a spherical joint we will be adding three constraints to the model, and we must correspondingly remove three of the constraints mentioned above. We cannot just remove three random constraints. For instance, we know that the model is going to have a variation of the elbow angle, so we cannot leave the model with a specification of constant elbow angle. We also know that shoulder flexion and extension is going to vary through the movement. That will account for the second degree of freedom. Finally, when the elbow is flexed and the hand is holding on to the handle, shoulder internal and external rotation is impossible. So that constraint will also have to be removed.

Let us begin by defining the spherical joint between the right hand and the handle. If you unfold the model tree in the left-hand side of the editor window, then you can come obtain the following:

At the very bottom of this tree you find a glove segment as well as a hand. The glove is a remedy for the fact that we have a rigid hand in the model. Rigid segments are infinitely strong, and when you attach something very strong to the environment you can sometimes get unreasonable results. So we have added an extra glove segment to the hand. The connection between the hand and the glove has a finite strength that emulates the grip strength of a normal hand. This means that by attaching stuff to the glove rather than to the hand we eliminate the potential problem of the model abusing the strong hand.

The natural position of this joint would be in the JointsAndDrivers.any file, because that is where we put the elements that connect the body to the environment. If you open this file you will see that it has a folder called Drivers that implements the joint angles specified in the mannequin file. But there is not a Joints folder. This is because the standing model does not have any actual joints with the environment. So we go to the top of the file and create a new folder for joints:

AnyFolder Joints = {

};

AnyFolder Drivers = {

We are going to make two spherical joints. The easiest way to do it is to create the first one with the object inserter and then copy it to make the second one. Place the cursor on the empty line between the two braces of the new Joints folder, pick the Classes tab, and unfold the class tree to locate the AnySphericalJoint. Right-click and insert a template:

AnyFolder Joints = {
  AnySphericalJoint <ObjectName> = 
  {
    AnyRefFrame &<Insert name0> = <Insert object reference (or full object definition)>;
    AnyRefFrame &<Insert name1> = <Insert object reference (or full object definition)>;
  };

};

We first define the necessary local names:

AnyFolder Joints = {
  AnySphericalJoint rhHandle = {
    AnyRefFrame &Glove = <Insert object reference (or full object definition)>;
    AnyRefFrame &Handle = <Insert object reference (or full object definition)>;
  };
};

The next step is to specify the two reference frames to be joined. Inthis case the twoframes will be the glove of the right hand and the right handle. Both of these can be located in the object tree provided the model is loaded. Click the Model tab and expand the tree through the HumanModel, BodyModel, Right, an down to the Glove segment as shown in the figure above. Erase the <> and its contents on the right hand side of the equality sign, right-click the Glove segment in the tree, and insert the object name:

AnyFolder Joints = {
  AnySphericalJoint rhHandle = {
    AnyRefFrame &Glove = Main.Model.HumanModel.Right.ShoulderArm.Seg.Glove;
    AnyRefFrame &Handle = <Insert object reference (or full object definition)>;
  };
};

Similarly, locate the Handle node in the Wheel segment in the EnvironmentModelpart of the tree and insert the name as the second reference frame:

AnyFolder Joints = {
  AnySphericalJoint rhHandle = {
    AnyRefFrame &Glove = Main.Model.HumanModel.Right.ShoulderArm.Seg.Glove;
    AnyRefFrame &Handle = Main.Model.EnvironmentModel.Wheel.rHandle;
  };
};

It is advisable when modifying models to make changes in small steps and verify that the model is working for each step. That way you can avoid agonies over mistakes that were made a long way upstream in the process. So, before we make the second connection between the left hand and the handle let us remove the now redundant constraints on the right arm and verify that it can move. We resolved in the introduction to this lesson to remove the joint drivers for elbow flexion, shoulder rotation, and shoulder flexion. Further down in the JointsAndDrivers file you can see that there is an include file with the drivers for each limb:

#if TRUNK == 1
  #include "TrunkDrivers.any"
  #else
  #endif
  
  
  #if RIGHT_ARM == 1
  #include "RightArmDrivers.any"
  #else
  #endif
  
  
  #if LEFT_ARM == 1
  #include "LeftArmDrivers.any"
  #else
  #endif
  
  
  #if RIGHT_LEG == 1
  #include "RightLegDrivers.any"
  #else
  #endif
  
  
  #if LEFT_LEG == 1
  #include "LeftLegDrivers.any"
  #else
  #endif

Double click on "RightArmDrivers.any" to open the file, you should see the following:

// ************************************
  // Drivers for the right arm
  // ************************************
  
  //Sterno clavicular joint driver
  AnyKinEqSimpleDriver SCDriverRight ={
    AnyKinMeasureOrg &ref1 =...HumanModel.Interface.Right.SternoClavicularJointProtraction;
    AnyKinMeasureOrg &ref2 =...HumanModel.Interface.Right.SternoClavicularJointElevation;
    AnyKinMeasureOrg &ref3 =...HumanModel.Interface.Right.SternoClavicularJointAxialRotation;
    DriverPos = pi/180*{
      .JntPos.Right.SternoClavicularJointProtraction,
      .JntPos.Right.SternoClavicularJointElevation,
      .JntPos.Right.SternoClavicularJointAxialRotation
    };
    DriverVel = {0.0,0.0,0};
    Reaction.Type={Off,Off,Off};
  };
  
  //Glenohumeral joint 
  AnyKinEqSimpleDriver GHDriverRight={
    AnyKinMeasureOrg &ref1 =...HumanModel.Interface.Right.GlenohumeralAbduction;
    AnyKinMeasureOrg &ref2 =...HumanModel.Interface.Right.GlenohumeralFlexion;
    AnyKinMeasureOrg &ref3 =...HumanModel.Interface.Right.GlenohumeralExternalRotation;
     DriverPos=pi/180*{
      .JntPos.Right.GlenohumeralAbduction,  //GH joint
      .JntPos.Right.GlenohumeralFlexion,  //GH joint
      .JntPos.Right.GlenohumeralExternalRotation  //GH joint
     };
     DriverVel = pi/180*{
      .JntVel.Right.GlenohumeralAbduction,  //GH joint
      .JntVel.Right.GlenohumeralFlexion,  //GH joint
      .JntVel.Right.GlenohumeralExternalRotation  //GH joint
     };    
     Reaction.Type={Off,Off,Off};
  };

  //Elbow flexion driver  
  AnyKinEqSimpleDriver ElbowFEDriverRight={
    AnyKinMeasureOrg  &Elbow =...HumanModel.Interface.Right.ElbowFlexion;
    DriverPos=pi/180*{.JntPos.Right.ElbowFlexion};  
    DriverVel = pi/180*{.JntVel.Right.ElbowFlexion};  
    Reaction.Type={Off};
  };

The elbow flexion driver is easy to remove simply by commenting it out. The glenohumeral driver has three separate degrees of freedom of which we can remove the flexion and the joint rotation. When we do so, we must rememberto also remove their entries in the DriversPos, DriverVel and Reaction.Type specifications:

//Glenohumeral joint 
  AnyKinEqSimpleDriver GHDriverRight={
    AnyKinMeasureOrg &ref1 =...HumanModel.Interface.Right.GlenohumeralAbduction;
//    AnyKinMeasureOrg &ref2 =...HumanModel.Interface.Right.GlenohumeralFlexion;
//    AnyKinMeasureOrg &ref3 =...HumanModel.Interface.Right.GlenohumeralExternalRotation;
//     DriverPos=pi/180*{
//     .JntPos.Right.GlenohumeralAbduction,  //GH joint
//      .JntPos.Right.GlenohumeralFlexion,  //GH joint
//      .JntPos.Right.GlenohumeralExternalRotation  //GH joint
//     };
//     DriverVel = pi/180*{
//      .JntVel.Right.GlenohumeralAbduction,  //GH joint
//      .JntVel.Right.GlenohumeralFlexion,  //GH joint
//      .JntVel.Right.GlenohumeralExternalRotation  //GH joint
//     };    
//     Reaction.Type={Off,Off,Off};
    DriverVel={0};
    Reaction.Type={Off};
  };
//Elbow flexion driver  
//  AnyKinEqSimpleDriver ElbowFEDriverRight={
//    AnyKinMeasureOrg  &Elbow =...HumanModel.Interface.Right.ElbowFlexion;
//    DriverPos=pi/180*{.JntPos.Right.ElbowFlexion};  
//    DriverVel = pi/180*{.JntVel.Right.ElbowFlexion};  
//    Reaction.Type={Off};
//  };

Try reloading the model and run the SetInitialConditions operation. The operation may fail, or you may geta chocking result like this:

How did that happen? Well, from a mechanical point-of-view, this solution is fully as good as the more anatomically compatible solution with the elbow bending the other way. Postures like this and failure to resolve the initial position can happen because the problem is nonlinear. This means that the solution (or lack thereof) depends on the starting position.So we must start the solution from a point that is closer to the result we want to get. This can be accomplished by imposing initial orientations on the segments. In hard-core AnyScript development this is done by means of the two segment properties r0 and Axes0. However, the standing model on which this application is built conveniently controls the initial posture through the mannequin.any file. So we can make the necessary changes there:

AnyFolder Right = {
      //Arm 
      AnyVar SternoClavicularJointProtraction=-23;   //This value is not used for initial position
      AnyVar SternoClavicularJointElevation=11.5;    //This value is not used for initial position
      AnyVar SternoClavicularJointAxialRotation=-20; //This value is not used for initial position
      
      AnyVar GlenohumeralFlexion = 50; 
      AnyVar GlenohumeralAbduction = 0; 
      AnyVar GlenohumeralInternalRotation = 0; 
      
      AnyVar ElbowFlexion = 40;

which causes the model to load with the arms closer to the desired posture. Notice that the mannequin file is set up to impose the same angles on the right and left hand sides. You can now run the KinematicAnalysis operation and see the model turning the wheel 180 degrees and the right arm following along. With that working, we can proceed to do exactly the same for the left arm. The first step is to add a joint, which we can copy from the one we just did for the right hand:

AnyFolder Joints = {
  AnySphericalJoint rhHandle = {
    AnyRefFrame &Glove = Main.Model.HumanModel.Right.ShoulderArm.Seg.Glove;
    AnyRefFrame &Handle = Main.Model.EnvironmentModel.Wheel.rHandle;
  };
    
  AnySphericalJoint lhHandle = {
    AnyRefFrame &Glove = Main.Model.HumanModel.Left.ShoulderArm.Seg.Glove;
    AnyRefFrame &Handle = Main.Model.EnvironmentModel.Wheel.lHandle;
  };  
};

Notice the changes of 'Right' to 'Left' in the copy. The second step is to remove the redundant drivers on the left arm exactly as we did for the right arm. Open the file "LeftArmDrivers.any":

//Glenohumeral joint driver
  AnyKinEqSimpleDriver GHDriverLeft={
    AnyKinMeasureOrg &ref1 =...HumanModel.Interface.Left.GlenohumeralAbduction;
//    AnyKinMeasureOrg &ref2 =...HumanModel.Interface.Left.GlenohumeralFlexion;
//   AnyKinMeasureOrg &ref3 =...HumanModel.Interface.Left.GlenohumeralExternalRotation;
//    DriverPos=pi/180*{
//      .JntPos.Left.GlenohumeralAbduction,  //GH joint
//      .JntPos.Left.GlenohumeralFlexion,  //GH joint
//      .JntPos.Left.GlenohumeralExternalRotation  //GH joint
//    };    
//    DriverVel = pi/180*{
//      .JntVel.Left.GlenohumeralAbduction,  //GH joint
//      .JntVel.Left.GlenohumeralFlexion,  //GH joint
//      .JntVel.Left.GlenohumeralExternalRotation  //GH joint
//    };    
//    Reaction.Type={Off,Off,Off};
    DriverVel={0};
    Reaction.Type={Off};
  };
  
  //Elbow flexion driver
//  AnyKinEqSimpleDriver ElbowFEDriverLeft={
//    AnyKinMeasureOrg  &Elbow =...HumanModel.Interface.Left.ElbowFlexion;
//    DriverPos=pi/180*{.JntPos.Left.ElbowFlexion};  
//    DriverVel = pi/180*{.JntVel.Left.ElbowFlexion};  
//    Reaction.Type={Off};
//  };

The left arm must also be positioned close to the posture is it going to take. Please make the following changes in the mannequin.any file:

AnyFolder Left = {
      //all values are set to be equal to the right side values 
      //feel free to change this!
      
      //Arm
      AnyVar SternoClavicularProtraction=.Right.SternoClavicularProtraction;
      AnyVar SternoClavicularElevation=.Right.SternoClavicularElevation;
      AnyVar SternoClavicularAxialRotation=.Right.SternoClavicularAxialRotation;
      
      AnyVar GlenohumeralFlexion = 0; 
      AnyVar GlenohumeralAbduction =.Right.GlenohumeralAbduction ;
      AnyVar GlenohumeralExternalRotation =.Right.GlenohumeralExternalRotation ;
      
      AnyVar ElbowFlexion = 100;

Now you should be able to run the kinematic analysis with both arms moving with the wheel. If you want to see an entire cycle, simply change tEnd in the study section in the main file from 1 to 2 seconds:

AnyBodyStudy Study = {
    AnyFolder &Model = .Model;
    tEnd = 2.0;
    Gravity = {0.0, -9.81, 0.0};
    nStep = 10;
  }; // End of study

Notice that you can furthermore control the pronation of the forearms by the setting in the mannequin file if you so desire. Notice also that, since we have retained the driver on the shoulder abduction, the lateral movement of the elbows may be unnatural. A natural movement can be imposed by information about the lateral elbow position from, for instance, a motion capture experiment.

Here is a helping hand if you did not succeed making the model in this lesson work: HandPump.3.zip .

With the kinematics in place, let us proceed to the computation of forces: Lesson 4: Kinetics .

AnyBody Technology A/S · Niels Jernes vej 10 · DK-9220 Aalborg Ø · Denmark · Tel. +45 9635 4286 · Fax. +45 9635 4599            Sitemap