Easydyn 1.2.3: Facult E Polytechnique de Mons Service de M Ecanique Rationnelle, Dynamique Et Vibrations
Easydyn 1.2.3: Facult E Polytechnique de Mons Service de M Ecanique Rationnelle, Dynamique Et Vibrations
EasyDyn 1.2.3
C++ library for the easy simulation
of dynamic problems
Boulevard Dolez 31
7000 MONS
BELGIQUE
Tél. : 32.65.37.41.81
Fax. : 32.65.37.41.83
Email: [email protected]
Chapter 1
http://mecara.fpms.ac.be
unzip EasyDyn-x.y.z
or
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
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.
http://www63/tok2.com/home/bitwalk/download.html
make
make
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
which will result into the creation of an executable called applic (applic.exe under
Windows).
Chapter 2
2.1 Introduction
The vec part of the library defines 4 classes
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
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
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
where
• 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
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)
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:
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
For the sake of simplicity, we will introduce the ◦ operator such that
To conclude this section, let us mention that the homogeneous transformation matrices
have the advantage to enjoy the following property
This property is often used to obtain a complex transformation matrix from the successive
multiplication of simpler matrices.
vec v;
vec v(1,2,3);
• by using put()
v.put(1,2,3);
v.zero();
v.unite();
As a result, vector v becomes a unitary vector with the same direction (v = v/|v|).
double L=v.length();
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;
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;
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
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)
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
A rotation tensor can be defined back as identity with the unite() method
R.unite();
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);
trot R,Rinv;
Rinv=R.inv();
R = R1 · R2 R=R1*R2;
R = R · R1 R*=R1;
v = R · v1 v=R*v1;
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.
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.
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);
LG = Φ G · ω (2.19)
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.
mth T;
T.R.r11=cos(theta);
T.e.x=2;
T.unite();
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);
vec v(1,2,3);
mth T;
T.e=v;
CHAPTER 2. THE EASYDYN VECTOR LIBRARY 15
vec v(0,-0.5,0);
mth T;
T=Trotz(th)*Tdisp(v); // or equivalently T=Trotz(th)*Tdisp(0,-0.5,0);
mth T,Tinv;
Tinv=T.inv();
T = T1 · T 2 T=T1*T2;
T = T · T1 T*=T1;
v = T ◦ v1 v=T*v1;
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
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.
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
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
To use this module, you will of course have to include the corresponding header in your
source file with
#include <EasyDyn/visu.h>
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
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.
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
with
• pt1 and pt2 the coordinate vectors of the end points of the line with respect to the
local coordinate system;
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
• c1, c2 and c3 the coordinate vectors of the vertices with respect to the local coor-
dinate system;
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
• 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
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 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
• 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);
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
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
• e1 and e2 the coordinate vectors of the two extreme axis points with respect to the
local coordinate system;
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
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
• e1 and e2 the coordinate vectors of the two extreme axis points with respect to the
local coordinate system;
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
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
• 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);
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
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");
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);
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
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();
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.
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.
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;
• 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()
• 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.
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
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
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.
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.
The reference configuration will be characterized by q̈0 , q̇0 , q0 which are expected to
verify the equations of motion
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
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)
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.
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)
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
double w0=2*3.14159265;
//--------------------------------------------------------------------
void ComputeResidual()
{
f[0]=qdd[0]+w0*w0*q[0];
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------------------------------------------------
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)
int main()
{
// Initialisation and memory allocation
nbrdof=1; application="oscil2";
InitFpmsSim();
// Initial configuration
q[0]=1;
CHAPTER 4. THE EASYDYN SIMULATION LIBRARY 38
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.
0.2
0
-0.2
-0.4
-0.6
-0.8
-1
0 1 2 3 4 5
Time (s)
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();
}
int main()
{
// Initialisation and memory allocation
nbrdof=1; application="oscil5";
InitEasyDynsim();
// Initial configuration
q[0]=0;
// Let’s go !
ComputePoles();
EndEasyDynsim();
}
Se 1 Se 2
p V
2 2 m k
p V
1 1
S1
S2
x
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
Although two equations are of first-order form, they can be naturally treated by spec-
ifying the 3 state variables as
Here is the code implementing the simulation of the hydraulic system (hydrjack.cpp
in the examples\testsim directory).
//--------------------------------------------------------------------
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));
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------------------------------------------------
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
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.
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
80 p2
70
60
50
40
30
20
10
0
0 0.2 0.4 0.6 0.8 1
Time (s)
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)
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)
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.
46
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 47
with
• 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.
• 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
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()
– 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).
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.
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
The routine AddSpringForce implements the efforts exerted by a spring attached to two
bodies; it is declared as
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
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
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
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).
//--------------------------------------------------------------------
{
WriteStateVariablesHeader(OutFile);
OutFile << endl;
}
//--------------------------------------------------------------------
{
SaveStateVariables(OutFile);
OutFile << endl;
}
//--------------------------------------------------------------------
void SetInertiaData()
//--------------------------------------------------------------------
void ComputeMotion()
{
CHAPTER 5. THE EASYDYN MULTIBODY LIBRARY 53
//--------------------------------------------------------------------
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.
y0
x0
O
y1
g
x1
G1
q1
A
y2
x2
G2
q2
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)
ω̇ 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)
//--------------------------------------------------------------------
{
WriteStateVariablesHeader(OutFile);
OutFile << endl;
}
//--------------------------------------------------------------------
{
SaveStateVariables(OutFile);
OutFile << endl;
}
//--------------------------------------------------------------------
void SetInertiaData()
//--------------------------------------------------------------------
void ComputeMotion()
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
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.
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
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
#include <fstream>
using namespace std;
scene thescene;
ofstream VanFile; // this file will be used to save the node positions
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
thescene.AddShape(s1);
thescene.AddShape(s2);
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; this requires three
operations
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
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
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)
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.
• 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
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
Optionally various flags can be activated by the user to select different options defined
in the table 6.3.
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":
nbrdof:= 2:
nbrbody:= 2:
nbrdep:= 0:
// Gravity vector.
gravity[1]:=0:
gravity[2]:=-9.81:
gravity[3]:=0:
// 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]:
// 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
// Title.
title:="Simulation of a slider-crank mechanism":
A OA=lc
body 0 AB=lr
body 1
q
O 0 α B body 2
x
nbrdof:= 1:
nbrbody:= 3:
nbrdep:= 0:
// Gravity vector.gravity[1]:=0:
gravity[2]:=-9.81:
gravity[3]:=0:
// 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:
// 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]
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