// ===========================================================================

// 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;

  }

 

}