|
Here's an AnyScript file to start on if you have not completed the previous lesson: demo.lesson5.any.
We have seen that models in AnyBody can move even though they do not have any muscles. This is because we can ask the system to perform a simple kinematic analysis that does not consider forces. However, things don't get really interesting until we add muscles to the model.
Skeletal muscles are very complicated mechanical actuators. They produce movement by pulling on our bones in complicated patterns determined by our central nervous system. One of the main features of AnyBody is that the system is able to predict realistic activation patterns for the muscles based on the movement and external load.
The behavior of real muscles depends on their operating conditions, tissue composition, oxygen supply, and many other properties, and scientists are still debating exactly how they work and what properties are important for their function. In AnyBody you can use several different models for the muscles' behavior, and some of them are quite sophisticated. Introducing all the features of muscle modeling is a subject fully worthy of its own tutorial. Here, we shall just define one very simple muscle model and use it indiscriminately for all the muscles of the arm we are building.
As always, we start by creating a folder for the muscles:
AnyFolder Muscles = {
}; // Muscles folder
The next step is to create a muscle model that we can use for definition of the properties of all the muscles.
AnyFolder Muscles = {
// Simple muscle model with constant strength = 300 Newton
AnyMuscleModel MusMdl = {
F0 = 300;
};
}; // Muscles folder
Now we can start adding muscles. If you want the model to move, you basically need muscles to actuate each joint in the system. Remember that muscles cannot push, so to allow a joint to move in both directions you have to define one muscle on each side of the joint in two dimensions. If you work in three dimensions and you have, say, a spherical joint, then you may need much more muscles than that. In fact, it can sometimes be difficult to figure out exactly how many muscles are required to drive a complex body model. It is very likely that your career in body modeling will involve quite a few frustrations caused by models refusing to compute due insufficient muscles.
Let's add just one muscle to start with. These lines will do the trick:
AnyFolder Muscles = {
// Simple muscle model with constant strength = 300 Newton
AnyMuscleModel MusMdl = {
F0 = 300;
};
//---------------------------------
AnyViaPointMuscle Brachialis = {
AnyMuscleModel &MusMdl = ..Muscles.MusMdl;
AnyRefNode &Org = ..Segs.UpperArm.Brachialis;
AnyRefNode &Ins = ..Segs.ForeArm.Brachialis;
AnyDrawMuscle DrwMus = {};
};
}; // Muscles folder
This is a definition of the elbow flexor, brachialis. The type of this muscle is AnyViaPointMuscle. It means that it goes from its origin to insertion via a number of predefined points. The via-points are the AnyRefNodes defined in the second and third property lines. If you have a muscle that goes in a straight line from origin to insertion, then you can just define two points like we have done here. If you have a more complicated muscle path, then all you need to do is to add the points in between the origin and insertion.
The physiological behavior of the muscle is defined by the first property
AnyMuscleModel &MusMdl = ..Muscles.MusMdl;
You can see that it points right back to the muscle model we started out by creating. Notice the two leading dots. Finally, the line
AnyDrawMuscle DrwMus = {};
ensures that the muscle is visible in the graphics window. Lets have a look at it. If you have the Model View window (you know, the one with the rendering of the model in it) open, then just hit F7. If you don't have the Model View window open, choose Window -> Model View (new) from the pull down menus at the top of the main frame. You should see a thick, red line connecting the muscle's origin and insertion points. There are other ways to visualize muscles, but we shall save that for the dedicated the muscle tutorial.
Notice that the muscle's position on the body might be a little strange because we have not yet positioned the segments relative to each other by a kinematic analysis.
All the other muscles are defined in the same way:
//---------------------------------
AnyViaPointMuscle Brachialis = {
AnyMuscleModel &MusMdl = ..Muscles.MusMdl;
AnyRefNode &Org = ..Segs.UpperArm.Brachialis;
AnyRefNode &Ins = ..Segs.ForeArm.Brachialis;
AnyDrawMuscle DrwMus = {};
};
//---------------------------------
AnyViaPointMuscle DeltodeusA = {
AnyMuscleModel &MusMdl = ..Muscles.MusMdl;
AnyRefNode &Org = ..GlobalRef.DeltodeusA;
AnyRefNode &Ins = ..Segs.UpperArm.DeltodeusA;
AnyDrawMuscle DrwMus = {};
};
//---------------------------------
AnyViaPointMuscle DeltodeusB = {
AnyMuscleModel &MusMdl = ..Muscles.MusMdl;
AnyRefNode &Org = ..GlobalRef.DeltodeusB;
AnyRefNode &Ins = ..Segs.UpperArm.DeltodeusB;
AnyDrawMuscle DrwMus = {};
};
//---------------------------------
AnyViaPointMuscle Brachioradialis = {
AnyMuscleModel &MusMdl = ..Muscles.MusMdl;
AnyRefNode &Org = ..Segs.UpperArm.Brachioradialis;
AnyRefNode &Ins = ..Segs.ForeArm.Brachioradialis;
AnyDrawMuscle DrwMus = {};
};
//---------------------------------
AnyViaPointMuscle BicepsShort = {
AnyMuscleModel &MusMdl = ..Muscles.MusMdl;
AnyRefNode &Org = ..Segs.UpperArm.BicepsShort;
AnyRefNode &Ins = ..Segs.ForeArm.Biceps;
AnyDrawMuscle DrwMus = {};
};
//---------------------------------
AnyViaPointMuscle TricepsShort = {
AnyMuscleModel &MusMdl = ..Muscles.MusMdl;
AnyRefNode &Org = ..Segs.UpperArm.TricepsShort;
AnyRefNode &Ins = ..Segs.ForeArm.Triceps;
AnyDrawMuscle DrwMus = {};
};
//---------------------------------
AnyViaPointMuscle BicepsLong = {
AnyMuscleModel &MusMdl = ..Muscles.MusMdl;
AnyRefNode &Org = ..GlobalRef.BicepsLong;
AnyRefNode &Ins = ..Segs.ForeArm.Biceps;
AnyDrawMuscle DrwMus = {};
};
//---------------------------------
AnyViaPointMuscle TricepsLong = {
AnyMuscleModel &MusMdl = ..Muscles.MusMdl;
AnyRefNode &Org = ..GlobalRef.TricepsLong;
AnyRefNode &Ins = ..Segs.ForeArm.Triceps;
AnyDrawMuscle DrwMus = {};
};
Try adding the data and viewing the result by reloading. You should get a picture more or less as what you see below:

The model does not seem to be correctly connected at the elbow. The ArmStudy actually contains a default operation for getting the elements ordered with respect to each other. It is the SetInitialConditions study in the tree at the upper left corner of the Main Frame. Try clicking it, then hit the Run button, and the segments fall into position as shown below.

We now have enough muscles in the model to start computing the muscle forces that can drive the motion. But there is one more detail to take care of, and it is both important and slightly intricate. The bottom line is: There must be something for the muscles to drive - some load to carry. We have not added any exterior forces to the model yet, but that is not the problem. You remember, perhaps, from Lesson 2 that each segment has a mass. Additionally, the ArmModelStudy is equipped with a standard gravity of -9.81 units in the global y direction. This means that gravity actually provides the external force the analysis needs to make any sense.
What is the problem then? Well, unless you specify otherwise, drivers, like the ones we added to the elbow and shoulder joints, act like motors. This means that they provide whatever moment or force that might be necessary to make the motion happen. Although it would be practical, few of us have motors built into our joints. Instead, we have very efficient muscles so we want to leave the task of providing force in the model to them. The way to do that is to set a property called Reaction.Type for the driver to zero. This is how it's done for the shoulder:
AnyKinEqSimpleDriver ShoulderMotion = {
AnyRevoluteJoint &Jnt = ..Jnts.Shoulder;
DriverPos = {-100*pi/180};
DriverVel = {30*pi/180};
Reaction.Type = {Off};
}; // Shoulder driver
This additional line makes sure that the driver provides the motion but not the moment. Why is AnyScript made that way? Why would anyone ever want to model a joint with a motor in it? The explanation is that AnyScript models for ergonomic studies often comprise machinery that the body of the model is connected to. And this machinery can have motors that provide moment or force input to the system. Why is the motor then switched on by default? Well, models under development often do not have enough muscles to move. Such models will not work before the last muscle is added unless they have motors in the drivers, and it is practical to be able to run an analysis now and then during development to check that the model works correctly.
As you can see, the single Off is encapsulated in braces, {Off}. This is because it is a vector. A driver by default has several components and hence all the data in the driver is vector quantities. For semantic reasons this applies even when the driver only controls one degree of freedom as it does here.
Add a similar line to the definition of the elbow driver and we are ready to compute muscle forces. Click the InverseDynamicAnalysis in the study tree at the bottom left of the screen and then the Run button, and watch the model move. It should look exactly like in the kinematic analysis, however, during this analysis, the AnyBody system computes all muscle and joint forces in addition to a whole lot of other useful information. To see it, you once again have to open a ChartFX window (if you don't have the one we used previously open) by means of the menu Window -> ChartFX 2D (new) in the pull down menus in the top of the main frame. In this new window, expand the ArmStudy -> Output -> Model -> Muscles branch. You should see a list of all the muscles appearing. Each of them can be expanded to reveal the data inside. Let us expand the brachialis muscle and investigate its force variation over the movement. You should see a node named Fm. If you click it, you should get a curve like the one shown below:

Notice that the force in the muscle drops as the movement proceeds. This is quite as expected, because the moment arm of the gravity about the elbow gets smaller as the elbow flexes, and less muscle force is therefore needed to carry it. If you look at the muscle force in the BicepsLong, you see a different pattern:

This muscle grows in force during the movement. That is because it is influenced by the movement of two joints, namely the shoulder and the elbow. In addition, it collaborates both with DeltoidusA on shoulder flexion, and with the other elbow flexors, and these muscles all have to level their work in relation to each other.
This might sound like there are heuristic rules built into AnyBody. This is not the case. AnyBody distributes the work between the muscles in a very systematic way: It solves an optimization problem to actuate muscles so that the maximum relative load on any muscle is minimized. This corresponds to postponing muscle fatigue as far as possible, and it causes muscle to collaborate as much as they can. This sometimes involves development of antagonistic muscle forces, i.e., forces that appear to contradict the movement but in fact relieve weaker muscles of load. Muscle synergy and the occasional presence of antagonists is well known from many experiments, and the minimum fatigue criterion used in AnyBody reproduces this behavior.
Now that we have the analysis going, we might want to investigate the model's behavior in different situations. A typical example could be to see how it carries an external load in addition to gravity. Let us imagine that the model is performing a dumbbell curl where it carries some load at the hand. We start by attaching a node to the forearm at the position of the palm. Add this definition to the ForeArm section:
AnyRefNode PalmNode = {
sRel = {0.27,0,0};
};
The next step is to add an external force. We make a folder for this purpose:
AnyFolder Loads = {
//---------------------------------
AnyForce3D Dumbbell = {
AnyRefNode &PalmNode = ..Segs.ForeArm.PalmNode;
F = {0,-100,0}; // Force in Newton
};
}; // Loads folder
That's all there is to it. Now you can analyze how the model will react to a downward force of 100 N (approximately 10 kg dumbbell weight). If you reload, rerun, and investigate the BicepsLong force again, you should see this:

The muscle force is obviously much larger than before, and the development is also different. It now reaches a maximum during the movement and drops off again.
Applied forces do not have to be constant. They can change with time and other properties in the model. Please refer to the tutorial on forces for more details.
There are infinitely many studies that could be made using even a simple model like this one, and you are encouraged to experiment a little or a lot. To get reliable results, however, would take at the very least an individual definition of the muscles with a realistic strength for each of them, and a more detailed modeling of the deltoid's origin-insertion path in the shoulder; it can be a comprehensive job to define a realistic body model which is exactly why most users would probably start out using the body model available from the AnyBody Research Project.
This tutorial, being of introductory nature, will instead skip to a new subject: How can we add realistic geometries of bones and other elements to our model?
Now, let's continue to Lesson 6: Adding real bone geometrics
|