The AnyBodyTM Modeling System Tutorials Version 3.0.0, September 2007 Copyright © 2007, AnyBodyTM Technology A/S Home: www.anybodytech.
1 Tutorials The AnyBody tutorials are step by step introductions to the use of the AnyBody system and in particular to construction of models in AnyScript. The tutorials are tightly linked to a collection of demo AnyScript files. These samples are usually developed as a response to popular requests by our users. The demo comes first, and a tutorial is subsequently developed around it. This pdf-document is a collection of the tutorials exported directly from the AnyBody web page.
2 Getting Started.................................................................................................................. 4 Lesson 1: Using the standing model .................................................................................. 6 Lesson 2: Controlling the posture...................................................................................... 9 Lesson 3: Reviewing analysis results ................................................................................
3 Trouble shooting AnyScript models ...............................................................................
4 Getting Started This tutorial is the starting point for new users. Its purpose is to allow users to get the first model up and running fairly quickly. The AnyBody Modeling System can be approached on a number of levels depending on the amount of detail the modeling task requires. Listing the approaches in top-down order may produce the following: • • • Loading a model defined by somebody else and changing simple parameters like the applied load or the posture.
5 • • easy to create a model of a gymnastic exercise on the floor this way. Constructing a model from single predefined body parts in the repository. This allows for detailed control of which body parts are included in the model and may be useful for, for instance, detailed investigations of the internal forces in a single limb. Constructing a body model and its environment bottom-up. This is recommended for users interested in development models that are not covered by the current model repository.
6 When you open AnyBody for the first time, the Demo tab does not contain any models, but only a short guide on how to extract the demo models. After having done this, brief descriptions and links to the models are available in the tab. In addition, it is easy to reinstall the demo models later, which may be useful when you have been playing around with them for a while; this way you can reset all the changes you have made.
7 //This model is only for kinematic analysis and should be used when playing //around with the kinematics of the model since leaving the muscles out, makes //the model run much faster #include "..\..\..\BRep\Aalborg\BodyModels\FullBodyModel\BodyModel_NoMuscles.any" //This model uses the simple constant force muscles //#include "..\..\..\BRep\Aalborg\BodyModels\FullBodyModel\BodyModel.
8 balance the extrnal forces. Please notice that it is possible to apply an external force large enough to require tension between the feet and the floor. Because of the rounding condition of the feet such a tension will be provided by the model but the situation may not be realistic because real feet rarely stick to the ground. It is time to load the model.
9 familiarize yourself with the options. Having loaded the model it is time to proceed to lesson 2: Controlling the posture. Lesson 2: Controlling the posture The Standing Model has been developed to a fairly complex level, automating many of the operations that are necessary to specify the posture of a full body model. The short story about the kinematics of the model is that it is based on a specification of angles in all the joints. These specifications can be found in one of the model files, mannequin.
10 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.
11 AnyVec3 AnyVec3 AnyVec3 AnyVec3 Hand Hip Knee Ankle = {0.000, 0.000, 0.000}; = {0.000, 0.000, 0.000}; = {0.000, 0.000, 0.000}; = {0.000, 0.000, 0.000}; }; }; // Loads The downward load of -50 N in the right hand roughly corresponds to a weight of 5 kg. To enable the model to actually carry the load we must equip it with muscles.
12 If you click once on InverseDynamicAnalysis and then on the Run button in the bottom of the window then the system will start analyzing the muscle and joint forces in the model under the influence of gravity and the load we applied to the hand. This takes a few seconds during which you will see the muscles standing out from the body and subsequently falling into place. When the analysis is finished you will notice a slight color change in the muscles and also some bulging, primarily in the right arm.
13 Clicking the node produces an empty cordinate system in the large field. The reason why it is empty is that the standard setting of the ChartFX View is to display time-varying data for moving models. In this simple case our model is static, so it does not make much sense to draw curves.
14 This tells you that to stand upright and carry the 50 N load in the right hand, the model is using 4.00e-001 = 40% of its maximum voluntary contraction. This means that the relative load of the muscle with the highest activity in the system is 40% of the muscle's strength. Even though one number is a very simplified way of regarding a system with hundreds of muscles, there are good mathematical reasons why this particular number is a good measure of the human effort of a particular task.
15 This shows that the force in this muscle branch is roughly 18 N. Notice the specification line above the graphics pane marked with the red circle above. This is where the specification of the current picture is listed. You can use this to plot several muscles at the same time. If you change Main.Study.Output.Model.HumanModel.Right.ShoulderArm.Mus.supraspinatus_3.Fm to Main.Study.Output.Model.HumanModel.Right.ShoulderArm.Mus.supraspinatus_*.Fm i.e.
16 All these branches have the same force, which is because they are assumed in the model to have the same strength. However, if you specify: Main.Study.Output.Model.HumanModel.Right.ShoulderArm.Mus.*.Fm then you will get all the muscles in the right shoulder and arm: The different muscles do indeed have very different forces. You can see the muscle name in a little pop-up window if you hold the mouse still over a given bar.
17 complex modeling tasks. The syntax of AnyScript is much like a Java, JavaScript, or C++ computer program. If you already know one of these programming languages, you will quickly feel at home with AnyScript. But don't be alarmed if you have no programming experience. AnyScript is very logically constructed, and this tutorial is designed to help new users getting started as gently as possible. So let us take the bull by the horns and get you introduced to the world of body modeling with AnyScript.
18 As you can see, the Main Frame window contains a smaller frame at the bottom. This frame provides much of your interaction with the system once you have a model running. Notice now in particular the empty rectangular lower portion of the frame. It is the Output Window. The system talks to you through this window. Notice that this window as well as many other text views in AnyBody can contain active links like in a HTML browser. These links can help you navigate faster around in the system.
19 The new windows is basically a text editor. This main pane of the Editor window will contain the actual AnyScript text. The system has already created the skeleton of a model for you from a built-in template. The narrow pane attached to the left side of the Main Frame is a tree view pane, where you find hierarchical representations of the model defined in the text window. If you are familiar with modern feature-based CAD systems, this idea will be very familar to you.
20 in the Main Frame toolbar and the key F7 is a convennient shortcut for this function. The script to model operation also saves your model files. The first time you save a new file, AnyBody requires you to give your model a name, so clicking the dialog. icon the first time produces a "Save As" Let's have a look at what the system has generated for you.
21 may know it from C++ or the Java language. Notice also that lines are terminated by semicolon ';'. Even the lines with closing braces must be terminated by a semicolon. If you do no terminate with a semicolon, then the statement continues on the next line. You can comment and uncomment a block of lines in one click by means of the buttons at the top of the Editor window. The only actual model element in the ArmModel is the declaration of the "AnyFixedRefFrame GlobalRef".
22 We now assume that you have removed eventual errors and have loaded the model successfully. If you are up to it, let's continue onward to Lesson 2: Segments. This is a typical error message. First there is a message ID, then a file location and finally the body of the message. The former two are written in blue ink and underlined to show the underlying active links. The file location is the line where the bug was found by the system.
23 // 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.
24 //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.
25 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.
26 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.
27 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.
28 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.
29 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 "//".
30 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.
31 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.
32 Lesson 4: Definition of movement Here's an AnyScript file to start on if you have not completed the previous lesson: demo.lesson4.any. If you have completed the three previous lessons, you should have a model with an upper arm grounded at the shoulder joint and connected to a forearm by the elbow. What we want to do now is to make the arm move. How can an arm with no muscles move? Well, in reality it cannot, but in what we are about to do here, the movement comes first, and the muscle forces afterwards.
33 AnyRevoluteJoint &Jnt = ..Jnts.Shoulder; and AnyRevoluteJoint &Jnt = ..Jnts.Elbow; are the ones that affiliate the two drivers with the shoulder and elbow joints respectively. They are constructed the same way as the joint definition in Lesson 3 in the sense that a local variable, Jnt, is declared and can be used instead of the longer global name if we need to reference the joint somewhere else inside the driver.
34 Try expanding the ArmStudy root. You will get a list of the study types that the system can perform. "Study" is a common name for operations you can perform on a model. When you click one of the studies, the buttons on the middle, lower part of the panel come to life. Try clicking the KinematicAnalysis study. With the buttons, you can now execute various types of analysis. The panel contains three buttons: • • • Run.
35 shown in the figure to the right. Directly under the ArmModelStudy branch you find the Output branch where all computed results are stored. Notice that the Output branch contains the folders we defined in the AnyScript model: GlobalRef, Segs, and so on. In the Segs folder you find ForeArm, and in that a branch for each of the nodes we defined on the arm. Try expanding the branch for the HandNode. It contains the field 'r' which is the position vector of the node.
36 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.
37 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.
38 }; //--------------------------------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.
39 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.
40 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.
41 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.
42 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.
43 very physiological. You may be wondering how you can add cool bones and other geometries that will impress your colleagues and look good in your presentations. You may want to put your model into an environment such as a room, a treadmill, or a bicycle to illustrate the purpose of the model. However, there may be other reasons than mere aesthetics why it can be advantageous to work with real geometries.
44 ScaleXYZ = {0.001, 0.001, 0.001}; }; When you reload the model, the picture you get should be similar to what you see below. The dumbbell is visible now and has the right size, but it is sitting at the center of gravity of the lower arm rather than at the hand, and it is not oriented correctly. The fact is that, when you attach something to a segment, it is positioned at the segment's origin which is usually the same as the center of mass.
45 We want to rotate the dumbbell 90 degrees about the y axis. We could do that by going back to the CAD system and modifying the dumbbell STL file, but an easier option is to rotate it directly inside AnyScript. A geometrical object that you insert gets the same orientation as the coordinate system it is attached to. In this case the dumbbell is attached to PalmNode.
46 This completes the Getting Started with AnyScript tutorial. The final result of the efforts is in demo.arm2d.any. Interface features This tutorial deals with the interface features of the AnyBody Modeling System. Before trying your luck with this tutorial, please complete the Getting Started with AnyScript tutorial. Much of the interface works like other types of windows software; you can copy and paste data, and you can arrange the various windows as you would expect.
47 • Lesson 5: The Command Line Application Let us quickly proceed to the first lesson: Windows and workspaces. Lesson 1: Windows and workspaces When you work with a model like this, you are likely to initially go through a series of model refinements, subsequently conduct a number of investigations, and finally extract data for further processing or reporting.
48 This indicates that you are now working in the first of the three user-defined layouts. Each layout can contain a different user-defined window setup, and you can switch between them by a single mouse click. Try running the HeelUpStudy.InverseDynamicAnalysis and open a ChartFX window to investigate the results.
49 It says "New Workspace" because you did not load a workspace when you started, and you have not yet saved the one you have created. Click File-> Save Workspace as..., pick a directory and a suitable name, and save the workspace. Then exit AnyBody, and start the system again. When you have re-started, click File->Load Workspace..., browse your way to the workspace file you just saved, and load it. You will get the windows layout back that you had when you started.
50 This brings up a new editor window with an empty file, and we can go ahead typing anything we want. The first thing you have probably noticed about the AnyScript editor is that it recognizes the predefined class names and highlights them automatically. It does this all the time as you are typing, and it is a great help to avoid misspellings that might later lead to annoying syntax errors. Syntax Highlighting When you start typing something, the writing color is black.
51 You are not forced to accept this. You can easily backspace to the beginning of the line and start your typing there, if you like that better. You might write something like: AnySeg Segment1 = { Mass = 1.0; The editor will discover that you did not like its suggested indentation, so the next line you type will begin at the same character as Mass, and you may proceed to finish the definition of the segment by typing: AnySeg Segment1 = { Mass = 1.0; Jii = {0.1,0.01,0.
52 What you see here is the Model Tree, which it the main tree view of AnyBody showing all objects in the loaded model in the structure they are created in the AnyScript code. The Model Tree is in principle available in many of AnyBody's windows, but some of the information is filtered out in some window types to make the tree view practical for specific purposes such as browsing output or operations in the model.
53 The Model Tree offers you several options to go from the tree to associated places the AnyScript code. There are, however, also options to go the opposite way, i.e. from the code to the Model Tree. Try right-clicking the code. You will them get a pop-up menu with several editor options. One of these is "Locate in Model Tree". It will probably be greyed, i.e. disabled, because you have not selected anything that can be related to the tree.
54 The third tab in the tree view is named Classes. It gives you access to a tree of the predefined classes in the system. From this tree you can insert templates of new objects. This eliminates much of the need to remember the syntax of each object and saves you many lookups in the reference manual. The use of the Classes Tree is described in the Getting Started with AnyScript tutorial. There are a couple of more tree views. These contains global objects that are available to your code.
55 If the model is not too big and the computer is not too slow, the computation runs fast enough to create a dynamic animation in real time or close to that. However, for many larger models, the computation is too slow to give you a dynamic impression of the model's movement. The model view then provides the opportunity to save the individual frames for subsequent processing into a video animation that you can play at any speed you like.
56 This resolves the kinematical constraints and puts the model into the position defined by its drivers at time step 0. It produces the picture shown below.
57 Notice that we are looking at the model directly from the side. The default viewing direction is the xy plane. This coincides well with the International Society of Biomechanics standard of letting the saggital plane coincide with the global xy plane.
58 • On/Off: This button switches automatic update of the window on and off. When switched off, the window does not update when the model is moving, and it is not possible to rotate, scale and pan the view. The advantage of switching the update off is that it makes the analysis run faster, especially on computers without a separate graphics processor. • Properties : Button that opens the properties window (equivalent to menu item Windows -> GUI Properties).
59 Recording video You may want to save a video file of you simulation for a presentation or simply to be able to show a large model running in real time. The model view provides the opportunity to save the individual graphics frames for subsequent processing into a video animation that you can play at any speed you like.
60 purpose. We at AnyBody Technology use a very good and inexpensive tool called VideoMach available from http://www.gromada.com/. Size matters Regardless of how videos are processed, they are rather data intensive, and it is a really good idea to plan the recording well. Depending a little on the image format, the size of the frames you are saving is proportional to the area of the Model View.
61 Notice that the window like all other windows in the AnyBody Modeling System is divided into a tree pane on the left and the actual data area to the right. If you play around a bit with the tree you will soon see that it resembles the trees from most of the other window types, but that some stuff is missing. This is because the tree is filtered, and it requires a further explanation: The AnyBody Modeling System contains a special type of data called output data.
62 Try clicking Ekin, Epot, and Emech in turn. You will notice that Epot and Emech are very similar. This is because the movement in this model is relatively slow, so the kinetic energy remains small throughout the simulation and has little influence. The KinematicError is not very interesting unless something is wrong with the analysis. It stores the error in the kinematic analysis as a measure of how far the kinematic constraints of the problem are from being satisfied.
63 Having an item graphed you may want to investigate the results a little closer, and the toolbar above the graph gives you different options for doing so. However, the first thing you might notice is that if you hold the mouse pointer still above the curve for a short moment, a small box will pop up and give you the name of the data series and the value of the closest data point. In the example to the right you can see how the little box informs you that the curve passes through point (0.04; 1.46e+002).
64 In some cases you can have curves with complicated shapes that you may want to investigate in details. The zoom tool is handy for that. When you press the toolbar button with the little magnifying glass, zoom mode switches on, and you can select an area of the chart for closer investigation by dragging the mouse. You can zoom again on the zoomed area and go as close to the detail you are interested in as you like. The zoom mode remains active until you click the magnifying glass again.
65 We have eight muscles in this model, so why do you only see two curves? The explanation is that all the muscles in this model have the same strength, so they team up in groups where all the muscles pull exactly the same. This model has three groups. The brown curve at the top, the green curve in the middle, and another green curve of inactive muscles on the x axis. So several curves are hidden under each of the curves you can see.
66 User-defined abscissa The default abscissa in the chart view is time. However, you can in principle plot data against any scalar property the system has computed. Let us imagine that the dumbbell curl study we are looking at is an ergonomic investigation of the effort of lifting the weight to different heights. In that case, it might be more relevant to plot the muscle force as a function of the height of the hand. The way to do so is simply to replace the ArmStudy.Output.Abscissa.
67 The three graphs (of which one is constant zero) is because the hand node position is a vector with three coordinates. We want to extract the height, which is the y coordinate, and use it as the abscissa. But the abscissa obviously cannot be a vector, so we must construct a scalar variable containing the y coordinate of the hand node in the AnyScript model. The way to do so represents a very useful and slightly subtle trick, and requires a bit of explanation.
68 As you can see, the tree has been extended with the new variable we have defined. The next step is to use this variable as the abscissa. Notice the first line of the panel above. It holds the time specification, but it is grayed out, and you cannot write anything in the field. To be able to change this line, first click the "Out" button. "Out" means that this is where to click if you want to select a new abscissa among the output variables.
69 the .CHT file. .CHT files are a convenient way of storing analysis data because they can subsequently be reformatted and displayed in other ways than you initially planned, for instance a stacked column diagram or a pie chart instead of curves. Data can also be exported from the Chart View via the clipboard. The "Copy to clipboard" icon on the toolbar gives you the opportunity to copy the present chart on different formats: • • • • As a bitmap picture.
70 Lesson 5: The Command Line Application The AnyBody Modeling System comes with a command line version included. It is named AnyBodyCon.exe ("Con" for console application), and you will find it in the directory where you install AnyBody. The command line version is - as the name indicates - a version of the AnyBody Modeling System with the user interface stripped off. This means that it is executed from a DOS command prompt or - more importantly - by a batch file or another software application.
71 understands eight different commands. You also always get help by using the 'help' command or by calling AnyBodyCon with /? argument. The latter approach will give you the full help including descriptions of the possible program arguments. The table below contain a description of the commands accepted by the AnyBody console. Command name Functionality Example: load "demo.outputfile.any" load "filename.any" This command loads an AnyScript model into the system and compiles it.
72 nearly as interesting as running the Windows version of the AnyBody Modeling System. So why bother? Well, the command line version of the AnyBody Modeling System faithfully performs all the computations you ask it to through the command line. But what good does it do you, and how can you access the results? You could issue print or printdown commands and have the results listed on the screen. It would give you a whole lot of probably completely useless numbers to look at.
73 As you can see, the command line version can produce output data that can be formatted according to your desire and processed further by other types of software. But the really great thing about the console application is that you can execute it from other software such as Matlab or Visual Basic and as such build it into an integrated system for large-scale biomechanical data processing such as response surface-based optimization.
74 where the classes with blue icons are the ones you can actually define. In this tutorial we shall focus on AnyBodyStudy and AnyBodyCalibrationStudy, while a seperate tutorial is dedicated to AnyParamStudy and AnyOptStudy. The AnyBodyStudy and Studies in general A study is really just a folder. It is a pair of braces between which you can place some specifications. Whatever you put between the braces becomes part of the study.
75 tEnd Ah, you guessed it already. This is the time at which the study ends. Contrary to tStart, this often has to be set by the user. The standard value is tEnd = 1.0, and if you want your study to span any more or less time, you have to set tEnd manually. A very common modeling mistake is to define data-based drivers such as the AnyKinEqInterPolDriver with a time span exceeding the interval from 0 to 1 and then wondering why only a small part of the movement interval gets simulated.
76 • calculation of any sort of forces. This means that you can run KinematicAnalysis as soon as you have the movement defined uniquely. You don't need any muscles in the model for this one. InverseDynamicAnalysis. This is a simulation of the forces involved in the given movement or posture and whatever can be derived from them.
77 In the following lessons we shall look in more detail at the different operations in an AnyBodyStudy and finally also at the AnyBodyCalibrationStudy. • • • • • Lesson Lesson Lesson Lesson Lesson 1: 2: 3: 4: 5: ModelInformation SetInitialConditions KinematicAnalysis InverseDynamicAnalysis AnyBodyCalibrationStudy We need a model with a bit more substance than the template we created above.
78 When you press the run button you will see a whole lot of text scrolling over the message pane below the study tree. You can scroll up and down using the vertical slider bar, but it is probably easier to maximize the window and move the divider bar up a little. At this point, if you scroll up a bit you will come to a line of asterixes where the output from the ModelInformation operation starts.
79 0: Main.ArmModel.Drivers.ShoulderMotion (1constr.) 1: Main.ArmModel.Drivers.ElbowMotion (1constr.) Other: - none! Total number of constraints: Joints: 10 Drivers: 2 Other: 0 Total: 12 ------------------------------------------------------------This section counts the kinematic constraints. The sum of constraints must add up to the number of degrees of freedom in the model, i.e. 12. You can see in the last line of the section above that this indeed the case.
80 A few special cases are: 1. 2. 3. The number of reaction and driver forces is less than the number of rigid body degrees of freedom in the model as it is the case here. This leaves some reactions to be provided by other elements, and these elements are usually the muscles in the model. If the number of reaction and driver forces is equal to the number of rigid body degrees of freedom, then the model is (usually) capable of balancing itself, and there is no use for muscles.
81 Drivers: 0: Main.ArmModel.Drivers.ElbowMotion (1constr.) Other: - none! Total number of constraints: Joints: 10 Drivers: 1 Other: 0 Total: 11 ------------------------------------------------------------The ModelInformation operation allows you to investigate in detail how many constraints are missing and which ones they may be. Let us shift the missing driver back in: //--------------------------------AnyKinEqSimpleDriver ShoulderMotion = { AnyRevoluteJoint &Jnt = ..Jnts.
82 And running the ModelInformation operation will give the following feedback: ------------------------------------------------------------3) List of reaction forces: 0: Main.ArmModel.Jnts.Shoulder.Constraints.Reaction(5 active of 5 reactions) 1: Main.ArmModel.Jnts.Elbow.Constraints.Reaction(5 active of 5 reactions) 2: Main.ArmModel.Drivers.ShoulderMotion.Reaction(1 active of 1 reactions) 3: Main.ArmModel.Drivers.ElbowMotion.
83 not do it automatically when you load the model. Running the SetInitialConditions operation produces a correctly assembled arm: The arm correctly assembled at the elbow by SetInitialConditions. Here's a more detailed explanation: The system must perform a kinematical analysis to connect the model correctly at the joints. This requires that the model is kinematically determinate.
84 Picking the step button. The first step re-establishes the load-time conditions. This means that it positions the modes as it was when you loaded it. This is useful for identification of kinematic problems. The second step positions the segments honoring the joints. The third does not seem to do much, but it is used for positioning muscles wrapping over surfaces. It is just not visible in this simple model.
85 An AnyBody model is really a collection of rigid segments. You can think of them as a bunch of potatoes floating around in space. Technically, each potato is called a "rigid body", but the term "body" can be misinterpreted in the context of a body modeling system like AnyBody, so we call them "segments". When a segment flows around in space, it can move in six different directions.
86 Running kinematic analysis Now that you know the basics of kinematic analysis, let us look at how it is performed. We need an example to work on, and this one will serve the purpose: demo.SliderCrank3D.any When you load it and open a Model View you will see that this is a very simple mechanism comprising only three segments. They are not yet connected correctly at their joints, but they will be if you run the KinematicAnalysis operation.
87 Why would anything in a smoothly running model behave like this? The answer lies in the ordinate axis. You will notice that it has no values on it, and if you hold the mouse over a point on the curve a small window will pop up and show you the value: You can see that the value is 4.45e-14. For all practical purposes this is zero, and this is also why there are no values on the ordinate axis. What you see here is really zero augmented by numerical round-off errors.
88 Lesson 4: Inverse Dynamic Analysis Inverse dynamic analysis is at the heart of what the AnyBody Modeling System does. An InverseDynamicAnalysis operation is like the KinematicAnalysis, except it is augmented with calculation of forces in the system. Computing forces in a rigid body mechanical system is more difficult than it may seem. In principle, resolving forces is a question of setting up the equilibrium equations and solving them.
89 For use in this tutorial, a slightly modified version of the model is provided here: demo.diffmusarm2D.any. Please download it, save it, and load it into the AnyBody Modeling System. How does a real human body handle this situation? Actually, not a lot is known about how the human body distributes force between redundant muscles. Compared to other scientific achievements, such as charting the human genome, it may seem like a simple matter to figure out how much a given muscle is pulling on a bone.
90 Subject to • • Equilibrium equations fulfilled Muscles are not allowed to push In the standard setup of InverseDynamicAnalysis operations in the AnyBody Modeling System, e1 and e2 are both zero. This means that the system is minimizing the maximum muscle activity in each time step. Let us have a look at the consequences of that. Have you loaded demo.diffmusarm2D.any into the system yet? If not, please do it now, and run the InverseDynamicAnalysis.
91 So the very systematic activation pattern becomes much more complex when viewed as muscle forces. Let us for a moment return to the activities again. They appear to range between approximately 0.30 and 1.20. These are direct measures of the load of the muscles. A load of 1.0 corresponds to the muscle working at its ultimate strength. In this case it appears that the muscles are about 20% overloaded when the dumbbell approaches the end of its movement.
92 This result is much different from the one we had before. The value of 1.0e+3 completely dominates the criterion, so here we are actually minimizing the sum of muscle activities. This has the effect of recruiting a minimum set of muscles and only those that are best suited at each position. This is known not to be correct because the muscles are not collaborating.
93 e2 in the criterion. This has two potentials: 1. 2. Small values of e2 may regularize complex problems numerically much like e1 can do. Large values of e2 can change the formulation of the problem into something different just like e1 can do, but unlike e1, it makes physiological sense to use large values of e2. Initially, try setting up the study like this: // The study: Operations to be performed on the model AnyBodyStudy ArmModelStudy = { AnyFolder &Model = .
94 As you can see, the tendencies are much the same as before, but the muscular synergy is less outspoken in the quadratic case, and the maximum muscle activity is therefore higher. Muscles recruited according to the quadratic criterion will tire before muscles recruited according to the min/max criterion, but the difference particularly for the activation envelope is not very dramatic. In any case, the AnyBody Modeling System gives you the opportunity to pick the criterion you believe is the best.
95 lengths in AnyBody is the assumption that each muscle-tendon unit has its optimal length at some particular position of the joints it spans. We simply define one or several studies that put the body model in these positions and adjust the lengths of the tendons to give the attached muscles their optimal lengths in those positions. When you subsequently run an analysis, the system uses the calibrated tendon lengths regardless of how they are defined in the AnyScript file.
96 What we have done here is to give BicepsLong a new and more advanced muscle model. Let's have a look at the consequences. Press the M<-S button or F7 and subsequently run the InverseDynamicAnalysis. Then, open a new ChartFX window to investigate the results. This graph shows the muscle force or more precisely the force in the tendon.
97 The parallel-elastic force sets in when the muscle is stretched beyond its optimal fiber length. In the movement of this example, the elbow starts at 90 degrees flexion, and as the graph shows, this gives rise to about 10 N of passive force at the beginning of the movement. This indicates that the tendon we have specified is too short. If the movement was extending the elbow instead of flexing it, the passive force would rise sharply.
98 Calibrating the muscle in a particular position requires a calibration study. It's basic definition is very simple: // ======================================================= // "The body study" // ======================================================= AnyBodyStudy ArmModelStudy = { AnyFolder &Model = Main.ArmModel; RecruitmentSolver = MinMaxSimplex; Gravity = {0.0, -9.81, 0.0}; }; // A new calibration study AnyBodyCalibrationStudy CalibrationStudy = { AnyFolder &Model = Main.
99 }; // ArmModel AnyFolder Drivers = { //--------------------------------AnyKinEqSimpleDriver ShoulderMotion = { AnyRevoluteJoint &Jnt = Main.ArmModel.Jnts.Shoulder; DriverPos = {-100*pi/180}; DriverVel = {30*pi/180}; Reaction.Type = {Off}; }; // Shoulder driver //--------------------------------AnyKinEqSimpleDriver ElbowMotion = { AnyRevoluteJoint &Jnt = Main.ArmModel.Jnts.Elbow; DriverPos = {90*pi/180}; DriverVel = {45*pi/180}; Reaction.
100 The final step is to modify the calibration study to use the calibration drivers: // A new calibration study // A new calibration study AnyBodyCalibrationStudy CalibrationStudy = { AnyFolder &Model = Main.ArmModel; AnyFolder &Drivers = .CalibrationDrivers; nStep = 1; }; // End of study What we have now is a study that uses the model together with two static drivers for calibration of the muscles, and a study that uses the model with the previous set of dynamic drivers.
101 Once again we need two drivers to put the model into the posture for calibration of the TricepsLong muscle: // ----------------------------------------------------// Triceps Calibration Drivers // ----------------------------------------------------AnyFolder TricepsCalibrationDrivers = { //--------------------------------AnyKinEqSimpleDriver ShoulderMotion = { AnyJoint &Jnt = Main.ArmModel.Jnts.Shoulder; DriverPos = {-90*pi/180}; // Vertical upper arm DriverVel = {0.0}; Reaction.
102 Muscle modeling Muscles are the actuators of living bodies. They are activated by the central nervous system (CNS) by a complicated electro-chemical process. Determining the activation that realizes a desired movement requires an extremely intricate control algorithm. The CNS is superior to any computer man has made in this respect.
103 length, pennation angle, tendon elasticity, and stiffness of passive tissues into account. Please refer to the reference manual for concise information about the available muscle models: 1. 2. 3. AnyMuscleModel - assuming constant strength of the muscle AnyMuscleModel3E - a three element model taking serial and parallel elastic elements into account along with fiber length and contraction velocity AnyMuscleModel2ELin - a bilinear model taking length and contraction velocity into account.
104 AnyRevoluteJoint Jnt = { AnyRefFrame &ref1 = .GlobalRef; AnyRefFrame &ref2 = .Arm.Jnt; Axis = z; }; // Drive the revolute joint at constant velocity AnyKinEqSimpleDriver Drv = { DriverPos = {-10*pi/180}; DriverVel = {40*pi/180}; AnyRevoluteJoint &Jnt = .Jnt; Reaction.Type = {0}; }; }; // MyModel // The study: Operations to be performed on the model AnyBodyStudy MyStudy = { AnyFolder &Model = .MyModel; RecruitmentSolver = MinMaxNRSimplex; Gravity = {0.0, -9.81, 0.
105 Notice that this class has three derived classes. These are more advanced muscle models, and we shall get to those later. However for the time being, place the cursor in the Editor View on an empty line just after the end brace of the driver definition, right-click the AnyMuscleModel class in the tree, and select "Insert Class Template".
106 The next step is to define a muscle that can use the model. This is actually the first of the two elements mentioned above: Muscle kinematics. Again, the AnyBody Modeling System provides a number of choices, and we shall start by picking the simplest one. It is instructive to once again use the tree to insert a template of the muscle object, because the tree reveals the class dependency.
107 Notice that we have left only two points in the list of via points. This is obviously the minimal requirement and will create a muscle in a single line from origin to insertion. But before we proceed with the definition of the muscle we must define the necessary points on the model to attach the muscle to.
108 InverseDynamicAnalysis. If you try it out and subsequently open a chart view, you are able to plot the muscle force: The muscle force is the item Fm in the list of properties you can plot for a muscle. As you can see, lots of other properties are available, but if you try to plot them you will find that many of them are zero. This is because they are not relevant for this very simple type of muscle. We shall return to the significance of the different properties later in this tutorial.
109 Let us play around with the settings a bit. An easy way to display all the settings is to discard our manually defined AnyDrawMuscle object and insert a template from the class tree instead: Erase the previous AnyDrawMuscle, right-click the AnyDrawMuscle in the tree view, an insert an instance: AnyViaPointMuscle Muscle1 = { AnyMuscleModel &Model = .SimpleModel; AnyRefFrame &Orig = .GlobalRef.M1Origin; AnyRefFrame &Ins = .Arm.M1Insertion; AnyDrawMuscle drw = { //RGB = {0.554688, 0.101563, 0.
110 //Transparency = 1.000000; //DrawOnOff = 1.000000; //Bulging = 0.000000; //ColorScale = 0.000000; //RGBColorScale = {0.957031, 0.785156, 0.785156}; //MaxStress = 250000.000000; }; }; Notice that the must be manually changed to drw (or any other sensible name). The commented lines (with // in front) are the optional settings. Un-commenting them will not change much because the values they have listed are the default settings. So we need to change some of the values.
111 up to an almost vertical position. If you plot the muscle force, Fm, again in a chart view, then you can see how the muscle force goes up drastically with the reduced moment arm: Consequently the muscle now bulges more towards the end of the movement than it does in the beginning: The muscle thickness does not have to reflect force.
112 AnyDrawMuscle drw = { //RGB = {0.554688, 0.101563, 0.117188}; //Transparency = 1.000000; //DrawOnOff = 1.000000; Bulging = 1; ColorScale = 1; //RGBColorScale = {0.957031, 0.785156, 0.785156}; MaxStress = 2500; }; When you reload and run the InverseDynamicAnalysis, you will notice that the red shade of the muscle changes as its activity grows: When the activity is zero, the color defaults to a rather pale red. You can control this "initial" value of the scaled color through the property RGBColorscale.
113 They are usually constrained by various obstacles on their way from origin to insertion, either by connective tissues or by the contact with bone surfaces. In the former case, the muscle tends to pass as a piecewise straight line between the constrained points, and this is relatively easy to to accomplish by means of an AnyViaPointMuscle. In the latter case, the muscle may engage and release contact with the bone surfaces it encounters.
114 AnyRefNode Jnt = { sRel = {-0.5, 0.0, 0}; }; AnyRefNode M1Insertion = { sRel = {0.3, 0.05, 0}; }; AnyDrawSeg drw = {}; }; The next step is to introduce a new point on the Arm segment to function as the via point: AnySeg Arm = { r = {0.500000, 0.000000, 0.000000}; Mass = 1.000000; Jii = {0.100000, 1.000000, 1.000000}*0.1; AnyRefNode Jnt = { sRel = {-0.5, 0.0, 0}; }; AnyRefNode M1Insertion = { sRel = {0.1, 0.0, 0}; }; AnyRefNode ViaPoint = { sRel = {0.0, 0.
115 A muscle can pass through an unlimited number of via points, and the points can be attached to different segments. This can be used to create rather complex kinematic behaviors of muscles, but it also requires care in the definition to avoid unrealistic muscle paths when the via points move about with the different segments. From-the-point of view of kinematic robustness, the wrapping muscles are easier to handle than via point muscles, but the price is a much higher computational expense.
116 AnyRefNode CylCenter = { sRel = {0, 0, -0.2}; }; }; // Global reference frame Having defined the point, we can proceed to create a surface. The wrapping algorithm in AnyBody will in principle work with any sort of surface including real bone surfaces, but for the time being only parametric surfaces are used.
117 Radius = 0.15; Length = 0.4; AnyDrawParamSurf drv = {}; //CapRatio = 0.100000; }; }; Which causes the cylinder to rotate 20 degrees about the y axis. There are a couple of things to notice about the cylinder: First of all the graphics looks like the cylinder is faceted. This is not really the case. Graphically it is displayed with facets out of consideration of the efficiency of the graphics display, but from the point-of-view of the muscle it is a perfect cylinder.
118 Jii = {0.100000, 1.000000, 1.000000}*0.1; AnyRefNode Jnt = { sRel = {-0.5, 0.0, 0}; }; AnyRefNode M1Insertion = { sRel = {0.3, 0.05, 0}; }; AnyRefNode M2Insertion = { sRel = {-0.2, 0.05, 0.05}; }; Notice that we have given the origin and insertion points a bit of offset in the z direction to make the problem a bit more exciting. The offset will cause the muscles to cross the cylinder in a non-perpendicular path to the cylinder axis such as for instance the pronator muscles of the human forearm do.
119 SPLine.StringMesh = 20; This line generates a sequence of 20 equidistant points on the shortest path muscle, and these are the points that are actually in contact with the wrapping surface(s). More points will give you a more accurate solution, but they also require more computation time. For shortest path muscles the computation time can be an important issue.
120 As you can see, both muscles are now wrapping over the cylinder, and we can run the InverseDynamicAnalysis. It seems to work, but the system provides the following warning: WARNING - Via-point 'Main.MyModel.GlobalRef.M1Origin' on 'Main.MyModel.Muscle1.SPLine' is located below the wrapping surface 'Main.MyModel.GlobalRef.CylCenter.WrapSurf'. This is a warning that you will see rather frequently when working with complex models with wrapping.
121 measure that is really a string that wraps just like a muscle but does nothing else than measure its own length. These objects can be used outside the muscle definition for various purposes in the model, for instance for definition of springs or rubber bands. After you load the model with the added InitWrapVectors, try using the Step button rather than the run button.
122 to go with a simpler model where the approximations are clear. In short, AnyBody has the following muscle models available AnyMuscleModel This is the simplest conceivable muscle model, and it is the one we have used in the preceding lessons of this tutorial. The only input to the model is the muscle's presumed isometric strength, F0, i.e. the force that the muscle can exert in a static condition at its optimum length.
123 F0 = 0; Lfbar = 0; Lt0 = 0; Epsilonbar = 0; V0 = 0; }; Let us briefly review the parameters: Parameter Function F0 In the simple muscle model, F0 is simply the strength of the muscle. In this two-parameter model, F0 is the ideal strength, i.e. the strength of the muscle at neutral fiber length and zero contraction velocity. F0 is measured in force units, i.e. Newton. Lfbar The neutral fiber length, i.e. the length of the contractile element at which the muscle has the strength of F0.
124 }; The parameters here are more or less random. In a moment we shall explain the ones that are less random, but first we must assign the new model to Muscle1: AnyShortestPathMuscle Muscle1 = { AnyMuscleModel &Model = .Model2; AnyRefFrame &Orig = .GlobalRef.M1Origin; AnyRefFrame &Via = .Arm.ViaPoint; AnySurface &srf = .GlobalRef.CylCenter.WrapSurf; AnyRefFrame &Ins = .Arm.M1Insertion; SPLine.
125 Now we can compare the variation of Lm and Lmdot to our settings of Lfbar and V0. Lm seems to vary between approximately 0.31 and 0.15. With an Lfbar of 0.3 (= 2x0.15) this means that the muscle must come close to the minimum length at which is has any strength when we approach the end of the movement. Lmdot varies between -0.24 and -0.06, and this is far from its speed limit V0 = -8, so the contraction speed is not expected to have much effect.
126 • • • • • • • • • • • • • • • • • • Fin is a force, but it has not physiological significance for a muscle except for internal purposes. The reason why it is included in the output is that it is inherited from the AnyScript classes that a muscle is derived from. Fout is a force, but it has not physiological significance for a muscle except for internal purposes. The reason why it is included in the output is that it is inherited from the AnyScript classes that a muscle is derived from.
127 • • • • • muscle model. EPOTmt is the total elastic potential energy in the muscle-tendon unit. Pt is not relevant for this muscle model. Pm is the mechanical power exerted by the muscle's contractile element. Pmt is the mechanical power of the muscle-tendon unit on the skeleton. Pmet is a crude estimate of the metabolic power consumption of the muscle taking different efficiencies for concentric and eccentric work into account.
128 reducing Lt0: AnyMuscleModel2ELin Model2 = { F0 = 200; Lfbar = 0.3; Lt0 = 0.3; Epsilonbar = 0.05; V0 = -0.3; }; This reduction of the tendon length from 0.5 to 0.3 meters is very significant compared to the nominal muscle fiber length of Lfbar = 0.3 m.
129 Definition of an external force requires two new elements in the model: The force itself and a new node on the arm, which we shall call hand, to which the load can be applied: // Define one simple segment AnySeg Arm = { r = {0.500000, 0.000000, 0.000000}; Mass = 1.000000; Jii = {0.100000, 1.000000, 1.000000}*0.1; AnyRefNode Jnt = { sRel = {-0.5, 0.0, 0}; }; AnyRefNode M1Insertion = { sRel = {0.3, 0.05, 0}; }; AnyRefNode M2Insertion = { sRel = {-0.2, 0.05, 0.05}; }; AnyRefNode ViaPoint = { sRel = {0.
130 The interesting point here is that with the long tendon and the high load, the muscle no longer contracts uniformly. In fact, the muscle extends for much of the movement due to the decreasing load which causes the elastic tendon to contract instead. While the two-parameter muscle model captures many of the properties of real muscles it also fails to reflect important parts of muscle physiology, so it should be applied with care. In particular it does not model passive elasticity.
131 The figure above is a schematic representation of the muscle model. We can get a complete impression of the parameters of the model if we pick the model from the Class List as we have done before and insert a template into our AnyScript model: AnyMuscleModel2ELin Model2 = { F0 = 200; Lfbar = 0.3; Lt0 = 0.3; Epsilonbar = 0.05; V0 = -0.
132 hence dimensionless. Jt and Jpe Jt and Jpe are elasticity factors for the tendon (serial-elastic) and parallel-elastic elements respectively. The background of these parameters is that the model presumes a nonlinear elasticity of these elements, and the precise shape of the force-deformation characteristics of the element are determined by Jt and Jpe respectively. In essence, Jt and Jpe are material constants and should not vary too much between different muscles or individuals.
133 AnyRefFrame &Ins = .Arm.M2Insertion; SPLine.StringMesh = 20; SPLine.InitWrapPosVectors = {{-0.2, -0.2, 0},{-0.05,-0.2, 0}}; AnyDrawMuscle drw = { Bulging = 0; ColorScale = 1; MaxStress = 250000; }; }; Finally, to have a more clean-cut case, we temporarily remove the external force that we previously added /*AnyForce3D Load = { AnyRefNode &Attachment = .Arm.Hand; F = {-100, -100, 0}; }; */ We are ready to try running the InverseDynamicAnalysis again.
134 From the time the passive force sets in, the tendon starts to elongate a little bit. The total origin-insertion length of the muscle-tendon unit is the tendon length plus the muscle length, i.e. Lm + Lt. When Lt is stretched, the effect is that the muscle fibers stretch that much less, and since the muscle's strength depends on the momentary length of the contractile element, the strain in the tendon can influence the strength of the muscle.
135 }; AnyRefNode M1Insertion = { sRel = {0.3, 0.05, 0}; }; AnyRefNode M2Insertion = { sRel = {-0.2, 0.05, 0.05}; }; AnyRefNode ViaPoint = { sRel = {0.0, 0.1, 0}; }; AnyRefNode Hand = { sRel = {0.5, 0.0, 0}; }; AnyDrawSeg drw = {}; }; AnyForce3D Load = { AnyRefNode &Attachment = .Arm.Hand; F = {0, 10, 0}; }; With this we can run the InverseDynamicAnalysis again and get the muscle to do some work.
136 Lt The length of the tendon. This appears to be constant, but the tendon length actually changes slightly over the movement with the changes of muscle force as described above. LmtDot The contraction velocity of the muscle-tendon unit. The value is positive because the muscle is getting longer. LmDot The contraction velocity of the contractile element of the muscle. The value is positive because the muscle is getting longer.
137 Fm The force in the contractile element is decreasing throughout the movement because the moment arm of the external force is reducing and also because the passive force in the muscle is contributing more and more to balancing the load. Ft The tendon force shows the reduction of the mucle action by virtue of the reduced external force's moment arm alone. A simplified explanation is that Ft = Fm + Fp, but this is not entirely true because we also have to account for the pennation angle.
138 PennationAngle The pennation angle is the angle between the muscle fiber direction and the muscle line of action. This angle changes when the muscle contracts and elongates, and the model takes this effect into account. EPOTt The elastic potential energy stored in the tendon. EPOTp The elastic potential energy stored in the parallel-elastic element of the muscle. EPOTmt The elastic potential energy stored in the entire muscle-tendon unit.
139 Pmt The mechanical power of the entire muscle-tendon unit, i.e. the rate of work performed on the skeleton. Notice that the power is negative because the muscle is extending against the force. Muscles behaving like this in the human body are often termed antagonistic muscles. Pmet A crude estimate of the metabolism in the muscle. The estimate is based on presumed efficiencies of the contractile element of 25% for concentric work and -120% for eccentric work.
140 Not only is the shape of the graph different; the maximum activity is also significantly higher. An error of 10% in an anthropometric data value is not uncommon considering the accuracy of measurement methods and variation between individuals, and if the influence on the final result is as strong as this, we would not be able to trust our results.
141 Try running the InverseDynamicAnalysis again and plot the Activity of Muscle2. You should see the following: As you can see, this is again very different from what we have seen before. Plotting the strength will reveal what has happened: What the MuscleCalibrationAnalysis does is to run through the specified movement and compute the variation of the origin-insertion length of the muscle.
142 Detailed calibration There is a more accurate and detailed way of calibrating tendons, but it requires additional information. More precisely it calibrates the tendon lengths at user-defined joint postures. So each muscle is associated with a certain set of joint postures for which the muscle is presumed to be at its neutral position. Please notice that the set of neutral joint postures is in principle different for each muscle in the system.
143 muscles are disregarded and the body is balanced entirely by joint torques. This type of analysis can provide important information about the function of limbs and joints, and it is extremely numerically efficient. Joint torque inverse dynamics can be accomplished by adding general muscles to the joints to replace the physiological muscles of the body. This way, the "muscle forces" computed in the general muscles will simply be the joint torques.
144 Reaction.Type = {0}; }; // Elbow driver }; // Driver folder AnyGeneralMuscle = { //ForceDirection = -1; AnyKinMeasure & = ; AnyMuscleModel & = ; }; Just as normal muscles, general muscles must be associated with a muscle model. Let us insert a simple one: AnyMuscleModel = { F0 = 0; }; AnyGeneralMuscle = { //ForceDirection = -1.
145 Having provided torques for the shoulder and elbow it should be possible to run the inverse dynamic analysis. However, attempting to do so will provide the same depressing error message as before. The reason is that general muscles share the ability to be unilateral with normal muscles. The direction of action is controlled by the variable ForceDirection.
146 Notice that in this case we have used the same strength (muscle model) for both joints. However, the maximum joint torque in physiological joints varies a lot. The knee extension strength, for instance is significantly larger than the elbow extension strength. If you perform this type of modeling you can define joint torque muscles with strengths comparable to the available joint torque and the system can give you an estimate of how many percent of each joint's strength is used in a given situation.
147 We are going to make a couple of changes to the simple arm model to investigate contact in more detail. We shall imagine that the hand of the model has a vertical wall to support against. We have to change the kinematics to make the arm slide along the wall. It would be really difficult to figure out which joint angle variations are needed to make the hand move vertically, so we drive the hand directly instead.
148 The muscle activity is rather constant which is the natural consequence of the moment arms being rather constant. The gravity as well as the applied load of 100 N are vertical, so one might be tempted to think that a horizontal support would not make much of a difference. We can do a quick test by simply switching on the horizontal support of the driver: Reaction.
149 F0 = 100.0; }; AnyMuscleModel ReacModel = { F0 = 10000.0; }; AnyGeneralMuscle WallReaction = { ForceDirection = -1; AnyKinMeasureOrg Org = { AnyKinMeasure &wall = ..HandPos; MeasureOrganizer = {0}; }; AnyMuscleModel &Model = .ReacModel; }; There are two things to notice here 1. 2. The muscle model for the reaction, ReacModel, is much stronger than the joint muscles. This is because the wall is presumed to be very strong. The ForceDirection property equals -1.
150 }; If you run the model again and plot the same graphs, you will see this: The wall is obviously useful in the initial stages of the movement where the torque generated by the reaction force is in the beneficial direction for both the joints. In the later stages of the movement the presence of the wall decreases the envelope of the muscle forces slightly, but it has increased the torque in the elbow.
151 As you can see, the model is very simple. The blue structure is an "arm" that extends from the center of the yellow Ground reference frame. It is hinged at the Ground's origin, and a driver bends it downwards. With the movement, the red ligament is stretched, and a force builds up in it. Try running the InverseDynamicAnalysis operation.
152 It looks like the force development is slightly nonlinear. This would make sense because ligament elasticity is generally nonlinear, but in this case it just shows that the abscissa is not the ligament length but rather an artificial "time" that is proportional to the joint angle. In the Chart View you can plot any output data against each other. Let's select instead of time the ligament length. Click the "Out" button, and the field containing the abscissa becomes white. You can now type LigStudy.
153 work with strain here rather than absolute length change? The reason is that ligaments are rather stiff structures, so small length changes can cause large forces, and it is therefore necessary that the slack length fits the model precisely. This length will usually have to be tuned to size changes of the body model. When we work with strain, the stiffness becomes a more generic property of the ligament and is independent of the length it gets calibrated to.
154 The specification has created a continuous slope of 0 where the curve previously had a kink. Notice that the curve converges back to the "nominal" slope given by the two points (L0,0) and (eps1,F1) If you try the following: AnyLigamentModelPol LigModel = { L0 = 1.30; // Slack length eps1 = 0.2; // Strain where F1 is valid F1 = 1000; // Force in the ligament at strain eps1 a0 = 0.
155 The significance of a1 is much the same, except it has its effect at the point (eps1,F1). Rather than at (L0,0). If, for instance you insert this: AnyLigamentModelPol LigModel = { L0 = 1.30; // Slack length eps1 = 0.2; // Strain where F1 is valid F1 = 1000; // Force in the ligament at strain eps1 a0 = 0.5; a1 = 0.0; }; - then you will get a curve that attains zero slope at (eps1,F1): So, a1 = 0.0 corresponds to zero slope, and the default value of a1 = 1.
156 the values of L0, eps1, and F1. You can similarly increase the slopes by increasing a1: Unlike normal fourth order polynomials, these curves will continue predictably with no oscillation for as long as desired after (eps1,F1). The reason for this behavior is the default setting of the parameter LinRegionOnOff = On which causes the curve to continue a linear behavior after (eps1,F1).
157 Clearly, this causes the curve to diverge after (eps1,F1), which is typical for higher order polynomials Unless you have some special reason for wanting the pure fourth-order behavior, we recommend that you leave LinRegionOnOff = On. Calibration Most ligaments in the body are rather stiff structures in which the force builds up quickly when they are stretched beyond the slack length. This means that a small error in slack length specification could lead to a large error in computed ligament force.
158 Double-click it, and its value is shown in the Object Description Window. You should find a value of Main.LigModel.LigModel.L0 = 1.300000; This is the slack length of the ligament at load time as defined in the ligament model. Now, run the LigCali.LigamentLengthAdjustment operation, and subsequently double-click the L0 property again. Now you will see a value of Main.LigModel.LigModel.L0 = 1.573132; The system has extended the ligament length a bit to fit the joint angle of -pi/4.
159 them you must have sound understanding of the laws of mechanics in general and of Newton's three laws of motion in particular.
160 Segments do not have any particular shape associated with them. By default a segment is originated in its Center of Mass (CoM), but it is possible to move the CoM away from the origin of the segment's reference frame. The mass properties are defined by means of a mass and an inertia tensor. The segments in the picture above visualize their mass properties by ellisoids. Another important property of a segment is that it can have nodes, so-called AnyRefNodes, assigned to it.
161 Please refer to the reference manual for further explanation. The Getting Started with AnyScript tutorial provides examples of segment definitions. Next up is Lesson 2: Joints. Lesson 2: Joints You normally think of a joint as something that provides the body with its movement capability. We interpret joints that way because we would not be able to move if our joints were rigid. But there is also an opposite perception of a joint: as a constraint.
162 The different types are described in detail in the reference manual. For examples on how to use joints, please download and study the following two examples: • • Slider crank in 2D Slider crank in 3D The next chapter is Lesson 3: Drivers. Lesson 3: Drivers Drivers create movement in a model. They are really functions of time determining the position of a joint or the distance between two points or some other kinematic measure at any given time through the simulation period.
163 But let us imagine that we wanted the hand to reach out an grab something at a specific position. It would probably be difficult to figure out precisely how to drive the two joint angles to put the hand in the position we wanted it to attain. Instead, we would want to be able to put the hand (actually the wrist since this simple model has no hand) directly at the desired position in space and have the elbow and shoulder joints follow implicitly. This is where the kinematic measures come into play.
164 Click Pos, and you will get three graphs tracking the x, y, and z components of the WristPos kinematic measure. The z component (blue curve) of the measure remains zero throughout the movement because the model is two-dimensional. The top curve (red) is the x component, and the bottom curve (green) is the y component.
165 interpolation driver instead. AnyFolder Drivers = { AnyKinEqSimpleDriver HandMotionXY = { }; }; // Drivers folder We can now fill contents into the HandMotionXY driver that will guide the hand through space: AnyFolder Drivers = { AnyKinEqSimpleDriver HandMotionXY = { AnyKinLinear &Jnt = ..KinematicMeasures.WristPos; MeasureOrganizer = {0,1}; DriverPos = {0.4,-0.5}; DriverVel = {0.2,0.5}; DriverAcc = {0.0,0.0}; Reaction.
166 0.00900900900 0.01001001000 0.01101101100 0.01201201200 0.01301301300 0.01401401400 0.01501501500 0.01601601600 0.01701701700 0.01801801800 0.01901901900 0.02002002000 0.83799541478 0.83717626771 0.83626918423 0.83527365810 0.83418913820 0.83301408734 0.83174961018 0.83039421700 0.82894718724 0.82740776078 0.82577513921 0.82404848719 -0.54567809793 -0.54693420265 -0.54832036673 -0.54983594020 -0.55148021065 -0.55325177839 -0.55515095782 -0.55717631355 -0.55932688186 -0.56160163587 -0.56399948535 -0.
167 We now have a linear measure that is in fact a three-dimensional vector from the origin of the global reference frame to the end point of the pendulum. But so far we are only measuring the vector. The next step is to actually drive it by the measured trajectory. We do so by introducing an interpolation driver.
168 forces to realize this movement. So we need to switch the reaction forces of the new driver off like this: AnyKinEqInterPolDriver P1Driver = { Type = Bspline; BsplineOrder = 4; FileName = "P1.txt"; AnyKinMeasure &Lin = .P1Lin; Reaction.Type = {Off, Off, Off}; }; Try loading the model again and run the Kinematic Analysis (In this tutorial we do not use the inverse dynamic analysis). Most likely it will not work.
169 afterwards. To directly drive just one coordinate we need a driver file with just one column of data in addition to the time column. Please download this version: p1x.txt and save it in the same directory as the other files of the model. Then make the following changes: AnyKinEqInterPolDriver P1Driver = { Type = Bspline; BsplineOrder = 4; FileName = "P1x.txt"; AnyKinMeasure &Lin = .P1Lin; MeasureOrganizer = {0}; Reaction.
170 to the path of the pendulum regardless of which direction the pendulum has. But before we can make that shift, we shall implement the smart way of picking a degree of freedom to drive that we promised in the preceding section. The idea is based on definition of a new segment representing the MOCAP marker: AnyKinEqInterPolDriver P1Driver = { Type = Bspline; BsplineOrder = 4; FileName = "P2x.txt"; AnyKinMeasure &Lin = .P1Lin; MeasureOrganizer = {0}; Reaction.
171 Type = Bspline; BsplineOrder = 4; FileName = "P1.txt"; AnyKinMeasure &Lin = .M1Lin; // MeasureOrganizer = {0}; Reaction.Type = {On, On, On}; }; AnyKinEq MarkerBodyConstraint = { AnyKinLinear lin = { AnyRefFrame &Marker = ..M1; AnyRefFrame &Body = ..Pendulum.P1; }; MeasureOrganizer = {0}; }; This brings us exactly back to where we started. If you have done everything right, you now have a model that oscillates like it did at the end of the preceding section.
172 // MeasureOrganizer = {0}; Reaction.Type = {On, On, On}; }; The model now uses the new P2.txt file containing all three coordinates to drive the movement. If you reload the model by pressing F7 and re-run the kinematic analysis, then you should see the same erroneous pendulum movement as before.
173 Notice that the accelerations are between approximately -500 and 600. Now, let us introduce some random noise. An easy way to do so is to simply truncate the decimals off the columns in the marker trajectory file. Please download this file, where the numbers only have three decimals: P2trunc.txt. Then make the following change in the model: AnyKinEqInterPolDriver M1Driver = { Type = Bspline; BsplineOrder = 4; FileName = "P2trunc.txt"; AnyKinMeasure &Lin = .M1Lin; // MeasureOrganizer = {0}; Reaction.
174 This appears to work very nicely. Plotting velocities produces this nice result: Still, there is not much indication that anything might be wrong with the result, except perhaps a tiny hint of visible noise near the turning points of the graphs.
175 Oops, something appears to have gone completely wrong here. The accelerations are noisy and several times larger than before. What could be the problem? The problem is actually, that the tiny amount of random noise we introduced by truncating some of the decimals from the marker trajectory gets amplified by an order of magnitude for each differentiation. The noise is indistinguishable on the position, hardly detectable on the velocities, but very large on the accelerations.
176 The first example is a rather basic application of time-varying forces to the well-known 2-D arm model. The example shows forces defined directly as a mathematical function of time and forces interpolated between a set of measured values. The second example illustrates the difference between locally and globally defined forces and how forces acting on a segment can be summed up.
177 The ampersand, '&', in front of the variable name specifies that this is a reference. What it means that MyFolderCopy will just point to MyFolder, so whatever you do to MyFolderCopy will happen to MyFolder. It is as simple as that. A pointer variable takes up very little space in the computer because it does not copy the data it is pointing to. This demo example illustrates some of the important uses of pointer variables: creatingandreferingtoobjects.
178 Right-click the files and save them in a directory of your choice. Then start AnyBody and load the main file, demo.include.any. Next up is Lesson 3: Mathematical Expressions. Lesson 3: Mathematical Expressions One of the definite advantages of a modeling language like AnyScript is that mathematical expressions become a natural element in model construction.
179 exchanging them, we shall end up with a very good supply of models that fit most purposes. The AnyBody Model Repository is an attempt to provide such a library. These are some of the tasks you will want to accomplish with predefined models: • • • To change the model pieces to fit your own purposes - preferably without tampering with the interior workings of the parts you are using. To be able to combine existing body parts to larger models.
180 and it is rather heavy computationally. For this reason the BRep directory is structured to enable the user to link applications to subsets of the body model such as the lower extremities or the shoulder model. The idea behind the division into ARep and BRep is that each user wants to model the human body in a special situation. This can take place in the ARep branch with references to the BRep branch but without tampering with the more delicate BRep parts at all.
181 You can find more information on the structuring of the individual body part files in the Structure lesson. In the rest of this tutorial we shall consider the situation where a new application is to be built using body parts from the Aalborg branch of the BRep. We shall do so using three different strategies of increasing complexity: 1. 2. 3. When an existing application is similar enough to what you want to do to form the basis of the new application.
182 The ARep branch of the repository contains a large amount of applications where different collections of body parts are hooked up to more or less complicated environments. Some of these environments may be extremely simple, such as a floor to stand on, while others may be mechanisms in their own right such as wheel chairs or bicycles with complicated crank mechanisms.
183 //This file contains joint angles which are used at load time // for setting the initial positions #include "Mannequin.any" // This file contains the exact same joint variables as the mannequin // file but their values are obtained from the model // once the kinematic analysis has been done #include "MannequinValuesFromModel.any" AnyFolder ModelEnvironmentConnection = { #include "JointsAndDrivers.any" //This file will read values in the "Mannequin.
184 AnyVar AnklePlantarFlexion =0.0; AnyVar AnkleEversion =0.0; }; AnyFolder Left = { This first section of the mannequin file contains the folder Posture of which you can only see a subset in the code above. The posture folder lets you specify anatomical joint angles in degrees, and when you subsequently load and run the model it will assume the posture you have specified. The bottom part of the the mannequin file contains this folder: AnyFolder Load = { AnyVec3 TopVertebra = {0.000, 0.000, 0.
185 #include "../../../BRep/Aalborg/BodyModels/FullBodyModel/BodyModel_NoMuscles.any" //This model uses the simple constant force muscles //#include "../../../BRep/Aalborg/BodyModels/FullBodyModel/BodyModel.any" //This model uses the simple constant force muscles for shoulder-arm and spine //but the 3 element hill type model for the legs //Remember to calibratate the legs before running the inversae anlysis //This is done by pressing Main.Bike3D.Model.humanModel.
186 AnyFolder EnvironmentModel = { /* ********************************************************** This folder contains the definition of the Environment - GlobalRefFrame ********************************************************** */ AnyFixedRefFrame GlobalRef = { #include "drawcoorsystem.any" AnyRefNode Hub = { sRel = {0.4, 1.4, 0.
187 Jii = {0.003, 0.003, 0.3}; AnyRefNode rHandle = { sRel = {0.2, 0, 0.1}; }; AnyRefNode lHandle = { sRel = {-0.2, 0, -0.1}; }; AnyDrawSeg drw = {}; }; Next we fix the wheel segment to the hub node by means of a revolute joint (notice that every time a new object is inserted it can be done from the Classes tree): AnySeg Wheel = { r0 = .GlobalRef.Hub.sRel; Mass = 5; Jii = {0.003, 0.003, 0.3}; AnyRefNode rHandle = { sRel = {0.2, 0, 0.1}; }; AnyRefNode lHandle = { sRel = {-0.2, 0, -0.
188 Here's some emergency help if you are having problems making the model work: HandPump.2.zip contains the three modified files from this lesson. The next step is to hook the hands up to the handles and get the arms moving in Lesson 3: Kinematics. 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.
189 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.
190 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.
191 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.
192 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 // .
193 Ouch! 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.
194 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.
195 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; RecruitmentSolver = MinMaxSimplex; tEnd = 2.
196 huge advantage when creating models like this one. In the real world, the muscles would be pulling on the bones, which causes the arms to exert forces on the handles, which subsequently creates the movement of the wheel. The distinction between kinematics and kinetics in AnyBody allows you to let the wheel rotation impose the kinematics of the entire system, i.e. reversely of how it happens in the real world, while the forces flow the correct way from the muscles to the handles.
197 This driver we replace by another driver that controls the two horizontal positions of the thorax with respect to the wheel hub. As you can see, this is pretty much a copy of the CoM driver that we just removed with the exception of the changed measure inside the driver. You can use the tree view to insert the long references to the wheel hub node and the thorax segment. //Constrain thorax with respect to the wheel hub AnyKinEqSimpleDriver WheelThorax = { AnyKinLinear Lin = { AnyRefFrame &Hub = Main.
198 AnyVar ElbowPronation = 50.0; Finally, to not have too large time steps, let us define a slightly higher resolution in the AnyBodyStudy in the main file: AnyBodyStudy Study = { AnyFolder &Model = .Model; RecruitmentSolver = MinMaxNRSimplex; tEnd = 2.0; Gravity = {0.001, -9.81, 0.001}; nStep = 20; MuscleEliminationTol = 1e-7; }; // End of study With this completed, we are ready to attempt an inverse dynamic analysis.
199 Modifications like these from an existing application to a new one probably accounts for 90% of the model development of AnyBody users. However, in some cases it is not possible to find a good existing application, and it can be advantageous to build your own model from the body parts in the repository. The next lessons, starting with Lesson 5, deal with such a case.
200 The model is primarily divided into three folders (a folder is a container of different objects much like a directory can contain files) as shown above. In fact, the structure contains a few more parts that we will get to later, but the elements shown above are the more important. In the middle you see the "HumanModel". This is where we keep the body parts that we are importing from the BRep part of the repository. This folder contains objects such as segments (bones), joints, muscles, and ligaments.
201 The model can be compiled, but it does not do much, and in any case we shall restructure it right away. As indicated above, we wish to separate the parts that deal with the environment into a dedicated file. Press the "New Include" button. This gives you an empty window. Now fill the following into the new include file: AnyFolder EnvironmentModel = { }; This folder is for keeping stuff that forms the environment. In this case it is the global reference frame, i.e.
202 AnyFixedRefFrame GlobalRef = { }; // Global reference frame AnySeg Pedal = { Mass = 2; Jii = {0.05, 0.001, 0.05}; AnyRefNode Hinge = { sRel = {0, -0.15, 0}; }; AnyRefNode FootNode = { sRel = {0, 0.15, 0}; }; AnyDrawSeg drw = {}; }; AnyRevoluteJoint HingeJoint = { Axis = z; AnyFixedRefFrame &Ground = .GlobalRef; AnyRefNode &Pedal = .Pedal.
203 A much simpler solution is to use a set of popular, pre-defined assemblies of body parts that come with the necessary interfaces to hook them up to the environment. This is what we shall do here, and it is not much more than specifying an include file. If you open up the BRep branch of the repository and go to the Aalborg section, you will find the following directories: Some of these directories are specfic body parts, while others contain various useful utilities.
204 Each of these body models comes in three different forms: 1. 2. 3. BodyModel.any is the basic version including simple muscle models, i.e. muscles that have constant strength regardless of length and contraction velocity. BodyModel_Mus3E.any is the version with Hill-type, three-element muscles that take the complexities of contraction dynamics, tendon elasticity, and many other physiological properties into account. BodyModel_NoMuscles.
205 they were originally defined, i.e. roughly like a 50th percentile European male: AnyFolder HumanModel={ #include "../../../BRep/Aalborg/BodyModels/RightLeg/BodyModel_NoMuscles.any" #include "../../../BRep/Aalborg/Scaling/ScalingStandard.any" }; Now we are at it, we also need to set the basif strength of muscles in the different body parts: AnyFolder HumanModel={ #include "../../../BRep/Aalborg/BodyModels/RightLeg/BodyModel_NoMuscles.any" #include "../../../BRepAalborg/Scaling/ScalingStandard.
206 AnyFolder Muscle ={ AnyVec3 RGB = .Colors.AnyBodyRed; AnyVar DrawOnOff = 1.0; AnyVar Bulging = 1.0; AnyVar ColorScale =1.0; AnyVec3 RGBColorScale = {0.957031, 0.785156, 0.785156}; AnyVar MaxStress = 100000.000000; //N/m^2 //This number is for graphics only! AnyVar Transparency =1.0; }; AnyFolder AnyVec3 AnyVec3 }; AnyFolder AnyVec3 AnyVec3 }; AnyFolder AnyVec3 AnyVec3 }; AnyFolder AnyVec3 AnyVec3 }; AnyFolder AnyVec3 AnyVec3 }; AnyFolder AnyVec3 }; SegmentAxes ={ RGB ={0,0,1}; ScaleXYZ ={0.0001,0.
207 AnyVar AnyVec3 AnyVar AnyVar AnyVar }; }; ScaleFactor=0.001; RGB = {1,0,0}; Thickness = 0.01; HeadThickness = 2*Thickness; HeadLength = 5*Thickness; AnyFolder Names={ AnyVec3 RGB={0,0,1}; AnyVec3 ScaleXYZ={0.01,0.01,0.01}; }; AnyFolder Marker={ AnyVec3 Color={0,0,1}; AnyVar Radius=0.005; }; }; //DrawSettings Then save the new file under the name "Drawsettings.any".
208 The pedal seems to be located in the middle of the pelvis, which is really a symptom of the warning that the model contains too few kinematic constraints. We have not made any specifications yet of how everything in the model is connected. This will be the topic of Lesson 7: Making Ends Meet. Lesson 7: Making Ends Meet So far we have accomplished to define an environment model with a simple pedal and a body model containing a pelvis and the right leg.
209 2. 3. 4. 5. 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.
210 AnyRefNode &Seat = Main.MyPedal.EnvironmentModel.GlobalRef.Hpoint; AnySeg &Pelvis = Main.MyPedal.HumanModel.Trunk.SegmentsLumbar.PelvisSeg; }; }; Save the file under the name JointsAndDrivers.any. Then insert the necessary include statement into the main file: AnyFolder HumanModel={ #include "../../../BRep/Aalborg/BodyModels/RightLeg/BodyModel_NoMuscles.any" #include "../../../BRepAalborg/Scaling/ScalingStandard.
211 When you load the model you will get an error in the InitialPositions.any file: ERROR(SCR.PRS9) : Repository.6.3/ARep/Aalborg/BBTutorial/InitialPositions.any(5) : object 'ref' : Unresolved Double-click the line number, and the file opens with the cursor placed at the infamous line. The error is that the file is referring to a folder called Model, which in our application is called MyPedal. Change the name in the two subsequent lines: AnyFolder &ref=Main.MyPedal.HumanModel; AnyFolder &JointPos=Main.
212 We can now forget about the InitialPositions.any file. All positioning from now on takes place in the Mannquin.any file. Open it up and make the following changes: AnyFolder Mannequin = { AnyFolder Posture = { //This controls the AnyVar PelvisPosX = AnyVar PelvisPosY = AnyVar PelvisPosZ = position of the pelvis wrt. to the global reference frame -0.7; 0.5; 0; What we have done here is to specify the load-time position of the pelvis to the place where we have the seat.
213 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.
214 Notice that the leg has moved slightly to honor the constraint that the foot must be on the pedal. 3. 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 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.
215 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->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.
216 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.
217 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. Now that the kinematics is in order, let us move on to the kinetic analysis in Lesson 8 and see what the model is good for. Lesson 8: Kinetics - Computing Forces With the kinematic analysis in place we are ready to compute forces and investigate ergonomic properties of the pedal arrangement.
218 The analysis runs in time from zero to one second, and the pedal angle develops in this time from 100 degrees (1.74 rad) to 145 degrees (2.53 rad). Let us presume that the pedal is loaded by a linear spring that is slack at 0 degrees and increases its moment linearly with the rotation of the hinge.
219 turned off inside the driver: AnyFolder Drivers = { AnyKinEqSimpleDriver AnkleDriver = { AnyUniversalJoint &Ankle = Main.MyPedal.HumanModel.Right.Leg.Jnt.Ankle; DriverPos = {1.570796, 0}; DriverVel = {0, 0}; Reaction.Type = {Off, Off}; }; 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}; Reaction.
220 Notice that the muscle forces are illustrated by the bulging of the muscles. In the ChartFx view near the top of the tree you can find the MaxMuscleActivity. It expresses the load on the body in percent of its strength. Plotting this property in the ChartFx View gives you the following result: Obviously holding the leg out in the air like that without the support of a pedal spring and holding up the weight of the pedal as well is rather strenuous and in fact requires about 44% of the body's strength.
221 F = -10*.HingeJoint.Pos; This produces the activity curve: Obviously the level is much lower now starting at just 12%, so the spring really seems to help. Let us try to double the stiffness: F = -20*.HingeJoint.
222 This appears to be equally good in terms of activity level and has the added quality of increasing muscle activity or effort for increasing angle. This can make it easier for the operator to control the pedal and thereby enhance the operability. The completed model is available here: PedalDemo.zip. The AnyBody Modeling System is all about making this type of investigation easy. The mechanical model we have put together in four simple lessons has a complexity worthy of a Ph.D.
223 The idea behind this system is to make the human model and the environment model as independent of each other as possible. Some models also have a folder called Mannequin for control of posture. Validation of models Somewhere on the way to the decision of using a biomechanical model you have probably asked yourself the question: Will I be able to trust the results I get? This is a very relevant question indeed.
224 Model data uncertainties In general, the models in the AnyScript Model Repository are based on data reported in the literature. They often come from studies of one or few subjects or cadavers, and the data has little or no statistical significance. You will find the references of the data listed in the comments in the individual AnyScript files.
225 very quick and the system predicts very rapid changes of muscle activation, then the result may not be realistic. Another possible source of error is the distribution of force between the muscles. The body has more muscles than strictly necessary to carry most loads, so is infinitely many different combinations of muscle forces will balance the external loads. The way AnyBody picks the right one is by an optimality criterion. The system presumes that the body wants to make the best of its resources.
226 To find velocities, the system automatically differentiates positional data with respect to time and we get the following: It still looks reasonable except for a suspicion that the maximum velocity around 12 m/s may be a bit high over such a short distance.
227 m/s^2 or 30 g. Notice that this is for the thorax and not a distal segment like a hand or a foot. It is not realistic, and it is in fact an artifact produced by the amplification of small errors in the positional signal through the two subsequent differentiations. If you work with recorded movement data, then it is very important to check that the accelerations are within reasonable limits.
228 disadvantage is that the number of computations grows exponentially with the number of parameters. A two-parameter problem with five values of each parameter leads to 5 x 5 = 25 analyses, which is usually no problem to do, while a five parameter problem will lead to 5^5 = 3125 analyses, which obviously is a more time-consuming undertaking, at least for larger models.
229 As you can see the model is very simple. It has two legs and a pelvis that is rigidly fixed to the seat. The feet are attached to the crank mechanism, and the crank is loaded by a sinusoidal torque and constant angular velocity producing a mean mechanical output of 165 W. It has a total of 18 muscles - nine on each leg. You can control the design parameters of the bicycle and the way the rider propels the pedals by means of the variables at the top of the main file.
230 fact an AnyScript operation (AnyOperation), called Analysis, which is a member of all design studies. To state an optimization or a parameter study properly, the design variables, the design measures, and the analysis must all be defined. Definition of a parameter study A parameter study is as the name indicates a study. Therefore its natural position in the model is below the existing AnyBodyStudy. We can insert a new parameter study by means of the object inserter mechanism from the class tree.
231 { //AnyOperation & = ; };*/ nStep = ; AnyDesVar & = ; //AnyDesVar & = ; AnyDesMeasure & = ; //AnyDesMeasure & = ; }; As you can see, this requires a bit of additional specif
232 The next specification deals with the parameters to vary: nStep = ; AnyDesVar SaddleHeight = { Val = Main.BikeParameters.SaddleHeight; Min = Val - 0.05; Max = Val + 0.03; }; AnyDesVar SaddlePos = { Val = Main.BikeParameters.SaddlePos; Min = Val - 0.07; Max = Val + 0.
233 AnyOutputFun MaxAct = { Val = .MaxMuscleActivity; }; }; This allows us to refer to Study.Output.MaxMuscleActivity before it actually gets created. AnyOutputFun is actually a class of mathematical function that returns the output (when existing) associated with the Val member. So here we have created a function called MaxAct that takes no arguments and returns the output data for .MaxMuscleActivity.
234 It is finally time try it out. If you have typed everything correctly, then you should be able to load the model and expand the Operations Tree in the left hand side of the Main Frame to this: Make sure you have a Model View window open. Select ParameterStudy as indicated and hit the "Run" button. You should see the model starting to cycle, and if you watch the vicinity of the saddle carefully, you will see that the hip joint is changing its position on a 5 x 5 grid.
235 The toolbar of this window indicates a kinship with the Model View window. Indeed, if you select the rotation button in the toolbar and drag the mouse with the left button down inside the coordinate system you will notice that the system rotates just like an ordinary Model View. Now, expand the Bike2D node in the tree until you can click the ParamStudy->Output->MaxAct->Val property.
236 combinations you may notice muscles beginning to bulge more and momentarily attain the color of magenta. This is the system's way of demonstrating that the muscles have been loaded above 100% of their strength. The reason why this happens is that, as the seat rises, the model gets into positions where it is difficult for the feet to reach the pedals. Just before the feet cannot reach the pedals the knee movements are accelerated causing large inertia forces in the system.
237 What this study reveals is that in terms of muscle activity to drive the bicycle a high seat is advantageous, but there seems to be a very sharp limit where the leg gets close to not being able to reach the pedals, and this should not be exceeded. One additional remark in this context is that this bicycle model has a predefined ankle angle variation whereas a real human can compensate for a higher seat by letting the ankle operate in a more plantar-flexed position.
238 // Useful variables for the optimization AnyFolder &r = Main.Bike2D.Model.Leg2D.Right.Mus; AnyFolder &l = Main.Bike2D.Model.Leg2D.Left.Mus; AnyVar Pmet = r.Ham.Pmet+r.BiFemSh.Pmet+r.GlutMax.Pmet+r.RectFem.Pmet+ r.Vasti.Pmet+r.Gas.Pmet+r.Sol.Pmet+r.TibAnt.Pmet+ l.Ham.Pmet+l.BiFemSh.Pmet+l.GlutMax.Pmet+l.RectFem.Pmet+ l.Vasti.Pmet+l.Gas.Pmet+l.Sol.Pmet+l.TibAnt.Pmet; AnyOutputFun MaxAct = { Val = .
239 AnyFolder &l = Main.Bike2D.Model.Leg2D.Left.Mus; AnyVar Pmet = r.Ham.Pmet+r.BiFemSh.Pmet+r.GlutMax.Pmet+r.RectFem.Pmet+ r.Vasti.Pmet+r.Gas.Pmet+r.Sol.Pmet+r.TibAnt.Pmet+ l.Ham.Pmet+l.BiFemSh.Pmet+l.GlutMax.Pmet+l.RectFem.Pmet+ l.Vasti.Pmet+l.Gas.Pmet+l.Sol.Pmet+l.TibAnt.Pmet; AnyOutputFun MaxAct = { Val = .MaxMuscleActivity; }; AnyOutputFun Metabolism = { Val = .Pmet; }; The second missing element is the actual integration of the function.
240 We shall return to the capabilities of the AnyChart in more detail in the next lesson, which deals with the definition of optimization studies. Optimization studies The parameter study introduced in the preceding lesson provides a complete overview of the design space, but the study is only feasible when the problem has few independent parameters, preferably one or two.
241 Minimize g0(x1..xn) Subject to gi(x1..xn) <= 0 Lj <= xj <= Uj where g0 is called the objective function, xj, j=1..n are the design variables, and gi, i=1..m are the constraints. The definition of an optimization problem in AnyBody is therefore a question of appointing independent parameters as design variables and dependent parameters as the objective function and constraints.
242 1. 2. Decide on a search direction. Perform a linear search to find the minimum along the chosen direction. This means that it is only necessary to perform analyses of the function values at the points that the algorithm actually visits and not all points in a predefined grid as we did in the parameter study.
243 AnyOperation &Operation = ..Study.InverseDynamicAnalysis; }; AnyDesVar SaddleHeight = { Val = Main.BikeParameters.SaddleHeight; Min = Val - 0.05; Max = Val + 0.03; }; AnyDesVar SaddlePos = { Val = Main.BikeParameters.SaddlePos; Min = Val - 0.07; Max = Val + 0.10; }; AnyDesMeasure Metab = { Val = secint(..Study.Metabolism(),..Study.tArray); Type = ObjectiveFun; }; }; Please notice that the AnyDesMeasure MaxAct was removed, and so was the entire line with the nStep specification.
244 If the model loads you should get a screen picture similar to the one above this text. Expand the OptStudy branch in the operations tree, click Optimization once and then the Run button. The model starts cycling and after a few rounds you will notice the saddle position changing, but not in a systematic grid like in the parameters study. What you will see is gradual changes back and forth in different directions until the changes wear off and the position converges.
245 The graph confirms that the vast majority of the improvement is obtained in a couple of iterations and the final iteration contributes only by a minor, almost insignificant adjustment. Such iterations with insignificant improvements occur due to the convergence criterion, i.e., the criterion that stops the optimization process.
246 select "New": This will give you a blank "Series 1". When you highlight it by clicking with the mouse you will see the list of Selected Objects in the right-hand pane is empty. We are going to fill in the SaddleHeight and SaddlePos variables from the OptStudy as Abscissa and Abscissa2, respectively. This is done by selecting Abscissa and Abscissa2 in turn and then expanding the OptStudy branch until the SaddleHeight.Val and SaddlePos.
247 Finally, in the Value field select OptStudy.Metab.Val and look carefully at the plot. You will see that an additional polyline has been added. It originates approximately at the middle of the surface and shows the path the optimization process has taken through the design space to the minimum point. You can change the color of the line by clicking the leftmost button (Properties) in the toolbar directly over the graphics pane.
248 This plot illustrates the convergence history in the "landscape" of the objective function. Here we can see the reasons for the convergence being as it is. Actually, the optimum value lies in a relatively flat region and therefore the exact mathematical location of the optimum may be of a more academic importance than practical relevance since we can find many design point with almost the same objective function value.
249 This reveals a somewhat jacket surface and a distinct (local) valley of the objective function. Minor changes of the input to the optimization process, whether it be the starting point or design variable bounds, can actually make the optimization process dive into this local valley and get stuck in there.
250 Notice how the final objective function value is slightly higher than the previous optimization result. Notice also how only the first iteration out of 7 provides significant improvement of the objective function. This step brings the design value down into to the valley. The remaining iterations zigzags in the bottom of the valley without being able to get up and out and without providing any visible improvement. Finally, the convergence criterion is fulfilled.
251 segment velocities, and any other model property that the system can compute. Enough talk; let's try the optimization with the constraint added. Please load the model again, select the optimization operation, and click the run button.
252 as in the unconstrained case. The path of the design values bounces off the constraint and finally it gets stuck on the constraint even though the objective function still has a downwards inclination. The constraint lies like a wall through the design space. We can see the convergence path along the constraint by plot the constraint value, i.e., the SeatDist.Val. This looks like: where it is obvious how the optimizer hits the constraint, bounces off, hits again, etc. and finally it converges.
253 This completes the introduction to optimization studies. Trouble shooting AnyScript models If you think mechanics is simple, it's probably just because you haven't worked with three-dimensional space yet. The laws of mechanics are pretty easy to comprehend as long as stuff is moving on a onedimensional line. When you go to two dimensions, complications such as rotational inertia and centrifugal forces start to play a role, but the equations are still not very difficult.
254 always that nice. First of all, the error messages are not always very descriptive. This is a problem the AnyBody Modeling System shares with any other computer language compiler in the market. It is not because programmers specifically want to bother their users. The problem is simply that error messages are generated by a very formal semantic analysis. This makes them very different from the natural human expression of the problem, and they can be difficult for the user to understand.
255 you will get the error message: Folder assignment expected for this object. What the message means is that this type of assignment is not allowed. You may argue that the error message is misleading because '=' is indeed an assignment operator. However, operators in AnyScript are polymorphic, and they are interpreted in the context of the variables they operate on, and for two folders no proper assignment operator exists.