0% found this document useful (0 votes)
24 views69 pages

Easydyn 1.2.3: Facult E Polytechnique de Mons Service de M Ecanique Rationnelle, Dynamique Et Vibrations

This document provides an overview of the EasyDyn C++ library for dynamic simulation. The library includes classes for defining vectors, rotation tensors, inertia tensors, and homogeneous transformation matrices. It implements operators between these classes to allow modeling vector expressions as in hand calculations. The document describes points, vectors, and frames used in vector calculus and modeling dynamic problems. It also reviews homogeneous transformation matrices which relate the position and orientation of frames.

Uploaded by

Gerre Nguba
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views69 pages

Easydyn 1.2.3: Facult E Polytechnique de Mons Service de M Ecanique Rationnelle, Dynamique Et Vibrations

This document provides an overview of the EasyDyn C++ library for dynamic simulation. The library includes classes for defining vectors, rotation tensors, inertia tensors, and homogeneous transformation matrices. It implements operators between these classes to allow modeling vector expressions as in hand calculations. The document describes points, vectors, and frames used in vector calculus and modeling dynamic problems. It also reviews homogeneous transformation matrices which relate the position and orientation of frames.

Uploaded by

Gerre Nguba
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 69

Faculté Polytechnique de Mons

Service de Mécanique Rationnelle,


Dynamique et Vibrations

EasyDyn 1.2.3
C++ library for the easy simulation
of dynamic problems

Olivier Verlinden, Georges Kouroussis

November 30, 2004

Boulevard Dolez 31
7000 MONS
BELGIQUE
Tél. : 32.65.37.41.81
Fax. : 32.65.37.41.83
Email: [email protected]
Chapter 1

Getting and installing the library

1.1 Getting the library


The library can be downloaded in source form from the software part of the web site
of the Department of Theoretical Mechanics, Dynamics and Vibrations of the Faculté
Polytechnique de Mons, a university in Belgium

http://mecara.fpms.ac.be

either in tarball or zip format.


Once you have chosen a parent directory, decompact the archive with

unzip EasyDyn-x.y.z

or

tar xvzf EasyDyn-x.y.z.tgz

1.2 Getting a compiler


To compile EasyDyn, you will need a C++ compiler. I recommend gcc the compiler of
the free software foundation, available for free from

http://www.gnu.org/software/gcc/gc.html

Pay attention that you need a version of gcc above 3.0, with the new implementation
of the I/O streams.
If you have not yet understood that you should drop Windows, it will probably be easier
to download mingw, a complete and easy to install implementation of gcc, available from

http://www.mingw.org

and the related environment dev-cpp available from

1
CHAPTER 1. GETTING AND INSTALLING THE LIBRARY 2

http://sourceforge.net/projects/dev-cpp

Have a look at the file installFR.win (unfortunately only in French so far) which de-
scribes the complete installation process under Windows.
However, as it is written in pure C++, it is very likely that EasyDyn can be compiled
with any modern C++ compiler.

1.3 Getting the GNU scientific library and LAPACK


To compile EasyDyn you will need to compile and install the GNU scientific Library and
LAPACK which can be obtained respectively from http://www.gnu.org/software/gsl
and http://www.netlib.org. The job is trivial under Unix in general.
You will find precompiled versions of the GSL and LAPACK for mingw on bitwalk

http://www63/tok2.com/home/bitwalk/download.html

1.4 Compiling and testing the library


To compile the EasyDyn library, a makefile is provided. It should work for any version
of gcc. It has been tested under Linux and under Windows with mingw. Compiling the
library is just a matter of entering

make

from the root directory of EasyDyn.


Please note that under mingw, make has been renamed mingw32-make to avoid confusion
with any other implementation.
At the end you should have the library libEasyDyn.a. You may remove all the object
files (*.o).
If you want to install the library for general use, just copy the subdirectory include/EasyDyn
into the general include directory of gcc and libEasyDyn.a into the general lib direc-
tory of gcc.
If you want to use another compiler, the library is just the collection of the objects
obtained by compilation of all the .cpp files in the root directory of EasyDyn.
If you want to compile the examples, a makefile is provided for each of them. Either
you have a file called makefile and you just type

make

or you have a file like oscil1.mak and you type

make -f oscil1.mak
CHAPTER 1. GETTING AND INSTALLING THE LIBRARY 3

If you want to compile a new application applic.cpp from a shell window, you will
have to issue

• to compile the application

c++ -c -I<EasyDynHome>/include applic.cpp

where <EasyDynHome> represents the root directory of EasyDyn; if successfull, the


operation will result in the creation of a file called applic.o

• to link the application

c++ applic.o -L<EasyDynHome> -lEasyDyn -lgsl -lgslcblas -llapack


-lblas -lg2c -o applic

which will result into the creation of an executable called applic (applic.exe under
Windows).
Chapter 2

The EasyDyn vector library

2.1 Introduction
The vec part of the library defines 4 classes

• vec : defining a 3D vector;

• trot : defining a second-order 3D rotation tensor;

• tiner : defining a second-order 3D inertia tensor;

• mth : defining an homogenous transformation matrix.

and implements various operators between these classes. As seen later, the operators
allow the user to program vector expressions as he would do by hand.
In the next sections

• variables a, b, and d represent real values;

• variables v, v1 , v2 relate to vectors;

• variables R, R1 , R2 relate to rotation tensors;

• variables Φ and ΦG relate to inertia tensors;

• variables T , T1 , T2 correspond to homogenous transformation matrices.

2.2 Some recalls about vector calculus


Vector calculus is a very powerful tool to develop the laws of mechanics. It is however
important to be very clear about notations and conventions.

4
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 5

zi
yi zj
i P r P/j
r P/i j yj
xi xj
eP
z0

0 y0
x0

Figure 2.1: Points, vectors and frames

2.2.1 Points, vectors and frames


Let us denote vectors by underlined boldface characters, such as a, which represents a
physical vector, characterized by a spatial direction and an amplitude.
For calculations, the vectors will have to be expressed with respect to a frame or
coordinate system. We will assume here that each frame is cartesian (orthonormal) and
composed of 3 dextrorsum axes X,Y and Z. The unit vectors corresponding to the axes of
a frame i will be denoted by xi , yi and zi . The components axi , ayi and azi of a vector a
with respect to a frame i are such that vector a can be reconstructed from its components
by

a = axi · xi + ayi · yi + azi · zi (2.1)

The set of components of a vector a, with respect to a frame i will be denoted by {a} i ,
which represents a 3x1 matrix such as
 
ax i
{a}i =  ayi 

 (2.2)
az i

The position of any point P can be described by its position with respect to a chosen
frame. We will denote rP/i the coordinate vector of point P with respect to frame i, that’s
to say the vector running from frame i to point P. The coordinates of point P in the
coordinate system of frame i correspond to the 3 components of vector rP/i , with respect
to frame i, gathered in the column matrix {rP/i }i .
Generally, a global reference exists and is referenced as frame 0. The coordinate vector
of a point P with respect to the global reference frame, that’s to say rP/0 can be denoted
for the sake of simplicity by eP .
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 6

2.2.2 Homogeneous transformation matrices


The homogenous transformation matrix is a formalism which allows to represent the sit-
uation of a frame with respect to another one. According to this formalism, the relative
situation of frame j with respect to frame i is expressed from the homogeneous transfor-
mation matrix Ti,j , of dimension 4x4, which can be partitioned in the following way:
à !
Ri,j {rj/i }i
Ti,j = (2.3)
000 1

where

• rj/i is the coordinate vector of frame j with respect to frame i;

• Ri,j is the rotation tensor describing the orientation of frame j with respect to
frame i.

Ti,j
zi zj
i
yi
xi j yj
xj

T0,i z0 T0,j

0 y0
x0

Figure 2.2: Homogeneous transformation matrices

Let us recall that the columns of Ri,j correspond to the unit vectors xj , yj and zj ,
expressed in the axes of frame i
³ ´
Ri,j = {xj }i {yj }i {zj }i (2.4)

and must of course hold the following constraints:

|xj | = 1 |xj | = 1 |xj | = 1 (2.5)


zj = xj × yj yj = zj × xj xj = y j × z j (2.6)

The rotation tensor can be used on its own to determine the coordinates of a vector in
a frame when they are given in an another one:

{a}i = Ri,j · {a}j (2.7)


CHAPTER 2. THE EASYDYN VECTOR LIBRARY 7

The homogeneous transformation matrices are not only used to describe the relative
situation of two frames but also permit to easily express the coordinates of a point with
respect to a frame from the ones with respect to another frame. The following relationship
can indeed be easily demonstrated
à ! à !
{rP/i }i {rP/j }j
= Ti,j · (2.8)
1 1

which is equivalent to

{rP/i }i = {rj/i }i + Ri,j · {rP/j }j (2.9)

For the sake of simplicity, we will introduce the ◦ operator such that

{rP/i }i = Ti,j ◦ {rP/j }j = {rj/i }i + Ri,j · {rP/j }j (2.10)

To conclude this section, let us mention that the homogeneous transformation matrices
have the advantage to enjoy the following property

Ti,k = Ti,j · Tj,k (2.11)

This property is often used to obtain a complex transformation matrix from the successive
multiplication of simpler matrices.

2.3 The 3D vector class vec


2.3.1 Variables of the class
The vec class consists of 3 public variables of type double: x, y and z, representing the
components of the vector in a orthonormal, dextrosum coordinate system.

2.3.2 Assignment methods


By default, all components are set to zero by the constructor. After declaration

vec v;

vector v is equal to zero (v.x=v.y=v.z=0).


It is however allowed to assign the vector a given value in the declaration

vec v(1,2,3);

There are different ways to change the components of a vector

• by changing directly the coordinates (the variables are public)

v.x=1; v.y=2; v.z=3;


CHAPTER 2. THE EASYDYN VECTOR LIBRARY 8

• by using put()

v.put(1,2,3);

To set all components to zero, the zero() method can be used

v.zero();

A vector can also be normalized with the method unite()

v.unite();

As a result, vector v becomes a unitary vector with the same direction (v = v/|v|).

2.3.3 Utility methods


The method length() gives the length of a vector

double L=v.length();

2.3.4 Calculus operators


The classical operators for addition, substraction, dot product and cross product of vectors
have been overloaded. Multiplication or division by a double have been overloaded as well.
The use of operators is natural and self-explanatory. Table 2.1 illustrates the operators
and their physical meaning. The left column gives the mathematical operation and the
right one the way it is written in C++.

v = v1 + v2 v=v1+v2;
v = v + v1 v+=v1;
v = −v1 v=-v1;
v = v1 − v2 v=v1-v2;
v = v − v1 v-=v1;
d = v1 · v2 d=v1*v2;
v = v1 × v2 v=v1^v2;
v = v1 · d v=v1*d;
v = d · v1 v=d*v1;
v =v·d v*=d;
v = v1 /d v=v1/d;
v = v/d v/=d;

Table 2.1: Vector operators

All operators between vectors assume that their coordinates are expressed in the same
coordinate system. If several coordinate systems are involved, the user must manage
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 9

himself the necessary transformations. The operation is made easy with the other classes
of the library: the rotation tensor and the homogenous transformation matrix.
Important remark
As the operator * was already used for the dot product, the operator ^ has been
chosen, by reference to the classical scale (Λ) also used to represent the cross-product.
Unfortunately, it doesn’t have the priority of a classical multiplication operator as it is
evaluated after + and -. Consequently the following statement

v1+v2^v3;

will be evaluated as (v1 + v2 ) × v3 .


The statement to evaluate v1 + v2 × v3 in the way it is generally understood is then

v1+(v2^v3);

To make it short, brackets are welcome to avoid misunderstanding between you and
the compiler in long statements with several operators.

2.3.5 Input/output
The input and output operators have been overloaded and can be used naturally with
vectors. Here is an example

vec v(1,2,3);
cout << ‘‘Vector v: ‘‘ << v << ‘‘\n’’;
vec v2;
cin >> v2;

On output, the three coordinates of the vector are sent to the stream, separated by some
space but with no end-of-line. On input, three real values are expected.
Here again, the priority of operator ^ has surprising consequences as it is evaluated
after << and >>. For example, the following code won’t be understood by the compiler

cout << v1^v2 << ‘‘\n’’;

and must be written

cout << (v1^v2) << ‘‘\n’’;

2.4 The rotation tensor class trot


2.4.1 Variables of the class
The trot class consists of 9 public variables of type double: r11, r12, r13, r21, r22, r23,
r31, r32 and r33, representing the components of the rotation tensor in an orthonormal
and positively oriented coordinate system.
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 10

The terms of the rotational tensor must verify the following constraints, expressing that
coordinate systems after transformation must remain orthonormal and positively oriented
2 2 2
r11 + r21 + r31 =1 (2.12)
2 2 2
r12 + r22 + r32 =1 (2.13)
2 2 2
r13 + r23 + r33 =1 (2.14)
r11 r12 + r21 r22 + r31 r32 =0 (2.15)
r11 r13 + r21 r23 + r31 r33 =0 (2.16)
r12 r13 + r22 r23 + r32 r33 =0 (2.17)

It is the responsability of the programmer to hold these constraints if the components


of a rotation tensor are assigned directly. The library doesn’t automatically verify them.

2.4.2 Assignment methods


By default, the rotation tensor corresponds to an identity matrix: all diagonal terms are
equal to 1 while other ones are null. After declaration

trot R;

tensor R is such that R.r11=R.r22=R.r33=1 and all other terms are equal to zero.
The terms of a tensor are public and can be changed directly. For example, a rotation
about the Z axis could be written

R.r11=cos(theta); R.r12=-sin(theta); R.r13=0;


R.r21=sin(theta); R.r22=cos(theta); R.r23=0;
R.r31=0; R.r32=0; R.r33=1;

A rotation tensor can be defined back as identity with the unite() method

R.unite();

2.4.3 Utility methods


The methods rotx(th), roty(th) and rotz(th) allow to directly define a rotation tensor
as a rotation of angle th about the X, Y or Z axis.

trot R,R1,R2;
R.rotx(0.1); R1.roty(0.2); R2.rotz(0.3);

The equivalent functions Rrotx, Rroty and Rrotz exist and return a rotation tensor.
The advantage is that a rotation tensor can be defined direcly as a combination of several
rotations.
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 11

trot R;
R=Rrotx(0.1)*Rroty(0.2)*Rrotz(0.3);

The inverse rotation tensor is given by the method inv()

trot R,Rinv;
Rinv=R.inv();

2.4.4 Calculus operators


As already seen in previous examples, the rotation tensors can be multiplied by each
other. A rotation tensor can also multiply a vector, implementing a change of coordinate
system. The use of operators is natural and self-explanatory. Table 2.2 illustrates the
operators and their physical meaning. The left column gives the mathematical operation
and the right one the way it is written in C++.

R = R1 · R2 R=R1*R2;
R = R · R1 R*=R1;
v = R · v1 v=R*v1;

Table 2.2: Rotation tensor operators

2.4.5 Unit vectors related to the rotation tensor


Each column of the rotation tensor corresponds to a unit vector. They are given respec-
tively by the methods ux(), uy() and uz(), returning a data type vec. If the tensor is
applied to a coordinate system, each vector gives the unit vectors of the new coordinate
system.

trot R=Rroty(0.4);
vec v=R.ux();

The user can also set directly each of the unit vectors. The corresponding methods are
setux(vec v), setuy(vec v) and setuz(vec v).

trot R;
vec v1(1,2,0),v2(-2,1,0);
v1.unite();
v2.unite();
R.setux(v1);
R.setuy(v2);

It is the responsability of the user to insure that the rotation matrix remains orthonor-
mal.
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 12

2.4.6 Input/output
The input and output operators have been overloaded and can be used naturally with
rotation tensors. Here is an example

trot R=Rrotz(1);
cout << ‘‘Tensor R: \n‘‘ << R;
trot R2;
cin >> R2;

On output, the 9 coordinates of the rotation tensor are sent to the stream, line by line (3
terms by line, separated by some space). A newline is output at the end of each line. On
input, 9 real values are expected.

2.5 The inertia tensor class tiner


2.5.1 Variables of the class
The tiner class consists of 6 public variables of type double: Ixx, Iyy, Izz, Ixy, Ixz and
Iyz representing the components of the inertia tensor of a body in an orthonormal and
positively oriented coordinate system. In a given coordinate system, the inertia tensor
can be seen as the following 3x3 matrix
 
Ixx −Ixy −Ixz
 −Ixy Iyy −Iyz  (2.18)


−Ixz −Iyz Izz

The terms on the diagonal are called moments of inertia while the others are called
products of inertia.
The matrix representing the inertia tensor is constant when expressed in a coordinate
system linked to the body. Otherwise, it depends on the orientation of the body.

2.5.2 Assignment methods


By default, all terms of the inertia tensor are null. At declaration

tiner Phi;

all variables (Ixx, Iyy, Izz, Ixy, Ixz, Iyz) related to tensor Phi are set to zero.
An inertia tensor can be assigned directly at declaration or with the put method

tiner Phi(1.1,1.2,1.3,0.1,0.2,0.3);
tiner Phi2;
Phi2.put(1.1,1.2,1.3,0.1,0.2,0.3);
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 13

the order of the parameters being Ixx, Iyy, Izz, Ixy, Ixz and Iyz.
Only the first 3 terms can be specified

tiner Phi(1.1,1.2,1.3);
tiner Phi2;
Phi2.put(1.1,1.2,1.3);

and the inertia products are then set to zero.


The terms of an inertia tensor are public and can also be assigned directly

Phi.Ixx=1.1; Phi.Iyy=1.2; Phi.Izz=1.3;


Phi.Ixy=0.1; Phi.Ixz=0.2; Phi.Iyz=0.3;

2.5.3 Calculus operators


The destiny of a tensor is to be applied to a vector to generate another vector. For
example, the momentum of a body about its center of gravity G is calculated by

LG = Φ G · ω (2.19)

with ΦG the inertia tensor with respect to the center of gravity.


Only one operator is then defined: the multiplication by a vector (cf. table 2.3),
corresponding to the following matrix product
     
v2x Ixx −Ixy −Ixz vx
 v2y  =  −Ixy Iyy −Iyz  ·  vy  (2.20)
    

v2z −Ixz −Iyz Izz vz

It is of interest to note that the expression is meaningful only if the components of


the inertia tensor and the vector are expressed in the same coordinate system.

v2 = Φ · v v2=Phi*v;
Table 2.3: Inertia tensor operators

2.5.4 Input/output
The input and output operators have been overloaded and can be used naturally with
inertia tensors. Here is an example

tiner Phi(1.1,1.2,1.3);
cout << ‘‘Tensor Phi: ‘‘ << Phi << ‘‘\n’’;
tiner Phi2;
cin >> Phi2;
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 14

On output, the 6 parameters of the rotation tensor are sent to the stream, in the order
Ixx, Iyy, Izz, Ixy, Ixz and Iyz, separated by some space. No newline is sent to the
stream. On input, 6 real values are expected, the order of the parameters being the same
as in output.

2.6 The homogeneous transformation matrix class mth


2.6.1 Variables of the class
The mth class consists of 2 public variables: a rotation tensor R and a vector e.

2.6.2 Assignment methods


At declaration, the vector and the rotation tensor get the default initial value of their
class, that’s to say the null vector and the identity tensor.
The terms of R and e are public and can be changed directly

mth T;
T.R.r11=cos(theta);
T.e.x=2;

An homogenous transformation matrix can be reinitialized with the unite() method

T.unite();

2.6.3 Utility methods


The methods rotx(th), roty(th) and rotz(th) of the rotation tensor allow to directly
define a transformation matrix corresponding to a rotation of angle th about the X, Y or
Z axis.

mth T,T1,T2;
T.R.rotx(0.1); T1.R.roty(0.2); T2.R.rotz(0.3);

The equivalent functions Trotx(th), Troty(th) and Trotz(th) exist and return an
homogeneous transformation matrix

mth T;
T=Trotx(0.1)*Troty(0.2)*Trotz(0.3);

A transformation matrix corresponding to a displacement can be defined from a vector

vec v(1,2,3);
mth T;
T.e=v;
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 15

The functions Tdisp(vec v) and Tdisp(double x, double y, double z) return an


mth and can also be used directly to define a matrix as a succession of elementary motions.
For example a frame at the end of a pendulum can be defined by

vec v(0,-0.5,0);
mth T;
T=Trotz(th)*Tdisp(v); // or equivalently T=Trotz(th)*Tdisp(0,-0.5,0);

The inverse transformation matrix is given by the method inv()

mth T,Tinv;
Tinv=T.inv();

2.6.4 Calculus operators


The operators are similar to the ones of the rotation tensor and are self-explanatory.
Table 2.4 illustrates the operators and their physical meaning. The left column gives the
mathematical operation and the right one the way it is written in C++.

T = T1 · T 2 T=T1*T2;
T = T · T1 T*=T1;
v = T ◦ v1 v=T*v1;

Table 2.4: Homogeneous transformation matrices operators

2.6.5 Unit vectors related to the rotation tensor


The unit vectors can of course be retrieved directly from the ones of the rotation tensor

mth T=Troty(0.4);
vec v=T.R.ux();

2.6.6 Input/output
The input and output operators have been overloaded and can be used naturally with
transformation matrices. Here is an example

mth T=Trotz(1);
cout << ‘‘Homogeneous transformation matrix T: \n‘‘ << T;
mth T2;
cin >> T2;

On output, the 12 coordinates of the rotation tensor are sent to the stream, line by line
(4 terms by line, separated by some space). A newline is output at the end of each line.
On input, 12 real values are expected.
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 16

2.7 Decomposition routines


2.7.1 Rotation decomposition
In order to decompose a rotation as 3 successive rotations about given axes, the library
yields the following procedures

void getrotxyz(trot R1, trot R2, double & th1, double & th2, double & th3,
vec &axe1, vec &axe2, vec &axe3);
void getrotyzx(trot R1, trot R2, double & th1, double & th2, double & th3,
vec &axe1, vec &axe2, vec &axe3);
void getrotzxy(trot R1, trot R2, double & th1, double & th2, double & th3,
vec &axe1, vec &axe2, vec &axe3);
void getrotyxz(trot R1, trot R2, double & th1, double & th2, double & th3,
vec &axe1, vec &axe2, vec &axe3);
void getrotxzy(trot R1, trot R2, double & th1, double & th2, double & th3,
vec &axe1, vec &axe2, vec &axe3);
void getrotzyx(trot R1, trot R2, double & th1, double & th2, double & th3,
vec &axe1, vec &axe2, vec &axe3);

For example, getrotxyz determines the 3 successive rotations about local axes X, Y
and Z to go from orientation R1 to orientation R2. On return, variables th1, th2 and th3
are the rotation angles while axe1, axe2 and axe3 are unit vectors corresponding to the
successive axes of rotation. Said in other words, after a call to getrotxyz, R2 is such that

R2=R1*Rrotx(th1)*Rroty(th2)*Rrotz(th3);

Moreover, the rotation axes in this example are such that axe1=R1.ux and axe3=R2.uz.
The other procedures are equivalent but correspond to different orders in the axes of
rotation.

2.7.2 Vector decomposition


The routine decomposevec allows to rebuild a vector as a linear combination of 3 given
base axes and is defined as

int decomposevec(vec a,vec axe1, vec axe2, vec axe3,


double &a1,double &a2,double &a3);

On return, the components a1, a2 and a3 are such that

a=a1*axe1+a2*axe2+a3*axe3;

The value returned by the procedure should be equal to zero. Otherwise, the base vectors
are not independent and the decomposition is not possible.
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 17

2.8 Example
The source file testvec.cpp under examples
testvec will allow to easily test all the procedures defined in the vector library. It also
illustrates how to use the library.
If you dispose of gcc, a makefile is provided and you will get the excutable by typing

make

The comments given by the program are self-explanatory.


Chapter 3

The EasyDyn visualization library

3.1 Introduction
The visu part of the library allows to easily create .vol and .van files used by EasyAnim
to visualize and animate a scene composed of moving objects. The visu module largely
uses the vector part of the library.
EasyDyn/visu relies on two principal classes

• shape : a shape attached to a moving object;

• scene : a set of shapes.

To use this module, you will of course have to include the corresponding header in your
source file with

#include <EasyDyn/visu.h>

3.2 The shapes


3.2.1 Structure
The abstract class shape is defined in the following way

class shape
{
protected:
mth *mthref;
int nbrnodes, nbredges, nbrsurf;
int *edgecolor, *surfcolor;
vec *nodecoord;
int *edgenode1, *edgenode2;
int *nbrnodesurf, **numnodesurf;
public:

18
CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 19

shape *nextshape;
int GetNbrNodes();
int GetNbrEdges();
int GetNbrSurf();
void WriteNodes(ostream &stream, int initnode);
void WriteNodes(mth *mthvisu,ostream &stream, int initnode, int norot=0);
void WriteEdges(ostream &stream, int initnode, int initedge);
void WriteSurf(ostream &stream, int initnode, int initsurf);
void WriteCoord(ostream &stream);
void WriteCoord(mth *mthvisu, ostream &stream, int norot=0);
virtual char* GetShapeType()=0;
virtual void WriteShape(ostream &stream)=0;
};

Basically, a shape consists of a set of nodes and a set of edges and surfaces defined
between nodes.
The number of nodes is given by variable nbrnodes which can be accessed by the
method GetNbrNodes(). The coordinate vectors of the nodes are stored in the vector array
nodecoord which must be allocated by the user. The vector coordinates are expressed
with respect to a local coordinate system, whose position is described by an homogeneous
transformation matrix pointed to by variable mthref. The evolution of this matrix is
managed by the user, allowing to move the shapes and to create the animation.
The number of edges is given by variable nbredges which can be accessed through the
method GetNbrEdges(). Each edge connects two nodes, whose index is stored in integer
arrays edgenode1 and edgenode2, which must be allocated by the user. The color of each
edge is stored in integer array edgecolor which must be allocated by the user. So far,
only color numbers from 0 to 15 can be defined, corresponding for historical reasons to
the ones defined in TurboPascal. The color codes are recalled in table 3.1.
Code Color Code Color
0 Black 8 Dark gray
1 Blue 9 Light blue
2 Green 10 Light green
3 Cyan 11 Light cyan
4 Red 12 Light red
5 Magenta 13 Light magenta
6 Brown 14 Yellow
7 Light gray 15 White

Table 3.1: Color codes in EasyDyn/visu

The number of surfaces is given by variable nbrsurf which can be accessed through
the method GetNbrSurf(). Each surface is assumed to be polygonal and connects any
number of nodes, specified in integer array nbrnodesurf (which must be allocated by the
user). The indices of the nodes are stored in the array of integer arrays numnodesurf,
which must be allocated by the user. The color of the surfaces is specified in the integer
CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 20

array surfcolor, according to the codes defined in table 3.1. The array surfcolor is
also allocated by the user.
The functions WriteNodes(), WriteEdges(), WriteSurf() and WriteCoord() are
used only by the scenes and are of little interest for the user. In the same way, the
pointer nextshape is used only for the scene where the shapes are stored as a pointed
list.
The function WriteShape() writes the information related to a shape to the screen or
to a file. It is not strictly necessary and can be left empty but can be used for example
to save the structure of a scene.

3.2.2 Predefined shapes


To make the use of the library easier, several predefined shapes are provided, correspond-
ing to classes derived from base class shape. In a general way, the user will declare a
pointer to base class shape, and allocate it as a derived class. Constructors are provided
to correctly initialize the predefined shapes. There exist 7 predefined shapes: the line, the
triangle, the box, the spline (class grspline), the frustum, the tyre and a last one (habfile)
where the structure of the shape is defined in an external text file.
Remark: for each predefined shape, a general constructor is defined to read the in-
formation related to the shape from a stream (the most often, it will be a file). This
information is assumed to be the one saved previously by the method WriteShape().
The constructor has the same form for each predefined shape and gives for example, for
the line

line(mth *mt, istream &stream);

with stream the input stream from which the information is read. The pointer mt has the
same meaning as in the other constructor form (see later) and relates to the coordinate
system in which the coordinates of the nodes of the shape are expressed.

The line

The class line defines a straight line between two points. Besides the stream version, the
following constructor is provided

line(mth *mt, vec pt1, vec pt2, int eclr);

with

• mt the pointer to the homogeneous transformation matrix describing the position


of the local coordinate system of the shape;

• pt1 and pt2 the coordinate vectors of the end points of the line with respect to the
local coordinate system;

• eclr the color code of the line.


CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 21

Here is an example

shape *s1;
vec e1(0,0,0), e2(1,0,0);
mth T=Trotz(0.5);
s1=new line(&T,e1,e2,3);

The triangle

The class triangle defines a triangle by its three vertices. Besides the stream version,
the following constructor is provided

triangle(mth *mt, vec c1, vec c2, vec c3, int eclr, int sclr);

with

• mt the pointer to the homogeneous transformation matrix describing the position


of the local coordinate system of the shape;

• c1, c2 and c3 the coordinate vectors of the vertices with respect to the local coor-
dinate system;

• eclr the color code of the edges;

• sclr the color code of the surface of the triangle.

Here is an example

shape *s1;
vec e1(0,0,0), e2(1,0,0), e3(0,1,0);
mth T=Troty(0.5);
s1=new triangle(&T,e1,e2,e3,3,4);

The box

The class box defines a rectangular parallelepiped from two extreme vertices (cf. figure
3.1). The edges of the box are parallel to the X, Y and Z axes of the local coordinate
system. Besides the stream version, the following constructor is provided

box(mth *mt, vec c1, vec c2, int eclr, int sclr);

with

• mt the pointer to the homogeneous transformation matrix describing the position


of the local coordinate system of the shape;

• c1 and c2 the coordinate vectors of the two extreme vertices with respect to the
local coordinate system;
CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 22

e1 1
z

y
x

e2
2

Figure 3.1: Parameters of the box shape

• eclr the color code of the edges;

• sclr the color code of the surfaces of the box.

Here is an example

shape *s1;
vec e1(-1,-1,-1), e2(1,1,1);
mth T=Tdisp(0.5,0,0);
s1=new box(&T,e1,e2,3,4);

The spline (class grspline)

The class grspline defines a spline from some points and the tangent vector of the curve
at these points. Besides the stream version, the following constructor is provided

grspline(mth *mt, vec *p, vec *t, int nt, int ns, int eclr);

with

• mt the pointer to the homogeneous transformation matrix describing the position


of the local coordinate system of the shape;

• p the coordinate vectors of the successive points describing the spline, with respect
to the local coordinate system;

• t the tangent vectors at the successive points with respect to the local coordinate
system; pay attention that the amplitude of the tangent vector is relevant and
modifies the layout of the curve;

• nt the number of sectors of the spline (equal to the number of points minus 1);

• ns the number of straight segments used to represent a sector of the spline;


CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 23

• eclr the color code of the edges.

Here is an example

shape *s1;
vec e[2], t[2];
// We should get approximately a quarter of a circle
e[0].put(1,0,0); e[1].put(0,1,0);
t[0].put(0,1.567,0); t[1].put(-1.567,0,0);
mth T=Tdisp(0.5,0,0);
s1=new grspline(&T,e,t,1,10,3);

The frustum

R2
z
R1
2 e2
1
e1
y
x

Figure 3.2: Parameters of the frustum shape

The class frustum defines a frustum from the two extreme points of its axis and
the corresponding radiuses (cf. figure 3.2). Besides the stream version, the following
constructor is provided

frustum(mth *mt, vec e1, vec e2, double r1, double r2, int nbs,
int eclr, int sclr);

with

• mt the pointer to the homogeneous transformation matrix describing the position


of the local coordinate system of the shape;

• e1 and e2 the coordinate vectors of the two extreme axis points with respect to the
local coordinate system;

• r1 the radius at the first point;

• r2 the radius at the second point;

• nbs the number of sectors used to represent the frustum;

• eclr the color code of the edges;


CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 24

• sclr the color code of the surfaces of the frustum.

Here is an example

shape *s1;
vec e1(-1,0,0), e2(1,0,0);
mth T=Tdisp(0.5,0,0);
s1=new frustum(&T,e1,e2,1.5,1.2,24,3,4);

The tyre

Rint
2
z
Rext 1
e2
e1
y
x

Figure 3.3: Parameters of the tyre shape

The class tyre defines a tyre from the two extreme points of its axis and the external
and internal radiuses (cf. figure 3.3). Besides the stream version, the following constructor
is provided

tyre(mth *mt, vec e1, vec e2, double ri, double re, int nbs,
int eclr, int sclr);

with

• mt the pointer to the homogeneous transformation matrix describing the position


of the local coordinate system of the shape;

• e1 and e2 the coordinate vectors of the two extreme axis points with respect to the
local coordinate system;

• ri the internal radius;

• re the external radius;

• nbs the number of sectors used to represent the tyre;

• eclr the color code of the edges;


CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 25

• sclr the color code of the surfaces of the frustum.

Here is an example

shape *s1;
vec e1(0,-0.1,0), e2(0,0.1,0);
mth T=Tdisp(1.3,0.8,0);
s1=new tyre(&T,e1,e2,0.18,0.25,12,3,4);

The gear

Figure 3.4: Example of a gear

The class gear defines a gear from the two extreme points of its axis, its module, the
number of teeth, and the hole radius. Besides the stream version, the following constructor
is provided

gear(mth *mt, vec e1, vec e2, double module, int nt, double alpha, double R,
int eclr, int sclr);

with

• mt the pointer to the homogeneous transformation matrix describing the position


of the local coordinate system of the shape;

• e1 and e2 the coordinate vectors of the two extreme axis points with respect to the
local coordinate system (definition similar to the one for frustum and tyre);

• module the module of the gear (for recall, the primitive diameter is equal to the
module times the number of teeth);
CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 26

• alpha an angle offset that can be used to adjust the gearing between two gears;

• R the hole radius (if the hole radius is higher than the primitive radius, the gear is
assumed to be a crown);

• eclr the color code of the edges;

• sclr the color code of the surfaces of the gear.

Here is an example of two connected gears

int nd1=40, nd2=30;


double module=0.0254, R1=0.5*nd1*module, R2=0.5*nd2*module;
mth T1,T2=Tdisp(R1+R2,0,0);
vec e1(0,0,0.1), e2(0,0,0.1);
shape *s1, *s2;
s1=new gear(&T1,e1,e2,module,nd1,0,0.5*R1,1,2);
s2=new gear(&T2,e1,e2,module,nd2,3.1416/nd2,0.5*R2,1,4);

It is of interest to note that a gear should always own at least 25 teeth to avoid
interference problems at the base of the teeth.

habfile

The class habfile defines a shape from a structure defined in a text file. The constructor
is declared in the following way

habfile(mth *mt, char *filename);

with filename the name of the file in which the structure of the shape is defined.
The structure of the file is the following
Nn Ne c e number of nodes, number of edges and edge color
x1 y1 z 1 local coordinates of node 1
x2 y2 z 2 local coordinates of node 2
:
xNn yNn z Nn local coordinates of last node
i 1 j1 indices of end nodes of edge 1
i 2 j2 indices of end nodes of edge 2
:
i N e jN e indices of end nodes of last edge
Ns c s Number of polygonal surfaces and surface color
N 1 i 1 j1 . . . number of vertices and node indices of polygon 1
N 2 i 2 j2 . . . number of vertices and node indices of polygon 2
:
NNs iNs jNs . . . number of vertices and node indices of last polygon
Here is an example
CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 27

shape *s1;
mth T=Trotz(0.9);
s1=new habfile(&T,"cube.hab");

3.2.3 Defining your own shapes


The user is free to redefine other classes derived from the base class shape. A look at the
code of the provided shapes will be more explanatory. However, note that you will have
to define at least

• a constructor and, ideally, a destructor;

• the method WriteShapes() which can anyway be empty.

3.3 The scenes


3.3.1 Building the scene
A scene is built by successively adding shapes, with the method AddShape. Here is an
example

shape *s1,*s2;
vec e1(-1,0,0), e2(1,0,0);
mth T1=Tdisp(5,0,0);
s1=new frustum(&T1,e1,e2,1.5,1.2,24,1,2);
vec e3(-1,-1,-1), e4(1,1,1);
mth T2;
s2=new box(&T2,e3,e4,3,4);
scene thescene;
thescene.AddShape(s1);
thescene.AddShape(s2);

3.3.2 Saving the scene


Once the scene has been built by adding shapes, it can be saved to a file with extension
.vol by means of the method CreateVolFile()

thescene.CreateVolFile("myscene.vol");

In this file, the structure of the scene is described in terms of nodes, edges and surfaces
(cf. later).
With only the vol file, the scene can be visualized with EasyAnim.
CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 28

3.3.3 Creating the animation


An animation is created by saving successive configurations in a file with extension .van.
This file comprises only the coordinates of the nodes, the structure in terms of edges and
surfaces remaining the one described in the associated .vol file.
If we go on with the same example, here is how we can create an animation with
rotating shapes

ofstream VanFile("myscene.van");
int i;
for (i=0;i<100;i++)
{
T1=Tdisp(5,0,0)*Trotz(i*0.02*6.2832);
T2=Troty(i*0.03*6.2832);
thescene.WriteCoord(VanFile);
}
VanFile.close();

3.3.4 Changing the observer


By default, the scene is observed from the global coordinate system. If a moving observer
is wanted, like for example the driver in a car, it can be specified with the method
SetVisuFrame

mth Tref=Tdisp(10,10,10);
thescene.SetVisuFrame(&Tref);

When the animation is created, the homogeneous transformation matrix related to the
observer evolves as defined by the user.
Sometimes, it is desirable to follow the scene from a moving frame but without rotating
with it. The method SetVisuFrame will then be called like this

thescene.SetVisuFrame(&Tref,1);

Only the displacement part of matrix Tref will then be taken into account. The direction
of view will remain parallel to the global axis.

3.4 Structure of the files


3.4.1 The .vol file
The structure of the file is the following
CHAPTER 3. THE EASYDYN VISUALIZATION LIBRARY 29

Comment line the first line is just a comment


Nn the number of nodes
1 x 1 y1 z 1 index (not used) and coordinates of node 1
2 x 2 y2 z 2 index (not used) and coordinates of node 2
:
N n xNn yNn z Nn index (not used) and coordinates of last node
Ne Number of edges
1 i 1 j1 c 1 index (not used), indices of end nodes and color of edge 1
2 i 2 j2 c 2 index (not used), indices of end nodes and color of edge 2
:
N e i N e jN e c N e index (not used), indices of end nodes and color of last node
Ns Number of polygonal surfaces
1 N 1 i 1 j1 . . . c 1 index (not used), number of vertices, node indices
and surface color of polygon 1
2 N 2 i 2 j2 . . . c 2 index (not used), number of vertices, node indices
and surface color of polygon 2
:
N s N N s i N s jN s . . . c N s index (not used), number of vertices, node indices
and surface color of last polygon

3.4.2 The .van file


The structure of the file is simple. If the scene comprises Nn nodes, the file is a suc-
cession of blocks of Nn lines giving the X,Y and Z coordinates of each node, each block
corresponding to a saved configuration. The structure of the block is
x1 y1 z 1 coordinates of node 1
x2 y2 z 2 coordinates of node 2
:
xNn yNn zNn coordinates of last node
During animation by EasyAnim, the configurations are read successively and displayed
on the screen.
Chapter 4

The EasyDyn simulation library

4.1 Introduction
The sim part of the library allows to easily simulate any system described by a set of
second order differential equations of the form
f (q, q̇, q̈, t) = 0 (4.1)
with

• t the time;
• q, q̇ and q̈ the vectors gathering the parameters of the system and their first and
second time derivatives;
• f the vector gathering the residuals of the differential equations governing the be-
haviour of the physical system.

Let’s recall that the problem can be solved only if the number of parameters is the same
as the number of differential equations.
The library was basically created to simulate the motion of mechanical systems but
can be used for any physical system whose behaviour is described in terms of second-order
differential equations.
First-order differential equations of the form
f (y, ẏ, t) = 0 (4.2)
can be solved as well by considering y = q̇ and ẏ = q̈, q becoming meaningless.

4.2 Structure and routines of the library


4.2.1 Global variables
The structure of the library is illustrated in figure 4.1. It involves the following global
variables

30
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 31

• int nbrdof the number of degrees of freedom of the system (or number of param-
eters or number of differential equations);

• double *f the array gathering the residuals of the considered differential equations

• double *q, *qd, *qdd the arrays gathering the parameters and their first and
second time derivatives;

• double t the time;

• char *application the name of the application used namely to create the result
file;

• int DEBUG an option which, if different from zero, activates the printing of various
information during the simulation (equal to zero by default).

To be sure to declare the global variables only once, the main program will have to define
EASYDYNSIMMAIN before including the header file.

Global variables
int nbrdof
double t
double *q, *qd, *qdd, *f
char *application
int DEBUG
Library
User
InitEasyDynSim()

main() EndEasyDynSim()

StaticEquilibrium()

ComputePoles()

WriteStateVariablesHeader()
WriteDataHeader() SaveStateVariables()
SaveData()
NewmarkIntegration()

ComputeResidual() NewmarkInterval()

NewmarkOneStep()

Figure 4.1: Structure of EasyDyn sim


CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 32

4.2.2 Routines that the user must provide


The user manages the main routine and must provide the following functions

• void ComputeResidual() which computes the residuals f in terms of q, qd, qdd


and time t;

• WriteDataHeader(ostream &OutFile) which sends to the OutFile output stream


the names, separated by some space, of the data the user wants to save; this
procedure is called only once at the beginning of an integration; eventually, it is
sufficient to call the provided routine WriteStateVariablesHeader which sends
the names of the data saved by the routine SaveStateVariables; pay attention
that a final linebreak must be sent, which is not done by the latter routine;

• SaveData(ostream &OutFile) which sends to the OutFile output stream the val-
ues, separated by some space, of the data the user wants to save; this procedure
is called automatically at regular intervals by some integration routines or can be
called by the main program; eventually, it is sufficient to call the provided routine
SaveStateVariables which sends the time followed, for each variable i, by the value
of q[i], qd[i] and qdd[i] (t q[0] qd[0] qdd[0] q[1] ...); pay attention that
a final linebreak must be sent, which is not done by the latter routine.

4.2.3 Initializing the process


Before calling any other procedure, the user must set the variable nbrdof and call the
routine InitEasyDynsim(), which allocates memory to all necessary arrays and sets all
terms of q, qd and qdd to zero. When this operation is done, the integration routines
can be called. Similarly at the end of the program, the routine EndEasyDynsim should be
called to clean the memory.

4.2.4 Integration routines


If the user wants the finest control on the integration, he will use the basic integration
routine

int NewmarkOneStep(double h, double &errqd, int *doflocked=0);

which performs an integration step with a time step h according to the Newmark formulas.
If the value returned by the function is different from zero, either the process was unable to
converge (1), or there was a numerical trouble (2). On return, errqd gives an estimation of
the rate of error on positions for the time step. The array doflocked allows to eventually
lock selected degrees of freedom. If doflocked is equal to zero it is ignored. Otherwise,
if doflocked[i] is different from zero, the ith degree of freedom is not modified by the
integration procedure and the ith residual is ignored. The evolution of the corresponding
degree of freedom can be specified in ComputeResidual. If not, it will follow a uniformly
accelerated evolution according to the initial conditions. Due to the ability of C++ to
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 33

use default arguments, doflocked will be automatically set to zero if it is not given in
the call.
At a higher level, we find the procedure

void NewmarkInterval(double tfinal, double &h, double hmax,


double *doflocked=0)

which integrates the equations up to time tfinal, with an initial time step h and a
maximum allowed time step hmax. To integrate over the interval, NewmarkInterval
makes successive calls to NewmarkOneStep while automatically adapting the time step to
keep the error below a chosen tolerance (1E-6).
The most often, the user will directly call the most general routine

void NewmarkIntegration(double tfinal, double hsave, double hmax,


int *doflocked=0)

which performs the integration up to time tfinal by regular time intervals equal to
hsave and with the maximum allowed time step hmax. The routine NewmarkIntegration
automatically opens a file called application.res, writes the header with the function
WriteDataHeader and saves the data after each interval by a call to SaveData. Practically,
NewmarkInterval is called for each integration interval.

4.2.5 Static equilibrium


For some particular cases, it is necessary to reach the static equilibrium before launching
the integration. This can be done by calling the following routine

void StaticEquilibrium(int *doflocked)

which search for the parameters qi verifying

f (q, q̇0 , q̈0 , t0 ) = 0 (4.3)

at time t0 for a given set of initial velocities and accelerations. The values of q̇0 and q̈0
are the ones in memory when calling StaticEquilibrium.
The most often, the accelerations will be equal to zero, which leads to a stationnary
behaviour. If velocities are equal to zero as well, the yielded configuration is an actual
static equlibrium position.
The vector doflocked specifies whether some particular degrees of freedom should be
locked during the process. Pratically, q[i] will be locked if doflocked is different from
zero.

4.2.6 Linearization and eigen values


It is sometimes interesting to evaluate the behaviour of a system by considering only small
perturbations with respect to a given reference configuration.
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 34

The reference configuration will be characterized by q̈0 , q̇0 , q0 which are expected to
verify the equations of motion

f (q0 , q̇0 , q̈0 , t0 ) = 0 (4.4)

The most often, the configuration corresponds to a static equilibrium configuration or a


stationnay motion (for example, a vehicle at constant speed in straight line).
The equations of motion can then be linearized in the following way

f (q0 + ∆q, q̇0 + ∆q̇, q̈0 + ∆q̈, t0 + t) ' M · ∆q̈ + CT · ∆q̇ + KT · ∆q = 0 (4.5)

with M, CT and KT respectively the mass matrix, the tangent damping matrix and the
tangent stiffness matrix, defined by
¯ ¯ ¯
∂fj ¯¯ ∂fj ¯¯ ∂fj ¯¯
Mij = CTij = KTij = (4.6)
∂ q̈j ¯0 ∂ q̇j ¯0 ∂qj ¯0
¯ ¯ ¯

The eigenvalues (or roots or poles) λi and the corresponding eigenvectors Ψi result
from the solution of the following eigenvalue problem
³ ´
λ2i M + λi CT + +KT · Ψi = 0 (4.7)

As damping and stiffness tangent matrices are not necessarily symmetric, the eigenval-
ues and eigen vectors can be complex. However, as all matrices are real, complex roots
are always complex conjugates.
The eigenvalue analysis allows to directly assess the stability of the system. For recall,
the system will be unstable as soon as the real part of any pole is positive. If the root has
an imaginary part, the associated motion is oscillatory, the imaginary part corresponding
to the damped pulsation.
The determination of the poles and eigenvectors about the current configuration can
be performed by means of the routine ComputePoles, declared in the following way

void ComputePoles(int *doflocked, double freqmin=0, double freqmax=1E30)

When calling ComputePoles, the equations of motion are first linearized. The eigen
values and eigen modes are then determined and saved. The complete list of poles is
saved in the file application.lst, with the following format (cf example oscil5.cpp)

POLE ALPHA OMEGA FREQ(Hz) DAMP_RATIO


2 -0.628319 6.25169 0.994987 0.1

The number of the pole does not necessarily begins from 1. This is due to the fact that in
the case of complex conjugates poles, only the last one is saved. ALPHA, OMEGA represent
the real and imaginary part of the pole and are related to the damped frequency (FREQ)
and damping ratio (DAMP RATIO) by
ω α
f= ξ = −√ (4.8)
2π α2 + ω 2
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 35

The eigen modes are saved in the file application.mod but only the ones whose frequency
is between freqmin and freqmax. With the default values of freqmin and freqmax, all
modes should be saved. If different values of freqmin and freqmax are specified, another
file called application.ls2 is created, with only the roots whose frequency falls in the
specified range.
The file application.mod consists of successive data sets corresponding to the saved
modes. Each dat set holds the following information
NumberOfPole RealPart ImagPart Freq DampingRatio
Ψ1 ,real Ψ1 ,imag
Ψ2 ,real Ψ2 ,imag
:
:
ΨN ,real ΨN ,imag
where N represents the number of degrees of freedom of the system.
Practically, the linearization is performed by finite differences, the eigenvalue problem
being solved by a call to the routine dggev of LAPACK.

4.3 A simple example: the harmonic oscillator


4.3.1 Equations to solve
The motion of a body of mass m, attached to the ground by a spring of stiffness k is
governed by the following equation

mq̈ + kq = 0 (4.9)

often rewritten as

q̈ + ω02 q = 0 (4.10)
k
with ω02 = m .
The solution of this differential equation is given by

q = A cos(ω0 t + φ) (4.11)

the amplitude A and the phase φ depending on the initial conditions.


In particular, if we choose ω0 = 2π, that’s to say a frequency of 1 Hz, and the initial
conditions q = 1 and q̇ = 0, the solution will be

q = cos(2πt) (4.12)

We will see how we can retrieve this solution with the help of EasyDyn.
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 36

4.3.2 The simplest way


The code below (oscil1.cpp) shows the simplest code to implement our problem. It is
based on a call to NewmarkIntegration

// Simulation of a mass-spring system (eigenfrequency=1 Hz)

#define EASYDYNSIMMAIN // to declare the global variables


#include <EasyDyn/sim.h>

double w0=2*3.14159265;

//--------------------------------------------------------------------

void ComputeResidual()
{
f[0]=qdd[0]+w0*w0*q[0];
}

//--------------------------------------------------------------------

void WriteDataHeader(ostream &OutFile)


{
WriteStateVariablesHeader(OutFile);
OutFile << endl;
}

//--------------------------------------------------------------------

void SaveData(ostream &OutFile)


{
SaveStateVariables(OutFile);
OutFile << endl;
}

//--------------------------------------------------------------------

int main()
{
// Initialisation and memory allocation
nbrdof=1; application="oscil1";
InitEasyDynsim();
// Initial configuration
q[0]=1;
// Let’s go !
NewmarkIntegration(5,0.01,0.005);
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 37

EndEasyDynsim();
}
//--------------------------------------------------------------------

After compiling and running the code, the file oscil1.res contains the evolution of
q, q̇ and q̈ which can be easily plotted by GNUPLOT or a MATAB-alike program. The
result is shown in figure 4.2

Harmonic oscillator
1

0.5
Position (m)

-0.5

-1
0 1 2 3 4 5
Time (s)

Figure 4.2: Results for the harmonic oscillator

4.3.3 Alternative implementations


If you want to manage the step by step procedure of the integration, you can call the
lower level routines NewmarkInterval or NewmarkOneStep.
If you call NewmarkInterval, you will only have to determine the initial accelerations
and to manage the creation of the result file bu the integration should proceed fluently.
The main routine of the program will look like this (example oscil2.cpp)

int main()
{
// Initialisation and memory allocation
nbrdof=1; application="oscil2";
InitFpmsSim();
// Initial configuration
q[0]=1;
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 38

// Opening of the result file


ofstream ResFile("oscil2.res");
// Determining initial accelerations
t=0;
double errqd;
NewmarkOneStep(0,errqd);
// Saving initial state
SaveData(ResFile);
// Let’s go !
double interval=0.01, tfinal=5, hmax=interval/2, h=hmax;
while (t<tfinal)
{
NewmarkInterval(t+interval,h,hmax);
cout << "t=" << t << endl;
SaveData(ResFile);
}
ResFile.close();
EndFpmsSim();
}

Note: the initial acceleration is determined by an initial call to NewmarkOneStep with


a null time step.
If you call NewmarkOneStep, you will have moreover to look at the stability of the
numerical integration. The main routine of the program will look like this (example
oscil3.cpp)

int main()
{
// Initialisation and memory allocation
nbrdof=1; application="oscil3";
InitFpmsSim();
// Initial configuration
q[0]=1;
// Opening of the result file
ofstream ResFile("oscil3.res");
// Determining initial accelerations
t=0;
double errqd;
NewmarkOneStep(0,errqd);
// Saving initial state
SaveData(ResFile);
// Let’s go !
double h=0.05, tfinal=5;
int code;
while (t<tfinal)
{
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 39

code=NewmarkOneStep(h,errqd);
cout << "t=" << t << endl;
if (code==1) { cout << "No convergence\n"; exit(1); }
if (code==2) { cout << "Numerical trouble\n"; exit(2); }
SaveData(ResFile);
}
ResFile.close();
EndFpmsSim();

A direct use of NewmarkOneStep can lead to inaccurate results if the time step is not
appropriate. Figure 4.3 shows the result obtained if there are only 20 time steps per
period.

Harmonic oscillator simulated with a bad time step


1
simulated
0.8 exact
0.6
0.4
Position (m)

0.2
0
-0.2
-0.4
-0.6
-0.8
-1
0 1 2 3 4 5
Time (s)

Figure 4.3: Results with a bad time step

4.3.4 Searching for the equilibrium position


You can determine the equilibrium position with a call to StaticEquilibrium. Here
below the main routine doing the job for the harmonic oscillator. The obtained position
should be equal to zero (example oscil4.cpp).

int main()
{
// Initialisation and memory allocation
nbrdof=1; application="oscil3";
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 40

InitFpmsSim();
// Initial configuration
q[0]=1;
t=0;
StaticEquilibrium();
cout << "Position reached for q=" << q[0] << endl;
EndFpmsSim();
}

4.3.5 Performing the linear analysis (eigen values)


You can determine the eigenvalues with a call to ComputePoles. Here below the main
routine doing the job for the harmonic oscillator. The operation is performed about the
equilibrium position (example oscil5.cpp).

int main()
{
// Initialisation and memory allocation
nbrdof=1; application="oscil5";
InitEasyDynsim();
// Initial configuration
q[0]=0;
// Let’s go !
ComputePoles();
EndEasyDynsim();
}

4.4 Another example: the hydraulic jack


The system represented in figure 4.4, consists of an hydraulic jack pushing a mass m,
attached to the ground by a spring of stiffness k. The jack comprises two chambers
numbered 1 and 2. It is a good test for EasyDyn as the hydraulic equations are well-
known to be particularly stiff.
The volume flow Qi entering in each chamber i (i=1,2) verifies on one hand the dis-
charge law through the throttling section Sei
s
2(pEi − pi )
Qi = Cd Sei ∗ sign(pEi − pi ) (4.13)
ρ
with Cd the orifice discharge coefficient, ρ the fluid density, pi the fluid pressure inside
the chamber, and pEi the circuit pressure at the entrance of the chamber.
On the other hand, the flow is driven by the variation of volume of the chamber and
by the variation of the fluid pressure
Vi
Qi = V̇i + ṗi (4.14)
K
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 41

Q1, pE1 Q2, pE2

 


Se 1 Se 2


  p V
2 2 m k 

p V
1 1 


 S1 


S2
x

Figure 4.4: Hydraulic system

with Vi the volume of the chamber and K the compressibility coefficient of the fluid.
If we consider that the position x=0 corresponds to the rest length of the spring, the
dynamic equilibrium of mass m is given by

mẍ + kx − p1 S1 + p2 S2 = 0 (4.15)

If V0i is the volume of the chamber for the position x=0, the volume can be expressed
in terms of x

V1 = V01 + S1 x V2 = V02 − S2 x (4.16)

with S1 and S2 the cross sections of chambers 1 and 2.


The other equations of motion are obtained by matching the two expressions of the
flow
V01 +S1 x
S1 ẋ + K
p˙1
r
2(pE1 −p1 )
−Cd Se1 ρ
∗ sign(pE1 − p1 ) = 0 (4.17)
V02 −S2 x
−S2 ẋ + K
p˙2
r
2(pE2 −p2 )
−Cd Se2 ρ
∗ sign(pE2 − p2 ) = 0 (4.18)

Although two equations are of first-order form, they can be naturally treated by spec-
ifying the 3 state variables as

q1 = x q˙2 = p1 q̇3 = p2 (4.19)

Here is the code implementing the simulation of the hydraulic system (hydrjack.cpp
in the examples\testsim directory).

// Simulation of a hydraulic jack pushing a mass-spring system


CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 42

#define EASYDYNSIMMAIN // to declare the global variables


#include <EasyDyn/sim.h>

double m=10, k=1E5, Kf=2E8, rho=860, pE1=1E6, pE2=1E6, S1=1E-3, S2=5E-4,


V01=1E-4, V02=3E-4, Cd=0.611, Se1=1E-5, Se2=1E-5;

//--------------------------------------------------------------------

void ComputeResidual()
{
double p1,p2,p1d,p2d;
p1=1E5*qd[1]; p1d=1E5*qdd[1]; // In qd, the pressure is in bar
p2=1E5*qd[2]; p2d=1E5*qdd[2];
pE1=1E6+9E6*(100*t);
if (t>0.01) pE1=1E7;
f[0]=m*qdd[0]+k*q[0]-p1*S1+p2*S2;
f[1]=S1*qd[0]+(V01+S1*q[0])*p1d/Kf
-Se1*Cd*sqrt(fabs(pE1-p1)/rho)*(pE1-p1)/(1+fabs(pE1-p1));
f[2]=-S2*qd[0]+(V02-S2*q[0])*p2d/Kf
-Se2*Cd*sqrt(fabs(pE2-p2)/rho)*(pE2-p2)/(1+fabs(pE2-p2));
}

//--------------------------------------------------------------------

void WriteDataHeader(ostream &OutFile)


{
WriteStateVariablesHeader(OutFile);
OutFile << endl;
}

//--------------------------------------------------------------------

void SaveData(ostream &OutFile)


{
SaveStateVariables(OutFile);
OutFile << endl;
}

//--------------------------------------------------------------------

int main()
{
// Initialization and memory allocation
nbrdof=3; application="hydrjack";
InitEasyDynsim();
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 43

// Initial configuration
qd[1]=pE2/1E5;
qd[2]=pE2/1E5;
// Let’s go !
DEBUG=1;
NewmarkIntegration(1,0.001,0.0005);
EndEasyDynsim();
}

//--------------------------------------------------------------------

The system has been simulated with the data in table 4.1 with the following initial
conditions

x0 = ẋ0 = 0 p1 0 = p2 0 =10 bar

for the pressure pE1 increasing linearly from 10 to 100 bar, in the interval [0:0.01] seconds.
The initial accelerations (ẍ, ṗ1 and ṗ2 ) are determined from the equations of motion.

Table 4.1: Simulation data for the hydraulic jack

m=10 kg k = 105 N/m K = 2 · 108 Pa


ρ = 860 kg/m3 pE2 = 10 bar S1 =0.001 m2
S2 =0.0005 m2 V01 = 10−4 m3 V01 = 3 · 10−4 m3
Cd = 0.611 Se1 =10−5 m2 Se2 =10−5 m2

It is of interest to note that the pressure has been expressed in bar so as to avoid
mixing state variables of completely different orders of magnitude.
Some results are presented in figures 4.5 to 4.8. The mass position (figure 4.5) is driven
initially by the flow through the orifices and stops when the equilibrium is reached between
the spring reaction and the force exerted by the jack. At the end of the simulation, the
pressure in the chambers is the one of the corresponding circuit (figure 4.6). The stiff
nature of the equations is illustrated on the evolution of the mass velocity (figure 4.7)
where the oscillations due to the fluid compressibility can be clearly identified. Figure 4.8
shows how the integration procedure adapts the time step during the simulation. This
evolution must be correlated with figure 4.7. In the beginning of the simulation, a small
time step is necessary due to heavy oscillations of the system. Later, the behaviour is
quasi-stationary and a larger time step is allowed. It can be seen that a maximum time
step of 0.0005 seconds has been specified by the user.
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 44

Simulation of a hydraulic system


0.1
0.09

Mass position (m)


0.08
0.07
0.06
0.05
0.04
0.03
0.02
0.01
0
0 0.2 0.4 0.6 0.8 1
Time (s)

Figure 4.5: Mass position

Simulation of a hydraulic system


110
100 p1
90
Pressures (bar)

80 p2
70
60
50
40
30
20
10
0
0 0.2 0.4 0.6 0.8 1
Time (s)

Figure 4.6: Pressure in the chambers

Simulation of a hydraulic system


0.7
Mass position (m)

0.6
0.5
0.4
0.3
0.2
0.1
0
-0.1
0 0.2 0.4 0.6 0.8 1
Time (s)

Figure 4.7: Mass velocity


CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 45

Simulation of a hydraulic system


0.00055
0.0005
0.00045
Time step (s)

0.0004
0.00035
0.0003
0.00025
0.0002
0.00015
0.0001
5e-05
0
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
Time (s)

Figure 4.8: Evolution of time step


Chapter 5

The EasyDyn multibody library

5.1 Introduction
The mbs part of the library is a frontend to the sim library for the simulation of multi-
body systems. It provides the routine ComputeResidual which automatically builds the
equations of motion if the user can provide
• the kinematics of the system, that’s to say the expression of position, velocity and
acceleration of each body in terms of the chosen configuration parameters and their
first and second time derivatives;
• the expression of external forces exerted on each body in terms of time, configuration
parameters and their time derivatives.

5.2 Structure of the library


5.2.1 Global variables
All the global variables of the sim library automatically exist in mbs. Morevover, we have
• int nbrbody: the number of bodies involved in the considered system;
• structbody *body: an array gathering the properties of all bodies in the system.
The structure structbody is declared in the following way
struct structbody
{
double mass;
tiner PhiG;
mth T0G,TrefG;
vec vG, aG, omega, omegad,
vGrel, aGrel, omegarel, omegadrel,
R, MG;
};

46
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 47

with

• mass the mass of the body;

• PhiG the inertia tensor of the body with respect to the center of gravity, expressed
in the coordinate system of the body;

• T0G the homogeneous tranformation matrix giving the situation of the coordinate
system of the body with respect to the global frame; the coordinate system of the
body must be located at the center of gravity;

• vG, aG the velocity and acceleration vectors of the center of gravity, the coordinates
being expressed in the global coordinate system;

• omega, omegad the rotational velocity and acceleration vectors of the body, the
coordinates being expressed in the global coordinate system;

• TrefG the homogeneous tranformation matrix giving the situation of the coordinate
system of the body with respect to the one of the body used as a reference to express
the relative motion;

• vGrel, aGrel the relative velocity and acceleration vectors of the center of gravity
with respect to the coordinate system of the body used as a reference to express
the relative motion; the coordinates are expressed in the coordinate system of the
reference body;

• omegarel, omegadrel the rotational velocity and acceleration vectors of the body
with respect to the coordinate system of the body used as a reference to express
the relative motion; the coordinates are expressed in the coordinate system of the
reference body;

• R,MG the resultant force and the resultant moment with respect to the center of
gravity, of inertia and applied efforts exerted on the body (the joint efforts don’t
need to be considered in the proposed approach); the coordinates are expressed in
the global coordinate system.

All data related to the relative motion (TrefG, vGrel, aGrel, omegarel and omegadrel)
are used only if the motion of the body is defined from the relative motion with respect
to another body.

5.2.2 Procedures that the user must provide


Like in sim, the user manages the main routine and must provide the following functions

• SetInertiaData; this procedure is called only once at the beginning and initializes
the inertia data of each body, that’s to say mass and PhiG; the software verifies the
following physical conditions

– the mass must be positive;


CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 48

Global variables
int nbrdof, nbrbody
structbody body*
double t
double *q, *qd, *qdd, *f
char *application
int DEBUG
User mbs sim
InitEasyDynmbs() InitEasyDynsim()
SetInertiaData()
EndEasyDynmbs() EndEasyDynsim()
main()
StaticEquilibrium()

WriteStateVariablesHeader()
SaveStateVariables()

WriteDataHeader() NewmarkIntegration()
SaveData()

ComputeResidual() NewmarkInterval()

ComputeMotionl() ComputeResidualmbs()
NewmarkOneStep()
AddAppliedEfforts() AddGravityForces()
AddSpringForce()
AddDamperForce()

Figure 5.1: Structure of EasyDyn mbs

– any diagonal term of the inertia tensor mustn’t be larger than the sum of the
two other ones.

• ComputeMotion() building for each body the position matrix T0G and the vectors
vG, aG, omega and omegad from the array of the configuration parameters q and
their time derivatives qd and qdd. All entities can be described directly or from
the relative motion with respect to another body. In this case, the user builds the
relative position matrix TrefG and the vectors defining the relative motion vGrel,
aGrel, omegarel and omegadrel from the array of the configuration parameters
q and their time derivatives qd and qdd. The global motion is finally built from
the motion of the reference body and the relative motion, by calling the procedure
ComposeMotion() (cf. later).

• AddAppliedEfforts adding to the vectors R and MG the contribution of the efforts


applied on each body (the inertia reactions being calculated automatically by the
internal routine ComputeInertiaEfforts); the job is made easier by some routines
implementing classical element forces like gravity, springs or dampers (cf. further).

• ComputeResidual() which the most often will simply call ComputeResidualmbs(),


CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 49

which builds the equations of motion from the efforts and the kinematics. The
procedures have been splitted in case the user would like to write supplementary
differential equations relative to non kinematic parameters, like for example the
model of a hydraulic actuator or a continuous controller.

5.2.3 Initializing the process


Before calling the simulation routines, the user must set the variables nbrdof and nbrbody
and call the routine InitEasyDynmbs(), which itself calls InitEasyDynsim, allocates
memory for the body array and calls SetInertiaData.
Similarly at the end of the program, the routine EndEasyDynmbs should be called to
clean the memory.

5.2.4 Simulation routines


As mbs is a frontend to sim which simply implements in a particular way the routine
ComputeResidual, the simulation routines are used in the same way as in sim.
The routine ComputeResidualmbs automatically computes the residuals of the equa-
tions of motion of a multibody system whose kinematics is described in ComputeMotion
and subjected to efforts described in AddAppliedEfforts.

5.2.5 Motion composition


The routine ComposeMotion is declared
void ComposeMotion(int ibody, int ibodyref)
and builds the global motion of body ibody from the one of the reference body ibodyref
and the relative motion with respect to this reference body.
The procedure assumes that the global motion (T0G, vG, aG, omega and omegad) of the
reference body and the relative motion (TrefG, vGrel, aGrel, omegarel and omegadrel)
of the considered body have been previously defined in terms of the configuration param-
eters and their first and second time derivatives.

5.2.6 Provided routines for applied efforts


Some routines are provided to help the user in writing the routine AddAppliedEfforts.

Gravity

The routine AddGravityForces adds the gravity contribution of all the bodies of the
system; it is declared as
void AddGravityForces(vec grav);
with grav the gravity vector, expressed in the global coordinate system.
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 50

Springs and dampers

The routine AddSpringForce implements the efforts exerted by a spring attached to two
bodies; it is declared as

void AddSpringForce(double K, double L0,


int ibodyA, vec rA, int ibodyB, vec rB);

with K and L0 the stiffness and the rest length of the spring, ibodyA and ibodyB the
numbers of the bodies connected by the spring, and rA and rB the vectors giving the
coordinates of the attachment points in the coordinate system of the corresponding
body.
The routine AddDamperForce implements the efforts exerted by a damper attached to
two bodies; it is declared as

void AddDamperForce(double C,
int ibodyA, vec rA, int ibodyB, vec rB);

with C the damping coefficient of the damper; ibodyA, ibodyB, rA and rB have the same
meaning as for the spring.

Tyre

The routine AddTyreEfforts allows the user to deal with vehicles. So far the ground is
limited to the XY plane. The use of tyres needs a basic understanding of the classical
tyre models. The one which is used in EasyDyn is the so-called model of the University of
Arizona, developed by Gim Gwanghun, completely described in his Ph.D. thesis (Vehicle
Dynamic Simulation with a Comprehensive Model for Pneumatic Tyres, Gim, Gwanghun,
University of Arizona, 1988). It is an analytical model.
The routine is declared by

void AddTyreEfforts(int ibody, vec axe, structtyre tyre)

with

• ibody the number of the body representing the wheel (the user must give the wheel
all necessary degrees of freedom, namely the axial rotation);

• axe a vector giving the direction of the rotation axis, expressed in the coordinate
system of the body; this vector doesn’t need to be unitary;

• tyre a variable of type structtyre gathering all physical data of the tyre.

The structure structtyre is declared in the following way, which is self explanatory

struct structtyre
{
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 51

double r1; // outer radius


double r2; // equivalent torus radius
double Kz; // vertical stiffness
double Cz; // vertical damping
double Fznom; // nominal vertical force on tyre
double Clongnom; // nominal longitudinal stiffness
double nlong; // Clong=Clongnom*(Fz/Fznom)^nlong
double Clatnom; // nominal cornering stiffness
double nlat; // Clat=Clatnom*(Fz/Fznom)^nlat
double Ccambernom; // nominal camber stiffness
double ncamber; // Ccamber=Ccambernom*(Fz/Fznom)^ncamber
double fClbs, fClbd; // Coulomb friction coefficients (static and dynamic)
};

As an indication, the longitudinal and cornering stiffnesses are worth, for a passenger
car radial tyre, about 8 times the nominal vertical force. For the same type of tyre, the
camber stiffness is about 0.6 times the nominal vertical force.


R2 





R1

   


  

Figure 5.2: Tyre geometry

In figure 5.2, the parameters r1 and r2 are illustrated. It can be seen that the tyre is
considered to be a torus. The research of the contact point is based on this assumption.

5.3 Examples
5.3.1 Mass-spring system
The mass-spring system presented in the previous chapter can also be simulated in a
multibody way.
The corresponding code is given below (file spdp.cpp in the examples\testmbs direc-
tory).

// Simulation of a mass-spring-damper system


CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 52

#define EASYDYNMBSMAIN // to declare the global variables


#include <EasyDyn/mbs.h>

// Definition of global application variables


vec ut; // direction of motion
// The result should be the same whatever ut

//--------------------------------------------------------------------

void WriteDataHeader(ostream &OutFile)

{
WriteStateVariablesHeader(OutFile);
OutFile << endl;
}

//--------------------------------------------------------------------

void SaveData(ostream &OutFile)

{
SaveStateVariables(OutFile);
OutFile << endl;
}

//--------------------------------------------------------------------

void SetInertiaData()

// Inertia for body 0 (=ground in this example)


body[0].mass=1;
body[0].PhiG.put(1,1,1); // no impact on the result anyway
// Inertia for body 1
body[1].mass=1;
body[1].PhiG.put(1,1,1); // no impact on the result anyway

//--------------------------------------------------------------------

void ComputeMotion()

{
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 53

// Kinematics for body 0


// =ground

// Kinematics for body 1


body[1].T0G=Tdisp(q[0]*ut);
body[1].vG=qd[0]*ut;
body[1].aG=qdd[0]*ut;

//--------------------------------------------------------------------

void AddAppliedEfforts()

{
// Contribution of external applied forces
vec gravity=39.478417*ut;
AddGravityForces(gravity);
AddSpringForce(39.478417,2,1,vcoord(0,0,0),0,2*ut);
// Uncomment the following if you want to add a damper
//AddDamperForce(1,0,2*ut,1,vcoord(0,0,0));
}

//--------------------------------------------------------------------

void ComputeResidual()

{
ComputeResidualmbs();
}

//--------------------------------------------------------------------

int main()

{
// Initialization and memory allocation
nbrdof=1;
nbrbody=2;
application="spdp";
InitEasyDynmbs();
// Initial configuration
// Everything =0, so nothing to do :-)
// Let’s go !
ut.put(1.1,2.2,3.3); ut.unite();
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 54

NewmarkIntegration(5,0.01,0.005);
// the clean way to finish
EndEasyDynmbs();
}
//--------------------------------------------------------------------

It can be seen in the code that the motion can be defined along any unit vector ut, for
the sake of testing the library. Moreover, a damper can be easily added.

5.3.2 Double pendulum


Let us consider the double pendulum illustrated in figure 5.3. It is composed of 2 bodies,
each one with its own frame. Two revolute joints constraint the motion of the bodies, on
O between the ground and body 1 and on A between bodies 1 and 2. It is easy to figure
out that the system has 2 degrees of freedom so that the configuration of the system can
be univoquely defined from angles q1 and q2 indicated on the figure.


 
 

 
 y0


x0
O
y1
g
x1
G1

q1
A
y2
x2
G2
q2

Figure 5.3: Double pendulum

The homogeneous transformation matrices giving the situation of the two bodies can
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 55

be easily established as
l1
 
 c1 −s1 0 s1
2

 
 l1 
T0,1  s1
= c1 0 − c1 (5.1)

2

 
 0 0 1 0
 

0 0 0 1

l2
 
 c12 −s12 0 l1 s1 + s12
2

 
 l2 
T0,2  s12
= c12 0 −l1 c1 − c12 (5.2)

2

 
 0 0 1 0
 

0 0 0 1

with l1 and l2 the lengths of the arms, c1 = cos(q1 ), s1 = sin(q1 ), c12 = cos(q1 + q2 ) and
s12 = sin(q1 + q2 ).
They also correspond to a succession of rotations and translations and can be written
in this form, from the utility routines provided in the vec module (cf. listing).
The translation and rotation velocities of each body are given in vector form by

ω1 = q̇1~z0 (5.3)
v G1 = ω̇ 1 × OG1 (5.4)
ω2 = (q̇1 + q̇2 )~z0 (5.5)
v G2 = ω̇ 1 × OA + ω 2 × AG2 (5.6)

The accelerations are written

ω̇ 1 = q̈1~z0 (5.7)
a G1 = ω̇ 1 × OG1 + ω 1 × (ω 1 × OG1 ) (5.8)
ω̇ 2 = (q̈1 + q̈2 )~z0 (5.9)
a G2 = ω̇ 1 × OA + ω 1 × (ω 1 × OA)
+ω̇ 2 × AG2 + ω 2 × (ω 2 × AG2 ) (5.10)

The gravity is the only force acting on the system.


Here is the complete code to simulate this double pendulum wih the mbs module (file
dp2.cpp in the examples\testmbs directory)

// Simulation of a double pendulum with relative coordinates

#define EASYDYNMBSMAIN // to declare the global variables


#include <EasyDyn/mbs.h>
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 56

// Definition of global application variables


double l1=1.2, l2=1.1;

//--------------------------------------------------------------------

void WriteDataHeader(ostream &OutFile)

{
WriteStateVariablesHeader(OutFile);
OutFile << endl;
}

//--------------------------------------------------------------------

void SaveData(ostream &OutFile)

{
SaveStateVariables(OutFile);
OutFile << endl;
}

//--------------------------------------------------------------------

void SetInertiaData()

// Inertia for body 0


body[0].mass=1.1;
body[0].PhiG.put(1,1,body[0].mass*l1*l1/12);
// Inertia for body 1
body[1].mass=0.9;
body[1].PhiG.put(1,1,body[1].mass*l2*l2/12);

//--------------------------------------------------------------------

void ComputeMotion()

// Kinematics for body 0


body[0].T0G=Trotz(q[0])*Tdisp(0,-0.5*l1,0);
body[0].omega.put(0,0,qd[0]);
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 57

body[0].omegad.put(0,0,qdd[0]);
vec OG1=body[0].T0G.e;
body[0].vG=(body[0].omega^OG1);
body[0].aG=(body[0].omegad^OG1)+(body[0].omega^(body[0].omega^OG1));
// Kinematics for body 1
body[1].T0G=Trotz(q[0])*Tdisp(0,-l1,0)*Trotz(q[1])*Tdisp(0,-0.5*l2,0);
body[1].omega=body[0].omega+vcoord(0,0,qd[1]);
body[1].omegad=body[0].omegad+vcoord(0,0,qdd[1]);
vec AG2=body[1].T0G.R*vcoord(0,-0.5*l2,0);
body[1].vG=2*body[0].vG+(body[1].omega^AG2);
body[1].aG=2*body[0].aG+(body[1].omegad^AG2)
+(body[1].omega^(body[1].omega^AG2));
}

//--------------------------------------------------------------------

void AddAppliedEfforts()

{
// Contribution of external applied forces
vec gravity(0,-9.81,0);
AddGravityForces(gravity);
}

//--------------------------------------------------------------------

int main()

{
// Initialisation and memory allocation
nbrdof=2;
nbrbody=2;
application="dp2";
InitEasyDynmbs();
// Initial configuration
q[1]=1;
// Let’s go !
NewmarkIntegration(5,0.01,0.005);
// The clean way to finish !
EndEasyDynmbs();
}
//--------------------------------------------------------------------
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 58

5.3.3 Double pendulum with a relative motion


In the case of the double pendulum presented in the previous section, the user can also
choose to define the motion of the second body with respect to the first one. The function
ComputeMotion will then be written in the following way.

void ComputeMotion()
{
// Kinematics for body 0
body[0].T0G=Trotz(q[0])*Tdisp(0,-0.5*l1,0);
body[0].omega.put(0,0,qd[0]);
body[0].omegad.put(0,0,qdd[0]);
vec OG1=body[0].T0G.e;
body[0].vG=(body[0].omega^OG1);
body[0].aG=(body[0].omegad^OG1)+(body[0].omega^(body[0].omega^OG1));
// Kinematics for body 1
body[1].TrefG=Tdisp(0,-0.5*l1,0)*Trotz(q[1])*Tdisp(0,-0.5*l2,0);
body[1].omegarel=vcoord(0,0,qd[1]);
body[1].omegadrel=vcoord(0,0,qdd[1]);
vec AG2=body[1].TrefG.R*vcoord(0,-0.5*l2,0);
body[1].vGrel=(body[1].omegarel^AG2);
body[1].aGrel=(body[1].omegadrel^AG2)
+(body[1].omegarel^(body[1].omegarel^AG2));
ComposeMotion(1,0);
}

It is important to notice that the relative motion is completely written in the axes of
the intermediary reference frame.

5.4 Module mbs and animation


The motion of the multibody system resulting from a time integration can be animated
with EasyAnim. For that purpose you will have to

1. globally declare a variable of type scene and an output stream for saving the images;
2. create graphical shapes attached to the bodies (practically to the homogeneous
transformation matrix describing the motion of the body)
3. add the shapes to the scene;
4. save the structure of the scene (specified in a file with extension .vol);
5. save the successive node positions in a file with extension .van

It is much easier to show how this is implemented on the example of the double pen-
dulum (cf. example dp2visu.cpp).
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 59

Figure 5.4: Visualization of the double pendulum

1. globally declare a variable of type scene and an output stream for saving the images;
the beginning of the file will look like this

#define EASYDYNMBSMAIN // to declare the global variables


#include <EasyDyn/mbs.h>
#include <EasyDyn/visu.h> // so that the scene can be declared

#include <fstream>
using namespace std;

scene thescene;
ofstream VanFile; // this file will be used to save the node positions

2. create graphical shapes attached to the bodies (practically to the homogeneous


transformation matrix describing the motion of the body)

shape *s1,*s2;
vec e1(-0.1,-0.6,-0.1), e2(0.1,0.6,0.1);
s1=new box(&(body[0].T0G),e1,e2,1,2);
vec e3(-0.1,-0.55,-0.1),e4(0.1,0.55,0.1);
s2=new box(&(body[1].T0G),e3,e4,1,2);
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 60

3. add the shapes to the scene;

thescene.AddShape(s1);
thescene.AddShape(s2);

4. save the structure of the scene (specified in a file with extension .vol);

ComputeMotion(); // to get relevant position matrices


thescene.CreateVolFile("dp2visu.vol");

5. save the successive node positions in a file with extension .van; this requires three
operations

• open the file before launching the integration


VanFile.open("dp2visu.van");
• save regularly the node positions, the easiest way being to add a line to the
routine SaveData which is automatically called by the integrator
void SaveData(ostream &OutFile)
{
SaveStateVariables(OutFile);
OutFile << endl;
thescene.WriteCoord(VanFile);
}
• do not forget to close the file before closing the application
EndEasyDynmbs();
VanFile.close();

The expected result under EasyAnim is illustrated in figure 5.4.

5.5 Provided routine for animation of eigen modes


If a linear analysis of the multibody system has been performed by a call to ComputePoles,
the files for animation can be created by a simple call to the routine

void CreateVmoFile(scene &sc)

The routine relies on the existence of the file application.mod as well as the one of a
scene variable (sc) linking graphical objects to the bodies.
The routine creates the files application.vol and application.vmo which allow the
visualization with EasyAnim (from version 1.2).
Chapter 6

The CAGeM module

6.1 Introduction
Even with the help of the vector library, the risk of mistake remains high when devel-
oping the expressions of velocities and accelerations. Moreover the kinematics remains
problematic for an unexperienced user.
A supplementary tool, called CAGeM (Computer Aided Generation of Motion), has been
developed to help the users of EasyDyn. This module is a simple MuPAD script which au-
tomatically builds a C++ application using the mbs part of EasyDyn. For the kinematic
part, CAGeM symbolically derives the expression of the homogeneous transformation matri-
ces and builds the expressions of the translation and rotation velocities and accelerations.
CAGeM is based on the fact that the homogeneous transformation matrix

à !
R0,i {ei }0
T0,i = (6.1)
000 1

yields, after time derivation, the rotation and the translation velocities as

d
{vi }0 = {e }0 (6.2)
dt i

{ω̃ i }0 = Ṙ0,i · RT0,i (6.3)

where {ω̃ i }0 is the skew symmetric matrix representing the vector product, such as:

 
0 −az ay
{a} =  az

0 −ax 
 (6.4)
−ay ax 0
(6.5)

One further derivation naturally leads to the accelerations

61
CHAPTER 6. THE CAGEM MODULE 62

d
{ai }0 = {v }0 (6.6)
dt i

d
{ω̇ i }0 = {ω }0 (6.7)
dt i
These relations can be easily obtained by using symbolic software. This method gives
an alternative to vector calculus to build the kinematics.

6.2 Installation
The MuPAD software is the result of several years of research at the University of Paderborn
(Germany). Since 1997 the development of interfaces and special applications of MuPAD
is done in a tight cooperation with SciFace Software. It can be downloaded free of charge
from the net at http://www.mupad.de and the installation is very easy (on Windows and
on Linux).
MuPAD is a general purpose computer algebra system for symbolic and numerical com-
putations. The librairy is open source so that users can examine the code, implement
their own routines and data types easily and can also dynamically link C/C++ compiled
modules for raw speed and flexibility. It also offers features comparable to its commercial
counterparts like Mathematica or MathCad.

For the installation of CAGeM on Windows, the user copies the file cagem.mu any-
where on the disc and give the corresponding directory on MuPAD session (menu view >>
options >> kernel in User-defined startup file prompt).

On Linux, the installation is slightly different. The user must create a directory .mu-
pad in his home directory, e.g. mkdir ~/.mupad and a new file userinit.mu, e.g. touch
~/.mupad/userinit.mu. This file must be edited to specify the MuPAD commands to ex-
ecute each time MuPAD starts. In this case, the only command is read("XXX/cagem.mu")
where XXX is the complete path of the file cagem.mu.

6.3 Structure of the user’s data file


To use CAGeM, the user provides a MuPAD code with the following information

• the number of bodies, the number of configuration parameters and, optionally, the
number of dependent parameters;
• the inertia data of each body;
• the expression of the homogeneous transformation matrices (T0G[i] or TrefG[i]
according as the motion is defined with respect to the ground or relatively to another
body) of each body, expressed in terms of the chosen configuration parameters;
CHAPTER 6. THE CAGEM MODULE 63

• the initial conditions;

• the gravity vector.

When the relative motion is defined with the variable TrefG[i], the user must indicate
the number of the reference body with the parameter BodyRef[i]. In this way, the C++
code will contain all the information to build the absolute motion (relative kinematics
and procedure ComposeMotion()).
According to the definition of the class tiner of the EasyDyn vector library, the com-
ponents of the inertia tensor are represented only by the 6 variables Ixx[i], Iyy[i],
Izz[i], Ixy[i], Ixz[i] and Iyz[i], i representing the number of body.
In the same way, the equivalent functions Trotx(theta), Troty(theta), Trotz(theta)
and Tdisp(x,y,z) exist on CAGeM and return an homogeneous transformation matrix. A
supplementary function Trotn(nx,ny,nz,theta) is included and defines a rotation about
an axis whose direction cosines are equal to nx , ny and nz

C + nx2 (1 − C) nx ny (1 − C) − nz S nx nz (1 − C) − ny S 0
 
 nz S + nx ny (1 − C) C + ny2 (1 − C) ny nz (1 − C) − nx S 0 
 
(6.8)
nx nz (1 − C) − ny S nx S + nx nz (1 − C) C + nz2 (1 − C) 0
 
 
0 0 0 1

where C = cos(theta), S = sin(theta).

Optionally various flags can be activated by the user to select different options defined
in the table 6.3.

6.4 Calling CAGeM


To start, call CAGeM with the simple command cagem(). A new window appears to
request the file (path and name) to analyze. In function of the options chosen by the user
on the data file the program gives on screen the CPU–time needed of each operation.

6.5 Examples
6.5.1 Double pendulum
The following code illustrates the user’s file related to the example of the double pendulum

// Title.
title:="Simulation of a double pendulum":

// Definition of nbrdof : number of degrees of freedom,


// nbrbody : number of bodies,
// nbrdep : number of dependent parameter(s) (optional).
CHAPTER 6. THE CAGEM MODULE 64

Flags Functionality Default


SIMPLIFY Simplification of the various kinematics terms. This op- 1
tion, if equal to zero, is used where the simplification
needs a long CPU–time.
FORCES There exist applied forces other then gravity, expected 0
to be defined by the user in the file *.AppEff.cpp, which
will be included in the main code
ANIM Some lines of code are added so as to create animation 0
files during integration (a basic shape is attached to each
body)
STATIC The equilibrium position is determined before the inte- 0
gration
PLOT A gnuplot script file is generated to plot the evolution of 0
the configuration parameters and their first and second
time derivatives
LATEX_FR Creation of LATEX 2ε report in French 0
LATEX_EN Creation of LATEX 2ε report in English 0

Table 6.1: Different flags in CAGeM

nbrdof:= 2:
nbrbody:= 2:
nbrdep:= 0:

// Gravity vector.
gravity[1]:=0:
gravity[2]:=-9.81:
gravity[3]:=0:

// Some constant for geometry.


l0:=1:
l1:=2:

// Inertia characteristics.
mass[0]:=1:
mass[1]:=2:
Ixx[0]:=1:
Ixx[1]:=1:
Iyy[0]:=1:
Iyy[1]:=1:
Izz[0]:=l0^2/12*mass[0]:
Izz[1]:=l1^2/12*mass[1]:

// The kinematic part only comes down to.


T0G[0] := Trotz(q[0]-PI/2) * Tdisp(l0/2,0,0):
T0G[1] := Trotz(q[0]-PI/2) * Tdisp(l0,0,0) * Trotz(q[1]) * Tdisp(l1/2,0,0):
// or TrefG[1] := Tdisp(l0/2,0,0) * Trotz(q[1]) * Tdisp(l1/2,0,0):
// BodyRef[1] := 0:
CHAPTER 6. THE CAGEM MODULE 65

// Initial conditions.
qi[0]:=3.14/2:

// Simulation condition.
FinalTime:=5:
StepSave:=0.01:
StepMax:=0.005:

// Optional flags.
SIMPLIFY:=1:
ANIM:=1:
PLOT:=1:
LATEX_EN:=1:

For the sake of illustration, the code generated to compute the accelerations of the two
bodies looks like this

body[0].aG.x = (1.0/2.0)*qdd[0]*cos(q[0]) - (1.0/2.0)*(qd[0]*qd[0])*sin(q[0]) ;


body[0].aG.y = (1.0/2.0)*qdd[0]*sin(q[0]) + (1.0/2.0)*(qd[0]*qd[0])*cos(q[0]) ;
body[0].aG.z = 0.0 ;
body[1].aG.x = qdd[0]*cos(q[0]) - (qd[0]*qd[0])*sin(q[0]) + qdd[0]*cos(q[0] + q[1])
+ qdd[1]*cos(q[0] + q[1]) - (qd[0]*qd[0])*sin(q[0] + q[1])
- (qd[1]*qd[1])*sin(q[0] + q[1]) - 2.0*qd[0]*qd[1]*sin(q[0] + q[1]) ;
body[1].aG.y = qdd[0]*sin(q[0]) + (qd[0]*qd[0])*cos(q[0]) + qdd[0]*sin(q[0] + q[1])
+ qdd[1]*sin(q[0] + q[1]) + (qd[0]*qd[0])*cos(q[0] + q[1])
+ (qd[1]*qd[1])*cos(q[0] + q[1]) + 2.0*qd[0]*qd[1]*cos(q[0] + q[1]) ;
body[1].aG.z = 0.0 ;

6.5.2 Slider-crank mechanism


The symbolic capabilities of MuPAD allow the user to define intermediary parameters. For
example, with the slider–crank mechanism illustrated in figure 6.1, the parameters α and
x can be expressed univoquely in terms of angle q0 by
à !
l1 sin(q0 )
α = arcsin (6.9)
l2
and

x = l1 cos(q0 ) + l1 cos(α) (6.10)


The relationships can be introduced symbolically in the MuPAD code describing the
system as

// Title.
title:="Simulation of a slider-crank mechanism":

// Definition of nbrdof : number of degrees of freedom,


// nbrbody : number of bodies,
// nbrdep : number of dependent parameter(s) (optional).
CHAPTER 6. THE CAGEM MODULE 66

A OA=lc
body 0 AB=lr
body 1

q
O 0 α B body 2

 

 
x

Figure 6.1: Slider–crank mechanism

nbrdof:= 1:
nbrbody:= 3:
nbrdep:= 0:

// Gravity vector.gravity[1]:=0:
gravity[2]:=-9.81:
gravity[3]:=0:

// Some relations for geometry.


lc := 1:
lr := 2:
alpha := arcsin(lc*sin(q[0])/lr):
x2 := lc*cos(q[0]) + lr*cos(alpha):

// Inertia characteristics.
mass[0]:=1:
mass[1]:=2:
mass[2]:=5:
Ixx[0]:=1:
Iyy[0]:=1:
Izz[0]:=mass[0]*lc^2/12:
Ixx[1]:=1:
Iyy[1]:=1:
Izz[1]:=mass[1]*lr^2/12:
Ixx[2]:=1:
Iyy[2]:=1:
Izz[2]:=1:

// The kinematic part only comes down to.


T0G[0]:= Trotz(q[0]) * Tdisp(lc/2,0,0):
T0G[1] := Tdisp(x2,0,0) * Trotz(-alpha) * Tdisp(-lr/2,0,0):
T0G[2] := Tdisp(x2,0,0):

// Initial conditions.
qi[0]:=1:

// Simulation condition.
FinalTime:=6:
CHAPTER 6. THE CAGEM MODULE 67

StepSave:=0.01:
StepMax:=0.005:

// Optional flags.
SIMPLIFY:=1:
ANIM:=1:
PLOT:=1:
LATEX_EN:=1:

For this example, the following relation gives a view of the results complexity

q̇ 0 sin(2 q0 ) −4 q̇
 q 
cos(2 q0 )
sin(q0 ) +7/8

 −



 2 0 8 


 q 

 cos(2 q0 ) 
4 +7/8
{vG,S1 } =  8 (6.11)

 q̇ 0 cos(q0 ) 



 2 

0

 

The response of the system subjected to gravity has been simulated from initial con-
ditions q0 = 1 rad and q̇0 = 0 rad/s. The time evolution of the dodies displacements,
represented in figure 6.2, shows that the mechanism comes back to the same position
after one oscillation, as there is no energy dissipation.

3
crank [rad]
slider [rad]
2 piston [m]

0
displacements

-1

-2

-3

-4

-5
0 1 2 3 4 5 6
Time [s]

Figure 6.2: Simulation of the slider–crank mechanism

Another way to define the slider–crank mechanism consist in using dependent para-
maters. So the two variables alpha and x2 can be remplaced by the two parameters
p[0] and p[1] defined in the same manner, after the script relative to the homogeneous
matrices :
CHAPTER 6. THE CAGEM MODULE 68

// The kinematic part only comes down to.


T0G[0]:= Trotz(q[0]) * Tdisp(lc/2,0,0):
T0G[1] := Tdisp(p[1],0,0) * Trotz(-p[0]) * Tdisp(-lr/2,0,0):
T0G[2] := Tdisp(p[1],0,0):

// The dependent parameters.


p[0] := arcsin(lc*sin(q[0])/lr):
p[1] := lc*cos(q[0]) + lr*cos(p[0]):

It is of course necessary to specify the number of dependent parameters on top of the


script (nbrdep:=2:).

You might also like