passare una variabile da arduino a processing [Risolto]

ciao a tutti ho un problema che devo risolvere a breve e sono disperato,
devo realizzare un miscelatore di liquidi che faccia entrare una certa quantità regolabile di due liquidi diversi per poi farli centrifugare per un determinato tempo ed infine scaricarli dalla centrifuga, il tutto gestito da arduino e visualizzato da processing, sono inchiodato o fatto i due listati, per arduino e processing, che da soli sembra funzionino, il problema nasce quando devo passare la variabile "stato" da arduino a processing, NON RIESCO A FARLO..... Vi prego aiutatemiiiiiiiii

il codice arduino:

int START;  //DICHIARO LA VARIABILE DI START INTERA
int T=2000;         //DICHIARO LA VARIABILE DI TEMPO PER LA ROTAZIONE E LE ASSEGNO 1 SECONDO
int T1;               //DICHIARO LA VARIABILE DI TEMPO INTERA PER L'APERTURA DELLA VALVOLA 1
int T2;              //DICHIARO LA VARIABILE DI TEMPO INTERA PER L'APERTURA DELLA VALVOLA 2
int stato=0;
int t;                 //VARIABILE CHE UTILIZZERO PER TEMPORIZARE LA ROTAZIONE
String valore;

void setup()
{
  Serial.begin(9600);
  pinMode(ST, INPUT);
  pinMode(P, INPUT);
  pinMode(LG, OUTPUT);
  pinMode(LR, OUTPUT);
  pinMode(LV, OUTPUT);
  pinMode(LM, OUTPUT);

}
/* MI CREO UN VOID PER LE TEMPORIZZAZIONI DELLE VALVOLE A CUI ASSEGNERO' I VALORI DEI TEMPI T1 PER LA PRIMA VALVOLA
 T2 PER LA SECONDA E LA LORO SOMMA PER LA TERZA*/
void ritardo(unsigned long ms)
{
  unsigned long tmp;
  tmp=millis();
  while((millis()-tmp)<= ms);
}

void loop() {


  switch (stato)
  {
    // FERMO TUTTO ED ASPETTO LA PRESSIONE DEL PULSANTE P
  case 0:
    valore="0";
    Serial.println(valore);
    delay(50);
    digitalWrite(LV,LOW);
    digitalWrite(LG,LOW);
    digitalWrite(LR,LOW);
    digitalWrite(LM,LOW);
    START=digitalRead(P); 
    if (START ==1)
    {
      stato=1;
    }
    break;

    //LEGGO IL VALORE DI LIQUIDO DA FAR ENTRARE DALLA PORTA ANALOGICA A0 ED APRO LA VALVOLA 1 PER IL TEMPO NECESSARIO
  case 1:
    valore="1";
    Serial.println(valore);
    delay(50);
    digitalWrite(LR,LOW);
    digitalWrite(LG,LOW);
    digitalWrite(LM,LOW);
    digitalWrite(LV,HIGH);
    T1=(analogRead(A0)*10);
    ritardo(T1);
    stato=2;
    break;

    /*CHIUDO LA VALVOLA 1, 
     LEGGO IL VALORE DI LIQUIDO DA FAR ENTRARE DALLA PORTA ANALOGICA A1 ED APRO LA VALVOLA 2 PER IL TEMPO NECESSARIO*/
  case 2:
    valore="2";
    Serial.println(valore);
    delay(50);
    digitalWrite(LR,LOW);
    digitalWrite(LG,HIGH);
    digitalWrite(LM,LOW);
    digitalWrite(LV,LOW);
    T2=(analogRead(A1)*10);
    ritardo(T2);
    t=millis();
    stato=3;
    break;

    //CHIUDO LA VALVOLA 2 E FACCIO PARTIRE LA CENTRIFUGA PER IL TEMPO IMPOSTATO IN "T"
  case 3:
    valore="3";
    Serial.println(valore);
    delay(50);
    digitalWrite(LV,LOW);
    digitalWrite(LG,LOW);
    digitalWrite(LR,LOW);

    if ((millis()-t)<= T)
    { 
      digitalWrite(LM, HIGH);   
      delay(100);             
      digitalWrite(LM, LOW);   
      delay(100);    
    }
    else   
      stato=4;
    break;
    /*FERMO LA CENTRIFUGA E APRO LA VALVOLA DI SCARICO 
     PER IL TEMPO DERIVANTE DALLA SOMMA DEL TEMPO DI APERTURA DELLE VALVOLE 1 E 2 */
  case 4:
    valore="4";
    Serial.println(valore);
    delay(50);
    digitalWrite(LV,LOW);
    digitalWrite(LG,LOW);
    digitalWrite(LR,HIGH);
    digitalWrite(LM,LOW);
    delay(T1+T2);
    stato=0;
    break;
   }
}

il codice processing:

import processing.serial.*;

Serial myPort;
int STATO;

int livello1=5000;
int livello2=4000;
int livello3=4000;
PImage img;
int stato=0;
int t;
int t1;
int t2;
int t3;

 void setup() {
   
   size(640, 480, P3D);        
background(#000000);            
img = loadImage("valvola.jpg"); 
 //posiziono a schermo le tre elettrovalvole
  image(img, 80, 40);            
  image(img, 480, 40);
  image(img, 360, 390);
  stroke(255);              
 //disegno le tubazioni
  line(150, 76, 300, 76);
  line(300, 76, 300, 120);
  line(340, 76, 340, 130);
  line(340, 76, 490, 76);
  line(320, 355, 320, 426);
  line(320, 426, 360, 426);
  
   String portName = Serial.list()[2];
  myPort = new Serial(this, portName, 9600);
  
 }

void draw()
{
  if ( myPort.available() > 0) {  
    STATO = myPort.read();        
  }
  
  
   switch (STATO)
  {
 case 0:
     fill(0);                                
   rect(389, 394, 20, 20);           
   translate(width/2, height/2); 
   rotateY(0.5);                      
   fill(201,201,201,100);        
   box(100,200,100);              
    /*detto la condizione di uscita dal caso "0" ed assegno alla variabile t 
      il valore del conteggio interno dei millisecondi*/
    
      // STATO = myPort.read();
       break;
       
 case 1: 
  fill(#FF0000); //assegno il colore rosso alla valvola di carico di sinistra
   rect(110, 44, 20, 20); //indico qualle rettangolo colorare, valvola di carico 1
   STATO = myPort.read();
    break;
   
    case 2: // eseguo le stesse operazioni del case 1, per la valvola di carico 2, e per la variabile t2
    fill(0);
   rect(110, 44, 20, 20);
   fill(#FF0000);
   rect(510, 44, 20, 20);
   
 // STATO = myPort.read();
   break;
   
   case 3:
  
   fill(0);
   rect(510, 44, 20, 20);
     
    if ( myPort.available() != 3)
    {  
    STATO = myPort.read();        
  }
     
     else { 
      lights();
    translate(width/2, height/2);
    rotateY(millis() * 0.01f);
    box(100,200,100);
       }
   break;
   
    case 4: 
      t=0;
   fill(#FF0000);
   rect(389, 394, 20, 20);
   translate(width/2, height/2);
   rotateY(0.5);
   fill(201,201,201,100);
   box(100,200,100);
   
  STATO = myPort.read(); 
   break; 
 }
  }

Grazie comunque per l'aiuto che ci date
Giuseppe

STATO = myPort.read();

legge una lettera. Tu hai inviato un numero (quindi composto da più lettere, una per cifra) seguita da un "a capo" (\n). quindi sevi usare la readUntil('\n');

tra l'latro è una cosa bruttissima da fare nel thread da disegno, perchè la seriale rallenterà il repaint, creando spiacevoli flick del video.

esiste una funzione che si chiama "serialEvent" che viene chiamata in automatico: quì leggi i dati available() e quando trovi il \n li metti nella giusta variabile ATOMICA (vedi AtomicInteger di java, perchè processing è java castrato). Quindi avrai due thread: uno nascosto che gestisce la seriale e fa funzionare la funzione serialEvent; l'altro gestisce il repaint.

sei troppo avanti per me .... non ci ho capito nulla :fearful:

Quello che dice @lesto sulla lettura da seriale è riferito a Processing.

Per la scrittura da Arduino se non sbaglio tu scrivi:
valore="0"; Serial.println(valore);
ovvero spedisci il carattere zero (NON zero ma il carattere) che equivale al valore ascii 48 (oltre ai due caratteri di andata a capo come detto da @lesto)

In Processing tu leggi da seriale e metti il valore dentro a variabile STATO che è int. Perciò se spedisci "0" da Arduino in Processing avrai dentro a STATO il valore 48.

Inoltre non sono sicuro che valore essendo String faccia la conversione giusta quando lo spari con Serial.println.
Quella variabile non serve a molto (almeno per ora)

Sarebbe meglio modificare in Arduino:

valore="0"; Serial.println(valore);

in una unica istruzione:

Serial.print("0");      // oppure   Serial.write('0');

e cosi ovunque spedisci nel programma; inutile mettere il valore in un variabile, trasmetterlo e poi quella variabile non serve più.

Poi in Processing o metti la variabile STATO a char oppure:

switch (STATO)
  { case 48:    // carattere 0=48

lesto:

STATO = myPort.read();

legge una lettera. Tu hai inviato un numero (quindi composto da più lettere, una per cifra) seguita da un "a capo" (\n). quindi sevi usare la readUntil('\n');

concentrati su questo che è il problema principale, sappi però che quando hai risolto qavrai problemi di grafica lenta e irresponsiva per via dei problemi descritti nella parte sul thread grafico/seriale

Una soluzione temporanea è sostituire su arduino le Serial.println(valore) in Serial.write((byte)valore) (ovvero scrivi un byte, e grezzo)
se valore = 123, per esempio, con la println() poi lato processing leggerai:
Serial.read() -> '1' (attenzione! carattere 1, che è diverso da numero 1, vedi tabella ascii)
Serial.read() -> '2'
Serial.read() -> '3'
Serial.read() -> '\n' (a capo, perchè hai usato la printLN)
Serial.read() -> -1 (nessun dato disponibile per ora) oppure la lettura successiva

se usi la write(valore) ottieni:
Serial.read() -> 0 (numero 0)
Serial.read() -> 123 (numero 123, non stringa "123")
Serial.read() -> -1 (nessun dato disponibile per ora) oppure la lettura successiva

se usi la write((byte)valore) ottieni:
Serial.read() -> 123 (numero 123, non stringa "123")
Serial.read() -> -1 (nessun dato disponibile per ora) oppure la lettura successiva

Dubito sia una cosa che risolverai in 24H

@lesto, dubbio mio.
In Arduino usa una variabile di tipo String. Ci mette un solo carattere. Ma la Serial.print() passandogli uno String, secondo te capisce di dover prendere da dentro l'oggetto un serie di caratteri ?

GRAZIE XD XD XD

siete gentilissimi, scusatemi ma sono un neofita autodidatta, ci lavorerò su al limite vi richiederò di nuovo aiuto,

per ora grazie
giuseppe

Per il discorso su serialEvent che ti ha suggerito @lesto, un link:
http://processing.org/reference/libraries/serial/serialEvent_.html

nid69ita:
@lesto, dubbio mio.
In Arduino usa una variabile di tipo String. Ci mette un solo carattere. Ma la Serial.print() passandogli uno String, secondo te capisce di dover prendere da dentro l'oggetto un serie di caratteri ?

sìsì, esiste una print e println sovraccarica che accetta la String.

oltre ai due caratteri di andata a capo

arduino accoda solo il "\n" se ricordo bene, non il \r\n (da verificare)

edit: nid69ita ti ha linkato il sito di processing, che è pieno di esempi con arduino... però PER FAVORE stai lontano da Firmdata

ho fatto diverse prove ma niente, non riesco a cambiare stato in processing, da arduino, con il monitor seriale vedo che i valori di uscita 01234 sono giusti ma non riesco ad acquisirli in processing, il listato ultimo è questo:
per arduino

int START;  //DICHIARO LA VARIABILE DI START INTERA
int T=2000; //DICHIARO LA VARIABILE DI TEMPO PER LA ROTAZIONE E LE ASSEGNO 1 SECONDO
int T1; //DICHIARO LA VARIABILE DI TEMPO INTERA PER L'APERTURA DELLA VALVOLA 1
int T2; //DICHIARO LA VARIABILE DI TEMPO INTERA PER L'APERTURA DELLA VALVOLA 2
int stato=0;
int t; //VARIABILE CHE UTILIZZERO PER TEMPORIZARE LA ROTAZIONE

void setup()
{
  Serial.begin(9600);
  pinMode(P, INPUT);
  pinMode(LG, OUTPUT);
  pinMode(LR, OUTPUT);
  pinMode(LV, OUTPUT);
  pinMode(LM, OUTPUT);

}
/* MI CREO UN VOID PER LE TEMPORIZZAZIONI DELLE VALVOLE A CUI ASSEGNERO' I VALORI DEI TEMPI T1 PER LA PRIMA VALVOLA
 T2 PER LA SECONDA E LA LORO SOMMA PER LA TERZA*/
void ritardo(unsigned long ms)
{
  unsigned long tmp;
  tmp=millis();
  while((millis()-tmp)<= ms);
}

void loop() {

  switch (stato)
  {
    // FERMO TUTTO ED ASPETTO LA PRESSIONE DEL PULSANTE P
  case 0:

    digitalWrite(LV,LOW);
    digitalWrite(LG,LOW);
    digitalWrite(LR,LOW);
    digitalWrite(LM,LOW);
    START=digitalRead(P); 
    if (START ==1)
    {
      stato=1;
      Serial.write('1');
      delay(50);
    }
    break;

    //LEGGO IL VALORE DI LIQUIDO DA FAR ENTRARE DALLA PORTA ANALOGICA A0 ED APRO LA VALVOLA 1 PER IL TEMPO NECESSARIO
  case 1:


    digitalWrite(LR,LOW);
    digitalWrite(LG,LOW);
    digitalWrite(LM,LOW);
    digitalWrite(LV,HIGH);
    T1=(analogRead(A0)*10);
    unsigned long tmp;
    tmp=millis();
    while((millis()-tmp)<= T1);

    Serial.write('2');
    delay(50);
    stato=2;
    break;

    /*CHIUDO LA VALVOLA 1, 
     LEGGO IL VALORE DI LIQUIDO DA FAR ENTRARE DALLA PORTA ANALOGICA A1 ED APRO LA VALVOLA 2 PER IL TEMPO NECESSARIO*/
  case 2:


    digitalWrite(LR,LOW);
    digitalWrite(LG,HIGH);
    digitalWrite(LM,LOW);
    digitalWrite(LV,LOW);
    T2=(analogRead(A1)*10);
    tmp=millis();
    while((millis()-tmp)<= T2);

    Serial.write('3');
    delay(50);
    stato=3;
    break;

    //CHIUDO LA VALVOLA 2 E FACCIO PARTIRE LA CENTRIFUGA PER IL TEMPO IMPOSTATO IN "T"
  case 3:

    digitalWrite(LV,LOW);
    digitalWrite(LG,LOW);
    digitalWrite(LR,LOW);
    digitalWrite(LM,HIGH);
    delay(T);
    Serial.write('4');
    delay(50);
    stato=4;
    break;
    /*FERMO LA CENTRIFUGA E APRO LA VALVOLA DI SCARICO 
     PER IL TEMPO DERIVANTE DALLA SOMMA DEL TEMPO DI APERTURA DELLE VALVOLE 1 E 2 */
  case 4:

    digitalWrite(LV,LOW);
    digitalWrite(LG,LOW);
    digitalWrite(LR,HIGH);
    digitalWrite(LM,LOW);
    delay(T1+T2);
    stato=0;
    Serial.write('0');
    delay(50);
    break;
  }
}

per processing:

import processing.serial.*;

Serial myPort;
int STATO;
PImage img;


void setup() {

  size(640, 480, P3D);         //dichiaro le dimensioni dello schermo 
  background(#000000);            //scelgo il colore di sfondo (nero) dello schermo
  img = loadImage("valvola.jpg"); //carico l'immgine dell'elettrovalvola
  //posiziono a schermo le tre elettrovalvole
  image(img, 80, 40);            
  image(img, 480, 40);
  image(img, 360, 390);
  stroke(255);              // assegno il colore bianco alle linee indicanti le tubazioni
  //disegno le tubazioni
  line(150, 76, 300, 76);
  line(300, 76, 300, 120);
  line(340, 76, 340, 130);
  line(340, 76, 490, 76);
  line(320, 355, 320, 426);
  line(320, 426, 360, 426);

  String portName = Serial.list()[2];
  myPort = new Serial(this, portName, 9600);
}

void draw()
{
  if ( myPort.available() > 0)
  {  
    STATO = myPort.read();
  }

  switch (STATO)
  {
  case 0:
    fill(0); //resetto il colore rosso della valvola di scarico 
    rect(389, 394, 20, 20); //indico qualle rettangolo annerire (valvola di scarico)
    translate(width/2, height/2); //do il comando di centrare l'immagine del parallelepipedo
    rotateY(0.5); //do il comando di rotazione di o.5 PIgreco, del parallelepipedo
    fill(201, 201, 201, 100); //scelgo il colore rgb da dare al parallelepipedo
    box(100, 200, 100);  //disegno il parallelepipedo
    STATO = myPort.read();
    break;

  case 1: 
    fill(#FF0000); //assegno il colore rosso alla valvola di carico di sinistra
    rect(110, 44, 20, 20); //indico qualle rettangolo colorare, valvola di carico 1
    STATO = myPort.read();
    break;

  case 2: // eseguo le stesse operazioni del case 1, per la valvola di carico 2, e per la variabile t2
    fill(0);
    rect(110, 44, 20, 20);
    fill(#FF0000);
    rect(510, 44, 20, 20);
    STATO = myPort.read();
    break;

  case 3:
    fill(0);
    rect(510, 44, 20, 20);
    if ( myPort.available() != 3)
    {  
      STATO = myPort.read();
    } else { 
      lights();
      translate(width/2, height/2);
      rotateY(millis() * 0.01f);
      box(100, 200, 100);
    }
    break;

  case 4: 
    fill(#FF0000);
    rect(389, 394, 20, 20);
    translate(width/2, height/2);
    rotateY(0.5);
    fill(201, 201, 201, 100);
    box(100, 200, 100);
    STATO = myPort.read(); 
    break;
  }
}

ho provato ha cambiare il valore dei case da 0,1,2,3,4, in 48,49,50,51,52 ma niente, ho provato ha cambiare int STATO in char STATO ma mi da errore........ non ne esco.... :frowning:

Prova cosi:

import processing.serial.*;

Serial myPort;
int STATO;
PImage img;

void setup() {
  size(640, 480, P3D);         //dichiaro le dimensioni dello schermo 
  background(#000000);            //scelgo il colore di sfondo (nero) dello schermo
  img = loadImage("valvola.jpg"); //carico l'immgine dell'elettrovalvola
  //posiziono a schermo le tre elettrovalvole
  image(img, 80, 40);            
  image(img, 480, 40);
  image(img, 360, 390);
  stroke(255);              // assegno il colore bianco alle linee indicanti le tubazioni
  //disegno le tubazioni
  line(150, 76, 300, 76);
  line(300, 76, 300, 120);
  line(340, 76, 340, 130);
  line(340, 76, 490, 76);
  line(320, 355, 320, 426);
  line(320, 426, 360, 426);

  String portName = Serial.list()[2];
  myPort = new Serial(this, portName, 9600);
}

void draw()
{
  if ( myPort.available() > 0)
  { STATO = myPort.read();
    GestisceStato();
  }
}

void GestisceStato()
{  switch (STATO)
  {
  case '0':
    fill(0); //resetto il colore rosso della valvola di scarico 
    rect(389, 394, 20, 20); //indico qualle rettangolo annerire (valvola di scarico)
    translate(width/2, height/2); //do il comando di centrare l'immagine del parallelepipedo
    rotateY(0.5); //do il comando di rotazione di o.5 PIgreco, del parallelepipedo
    fill(201, 201, 201, 100); //scelgo il colore rgb da dare al parallelepipedo
    box(100, 200, 100);  //disegno il parallelepipedo
    STATO = myPort.read();
    break;
  case '1': 
    fill(#FF0000); //assegno il colore rosso alla valvola di carico di sinistra
    rect(110, 44, 20, 20); //indico qualle rettangolo colorare, valvola di carico 1
    STATO = myPort.read();
    break;
  case '2': // eseguo le stesse operazioni del case 1, per la valvola di carico 2, e per la variabile t2
    fill(0);
    rect(110, 44, 20, 20);
    fill(#FF0000);
    rect(510, 44, 20, 20);
    STATO = myPort.read();
    break;
  case '3':
    fill(0);
    rect(510, 44, 20, 20);
    if ( myPort.available() != 3)
    {  
      STATO = myPort.read();
    } else { 
      lights();
      translate(width/2, height/2);
      rotateY(millis() * 0.01f);
      box(100, 200, 100);
    }
    break;
  case '4': 
    fill(#FF0000);
    rect(389, 394, 20, 20);
    translate(width/2, height/2);
    rotateY(0.5);
    fill(201, 201, 201, 100);
    box(100, 200, 100);
    STATO = myPort.read(); 
    break;
  }
}

Primo tutto lo switch deve stare dentro al if della available (creato una funzione per facilitarlo)
Secondo se su monitor veri 0,1,2 vuol dire che sono caratteri, perciò nello switch li vedi come '0' '1' ....
A me funziona. Almeno, mandando 0 vedo un cubo grigio, 1 e 2 accendono/spengono 2 quadrati che diventano rossi in alto a sinistra e destra.
Ho spedito i dati su seriale non da Arduino però. Spero che con i collegamenti che hai fatto tu, effettivamente da Processing stai leggendo dalla porta seriale COM giusta (io di com ne ho 4, se sbagli numero non leggi nulla).

ciao nid69ita, grazie per la risposta,
ho provao ma non va, la seriale da cui carico il programma per arduino è la due, e con arduino funziona ha processing credo di averli dato la 2 da leggere:

 String portName = Serial.list()[2];

quindi.....booo?

Io ho usato un programma in VB in cui posso scrivere caratteri e spararli su seriale virtuale.
Ho creato una seriale virtuale COM2 su cui spedisco i caratteri da VB al Processing (porta list[1]) e funziona.
Secondo me, visto che il programma Processing funziona, e il programma in Arduino non vedo errori (anzi tu su monitor seriale vedi i caratteri spediti da Arduino) allora c'e' un problema sulla comunicazione seriale.

Processing deve usare la stessa seriale di Arduino. Sicuro sia la 2?
String portName = Serial.list()[2];

Attenzione che quel 2 non è detto sia COM2.
Quel 2 è l'elemento numero 2 della lista delle porte.
Se nella lista:
list[0]=>COM1
list[1]=>COM2
list[2]=>COM3
...
etc.

Allora per COM2 devi usare list()[1]

FUNZIONAAAAAAAAAAAAAAAAAAAAAAAAAAA :slight_smile: :smiley: XD :grin:

non avevo fatto il listato delle seriali, effettivamente era la 1.

ho un problema di grafica, ma quella la risolvo faclmenete,

non so come ringraziarti,

se passi dal trentino hai una bevuta pagata.....

grazie ancora

Figurati, di niente.
Se è risolto puoi modificare il titolo (al primo post credo) aggiungendo [Risolto]
Buona domenica :slight_smile:

anche a te nid69ita, grazie ancora

ctsgm:
ho fatto diverse prove ma niente, non riesco a cambiare stato in processing, da arduino, con il monitor seriale vedo che i valori di uscita 01234 sono giusti ma non riesco ad acquisirli in processing, il listato ultimo è questo:

l'errore sta che lato arduino scrivi '0' (carattere 0) e poi però latro pocessing fai il case con 0 (numero 0), il che non è la stessa cosa!

ho provao ma non va

con che errore?

credo di averli dato la 2 da leggere

se non sei sicuro.. allora non hai fatto abbastanza prove :slight_smile:
BTW se sai che la tua porta seriale è la COM2, per esempio, allora al posto di fare

String portName = Serial.list()[2];

fai

String portName = "COM2";

grazie Lesto,

ma l'errore è stato quello di dare per scontato che per processing la porta fosse la stessa che usavo per Arduino, quindi non ho neanche chiesto il listato delle porte a processing (errore gravissimo a quanto pare) infatti dopo aver fatto: println (Serial.list ());
ho visto che, la com2 processing la nominava[1] non puoi capire quante volte ho modificato il programma ed alla fine era na cazz... ma meglio cosi, ora ho il problema di far ruotare il perallelepipedo nel case 3, ma conto di arrivarci rapidamente....

grazie ancora
Giuseppe