fdrg — 2009-11-16 18:05:32

Bonjour à tous!

me voilà nouveau sur codelab. je suis etudiant en master arts et technologies numeriques à Rennes 2 et quelques elements pour realiser mon projet me manque.
Dans un premier temps j'aimerais savoir si quelqu'un pourrai me tuyauter sur un code que je tente de mettre en place. Celui ci consiste tout d'abord à faire tourner un globe terrestre avec des etoiles. Le globe est un objet et les etoiles en sont un autre mais je n'arrive pas à faire passer le globe au premier plan, il reste caché par les etoiles...
voici au point où j'en suis dans le code:

Code (p5) :

import processing.opengl.*;
PImage bg ;
PImage texmap;

float globeRadius = 450;
float universeRadius = 1400;
float[] cx, cz, sphereX, sphereY, sphereZ;
float sinLUT[];
float cosLUT[];
float SINCOS_PRECISION = 0.5;
int SINCOS_LENGTH = int(360.0 / SINCOS_PRECISION);
float a; 
int sDetail = 35; 


void setup() {
  size(1440, 900, OPENGL);  
  bg = loadImage("tuto_h16_5-698da.jpg");
  initializeSphere(sDetail);
  texmap = loadImage("carte_monde.jpg");    
  initializeSphere(sDetail);
  
  
}

void draw() {
  background(0);
  translate(width/2, height/2);
  pushMatrix();
  noFill();
  stroke(255,200);
  strokeWeight(2);
  smooth();
  popMatrix();
  lights();  
  fill(200);
  noStroke();
  textureMode(IMAGE); 
  textureMode(IMAGE);
  rotateY(a*2);
  rotateX(radians(-23));
  rotateY(radians(-23));
  rotateX(1/2*PI);
  a += 0.01;
  renderUniverse();
  renderGlobe(); 
  
}

void renderUniverse () {
  textureMode (IMAGE);
  texturedSphere(universeRadius, bg);
}

void renderGlobe() {
  textureMode(IMAGE);
  texturedSphere(globeRadius, texmap);
 
}




void initializeSphere(int res)
{
  sinLUT = new float[SINCOS_LENGTH];
  cosLUT = new float[SINCOS_LENGTH];

  for (int i = 0; i < SINCOS_LENGTH; i++) {
    sinLUT[i] = (float) Math.sin(i * DEG_TO_RAD * SINCOS_PRECISION);
    cosLUT[i] = (float) Math.cos(i * DEG_TO_RAD * SINCOS_PRECISION);
  }

  float delta = (float)SINCOS_LENGTH/res;
  float[] cx = new float[res];
  float[] cz = new float[res];
  
  // Calc unit circle in XZ plane
  for (int i = 0; i < res; i++) {
    cx[i] = -cosLUT[(int) (i*delta) % SINCOS_LENGTH];
    cz[i] = sinLUT[(int) (i*delta) % SINCOS_LENGTH];
  }
  
  // Computing vertexlist vertexlist starts at south pole
  int vertCount = res * (res-1) + 2;
  int currVert = 0;
  
  // Re-init arrays to store vertices
  sphereX = new float[vertCount];
  sphereY = new float[vertCount];
  sphereZ = new float[vertCount];
  float angle_step = (SINCOS_LENGTH*0.5f)/res;
  float angle = angle_step;
  
  // Step along Y axis
  for (int i = 1; i < res; i++) {
    float curradius = sinLUT[(int) angle % SINCOS_LENGTH];
    float currY = -cosLUT[(int) angle % SINCOS_LENGTH];
    for (int j = 0; j < res; j++) {
      sphereX[currVert] = cx[j] * curradius;
      sphereY[currVert] = currY;
      sphereZ[currVert++] = cz[j] * curradius;
    }
    angle += angle_step;
  }
  sDetail = res;
}

// Generic routine to draw textured sphere
void texturedSphere(float r, PImage t) 
{
  int v1,v11,v2;
  r = (r + 240 ) * 0.33;
  beginShape(TRIANGLE_STRIP);
  texture(t);
  float iu=(float)(t.width-1)/(sDetail);
  float iv=(float)(t.height-1)/(sDetail);
  float u=0,v=iv;
  for (int i = 0; i < sDetail; i++) {
    vertex(0, -r, 0,u,0);
    vertex(sphereX[i]*r, sphereY[i]*r, sphereZ[i]*r, u, v);
    u+=iu;
  }
  vertex(0, -r, 0,u,0);
  vertex(sphereX[0]*r, sphereY[0]*r, sphereZ[0]*r, u, v);
  endShape();   
  
  // Middle rings
  int voff = 0;
  for(int i = 2; i < sDetail; i++) {
    v1=v11=voff;
    voff += sDetail;
    v2=voff;
    u=0;
    beginShape(TRIANGLE_STRIP);
    texture(t);
    for (int j = 0; j < sDetail; j++) {
      vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1++]*r, u, v);
      vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2++]*r, u, v+iv);
      u+=iu;
    }
  
    // Close each ring
    v1=v11;
    v2=voff;
    vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1]*r, u, v);
    vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v+iv);
    endShape();
    v+=iv;
  }
  u=0;
  
  // Add the northern cap
  beginShape(TRIANGLE_STRIP);
  texture(t);
  for (int i = 0; i < sDetail; i++) {
    v2 = voff + i;
    vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v);
    vertex(0, r, 0,u,v+iv);    
    u+=iu;
  }
  vertex(sphereX[voff]*r, sphereY[voff]*r, sphereZ[voff]*r, u, v);
  endShape();
  
}

ceci est la premiere partie de mon travail. Dans un second temps ; pour une explication complete, je souhaite que la vitesse de rotation du globe fluctue selon les variations de battement cardiaque. mais ceci sera une autre etape que j'espere pouvoir resoudre.

je vous remercie d'avance.

Fred.

fdrg — 2009-11-17 10:03:03

En fait, apres réflexion, je crois que mon probleme se trouve etre une question de classe à creer! mais ouha, je ne comprends pas bien comment l'integrer dans ce sketch. est-il possible de creer une classe avec PImage?

si quelqu'un peut me venir en aide je le remercie d'avance.

emoc — 2009-11-17 15:05:10

Bonjour et bienvenue,

Je ne suis pas bien sûr d'avoir compris ton problème, mais j'ai fait un essai en remplaçant size(1440, 900, OPENGL); par size(600, 400, OPENGL); et translate(width/2, height/2); par translate(width, height); et les objets ont l'air correctement placés, évidemment je n'ai pas les images que tu utilises en texture, donc j'ai pris ce que j'avais sous la main.
Est ce que ce ne serait pas plutot un problème de placement de caméra dans l'espace, que tu ne définis pas?

fdrg — 2009-11-17 18:24:31

Bonsoir, et un grand merci!!

Effectivement le problème était un placement de camera, problème que j'ai maintenant compris. Finalement je n'ai changé que les valeurs float universeRadius = 2000; puisque je tiens à ce que float globeRadius soit au centre et que float universeRadius tourne sur ce même centre.
Par contre je ne sais pas si j'en demande trop, mais j'aimerais réellement comprendre et réussir à faire mon premier sketch conséquent.

Je m'explique, maintenant que tout cela fonctionne, je voudrai savoir s'il est possible en créant deux classes différentes de faire tourner mes deux objets à vitesse différentes en sachant que la variation de la vitesse de globeRadius sera contrôler par un cardiofrequencemetre et que celle de universeRadius restera constante.
Ou je me demande s'il ne faut pas que je créer un newrotateY. quelle serait la chose la plus logique?

merci encore.

emoc — 2009-11-18 10:18:56

fdrg a écrit:

je voudrai savoir s'il est possible en créant deux classes différentes de faire tourner mes deux objets à vitesse différentes en sachant que la variation de la vitesse de globeRadius sera contrôler par un cardiofrequencemetre et que celle de universeRadius restera constante.
Ou je me demande s'il ne faut pas que je créer un newrotateY. quelle serait la chose la plus logique?

En utilisant le sketch tel qu'il est, tu peux très bien modifier les deux vitesses de rotation indépendamment, en créant une variable pour chacune (float a, b; plutot que float a; ), ces variables sont modifiées en fonction des données de tes capteurs. Pour faire tourner les objets indépendamment, une structure comme ça dans le draw() fera l'affaire :

  a += 0.01;
  b += 0.05
  rotateY(a);
  renderUniverse();
  rotateY(b);
  renderGlobe();

Voila pour la solution minimum, tu peux aussi créer des classes et inclure les coordonnées de position, rotation dans les instances d'objet, mais ce serait surtout utile si tu multipliais les globes, et ça t'oblige à refondre tout le code.

22_79 — 2009-11-18 11:50:03

Salut fdrg,

Pour compléter un peu emoc,
Créer deux classes pour donner deux vitesses différentes, c'est un peu comme sortir un bazooka pour tuer une guêpe.
La classe correspond à un type  ... l'objet générique Voiture est une classe par ex.
Tu peux ainsi imaginer deux objets voitures de la classe Voiture qui aillent à des vitesses différentes

Je n'ai pas regardé ton code en détail, mais dans ton cas, il me semble que tout tes objets doivent être de la même classe ... mettons ElementSpatial ... seulement, ils ne seront pas initialisés avec la même vitesse ou la même position par ex.

class ElementSpatial {

  PImage texture;
  float vitesseRot;
  Vector3D position;

...

  ElementSpatial(PImage texture, float vitesseRot, Vector3D postion){
    this.texture = texture;
   ...
  }

}

fdrg — 2009-11-18 18:00:40

Bonsoir,

et bien merci encore une fois. j'ai bien pris note de vos conseils et pour l'instant je vais tenter de rester dans le simple et me concentrer sur un seul globe. Je pense qu'il vaut mieux que je reste dans la simplicité plutot que de me lancer dans une chose trop complexe qui perdrait son sens premier. Par contre j'attends que mes capteurs arrivent et je ferai quelques test.
Je vous communiquerai l'avancée de tout cela si cela ne vous ennuie pas.

emoc — 2009-11-18 18:46:43

Oui, tiens nous au courant de tes avancées

fdrg — 2009-11-23 15:17:23

Bonjour,



me voilà à nouveau par là!!
bon mon cardiofrequencemètre est bien arrivé et après quelques bidouilles j'arrive à avoir un signal, faible mais il est bien là. Cela reste pourtant encore à travailler.

Mon souci actuel est de faire communiquer Arduino avec Processing. Pour l'instant je n'utilise qu'un potentiomètre réglable pour faire varier la vitesse de rotation de mon globe. Le seul hic, c'est qu'il tourne à toute vitesse et changer la valeur du potar n'affecte en rien la vitesse de rotation.

j'ai essaye avec ce code :

Code (processing) :

import processing.serial.*;

Serial myPort;  // Create object from Serial class
float val;      // Data received from the serial port




import processing.opengl.*;
PImage bg ;
PImage texmap;

float globeRadius = 450;
float universeRadius = 2000;
float[] cx, cz, sphereX, sphereY, sphereZ;
float sinLUT[];
float cosLUT[];
float SINCOS_PRECISION = 0.5;
int SINCOS_LENGTH = int(360.0 / SINCOS_PRECISION);
float a, b ;
int sDetail = 35; 


void setup() {
  size(1440, 800, OPENGL);  
  bg = loadImage("tuto_h16_5-698da.jpg");
  initializeSphere(sDetail);
  texmap = loadImage("carte_monde.jpg");    
  initializeSphere(sDetail);
  
  
  
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600);
  
}

void draw() {
  background(0);
  translate(width/2, height/2);
  pushMatrix();
  noFill();
  stroke(255,200);
  strokeWeight(2);
  smooth();
  popMatrix();
  specular(0, 0, 0);
  fill(200);
  noStroke();
  textureMode(IMAGE); 
  textureMode(IMAGE);
  rotateY(a*2);
  rotateX(radians(-23));
  rotateY(radians(-23));
  rotateX(1/2*PI);
  a += 0.01;
  b += val;
  renderUniverse();
  rotateY(b);
  renderGlobe(); 
  
    if ( myPort.available() > 0) {  // If data is available,
    val = myPort.read();         // read it and store it in val
    }
}

void renderUniverse () {
  textureMode (IMAGE);
  texturedSphere(universeRadius, bg);
}

void renderGlobe() {
  textureMode(IMAGE);
  texturedSphere(globeRadius, texmap);
 
}




void initializeSphere(int res)
{
  sinLUT = new float[SINCOS_LENGTH];
  cosLUT = new float[SINCOS_LENGTH];

  for (int i = 0; i < SINCOS_LENGTH; i++) {
    sinLUT[i] = (float) Math.sin(i * DEG_TO_RAD * SINCOS_PRECISION);
    cosLUT[i] = (float) Math.cos(i * DEG_TO_RAD * SINCOS_PRECISION);
  }

  float delta = (float)SINCOS_LENGTH/res;
  float[] cx = new float[res];
  float[] cz = new float[res];
  
  // Calc unit circle in XZ plane
  for (int i = 0; i < res; i++) {
    cx[i] = -cosLUT[(int) (i*delta) % SINCOS_LENGTH];
    cz[i] = sinLUT[(int) (i*delta) % SINCOS_LENGTH];
  }
  
  // Computing vertexlist vertexlist starts at south pole
  int vertCount = res * (res-1) + 2;
  int currVert = 0;
  
  // Re-init arrays to store vertices
  sphereX = new float[vertCount];
  sphereY = new float[vertCount];
  sphereZ = new float[vertCount];
  float angle_step = (SINCOS_LENGTH*0.5f)/res;
  float angle = angle_step;
  
  // Step along Y axis
  for (int i = 1; i < res; i++) {
    float curradius = sinLUT[(int) angle % SINCOS_LENGTH];
    float currY = -cosLUT[(int) angle % SINCOS_LENGTH];
    for (int j = 0; j < res; j++) {
      sphereX[currVert] = cx[j] * curradius;
      sphereY[currVert] = currY;
      sphereZ[currVert++] = cz[j] * curradius;
    }
    angle += angle_step;
  }
  sDetail = res;
}

// Generic routine to draw textured sphere
void texturedSphere(float r, PImage t) 
{
  int v1,v11,v2;
  r = (r + 240 ) * 0.33;
  beginShape(TRIANGLE_STRIP);
  texture(t);
  float iu=(float)(t.width-1)/(sDetail);
  float iv=(float)(t.height-1)/(sDetail);
  float u=0,v=iv;
  for (int i = 0; i < sDetail; i++) {
    vertex(0, -r, 0,u,0);
    vertex(sphereX[i]*r, sphereY[i]*r, sphereZ[i]*r, u, v);
    u+=iu;
  }
  vertex(0, -r, 0,u,0);
  vertex(sphereX[0]*r, sphereY[0]*r, sphereZ[0]*r, u, v);
  endShape();   
  
  // Middle rings
  int voff = 0;
  for(int i = 2; i < sDetail; i++) {
    v1=v11=voff;
    voff += sDetail;
    v2=voff;
    u=0;
    beginShape(TRIANGLE_STRIP);
    texture(t);
    for (int j = 0; j < sDetail; j++) {
      vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1++]*r, u, v);
      vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2++]*r, u, v+iv);
      u+=iu;
    }
  
    // Close each ring
    v1=v11;
    v2=voff;
    vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1]*r, u, v);
    vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v+iv);
    endShape();
    v+=iv;
  }
  u=0;
  
  // Add the northern cap
  beginShape(TRIANGLE_STRIP);
  texture(t);
  for (int i = 0; i < sDetail; i++) {
    v2 = voff + i;
    vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v);
    vertex(0, r, 0,u,v+iv);    
    u+=iu;
  }
  vertex(sphereX[voff]*r, sphereY[voff]*r, sphereZ[voff]*r, u, v);
  endShape();
  
}

et rien....

mais aussi avec la base de ce code:

Code (processing) :

import processing.serial.*;

Serial myPort;        // The serial port
int yPos = 1;         // horizontal position of the graph

void setup () {
  size( 400, 300);
  // List all the available serial ports
  println(Serial.list());
  // I know that the first port in the serial list on my mac
  // is always my  Arduino, so I open Serial.list()[0].
  // Open whatever port is the one you're using.
  myPort = new Serial(this, Serial.list()[0], 9600);
  // don't generate a serialEvent() unless you get a newline character:
  myPort.bufferUntil('\n');
  // set inital background:
  background(0);
}
void draw () {
  // everything happens in the serialEvent()
}

void serialEvent (Serial myPort) {
  // get the ASCII string:
  String inString = myPort.readStringUntil('\n');

  if (inString != null) {
    // trim off any whitespace:
    inString = trim(inString);
    // convert to an int and map to the screen height:
    float inByte = float(inString); 
    inByte = map(inByte, 0, 1023, 0, height);

    // draw the line:
    stroke(127,34,255);
    line(yPos, height, yPos, height - inByte);

    // at the edge of the screen, go back to the beginning:
    if (yPos >= width) {
      yPos = 0;
      background(0); 
    } 
    else {
      // increment the horizontal position:
      yPos++;
    }
  }
}

et rien non plus.


j'utilise le code suivant pour Arduino:

void setup() {
   // initialize the serial communication:
   Serial.begin(9600);
 }

 void loop() {
   // send the value of analog input 0:
   Serial.println(analogRead(0));
   // wait a bit for the analog-to-digital converter 
   // to stabilize after the last reading:
   delay(10);
 }

j'avoue que je ne n'arrive pas à comprendre pourquoi cela ne fonctionne pas, mais je continu à potasser!

emoc — 2009-11-24 09:23:21

fdrg a écrit:

Le seul hic, c'est qu'il tourne à toute vitesse et changer la valeur du potar n'affecte en rien la vitesse de rotation.

C'est normal, Arduino envoie la valeur du potentiomètre en permanence (toutes les 10 millisecondes, en fait). Processing reçoit donc de nouvelles données en permanence, et comme ta boucle draw se répète aussi vite que le permet ta machine, à chaque rafraichissement b += val; et ton globe tourne de plus en plus vite.

Plutot que b += val; essaie b = val; ou b = val / 100; :)


ps : Pour que la balise [ code ] [ / code ] fonctionne, il faut placer le code entre les deux. Tu peux aussi utiliser [ code = processing ] pour appliquer une coloration syntaxique.

fdrg — 2009-11-24 11:22:39

en fait en utilisant que se soit b = val, b = val/100 ou autre le globe saccade à present. je suis paumé...

est-ce que la fonction map() ne me serait pas utile afin de definir des tours de rotation par tranche de 10 par exemple pour les données du potar ?

par contre j'ai retirer cela : if ( myPort.available() > 0) puisque je souhaite que le globe tourne à une vitesse constante lorsque qu'aucune données n'est envoyées.

Autre question, lorsque je vais faire mes test avec le cardiofrequencemetre, est-ce que Arduino le considère bien comme une donnée numérique ?

je ferais attention lors de mes prochaines publications quant à l'introduction des codes.

merci.

emoc — 2009-11-24 15:10:51

Je ne sais pas trop ou tu en es dans ton code, renvoie peut-être une version actualisée.
Il faudrait que tu définisses comment le capteur influe sur la rotation : il ajoute une accélération ? Ca te permettra de traiter les valeurs numériques avant de modifier la rotation.

Sinon avec ton potentiomètre tu peux essayer b += val / 10000; ça devrait le faire tourner beaucoup plus doucement! Ton potentiomètre renvoie quelle écart de valeurs numériques, entre 0 et 1024 ? Si c'est le cas, tu peux par exemple enlever 512 à cette valeur avant de l'ajouter à b (la vitesse de rotation du globe, comme ça selon la position du potentiomètre cela donnera une vitesse positive ou négative)

Pour le cardiofréquencemètre, qu'est ce que c'est ? Un capteur de quel type ? Un lien serait bienvenu :)

fdrg — 2009-11-24 17:38:17

En fait oui je cherche à ajouter une accélération à la vitesse de rotation du globe par le potentiomètre dans un premier temps pour pouvoir comprendre se qui se passe, puis par le cardiofrequencemetre ensuite. Cela sera la vitesse du rythme cardiaque qui va commander la vitesse de rotation du globe. Voilà un lien pour le cardiofrequencemetre : http://www.ecole-art-aix.fr/article2963.html

Sinon voilà ou j'en suis dans le code :

Code (processing) :

import processing.serial.*;

Serial myPort;  // Create object from Serial class
float val;      // Data received from the serial port




import processing.opengl.*;
PImage bg ;
PImage texmap;

float globeRadius = 450;
float universeRadius = 2000;
float[] cx, cz, sphereX, sphereY, sphereZ;
float sinLUT[];
float cosLUT[];
float SINCOS_PRECISION = 0.5;
int SINCOS_LENGTH = int(360.0 / SINCOS_PRECISION);
float a, b ;
int sDetail = 35; 


void setup() {
  size(1440, 800, OPENGL);  
  bg = loadImage("tuto_h16_5-698da.jpg");
  initializeSphere(sDetail);
  texmap = loadImage("carte_monde.jpg");    
  initializeSphere(sDetail);
  
  
  
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600);
  
}

void draw() {
  background(0);
  translate(width/2, height/2);
  pushMatrix();
  noFill();
  stroke(255,200);
  strokeWeight(2);
  smooth();
  popMatrix();
  specular(0, 0, 0);
  fill(200);
  noStroke();
  textureMode(IMAGE); 
  textureMode(IMAGE);
  rotateY(a*2);
  rotateX(radians(-23));
  rotateY(radians(-23));
  rotateX(1/2*PI);
  a += 0.01;
  b = val;
  renderUniverse();
  rotateY(b);
  renderGlobe(); 
  
    if ( myPort.available() > 0) {  // If data is available,
    val = myPort.read();         // read it and store it in val
    }
}

void renderUniverse () {
  textureMode (IMAGE);
  texturedSphere(universeRadius, bg);
}

void renderGlobe() {
  textureMode(IMAGE);
  texturedSphere(globeRadius, texmap);
 
}




void initializeSphere(int res)
{
  sinLUT = new float[SINCOS_LENGTH];
  cosLUT = new float[SINCOS_LENGTH];

  for (int i = 0; i < SINCOS_LENGTH; i++) {
    sinLUT[i] = (float) Math.sin(i * DEG_TO_RAD * SINCOS_PRECISION);
    cosLUT[i] = (float) Math.cos(i * DEG_TO_RAD * SINCOS_PRECISION);
  }

  float delta = (float)SINCOS_LENGTH/res;
  float[] cx = new float[res];
  float[] cz = new float[res];
  
  // Calc unit circle in XZ plane
  for (int i = 0; i < res; i++) {
    cx[i] = -cosLUT[(int) (i*delta) % SINCOS_LENGTH];
    cz[i] = sinLUT[(int) (i*delta) % SINCOS_LENGTH];
  }
  
  // Computing vertexlist vertexlist starts at south pole
  int vertCount = res * (res-1) + 2;
  int currVert = 0;
  
  // Re-init arrays to store vertices
  sphereX = new float[vertCount];
  sphereY = new float[vertCount];
  sphereZ = new float[vertCount];
  float angle_step = (SINCOS_LENGTH*0.5f)/res;
  float angle = angle_step;
  
  // Step along Y axis
  for (int i = 1; i < res; i++) {
    float curradius = sinLUT[(int) angle % SINCOS_LENGTH];
    float currY = -cosLUT[(int) angle % SINCOS_LENGTH];
    for (int j = 0; j < res; j++) {
      sphereX[currVert] = cx[j] * curradius;
      sphereY[currVert] = currY;
      sphereZ[currVert++] = cz[j] * curradius;
    }
    angle += angle_step;
  }
  sDetail = res;
}

// Generic routine to draw textured sphere
void texturedSphere(float r, PImage t) 
{
  int v1,v11,v2;
  r = (r + 240 ) * 0.33;
  beginShape(TRIANGLE_STRIP);
  texture(t);
  float iu=(float)(t.width-1)/(sDetail);
  float iv=(float)(t.height-1)/(sDetail);
  float u=0,v=iv;
  for (int i = 0; i < sDetail; i++) {
    vertex(0, -r, 0,u,0);
    vertex(sphereX[i]*r, sphereY[i]*r, sphereZ[i]*r, u, v);
    u+=iu;
  }
  vertex(0, -r, 0,u,0);
  vertex(sphereX[0]*r, sphereY[0]*r, sphereZ[0]*r, u, v);
  endShape();   
  
  // Middle rings
  int voff = 0;
  for(int i = 2; i < sDetail; i++) {
    v1=v11=voff;
    voff += sDetail;
    v2=voff;
    u=0;
    beginShape(TRIANGLE_STRIP);
    texture(t);
    for (int j = 0; j < sDetail; j++) {
      vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1++]*r, u, v);
      vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2++]*r, u, v+iv);
      u+=iu;
    }
  
    // Close each ring
    v1=v11;
    v2=voff;
    vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1]*r, u, v);
    vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v+iv);
    endShape();
    v+=iv;
  }
  u=0;
  
  // Add the northern cap
  beginShape(TRIANGLE_STRIP);
  texture(t);
  for (int i = 0; i < sDetail; i++) {
    v2 = voff + i;
    vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v);
    vertex(0, r, 0,u,v+iv);    
    u+=iu;
  }
  vertex(sphereX[voff]*r, sphereY[voff]*r, sphereZ[voff]*r, u, v);
  endShape();
}
emoc — 2009-11-25 20:57:21

Hello,

J'ai jeté un oeil sur la page du cardio-fréquencemètre, si je comprends bien il envoie une pulsation sonore pour chaque pulsation cardiaque, il va falloir que tu retrouves le BPM à partir de ces pulsations, et te baser sur un rythme moyen pour en évaluer les variations, soit c'est le programme arduino qui s'en occupe, soit c'est processing. C'est assez différent du fonctionnement d'un potentiomètre qui envoie chaque fois qu'on lui demande sa valeur de résistance. Est ce que tu as essayé d'utiliser le potentiomètre en lui fixant une valeur moyenne (voir 2 messages plus haut...) ?

fdrg — 2009-11-26 10:33:32

Salut,

en fait je ne me sers pas du cardiofrequencemetre comme la personne sur la page. Je ne souhaite pas récupérer de signal sonore mais simplement les variations électriques que le rythme cardiaque produit pour faire varier la vitesse de mon globe. Au final j'espère que mon globe tourne, par exemple à 60trs/min lorsque les bpm son à 60 et ainsi de suite. Voilà un autre lien mais cette fois-ci la personne utilise Pure Data : http://www.gael-l.com/index.php/92/quan … fait-boum/

Du coup je souhaite tout d'abord utiliser un potentiomètre pour bien comprendre le fonctionnement de l'acquisition de données de Arduino et leurs traitement par Processing. Par contre je n'ai pas réussi à faire fonctionner mon code en fixant une valeur moyenne au potentiomètre, je crois que je n'ai pas tout compris....
Par contre mon potentiomètre envoi un écart de valeurs numériques entre 0 et 1023.

Je continu à chercher des solutions qui j'espère vont fonctionner.

merci de ton aide.

emoc — 2009-11-27 13:43:44

Salut,

J'ai modifié ton code. Le potentiomètre permet de régler un battement cardiaque entre 60 et 180, et modifie la vitesse de rotation du globe, j'ai simplifié le draw() ou il y avait plusieurs choses inutiles. Cette ligne est importante : b += 0.01 + (battement - 60) / 300; c'est ce qui définit la vitesse de rotation du globe. J'ai aussi changé les textures car je n'ai pas tes images, il faut que tu remettes les tiennes...

Code (processing) :

import processing.serial.*;

Serial myPort;  // Create object from Serial class
float val;      // Data received from the serial port

import processing.opengl.*;
PImage bg ;
PImage texmap;

float globeRadius = 450;
float universeRadius = 2000;
float[] cx, cz, sphereX, sphereY, sphereZ;
float sinLUT[];
float cosLUT[];
float SINCOS_PRECISION = 0.5;
int SINCOS_LENGTH = int(360.0 / SINCOS_PRECISION);
float a, b ;
int sDetail = 35; 
float battement = 80;

void setup() {
  size(1440, 800, OPENGL);  
  bg = loadImage("img1.jpg");
  initializeSphere(sDetail);
  texmap = loadImage("img2.jpg");    
  initializeSphere(sDetail);
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600); 
}

void draw() {
  background(0);
  translate(width/2, height/2);
  smooth();
  specular(0, 0, 0);
  noStroke();

  // rotation de l'univers
  pushMatrix();
  a += 0.01;
  rotateY(a*2);
  rotateX(1 / TWO_PI);
  renderUniverse();
  popMatrix();
  
  // rotation du globe 
  pushMatrix();
  if ( myPort.available() > 0) {  // If data is available,
    val = myPort.read();         // read it and store it in val
    battement = map(val, 0, 1023, 60, 180);
  }
  b += 0.01 + (battement - 60) / 300;
  rotateY(b);
  renderGlobe(); 
  popMatrix();
}

void renderUniverse () {
  textureMode (IMAGE);
  texturedSphere(universeRadius, bg);
}

void renderGlobe() {
  textureMode(IMAGE);
  texturedSphere(globeRadius, texmap);
 
}

void keyPressed() {
  if (key == '+') battement ++;
  if (key == '-') battement --;
  if (key == 'p') println("battement : " + battement);
}



void initializeSphere(int res)
{
  sinLUT = new float[SINCOS_LENGTH];
  cosLUT = new float[SINCOS_LENGTH];

  for (int i = 0; i < SINCOS_LENGTH; i++) {
    sinLUT[i] = (float) Math.sin(i * DEG_TO_RAD * SINCOS_PRECISION);
    cosLUT[i] = (float) Math.cos(i * DEG_TO_RAD * SINCOS_PRECISION);
  }

  float delta = (float)SINCOS_LENGTH/res;
  float[] cx = new float[res];
  float[] cz = new float[res];
  
  // Calc unit circle in XZ plane
  for (int i = 0; i < res; i++) {
    cx[i] = -cosLUT[(int) (i*delta) % SINCOS_LENGTH];
    cz[i] = sinLUT[(int) (i*delta) % SINCOS_LENGTH];
  }
  
  // Computing vertexlist vertexlist starts at south pole
  int vertCount = res * (res-1) + 2;
  int currVert = 0;
  
  // Re-init arrays to store vertices
  sphereX = new float[vertCount];
  sphereY = new float[vertCount];
  sphereZ = new float[vertCount];
  float angle_step = (SINCOS_LENGTH*0.5f)/res;
  float angle = angle_step;
  
  // Step along Y axis
  for (int i = 1; i < res; i++) {
    float curradius = sinLUT[(int) angle % SINCOS_LENGTH];
    float currY = -cosLUT[(int) angle % SINCOS_LENGTH];
    for (int j = 0; j < res; j++) {
      sphereX[currVert] = cx[j] * curradius;
      sphereY[currVert] = currY;
      sphereZ[currVert++] = cz[j] * curradius;
    }
    angle += angle_step;
  }
  sDetail = res;
}

// Generic routine to draw textured sphere
void texturedSphere(float r, PImage t) 
{
  int v1,v11,v2;
  r = (r + 240 ) * 0.33;
  beginShape(TRIANGLE_STRIP);
  texture(t);
  float iu=(float)(t.width-1)/(sDetail);
  float iv=(float)(t.height-1)/(sDetail);
  float u=0,v=iv;
  for (int i = 0; i < sDetail; i++) {
    vertex(0, -r, 0,u,0);
    vertex(sphereX[i]*r, sphereY[i]*r, sphereZ[i]*r, u, v);
    u+=iu;
  }
  vertex(0, -r, 0,u,0);
  vertex(sphereX[0]*r, sphereY[0]*r, sphereZ[0]*r, u, v);
  endShape();   
  
  // Middle rings
  int voff = 0;
  for(int i = 2; i < sDetail; i++) {
    v1=v11=voff;
    voff += sDetail;
    v2=voff;
    u=0;
    beginShape(TRIANGLE_STRIP);
    texture(t);
    for (int j = 0; j < sDetail; j++) {
      vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1++]*r, u, v);
      vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2++]*r, u, v+iv);
      u+=iu;
    }
  
    // Close each ring
    v1=v11;
    v2=voff;
    vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1]*r, u, v);
    vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v+iv);
    endShape();
    v+=iv;
  }
  u=0;
  
  // Add the northern cap
  beginShape(TRIANGLE_STRIP);
  texture(t);
  for (int i = 0; i < sDetail; i++) {
    v2 = voff + i;
    vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v);
    vertex(0, r, 0,u,v+iv);    
    u+=iu;
  }
  vertex(sphereX[voff]*r, sphereY[voff]*r, sphereZ[voff]*r, u, v);
  endShape();
}
fdrg — 2009-11-29 17:21:45

Salut,


j'ai bien étudier le code que tu m'a proposé et je n'arrive pas à tout comprendre. En fait mes valeurs de battements que j'ai ne varie qu'entre 60 et 65 lorsque je modifie la valeur potentiomètre, et je n'ai pas l'impression de voir accélérer ou décélérer la terre. Rien ne change non plus avec void keypressed ();, Cela dit println fonctionne. Je ne sais pas trop, est-ce qu'il est possible que mon programme Arduino ne soit pas adapté pour communiquer avec ce code dans Processing ? J'ai réglé la carte pour recevoir des info analogiques sur le port 0, faut-il que je serve des entrées numériques?

J'ai juste rajouté quelques données dans void draw(); comme rotateX(radians(-23));
  rotateY(radians(-23)); car je souhaite que le globe tourne avec ces angles de rotations, mais rien de très important.

emoc — 2009-12-01 19:31:51

fdrg a écrit:

En fait mes valeurs de battements que j'ai ne varie qu'entre 60 et 65 lorsque je modifie la valeur potentiomètre, et je n'ai pas l'impression de voir accélérer ou décélérer la terre.

C'est normal que tu ne vois pas grand chose changer entre 60 et 65, l'écart maximum est prévu entre 60 et 180, et donc avec une différence de 5, il ne se passe pas grand chose. Par contre, c'est bizarre que ton potentiomètre ne produise pas un écart plus important. Tu devrais tester les valeurs reçues avec un sketch très simple (juste recevoir les valeurs et les afficher en println), ça permettra de savoir s'il envoie bien des valeurs entre 0 et 1023

fdrg a écrit:

Rien ne change non plus avec void keypressed ();, Cela dit println fonctionne.

C'est normal qu'il ne se passe rien avec keypressed si ton potentiomètre est relié, les valeurs envoyées par arduino définissent le battement, en passant par dessus celles des touches. J'ai utilisé ça car je n'ai pas de potentiomètre / arduino relié, essaie le sketch sans le relier et tu pourras visualiser la "gamme" de vitesse en utilisant le clavier.

fdrg a écrit:

Je ne sais pas trop, est-ce qu'il est possible que mon programme Arduino ne soit pas adapté pour communiquer avec ce code dans Processing ? J'ai réglé la carte pour recevoir des info analogiques sur le port 0, faut-il que je serve des entrées numériques?

Oui c'est logique, le potentiomètre est un composant analogique, par contre je ne peux pas savoir si ton programme arduino déconne, envoie le si tu veux, ou testes avec le sketch très simple comme je te propose plus haut, tu verras si les valeurs sont bien envoyées.

fdrg — 2009-12-11 17:36:15

Salut et merci de ta réponse.

Désolé de ne pas me manifester plus tôt mais les joies d'un master mon appelée à l'écriture théorique! Donc malheureusement pas trop le temps de potasser mon code...

j'ai quand même essayé avec seulement void keypressed  () et ca fonctionne parfaitement!
par contre je n'ai pas encore eu le temps de tester mon potentiomètre avec un code simple mais je vais m'y mettre.

voilà pour le code Arduino que j'utilise:

Code (processing) :

 void setup() {
   // initialize the serial communication:
   Serial.begin(9600);
 }

 void loop() {
   // send the value of analog input 0:
   Serial.println(analogRead(0));
   // wait a bit for the analog-to-digital converter 
   // to stabilize after the last reading:
   delay(10);
 }

je donnerai des nouvelles dès que possible
à bientôt

emoc — 2009-12-15 23:28:01

ok, à suivre donc... Mais il ne manque pas des trucs dans ton programme pour arduino, la définition du port d'entrée par exemple ?

fdrg — 2010-03-22 10:12:24

Bonjour à tous le monde!

voilà maintenant bien longtemps que je ne vous avais pas donner de nouvelles, mais la rédaction de mon mémoire me prends pas mal de temps...

Par contre j'ai quand même pu avancer dans mon programme que je tente de mettre en place.  A ce sujet j'ai enfin réussi à faire correctement dialoguer mon capteur cardiaque et Processing grâce à Firmata standard chargé sur ma carte Arduino.

Maintenant il s'avère qu'un cardio-fréquencemètre n'est pas vraiment très précis, je vais donc tenter d'acquérir un oxymètre qui apparemment le serait plus, et vous tiendrais au courant.

Voilà le code Processing que j'ai obtenu, si quelqu'un avait des suggestion sur celui-ci, je suis preneur.

Code (processing) :

Par contre je rencontre encore un petit souci qui est que mon globe tourne à présent dans un sens puis dans l'autre. Je pense que c'est du à la polarité, mais je n'ai pas d'idée pour modifier cela dans mon code afin que l' globe ne tourne plus que dans un sens. Est-ce possible?

Je vous remercie.
A bientôt.

emoc — 2010-03-23 17:38:55

Salut,

c'est la variable 'b' qui définit la rotation du globe, quelles sont ses valeurs ? Pour le savoir rajoute

println("b : " + b);

avant rotateY(b);

Tu peux copier coller les résultats ici, ça devrait permettre de comprendre pourquoi ton globe tourne comme ça

fdrg — 2010-03-23 20:38:38

Salut et merci Emoc,


j'ai rajouté ce que tu m'a conseiller dans le programme et voilà ce que j'obtiens en quelque secondes:
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 17.576666
b : 19.201666
b : 20.014166
b : 21.139166
b : 21.514166
b : 21.951666
b : 21.889166
b : 21.701666
b : 21.201666
b : 20.764166
b : 19.326666
b : 17.389166
b : 15.514167
b : 14.639167
b : 12.951667
b : 12.326667
b : 10.764167
b : 10.014167
b : 8.639167
b : 8.139167
b : 7.3891664
b : 6.8266673
b : 6.639167
b : 6.8266673
b : 7.014167
b : 8.139167
b : 8.639167
b : 9.826667
b : 10.764167
b : 12.389166
b : 13.201667
b : 14.514167
b : 15.201666
b : 15.326667


Je ne comprends pas vraiment pourquoi les valeurs augmentent puis diminues.
J'imagine que ma ligne de code d'incrémentation pour la valeur b ; soit celle de la rotation du globe n'est pas correct.  Par contre je ne sais pas non plus pourquoi le globe tourne alternativement dans un sens puis dans un autre.
j'avoue que je suis un peu perdu...

emoc — 2010-03-23 21:55:56

b correspond à l'angle de rotation Y, il est mis à jour à chaque passage dans draw(), c'est à dire selon le framerate (que tu ne définis pas, donc "aussi vite que possible"), donc l'angle est renouvelé à chaque fois
b est un angle en radians donc entre 0 et 2 x PI (env. 6.28) , par exemple quand b vaut 19.20 la rotation appliquée est de + de 3 tours! La variation de rotation est très importante, vu la liste de valeurs que tu as posté. Je pense que l'effet de rotation inverse est du à ça, c'est le même phénomène quand tu vois une roue de vélo filmée, tu peux avoir l'impression qu'elle va à l'envers mais en fait c'est qu'elle fait un tout petit moins qu'un tour complet et c'est ce moment qui est impressionné sur la pellicule.

Dans ton code b est défini par la valeur venant d'arduino puis modifié dans un 2e temps par la variable 'battement' (ce qui n'a plus d'intérêt dans ton nouveau code) Cette ligne d'incrémentation ne sert pas à grand chose, elle rajoute toujours la même valeur (0.076666...) puisque 'battement' est constant.

Il faut que tu arrives à bien comprendre ce qui sort brut de l'arduino pour voir comment tu 'mappes' ces valeurs, pour avoir une rotation correcte, là je ne comprends pas trop pourquoi tu divises la valeur d'arduino par la largeur de l'image pour ensuite remultiplier par 90 ?

Connais tu les valeurs brutes qui sortent d'arduino? (c'est à dire, ce qu'envoie ton capteur) Avec ça on pourrait probablement y arriver :)

fdrg — 2010-03-24 13:45:09

Merci Emoc.

En fait lorsque j'essaye de voir se qu'il se passe dans arduino et le moniteur série ne m'indique que ü. Bizarre.

Par contre j'ai changé cette ligne de code float b = arduino.analogRead(0);

à présent le globe tourne à toute vitesse.

j'obtiens ces résultats avec println()
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 0.07666667
b : 208.07666
b : 206.07666
b : 270.07666
b : 283.07666
b : 214.07666
b : 138.07666
b : 118.07667
b : 111.07667
b : 101.07667
b : 94.07667
b : 93.07667
b : 95.07667
b : 105.07667
b : 117.07667
b : 137.07666

ils ont l'air toujours aussi instables mais plus élevés.
Du coup je ne sais pas trop comment faire pour avoir les données que Arduino reçois directement

emoc — 2010-03-24 14:15:47

fdrg a écrit:

à présent le globe tourne à toute vitesse.

C'est normal, au vu des valeurs pour des angles en radians

fdrg a écrit:

Du coup je ne sais pas trop comment faire pour avoir les données que Arduino reçois directement

A priori, à chaque passage dans draw, la valeur est lue directement sur l'entrée analogique de l'arduino, donc ce sont les valeurs qui viennent du capteur. D'ailleurs que capte réellement ce capteur et que signifient ces valeurs? Dans le petit extrait que tu donnes, on voit bien que ça dessine une courbe avec un pic à 283 puis ça descend et ça remonte.

A ta place, je ferais un graphique des valeurs reçues par le capteur (en Y) dans le temps (en X), ça te permettra de comprendre comment il fonctionne et de voir à partir de ça comment en déduire la pulsation cardiaque.

fdrg — 2010-03-24 15:32:11

Et bien mon capteur est un cardio-fréquencemètre et capte le rythme cardiaque de mon coeur via une ceinture thoracique. Maintenant je me demande si l'utilisation d'un oxymètre que l'on placerait sur un doigt ne serait pas plus précise.

Par contre je n'arrive pas à réaliser un code correcte pour faire un graphique... le voici:

Code (processing) :

En fait je ne sais pas comment faire pour que String inString interagisse par rapport à Arduino. J'ai pas mal de chose à apprendre encore!

emoc — 2010-03-24 15:56:38

fdrg a écrit:

Et bien mon capteur est un cardio-fréquencemètre et capte le rythme cardiaque de mon coeur via une ceinture thoracique.

Oui oui, mais que transmet il ? Ce que je veux dire, c'est que je pense que le capteur permet de retrouver la pulsation cardiaque mais qu'il ne transmet pas directement la pulsation. Ce que tu veux obtenir, c'est la pulsation, 90 par exemple, si le capteur transmettait ça, 'b' oscillerait autour de 90 (une fois quelques secondes passées pour obtenir la première valeur). Mais, au vu des valeurs, ça ne marche pas comme ça :)

Qu'est ce qui ne marche pas dans ton code? (je n'ai pas d'arduino branché) rien ne s'affiche ? tu as des erreurs ?

fdrg — 2010-03-24 16:59:58

Je comprends mieux ta question. En fait se que je capte du cardio-fréquencemètre c'est un signal électrique qui varie à peu près entre 0 et 0,2 volt au voltmètre (mon matos est un peu vieux donc pas vraiment précis je pense).

En fait je cherche exactement à capter la pulsation pour faire varier "b", donc la vitesse de rotation du globe. Mais j'ai apparemment du boulot pour obtenir ca.

Pour mon code de graphique j'ai l'erreur me disant qu'il ne peut pas convertir int vers String.

emoc — 2010-03-24 17:28:48

fdrg a écrit:

Mais j'ai apparemment du boulot pour obtenir ca.

Pour mon code de graphique j'ai l'erreur me disant qu'il ne peut pas convertir int vers String.

Oui, il y a un traitement à appliquer pour extraire la pulsation de ce signal.
Sinon, pour le code du graphique, arduino doit renvoyer un 'int' plutot qu'un 'string', donc pas besoin de traiter comme une chaine de caractère, l'exemple sur lequel tu te bases doit être adapté, déjà remplace

String inString = arduino.analogRead(0) ;

par

int inInt = arduino.analogRead(0) ;

et adapte la suite avec cette nouvelle variable (tu peux aussi enlever la ligne avec trim)

fdrg — 2010-03-25 15:38:48

Ok merci,


il faudrait donc en fait que j'établisse un rapport entre le signal électrique d'entré et un rythme de rotation. Par exemple entre 0 0.05v, un battement de 60, 0.10v, 70 etc. Puis pour chaque rythme une vitesse de rotation du globe adapté à Processing. Il y à du taf!!

Sinon pour le code du graphique j'ai modifié ce que tu m'a dit mais il y a un autre code d'erreur : me disant que != n'est pas défini pour l'argument int, null. Voilà le code que j'ai modifié :

Code (processing) :

emoc — 2010-03-25 15:48:37

fdrg a écrit:

il faudrait donc en fait que j'établisse un rapport entre le signal électrique d'entré et un rythme de rotation. Par exemple entre 0 0.05v, un battement de 60, 0.10v, 70 etc. Puis pour chaque rythme une vitesse de rotation du globe adapté à Processing. Il y à du taf!!

Non, je ne crois pas que ça suffise, le niveau électrique ne renvoie pas la pulsation, la correspondance ne peut pas être établie comme ça, tu devrais y voir plus clair avec le graphique

fdrg a écrit:

Sinon pour le code du graphique j'ai modifié ce que tu m'a dit mais il y a un autre code d'erreur : me disant que != n'est pas défini pour l'argument int, null. Voilà le code que j'ai modifié :

Essaie d'enlever le test (if (inInt != null)), inutile maitenant que ce n'est plus une string

fdrg — 2010-03-29 15:51:06

Salut,

j'ai enlevé (if (inInt != null)) mais je me trouve avec une autre erreur : Error inside Serial.<init>()

j'ai donc modifié le code comme ceci :

Code (processing) :

Mais à ma grande déception il ne se passe rien dans le graphique. Là je suis franchement perdu.

Je continu de chercher par contre un moyen de récupérer et de pouvoir traiter le signal que m'envoie le cardio-fréquencemètre, voir d'utilisé un autre capteur.

emoc — 2010-03-29 16:10:06

Enlever (if (inInt != null)) ok, mais il faut aussi que tu enlèves les crochets { et } (lignes 29 et 48) qui correspondaient au test if
Je ne sais pas si l'erreur vient de là mais ça m'étonnerait que ça puisse fonctionner en l'état...

fdrg — 2010-03-29 17:09:55

J'ai bien enlevé les deux crochets mais le problème persiste.
Je vais donc tenter de reprendre mon code depuis le début et essayé de trouver l'erreur.

fdrg — 2010-04-09 20:53:46

Salut,

ca y est!!! voilà un code qui fonctionne!!! Du moins avec un potentiomètre. J'arrive donc à régler la vitesse de rotation du globe selon la position du potar. Voici le code :

Code (processing) :

Bon maintenant il me reste à trouver le moyen de faire fonctionner cela avec un capteur cardiaque...