So far we have accomplished to define an environment model with a simple pedal and a body model containing the trunk and the right leg. What the application is still missing is specifications of how the different elements are connected and how the model moves. With kinematics it is usually a good idea to begin with an inventory of degrees of freedom (DOFs) in the model.
The pedal is simple: It is hinged to the global reference frame and therefore just has just one movement capability, namely a rotation about the hinge. The body model is more complicated. It is disconnected from everything and is therefore floating around in space. Furthermore it has a number of internal degrees of freedom that must be controlled: Three rotations in the trunk, three rotations in the hip, one rotation in the knee, and two rotations in the ankle. With the nineDOFs of the entire body model in space and the single DOF of the pedal, this adds up to 16 DOFs. In other words, we need 16 constraints before the model is kinematically determinate.
This is what we plan to do:
- The pelvis will be fixed completely at a point corresponding to the contact to a seat. This will do away with 6 DOFs leaving us with 10 more to specify.
- The 3 rotations of the trunk will be specified by a driver to a constant position. This leaves us with 7 more constraints to specify.
- The foot will be connected to the pedal by a spherical joint having 3 constraints. This leaves us with 4 more constraints to specify.
- The ankle angle will be presumed fixed by two constraints. This leaves 2 DOFs to be constrained.
- The lateral position of the knee will be specified by a driver. This leaves a single degree of freedom in the system.
- Finally, we are going to drive the pedal angle. With the aforementioned constraints this will allow us to specify the posture of the entire system by this single driver.
1. Fixing the pelvis to the global reference frame
We previously joined the pedal to the origin of the global reference frame. This means that the 'seat' to which we shall fix the pelvis must be displaced a suitable distance from the origin. In the Environment.any file, add the following to the definition of the GlobalReferenceFrame:
AnyFixedRefFrame GlobalRef = {
AnyRefNode Hpoint = {
sRel = {-0.7, 0.5, 0};
};
}; // Global reference frame
The name Hpoint is a term used in the seating industry to characterize the position of the pelvis in a seat. Here we shall simply attach the pelvis to this point by means of a rigid connection.
All such specifications are traditionally put into a folder called ModelEnvironmentConnection, and for historical reasons it is placed in an include file called JointsAndDrivers.any. Hit the 'New Include' button
on the toolbar. It brings up an empty window where we can define the objects we need.:
// This file contains the connections between the model
// and the environment along with the motion drivers
AnyFolder Joints = {
AnyStdJoint SeatPelvis = {
AnyRefNode &Seat = ;
AnySeg &Pelvis = ;
};
};
The local pointer variables &Seat and &Pelvis need something to point to. The best way of locating the necessary points is to use the object tree at the left hand side of the editor window. Place your cursor in the editor window on the &Seat line just before the final semicolon. Then expand the three in the left hand side of the window through MyPedal, EnvironmentModel,GlobalRef to find theHpoint that we defined previously. Right-clickHpoint and choose 'Insert Object Name'. The full name of theHpoint is inserted at the position of the cursor.
We must repeat the procedure for the Pelvis. Place the cursor on the &Pelvis line just before the semicolon and subsequently expand the object tree through HumanModel, BodyModel, Trunk, SegmentsLumbar. Inside the lumbar segments folder you will find the PelvisSeg. Right-click and insert the object name. You should now have the following:
AnyFolder Joints = {
AnyStdJoint SeatPelvis = {
AnyRefNode &Seat = Main.MyPedal.EnvironmentModel.GlobalRef.Hpoint;
AnySeg &Pelvis = Main.HumanModel.BodyModel.Trunk.SegmentsLumbar.PelvisSeg;
};
};
Save the file under the name JointsAndDrivers.any. Then insert the necessary include statement into the main file:
AnyFolder MyPedal = {
AnyFolder &HumanModel=.HumanModel.BodyModel;
#include "Environment.any"
#include "Mannequin.any"
AnyFolder ModelEnvironmentConnection = {
#include "JointsAndDrivers.any"
};
}; // MyPedal
Hit F7 to reload the model. The model still loads in the same position as before. If you run the SetInitialConditions operation, the body modelmay move backward with the pelvis to the point you have specified (You may have to click the model view to update the picture). This brings up the challenge of getting the model elements aligned reasonably at load time. This is an important topic because the model will be unable to resolve the initial conditions when we add more constraints if all the segments are loaded in a big mess on top of each other.
As you might remember from the previous lesson the initial positions are controlled by the mannequin file. Open it up and make the following changes:
AnyFolder Mannequin = {
AnyFolder Posture = {
//This controls the position of the pelvis wrt. to the global reference frame
AnyVar PelvisPosX = -0.7;
AnyVar PelvisPosY = 0.5;
AnyVar PelvisPosZ = 0;
What we have done here is to specify the load-time position of the pelvis to the place where we have the seat. After reload you should be able to see in the model view that the body model has moved to a new position. It is also a good idea to specify the initial joint angles so that the foot comes closer to the pedal. This can be done further down in the Mannequin file:
AnyFolder Right = {
//Arm
AnyVar SternoClavicularProtraction=-23; //This value is not used for initial position
AnyVar SternoClavicularElevation=11.5; //This value is not used for initial position
AnyVar SternoClavicularAxialRotation=-20; //This value is not used for initial position
AnyVar GlenohumeralFlexion =-0;
AnyVar GlenohumeralAbduction = 10;
AnyVar GlenohumeralExternalRotation = 0;
AnyVar ElbowFlexion = 0.01;
AnyVar ElbowPronation = 10.0;
AnyVar WristFlexion =0;
AnyVar WristAbduction =0;
AnyVar HipFlexion = 110.0;
AnyVar HipAbduction = 5.0;
AnyVar HipExternalRotation = 0.0;
AnyVar KneeFlexion = 100.0;
On reload you will see that the body now loads in pretty much the desired position. Notice that this is only to bring the body close to where it will eventually be. It is not necessary to align the model exactly with the pedal. The kinematic constraints will take care of this once they are properly defined.
2. Fix the trunk position
In this model the trunk does not play any kinematic role. Its purpose is only to include the psoas muscles connected to the leg. So we should simply set it to a fix position. The trunk has three free rotations, flexion, lateral bending and axial rotation plus the rotation of the skull that we will fix to zero degree. This can be done by a so-called simple driver. In the JointsAndDrivers file we shall introduce a driver section below the Joints folder:
AnyFolder Joints = {
AnyStdJoint SeatPelvis = {
AnyRefNode &Seat = Main.MyPedal.EnvironmentModel.GlobalRef.Hpoint;
AnySeg &Pelvis = Main.MyPedal.HumanModel.Trunk.SegmentsLumbar.PelvisSeg;
};
};
AnyFolder Drivers = {
};
We then insert two simple drivers into the Drivers folder:
AnyFolder Drivers = {
AnyKinEqSimpleDriver PostureDriver ={
AnyKinMeasureOrg &Ref2 = ...HumanModel.Interface.Trunk.PelvisThoraxLateralBending;
AnyKinMeasureOrg &Ref3 = ...HumanModel.Interface.Trunk.PelvisThoraxRotation;
AnyKinMeasureOrg &Ref1 = ...HumanModel.Interface.Trunk.PelvisThoraxExtension;
DriverPos = {0,0,0};
DriverVel = {0,0,0};
};
AnyKinEqSimpleDriver NeckJntDriver = {
AnyRevoluteJoint &T12L1Joint = ...HumanModel.Interface.Trunk.NeckJoint;
DriverPos = {0};
DriverVel = {0};
};
};
Most of this came about the same way as we have done previously: The definition of the AnyKinEqSimpleDriver (and indeed its complex name) came from the object inserterin the Classes tree at the left handside of the editor window. The complete name of the thorax and neck rotations was inserted from the object tree. The joints are going to be static and in their neutral position, so the DriverVel and DriverPos are simply zero .
3. Connecting the foot to the pedal
The foot will be connected to the pedal by a spherical joint. This is defined inside the JointsAndDrivers file in the following way:
AnySphericalJoint PedalFoot = {
AnyRefNode &Pedal = Main.MyPedal.EnvironmentModel.Pedal.FootNode;
AnyRefNode &Foot = Main.MyPedal.HumanModel.Right.Leg.Seg.Foot.MetatarsalJoint2Node;
};
We have cheated just a little.It is possible to define new nodes on the foot for attachment to a specific place, but we have taken the cheap-and-dirty solution of picking an existing point close to where we presume the contact with the pedal will be. The MetatarsalJoint2Nodeis a good approximation.
4. Setting the ankle angle
The ankle in this body model is a universal joint, which means that it has two degrees of freedom. We wish to constrain these to degrees of freedom to predefined values. This can be done by the simple driver. We shall introduce the simple driver into the Drivers folder:
AnyFolder Drivers = {
AnyKinEqSimpleDriver PostureDriver ={
AnyKinMeasureOrg &Ref2 = ...HumanModel.Interface.Trunk.PelvisThoraxLateralBending;
AnyKinMeasureOrg &Ref3 = ...HumanModel.Interface.Trunk.PelvisThoraxRotation;
AnyKinMeasureOrg &Ref1 = ...HumanModel.Interface.Trunk.PelvisThoraxExtension;
DriverPos = {0,0,0};
DriverVel = {0,0,0};
};
AnyKinEqSimpleDriver NeckJntDriver = {
AnyRevoluteJoint &T12L1Joint = ...HumanModel.Interface.Trunk.NeckJoint;
DriverPos = {0};
DriverVel = {0};
};
AnyKinEqSimpleDriver AnkleDriver = {
AnyUniversalJoint &Ankle = Main.MyPedal.HumanModel.Right.Leg.Jnt.Ankle;
DriverPos = {};
DriverVel = {0, 0};
};
};
Like before the driver and joint name are inserted from the model three. This time what is remaining is the DriverPos specification. It is currently an empty pair of braces. The problem here is to know which of the two degrees of freedom is which. Fortunately, the model is already loaded, and we can get the current values for the ankle angles from the object tree. Click your way through the tree to HumanModel->BodyModel->Right->Leg->Jnt->Ankle, and double-click the Pos property. The current angles are dumped in the message window:
Main.MyPedal.HumanModel.Right.Leg.Jnt.Ankle.Pos = { 1.226519, -0.265366 };
Now we know which value to assign to the joint angle driver:
AnyFolder Drivers = {
AnyKinEqSimpleDriver AnkleDriver = {
AnyUniversalJoint &Ankle = Main.MyPedal.HumanModel.Right.Leg.Jnt.Ankle;
DriverPos = {1.226519, -0.265366};
DriverVel = {0, 0};
};
};
The model should load again with no significant difference.
5. Fix the lateral position of the knee
Imagine your pelvis on a seat and your foot resting on a point like the model is right now. You can still move your knee sideways either medially or laterally rotating the leg about an axis through the foot contact point and the hip joint. We must constrain this movement, and the easiest way to do it is by fixing the knee laterally.
We shall do this by another simple driver in conjunction with a linear measure. Let us add another driver to the Drivers folder:
AnyFolder Drivers = {
AnyKinEqSimpleDriver PostureDriver ={
AnyKinMeasureOrg &Ref2 = ...HumanModel.Interface.Trunk.PelvisThoraxLateralBending;
AnyKinMeasureOrg &Ref3 = ...HumanModel.Interface.Trunk.PelvisThoraxRotation;
AnyKinMeasureOrg &Ref1 = ...HumanModel.Interface.Trunk.PelvisThoraxExtension;
DriverPos = {0,0,0};
DriverVel = {0,0,0};
};
AnyKinEqSimpleDriver NeckJntDriver = {
AnyRevoluteJoint &T12L1Joint = ...HumanModel.Interface.Trunk.NeckJoint;
DriverPos = {0};
DriverVel = {0};
};
AnyKinEqSimpleDriver AnkleDriver = {
AnyUniversalJoint &Ankle = Main.MyPedal.HumanModel.Right.Leg.Jnt.Ankle;
DriverPos = {1.570796, 0};
DriverVel = {0, 0};
};
AnyKinEqSimpleDriver KneeDriver = {
DriverPos = {0};
DriverVel = {0};
};
};
This empty driver needs something to drive. We are going to create a linear measure between the global reference frame and the knee:
AnyKinEqSimpleDriver KneeDriver = {
AnyKinLinear GlobKnee = {
AnyRefFrame &Glob = Main.MyPedal.EnvironmentModel.GlobalRef;
AnyRefFrame &Knee = Main.MyPedal.HumanModel.Right.Leg.Seg.Thigh.KneeJoint;
};
DriverPos = {0};
DriverVel = {0};
};
};
The AnyKinLinear is really a vector between the two points it refers to, i.e. in this case the position of the knee in the global reference frame. However, we only wish to drive one of the coordinates of this vector, namely the lateral coordinate. This is the z coordinate, which in an AnyScript™ model has number two, because numbering begins at 0. To drive only this one coordinate, we insert a measure organizer:
AnyKinEqSimpleDriver KneeDriver = {
AnyKinLinear GlobKnee = {
AnyRefFrame &Glob = Main.MyPedal.EnvironmentModel.GlobalRef;
AnyRefFrame &Knee = Main.MyPedal.HumanModel.Right.Leg.Seg.Thigh.KneeJoint;
};
MeasureOrganizer = {2};
DriverPos = {0};
DriverVel = {0};
};
};
This has the effect of neglecting the x and y coordinates of the vector returned by the linear measure. You should be able to load the model again, but there is no visible difference.
6. Drive the pedal
The final step is to drive the movement of the pedal. It is hinged to the origin of the coordinate system, and we shall add a driver to the joint angle pretty much like we did with the ankle and the knee.
AnyKinEqSimpleDriver KneeDriver = {
AnyKinLinear GlobKnee = {
AnyRefFrame &Glob = Main.MyPedal.EnvironmentModel.GlobalRef;
AnyRefFrame &Knee = Main.MyPedal.HumanModel.Right.Leg.Seg.Thigh.KneeJoint;
};
MeasureOrganizer = {2};
DriverPos = {0};
DriverVel = {0};
};
AnyKinEqSimpleDriver Pedal = {
AnyRevoluteJoint &Hinge = Main.MyPedal.EnvironmentModel.HingeJoint;
DriverPos = {100*pi/180};
DriverVel = {45*pi/180};
};
This puts the pedal in an initial 100 degree angle compared to vertical. It also specifies a movement with an angular velocity of 45 degrees per second, but let us postpone the investigation of that for later.
For now, hit F7 again to reload the model. Notice that the system no longer complains about the model being kinematically indeterminate. Runthe SetInitialConditions operation to get things connected. With a little luck you will get this picture:
With the model kinematically determinate we can proceed and run the KinematicAnalysis operation. Doing so will show you the movement of the entire system as the pedal is rotating.
