|
Here's an AnyScript file to start on if you have not completed the previous lesson: demo.lesson3.any.
You can think of joints in different ways. We tend to perceive them as providers of freedom, which is correct compared to a rigid structure. However in dynamics it is often practical to perceive joints to be constraining movement rather than releasing it. Two segments that are not joined (constrained) in any way have 2 x 6 = 12 degrees of freedom. When you join them, you take some of these degrees of freedom away. The different joint types distinguish themselves by the degrees of freedom they remove from the connected segments.
A segment without joints is basically floating free in space. When you connect the segments by joints, you bind them together in some sense. But the mechanism as a whole can still fly around in space.
Not knowing where stuff is in space can be very impractical so the first thing to do is usually to ground the mechanism somewhere. Perhaps you remember that the system added these lines somewhere in the top of the AnyScript model:
AnyFixedRefFrame GlobalRef = {
// Todo: Add points for grounding
// of the model here
}; // Global reference frame
This is actually the definition of a global reference frame of the model. You can think of it as a coordinate system fixed somewhere in global space. Otherwise, it is just like a segment in the sense that we can add points to it for attachment of joints and muscles. Lets do just that. Again you can insert the objects with the object inserter or to save time simply cut and paste the following lines into your model:
AnyFixedRefFrame GlobalRef = {
AnyDrawRefFrame DrwGlobalRef = {};
AnyRefNode Shoulder = {
sRel = {0,0,0};
};
AnyRefNode DeltodeusA = {
sRel = {0.05,0,0};
};
AnyRefNode DeltodeusB = {
sRel = {-0.05,0,0};
};
AnyRefNode BicepsLong = {
sRel = {0.1,0,0};
};
AnyRefNode TricepsLong = {
sRel = {-0.1,0,0};
};
}; // Global reference frame
The first line, "AnyDrawRefFrame ..." does nothing else than cause the global reference system to be displayed in the graphics window. If for some reason you don't want the reference frame to be visible, just erase this line or make it a comment by prefixing it with "//". It is often nice to have a visualization of the global reference frame, but the current version may be a bit on the large side for the model. Let us reduce the size a little bit and change the color to better distinguish it from the yellow segments:
AnyDrawRefFrame DrwGlobalRef = {
ScaleXYZ = {0.1, 0.1, 0.1};
RGB = {0,1,0};
};
The remaining lines are definitions of points in the global reference frame.
Now that we have the necessary points available, we can go ahead and fix the upper arm to the global reference frame by means of a "shoulder" joint. A real shoulder is a very complex mechanism with several joints in it, but for this 2-D model, we shall just define a simple hinge. We create a new folder to contain the joints and define the shoulder:
}; // LowerArm
}; // Segs folder
AnyFolder Jnts = {
//---------------------------------
AnyRevoluteJoint Shoulder = {
Axis = z;
AnyRefNode &GroundNode = ..GlobalRef.Shoulder;
AnyRefNode &UpperArmNode = ..Segs.UpperArm.ShoulderNode;
}; // Shoulder joint
}; // Jnts folder
A hinge is technically called a revolute joint, and this is what the type definition "AnyRevoluteJoint" means. After that, the definition is just a matter of setting the properties of the joint that make it behave the way we want. Let's have a closer look at each property:
Axis = z;
The AnyBody system is inherently three-dimensional. This applies also when we are creating a model that will only operate in two dimensions, and it means that a revolute joint must know which axis to rotate about. The property Axis = z simply specifies that the segment will rotate about the z axis of the node at the joint. Does that sound complicated?
Well, a segment is really a reference frame. The nodes on segments are also reference frames, and each reference frame can have its orientation defined by the user. A joint of this type forces the two z axes of the two joined nodes to be parallel. You can control the mutual orientation of the two joined segments by rotating the reference frames of the nodes you are connecting. This is relevant if you want one of the joints to rotate about some skew axis.
The joint connects several segments, and it needs to know which point on each segment to attach to. For this purpose, we have lines like
AnyRefNode &GroundNode = ..GlobalRef.Shoulder;
AnyRefNode &UpperArmNode = ..Segs.UpperArm.ShoulderNode;
The simple explanation is that these lines define nodes on the GlobalRef and UpperArm to which the joint attaches. Notice the two dots in front of the names. They signify that the GlobalRef and Segs folders are defined two levels up compared to where we are now in the model. If you neglected the two dots, then AnyBody would be searching for the two objects in the Shoulder folder, and would not be able to find them. This "dot" system is quite similar to the system you may know from directory structures in Dos, Windows, Unix, or just about any other computer operating system.
But there is more to it than that. You can see that the Shoulder point on GlobalRef has been given the local name of "GroundNode". This means that, within the context of this joint, we can hereafter refer to the point as "GroundNode". This is practical because it allows us to assign shorter names to long external references.
Another specialty is the '&' in front of the local name. If you have C++ experience, you should be familiar with this. It means that GroundNode is a reference (a pointer) to GlobalRef.Shoulder rather than a copy of it. So if GlobalRef.Shoulder moves around, Shoulder.GroundNode follows with it. Hit F7 to load the model again to make sure that the definition is correct.
We need an elbow joint before we are finished: the elbow. The definition is completely parallel to what you have just seen, but we shall use one of the handy tools to define the references. The skeleton of the elbow joint is as follows:
AnyFolder Jnts = {
//---------------------------------
AnyRevoluteJoint Shoulder = {
Axis = z;
AnyRefNode &GroundNode = ..GlobalRef.Shoulder;
AnyRefNode &UpperArmNode = ..Segs.UpperArm.ShoulderNode;
}; // Shoulder joint
AnyRevoluteJoint Elbow = {
Axis = z;
AnyRefNode &UpperArmNode = ;
AnyRefNode &ForeArmNode = ;
}; // Elbow joint
}; // Jnts folder
As you can clearly see, the nodes in the Elbow joint are not pointing at anything yet. In this simple model it is easy to find the relative path of the pertinent nodes on the upper arm and the forearm, but in a complex model it can be very difficult to sort these references out. So the system offers a tool to help you. If you click the model tab in the tree view on the left hand side of the editor window, then the tree of objects in the loaded model appears. Anything that was defined in the model when it was recently successfully loaded can be found in this tree including the two nodes we are going to connect in the elbow. Click to place the cursor just before the semicolon in the &UpperArmNode definition in the Elbow joint. Then expand the tree as shown below.
When you right-click the ElbowNode you can select "Insert object name" from the context menu. This writes the full path of the node into the Elbow joint definition where you placed the cursor. Notice that this method inserts the absolute and not the relative path. Repeat the pocess to expand the ForeArm segment and insert its ElbowNode in the line below to obtain this:
AnyRevoluteJoint Elbow = {
Axis = z;
AnyRefNode &UpperArmNode = Main.ArmModel.Segs.UpperArm.ElbowNode;
AnyRefNode &ForeArmNode = Main.ArmModel.Segs.ForeArm.ElbowNode;
}; // Elbow joint
Seems like everything is connected now. So why do we still get the annoying error message:
Model Warning: Study 'Main.ArmStudy' contains too few kinematic constraints to be kinematically determinate.
when we reload the model? The explanation is that we have connected the model but we have not specified its position yet. Each of the two joints can still take any angular position, so there are two degrees of freedom left to specify before AnyBody can determine the mechanism's position. This is taken care of by kinematic drivers.
They are one of the subjects of Lesson 4: Definition of movement.
|