//
===========================================================================
// Name of
program: SimulBall5.pde
// Language:
Processing ver 0133
// Function:
- Multiple balls, with input from accelerometer.
// - This program reads data from the
Arduino board with the program
//
"readAndSendAccelerometer.pde" loaded.
// Ver.
16.11.2007
// Author:
alvaro cassinelli
//
===========================================================================
//
Libraries:
import
processing.serial.*;
// Global
variables:
// The
serial port, to be used by ALL the object.
Serial
serialPort;
// an
additional global variable fx and fy to avoid reading the
//
accelerometer data for each particle:
float globalFx,
globalFy;
// The ARRAY
of particles, here 5
classBall[]
ball=new classBall[5];
void setup()
{
// define size of the displaying screen:
size(700,500);
//instantiate ALL the particles, one by one,
with different positions, radius and masses
// rem: in this example, the radius is
proportional to the mass (see the constructor!)
for (int i=0; i<5; i++) ball[i]=new
classBall(random(0,width),random(0,height),random(0.01,0.09));
// Check the serial port available on this
computer:
serialPort.list();
// Open the (convenient) serial port:
serialPort = new Serial(this,
"COM3", 9600);
// set the trigger for the serialEvent
function: callback to this function when the buffer receives a carriage return:
serialPort.bufferUntil(10); // 10 is the
ASCII code of the carriage return.
}
// The
"infinite looping function":
void draw()
{
// clear the display area:
background(255);
// now, for treat the balls sequentially:
for (int i=0; i<5; i++) {
// displays the ball with index i in the
object array:
ball[i].displayBall();
// update kinematic variables of ball with
index i in the object array:
ball[i].updateNewton();
}
}
void
serialEvent(Serial serialPort) {
// NORMALLY the program would come here when
the buffer receives the character 10..
// read the string in the buffer until it
finds a special character
String
myString=serialPort.readStringUntil(10); // 10 is the carriage return ASCII
code!
if (myString != null) { // this shouldn't be
necessary if bufferUntil were working okay!
myString=trim(myString); // takes away the
spaces and carriage return codes
//split the string at the commas (the
packet delimiters!) and convert the ASCII decimal numbers to integers:
int data[] = int(split(myString, ','));
// now, check if we actually received all
the data! (we could have been reading from the second value...)
if (data.length==2) {
// assign the read value to the global force,
using a special conversion function (that we will calibrate)
globalFx=convertData(data[0], 5000, 327,
263, 396);
globalFy=convertData(data[1], 5000, 326,
265, 403);
}
}
}
// convert
the value read from the accelerometer to the force on the ball:
float
convertData(int value, float gain, int offset, int minvalue, int maxvalue) {
float force;
force=1.0*gain*(value-offset)/(maxvalue-minvalue);
return(force);
}
class
classBall {
//
Intrinsic variables of the ball: (as public)
// Again, in Processing, their default value
can be set here (at declaration):
// there is no need to create a "default
setting" overloaded contructor
float x=width/2, y=height/2; // start the
ball in the middle of the screen
float x1, y1;
float vx=0, vy=0, vx0=0, vy0=0;
float ax, ay;
float fx, fy;
float m=0.01;
float dt=0.002;
float springFactor=1.0;
float ballRadius=15;
// Methods: (as public). These are just the
functions in the previsou SimulBall2.pde program,
// plus a new method, called a CONSTRUCTOR
that helps initializing the object:
// Overloaded constructor with input
parameters for initial position, mass (and perhaps speed)
//REM1 the overloaded contructor is MANDATORY
in processing, even if it does not take any parameter
classBall(float initX, float initY, float
mass) {
x=initX;
y=initY;
m=mass;
ballRadius=1000*mass; //we will make the
radius is proportional to the mass (same "density" for the balls? no!
;)
}
void displayBall() {
//
display the ball as a solid disc:
fill(0,0,250);
ellipse(x, y, ballRadius, ballRadius);
}
void updateNewton() {
// update motion variables using Newton
dynamics
// compute current acceleration, using the
GLOBAL FORCE:
ax=globalFx/m;
ay=globalFy/m;
// update position :
x1=x+vx*dt+ax*dt*dt/2;
y1=y+vy*dt+ay*dt*dt/2;
//update speed :
vx=vx0+ax*dt;
vy=vy0+ay*dt;
// Test boundary conditions:
if ((x1<0)||(x1>width)) {
vx=-0.6*vx0;
x1=x;
};
if ((y1<0)||(y1>height)) {
vy=-0.6*vy0;
y1=y;
};
// Update the current position and past
speed:
x=x1;
y=y1;
vx0=vx;
vy0=vy;
}
}