|
Here's an AnyScript file to start on if you have not completed the previous lesson: demo.lesson2.any
There are some elements that must be present in a body model for it to make any sense at all. The first one is segments. They are the rigid elements of the body that move around when the model does its stuff. When modeling a human or other higher life form, they usually correspond to the bones of the body. However, they can also be used to model machines, tools, and other things that might be a part of the model but do not belong to the human body. Hence the more general term "segment"*.
A segment is really nothing but a frame of reference that can move around in space and change its orientation. It has an origin where its center of mass is assumed to be located, and it has axes coinciding with its principal inertia axes.
We shall start by defining a folder for the segments. Please add the following text to your model (new text marked by red):
// The actual body model goes in this folder
AnyFolder ArmModel = {
// Global Reference Frame
AnyFixedRefFrame GlobalRef = {
// Todo: Add points for grounding
// of the model here
}; // Global reference frame
// Segments
AnyFolder Segs = {
}; // Segs folder
}; // ArmModel
Did you notice that the word AnyFolder turned blue as soon as you typed its last letter? If it did not, you have mistyped something. Try loading the model by clicking the icon (or pressing F7). If you expand the ArmModel branch in the tree view, you should see a new, empty branch named Segs. It is the new folder you just defined. We are now ready to add a segment to the model, and this would probably be a good time to introduce you to the object inserter.
If you look at the left hand side of the tree view in the editor window, you will notice tabs running down the vertical edge. The tabs give you access to different tree views or let you close the tree view completely if you would rather use the space for something else. One of the tabs is called "Classes" and it produces a tree that has two branches at its root. Both of these branches contain all the predefined classes in AnyScript. In the first branch, "ClassTree", the classes are ordered hierarchically. This reflects the object-oriented idea that classes inherit properties from each other. This might be a way of locating a class with particular properties if you are not sure of the class name.
The other branch, "Class List", simply contains an alphabetical list of all the classes. This is useful if you know the name of the class you are looking for. Try opening each of the two trees and look for the class AnySeg. Then make sure the cursor in the editor window is located inside the newly defined AnyFolder Segs. Finally, right-click the AnySeg class name in the tree and choose "Insert object". You should get this:
// Segments
AnyFolder Segs = {
AnySeg <ObjectName>
{
//r0 = {0, 0, 0};
//rDot0 = {0, 0, 0};
//Axes0 = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
//omega0 = {0, 0, 0};
Mass = 0;
Jii = {0, 0, 0};
//Jij = {0, 0, 0};
//sCoM = {0, 0, 0};
};
}; // Segs folder
The object inserter has created a template of a segment for you. It contains all the properties you can set for an AnySeg object. Some of them are active while other are commented out by two leading slashes. The ones that are commented out are optional properties. You can set them if you like, but if you leave them out they will retain the values already indicated in the inserted lines. If you do not plan on using them, you can erase them. The object properties without leading slashes are those that must be set. This is the case for Mass and Jii, for instance, which are respectively the mass of the segment and the diagonal elements of the inertia tensor. In a system that simulates dynamics, all segments must have mass and inertia. The system allows you to set them to zero, but it does not make sense not to set them at all.
More formally, object properties are divided into three different groups: - Obligatory. Like Mass and Jii, these must be set by the user when the object is defined
- Access denied. These are computed automatically by the system and cannot be specified by the user.
- Optional. These can be set by the user or left to their default values.
You can find a complete description of all possible properties of all objects in the reference manual.
Let us give the new segment the name UpperArm and set its Mass = 2 and also assign reasonable values for Jii:
AnySeg UpperArm = {
//r0 = {0, 0, 0};
//Axes0 = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
Mass = 2;
Jii = {0.001, 0.01, 0.01};
}; //UpperArm
Click again (or press F7). Among the messages you get are:
Model Warning: Study 'Main.ArmStudy' contains too few kinematic constraints to be kinematically determinate.
Don't worry about it just now. It only means that you are not finished with the necessary elements to do an actual analysis yet.
Now that we have a physical object in the model, let's see what it looks like. To make something visible in AnyBody, you have to add a line that defines visibility:
AnySeg UpperArm = {
//r0 = {0, 0, 0};
//Axes0 = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
Mass = 2;
Jii = {0.001, 0.01, 0.01};
AnyDrawSeg drw = {};
}; // UpperArm
Reload the model, and then choose the menus Window -> Model View (new). This opens a graphics window and displays what looks like a long yellow ellipse. On the toolbar at the top of the graphics window, click the rotation icon . Then click inside the graphics field and drag the mouse in some direction. This causes the yellow ellipse to rotate, and you will see that it is actually an ellipsoid with a coordinate system through it. If you entered the inertia properties in the Jii specification as written above, then your ellipsoid should be ten times as long as it is wide. Try changing the "0.001" to "0.01" and reload. The ellipsoid becomes spherical. The dimensions of the ellipsoid are scaled this way to fit the mass properties of the segment you are defining. It is best to change Jii back to {0.001,0.01,0.01} again.
As you can see, Jii is a vector. If you know your basic mechanics, you may wonder why it is not a 3 x 3 matrix. The reason is that Jii only contains the diagonal members (the moments of inertia), which is all you need to specify if your segment-fixed reference frame is aligned with the principal axes. If not, the off-diagonal elements (the deviation moments) can be specified in a property called Jij, which by default contains zeros.
We are eventually going to attach things like muscles, joints, external loads, and visualization objects to our segments. To this end we need attachment points. They are defined in the local coordinate system of the segment. For a given body part it may be a laborious and difficult task to sort out the correct points. Fortunately, good people have done much of the work for you, and, if you construct your model wisely, you can often grab most of what you need from models defined by other people. For now, let us assume that you have sorted out the coordinates of all the points you need on UpperArm, and that you are ready to start adding them. Rather than going through the drill with the object inserter, you can copy and paste the following lines:
AnySeg UpperArm = {
//r0 = {0, 0, 0};
//Axes0 = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
Mass = 2;
Jii = {0.001, 0.01, 0.01};
AnyDrawSeg drw = {};
AnyRefNode ShoulderNode = {
sRel = {-0.2,0,0};
};
AnyRefNode ElbowNode = {
sRel = {0.2,0,0};
};
AnyRefNode DeltodeusA = {
sRel = {-0.1,0,0.02};
};
AnyRefNode DeltodeusB = {
sRel = {-0.1,0,-0.02};
};
AnyRefNode Brachialis = {
sRel = {0.1,0,0.01};
};
AnyRefNode BicepsShort = {
sRel = {-0.1,0,0.03};
};
AnyRefNode Brachioradialis = {
sRel = {0.05,0,0.02};
};
AnyRefNode TricepsShort = {
sRel = {-0.1,0,-0.01};
};
}; // UpperArm
Try loading the model again and have a look at the graphical representation. If you zoom out enough, you should see your points floating around the ellipsoid connected to its center of gravity by yellow pins.
One segment does not make much of a mechanism, so let's define a forearm as well. In the segs folder, add these lines:
AnySeg ForeArm = {
Mass = 2.0;
Jii = {0.001,0.01,0.01};
AnyRefNode ElbowNode = {
sRel = {-0.2,0,0};
};
AnyRefNode HandNode = {
sRel = {0.2,0,0};
};
AnyRefNode Brachialis = {
sRel = {-0.1,0,0.02};
};
AnyRefNode Brachioradialis = {
sRel = {0.0,0,0.02};
};
AnyRefNode Biceps = {
sRel = {-0.15,0,0.01};
};
AnyRefNode Triceps = {
sRel = {-0.25,0,-0.05};
};
AnyDrawSeg DrwSeg = {};
}; // ForeArm
}; // Segs folder
When you reload the model you may not be able to see that the forearm has been added. In fact it is there, but it is placed exactly on top of the upper arm and since the two segments have similar mass properties, it is impossible to see which is which.
Before we proceed it might be worth thinking a bit about why objects get placed the way they do in the model and how we can control the placement. The first thing to notice is that we are in the process of making a model of a living organism which supposedly will move about changing its position all the time. So there really is no "right" placement of a segment in the model. The second thing to notice is that even if we are able to exercise some control over the placement of objects, then at least we have not done so yet. So this is why the system for lack of better information places both segments at the origin of the global reference frame at load time.
What eventually will happen is that we will define joints to constrain the segments with respect to each other and also drivers to specify how the mechanism will move. When all that is done, these specifications will determine where everything is at every point in time. But we need to go through several steps of definitions and subsequently the system must do some equation solving before everything can fall into its "right" position. So what to do in the meantime? Well, perhaps you noticed that the UpperArm segment we originally created with the object inserter has two properties named r0 and Axes0. These two properties determine the location and orientation of the segment at load time. The r0's are easy because they are simply three-dimensional coordinates in space. So we can separate the two segments at load time like this:
AnySeg UpperArm = {
r0 = {0, 0.3, 0};
//Axes0 = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
Mass = 2;
Jii = {0.001, 0.01, 0.01};
AnyDrawSeg drw = {};
and
AnySeg ForeArm = {
r0 = {0.3, 0, 0};
Mass = 2.0;
Jii = {0.001,0.01,0.01};
This will clearly separate the segments in your model view:

So far so good. But it might improve the visual impression if the were also oriented a bit like we would expect an arm to be. This involves the Axes0 property, which is really a rotation matrix. Such matrices are a bit difficult to cook up on the fly. The predefined version in the UpperArm segment looks like this:
AnySeg UpperArm = {
r0 = {0, 0.3, 0};
Axes0 = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
If your spatial capacity is really good, you can start figuring out unit vectors for the coordinate system orientation you want and insert them into the Axes0 specification instead of the existing ones. But there is an easier solution: AnyScript has a standard function named RotMat, which returns a rotation matrix corresponding to a given axis and rotation angle. Therefore, we can specify:
AnySeg UpperArm = {
r0 = {0, 0.3, 0};
Axes0 =RotMat(-90*pi/180, z);
When you reload again you will see that the UpperArm is indeed rotated -90 degrees about the z axis as the function arguments indicate. Notice the multiplication of the angle by pi/180. AnyBody identifies the word "pi" as 3.14159... and dividing this with 180 gives the conversion factor between degrees and radians. Angles in AnyScript are always in radians, but anywhere a number is expected you can substitute it by a mathematical expression just like in other programming languages.
In the next section we will look at how joints can be used to constrain the movement of segments and allow them to articulate the way we desire. So if you are up to it, let's continue onward to Lesson 3: Connecting segments by joints.
-------------------------------- *In rigid body dynamics terminology, a "segment" would be called a "rigid body", but to avoid unnecessary confusion between the rigid bodies and the total body model, we have chosen to use "segments" for the rigid parts of the model.
|