3 Mechanical Models I

3.5 Frame springs

Another way to connect two rigid bodies together is to use a frame spring, which is a six dimensional spring that generates restoring forces and moments between coordinate frames.

3.5.1 Frame spring coordinate frames

Figure 3.26: A frame spring connecting two coordinate frames D and C.

The basic idea of a frame spring is shown in Figure 3.26. It generates restoring forces and moments on two frames C and D which are a function of {\bf T}_{DC} and \hat{\bf v}_{DC} (the spatial velocity of frame D with respect to frame C).

Decomposing forces into stiffness and damping terms, the force {\bf f}_{C} and moment \boldsymbol{\tau}_{C} acting on C can be expressed as

\displaystyle{\bf f}_{C} \displaystyle={\bf f}_{k}({\bf T}_{DC})+{\bf f}_{d}(\hat{\bf v}_{DC})
\displaystyle\boldsymbol{\tau}_{C} \displaystyle=\boldsymbol{\tau}_{k}({\bf T}_{DC})+\boldsymbol{\tau}_{d}(\hat{%
\bf v}_{DC}). (3.31)

where the translational and rotational forces {\bf f}_{k}, {\bf f}_{d}, \boldsymbol{\tau}_{k}, and \boldsymbol{\tau}_{d} are general functions of {\bf T}_{DC} and \hat{\bf v}_{DC}.

The forces acting on D are equal and opposite, so that

\displaystyle{\bf f}_{D} \displaystyle=-{\bf f}_{C},
\displaystyle\boldsymbol{\tau}_{D} \displaystyle=-\boldsymbol{\tau}_{C}. (3.32)
Figure 3.27: A frame spring connecting two rigid bodies A and B.

If frames C and D are attached to a pair of rigid bodies A and B, then a frame spring can be used to connect them in a manner analogous to a joint. As with joints, C and D generally do not coincide with the body frames, and are instead offset from them by fixed transforms {\bf T}_{CA} and {\bf T}_{DB} (Figure 3.27).

3.5.2 Frame materials

The restoring forces (3.31) generated in a frame spring depend on the frame material associated with the spring. Frame materials are defined in the package artisynth.core.materials, and are subclassed from FrameMaterial. The most basic type of material is a LinearFrameMaterial, in which the restoring forces are determined from

\displaystyle{\bf f}_{C} \displaystyle={\bf K}_{t}\,{\bf x}_{DC}+{\bf D}_{t}\,{\bf v}_{DC}
\displaystyle\boldsymbol{\tau}_{C} \displaystyle={\bf K}_{r}\,\hat{\boldsymbol{\theta}}_{DC}+{\bf D}_{r}\,%
\boldsymbol{\omega}_{DC}

where \hat{\boldsymbol{\theta}}_{DC} gives the small angle approximation of the rotational components of {\bf X}_{DC} with respect to the x, y, and z axes, and

\displaystyle{\bf K}_{t}\equiv\left(\begin{matrix}k_{tx}&0&0\\
0&k_{ty}&0\\
0&0&k_{tz}\end{matrix}\right),\;{\bf D}_{t}\equiv\left(\begin{matrix}d_{tx}&0&%
0\\
0&d_{ty}&0\\
0&0&d_{tz}\end{matrix}\right),
\displaystyle{\bf K}_{r}\equiv\left(\begin{matrix}k_{rx}&0&0\\
0&k_{ry}&0\\
0&0&k_{rz}\end{matrix}\right),\;{\bf D}_{r}\equiv\left(\begin{matrix}d_{rx}&0&%
0\\
0&d_{ry}&0\\
0&0&d_{rz}\end{matrix}\right).

are the stiffness and damping matrices. The diagonal values defining each matrix are stored in the 3-dimensional vectors {\bf k}_{t}, {\bf k}_{r}, {\bf d}_{t}, and {\bf d}_{r} which are exposed as the stiffness, rotaryStiffness, damping, and rotaryDamping properties of the material. Each of these specifies stiffness or damping values along or about a particular axis. Specifying different values for different axes will result in anisotropic behavior.

Other frame materials offering nonlinear behavior may be defined in artisynth.core.materials.

3.5.3 Creating frame springs

Frame springs are implemented by the class FrameSpring. Creating a frame spring generally involves instantiating this class, and then setting the material, the bodies A and B, and the transforms {\bf T}_{CA} and {\bf T}_{DB}.

A typical construction sequence might look like this:

  FrameSpring spring = new FrameSpring ("springA");
  spring.setMaterial (new LinearFrameMaterial (kt, kr, dt, dr));
  spring.setFrames (bodyA, bodyB, TDW);

The material is set using setMaterial(). The example above uses a LinearFrameMaterial, created with a constructor that sets {\bf k}_{t}, {\bf k}_{r}, {\bf d}_{t}, and {\bf d}_{r} to uniform Isotropic values specified by kt, kr, dt, and dr.

The bodies and transforms can be set in the same manner as for joints (Section 3.3.3), with the methods
setFrames(bodyA,bodyB,TDW) and setFrames(bodyA,TCA,bodyB,TDB) assuming the role of the setBodies() methods used for joints. The former takes D specified in world coordinates and computes {\bf T}_{CA} and {\bf T}_{DB} assuming that there is no initial spring displacement (i.e., that {\bf T}_{DC}={\bf I}), while the latter allows {\bf T}_{CA} and {\bf T}_{DB} to be specified explicitly with {\bf T}_{DC} assuming whatever value is implied.

Frame springs and joints are often placed together, using the same transforms {\bf T}_{CA} and {\bf T}_{DB}, with the spring providing restoring forces to help keep the joint within prescribed bounds.

As with joints, a frame spring can be connected to only a single body, by specifying frameB as null. Frame B is then taken to be the world coordinate frame W.

3.5.4 Example: two bodies connected by a frame spring

Figure 3.28: LumbarFrameSpring model loaded into ArtiSynth.

A simple model showing two simplified lumbar vertebrae, modeled as rigid bodies and connected by a frame spring, is defined in

  artisynth.demos.tutorial.LumbarFrameSpring

The definition for the entire model class is shown here:

1 package artisynth.demos.tutorial;
2
3 import java.io.IOException;
4 import java.io.File;
5 import java.awt.Color;
6 import artisynth.core.modelbase.*;
7 import artisynth.core.mechmodels.*;
8 import artisynth.core.materials.*;
9 import artisynth.core.workspace.RootModel;
10 import maspack.matrix.*;
11 import maspack.geometry.*;
12 import maspack.render.*;
13 import maspack.util.PathFinder;
14
15 /**
16  * Demo of two rigid bodies connected by a 6 DOF frame spring
17  */
18 public class LumbarFrameSpring extends RootModel {
19
20    double density = 1500;
21
22    // path from which meshes will be read
23    private String geometryDir = PathFinder.getSourceRelativePath (
24       LumbarFrameSpring.class, "../mech/geometry/");
25
26    // create and add a rigid body from a mesh
27    public RigidBody addBone (MechModel mech, String name) throws IOException {
28       PolygonalMesh mesh = new PolygonalMesh (new File (geometryDir+name+".obj"));
29       RigidBody rb = RigidBody.createFromMesh (name, mesh, density, /*scale=*/1);
30       mech.addRigidBody (rb);
31       return rb;
32    }
33
34    public void build (String[] args) throws IOException {
35
36       // create mech model and set it’s properties
37       MechModel mech = new MechModel ("mech");
38       mech.setGravity (0, 0, -1.0);
39       mech.setFrameDamping (0.10);
40       mech.setRotaryDamping (0.001);
41       addModel (mech);
42
43       // create two rigid bodies and second one to be fixed
44       RigidBody lumbar1 = addBone (mech, "lumbar1");
45       RigidBody lumbar2 = addBone (mech, "lumbar2");
46       lumbar1.setPose (new RigidTransform3d (-0.016, 0.039, 0));
47       lumbar2.setDynamic (false);
48
49       // flip entire mech model around
50       mech.transformGeometry (
51          new RigidTransform3d (0, 0, 0, 0, 0, Math.toRadians (90)));
52
53       //create and add the frame spring
54       FrameSpring spring = new FrameSpring (null);
55       spring.setMaterial (
56          new LinearFrameMaterial (
57             /*ktrans=*/100, /*krot=*/0.01, /*dtrans=*/0, /*drot=*/0));
58       spring.setFrames (lumbar1, lumbar2, lumbar1.getPose());
59       mech.addFrameSpring (spring);
60
61       // set render properties for components
62       RenderProps.setLineColor (spring, Color.RED);
63       RenderProps.setLineWidth (spring, 3);
64       spring.setAxisLength (0.02);
65       RenderProps.setFaceColor (mech, new Color (238, 232, 170)); // bone color
66    }
67 }

For convenience, the code to create and add each vertebrae is wrapped into the method addBone() defined at lines 27-32. This method takes two arguments: the MechModel to which the bone should be added, and the name of the bone. Surface meshes for the bones are located in .obj files located in the directory ../mech/geometry relative to the source directory for the model itself. PathFinder.getSourceRelativePath() is used to find a proper path to this directory (see Section 2.6) given the model class type (LumbarFrameSpring.class), and this is stored in the static string geometryDir. Within addBone(), the directory path and the bone name are used to create a path to the bone mesh itself, which is in turn used to create a PolygonalMesh (line 28). The mesh is then used in conjunction with a density to create a rigid body which is added to the MechModel (lines 29-30) and returned.

The build() method begins by creating and adding a MechModel, specifying a low value for gravity, and setting the rigid body damping properties frameDamping and rotaryDamping (lines 37-41). (The damping parameters are needed here because the frame spring itself is created with no damping.) Rigid bodies representing the vertebrae lumbar1 and lumbar2 are then created by calling addBone() (lines 44-45), lumbar1 is translated by setting the origin of its pose to (-0.016,0.039,0)^{T}, and lumbar2 is set to be fixed by making it non-dynamic (line 47).

Figure 3.29: LumbarFrameSpring model as it would appear if not rotated about the x axis.

At this point in the construction, if the model were to be loaded, it would appear as in Figure 3.29. To change the viewpoint to that seen in Figure 3.28, we rotate the entire model about the x axis (line 50). This is done using transformGeometry(X), which transforms the geometry of an entire model using a rigid or affine transform. This method is described in more detail in Section 4.7.

The frame spring is created and added at lines 54-59, using the methods described in Section 3.5.3, with frame D set to the (initial) pose of lumbar1.

Render properties are set starting at line 62. By default, a frame spring renders as a pair of red, green, blue coordinate axes showing frames C and D, along with a line connecting them. The line width and the color of the connecting line are controlled by the line render properties lineWidth and lineColor, while the length of the coordinate axes is controlled by the special frame spring property axisLength.

To run this example in ArtiSynth, select All demos > tutorial > LumbarFrameSpring from the Models menu. The model should load and initially appear as in Figure 3.28. Running the model (Section 1.5.3) will cause lumbar1 to fall slightly under gravity until the frame spring arrests the motion. To get a sense of the spring’s behavior, one can interactively apply forces to lumbar1 using the pull tool (see the section “Pull Manipulation” in the ArtiSynth User Interface Guide).