Arduino Led e Velocità Motore GUI

Salve a tutti,
Sto realizzando un sistema con arduino che mi faccia accendere dei led e mi controlli la velocità di un motore e me la stampi.Tutto ovviamente controllato da una GUI.

Per quanto riguarda arduino tutto funziona perfettamente credo.Seguendo un tutorial esterno son riuscito a far visualizzare la velocità del motore in mph da terminale.La lettura viene effettuata con un magnete che chiude il segnale ogni qualvolta il magnete applicato sul motore passa sul sensore.Ora il mio problema e farla visualizzare da gui.Vi posto i miei due sorgenti:Il primo di arduino il secondo della GUI in Processing.

Arduino Code

const int pinled=13;
int val;
#define reed A0//pin connected to read switch

//storage variables
int reedVal;
long timer;// time between one full rotation (in ms)
float mph;
float radius = 13.5;// tire radius (in inches)
float circumference;

int maxReedCounter = 100;//min time (in ms) of one rotation (for debouncing)
int reedCounter;
 void setup(){
   Serial.begin(9600);
   
  pinMode(pinled, OUTPUT); 
  pinMode(0, INPUT);
    reedCounter = maxReedCounter;
  circumference = 2*3.14*radius;
  pinMode(reed, INPUT);
  
  // TIMER SETUP- the timer interrupt allows precise timed measurements of the reed switch
  //for more info about configuration of arduino timers see http://arduino.cc/playground/Code/Timer1
  cli();//stop interrupts

  //set timer1 interrupt at 1kHz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;
  // set timer count for 1khz increments
  OCR1A = 1999;// = (1/1000) / ((1/(16*10^6))*8) - 1
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS11 bit for 8 prescaler
  TCCR1B |= (1 << CS11);   
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  
  sei();//allow interrupts
  //END TIMER SETUP
   }
   ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz to measure reed switch
  reedVal = digitalRead(reed);//get val of A0
  if (reedVal){//if reed switch is closed
    if (reedCounter == 0){//min time between pulses has passed
      mph = (56.8*float(circumference))/float(timer);//calculate miles per hour
      timer = 0;//reset timer
      reedCounter = maxReedCounter;//reset reedCounter
    }
    else{
      if (reedCounter > 0){//don't let reedCounter go negative
        reedCounter -= 1;//decrement reedCounter
      }
    }
  }
  else{//if reed switch is open
    if (reedCounter > 0){//don't let reedCounter go negative
      reedCounter -= 1;//decrement reedCounter
    }
  }
  if (timer > 2000){
    mph = 0;//if no new pulses from reed switch- tire is still, set mph to 0
  }
  else{
    timer += 1;//increment timer
  } 
}
 void displayMPH(){
  Serial.println(mph);

}
  void loop()
  {
    if(Serial.available() >0)
    {
       val= Serial.read();
      if(val == 'S')
      {
  digitalWrite(pinled, HIGH);
  delay(1000);
  digitalWrite(pinled, LOW);
  }else if(val == 'N')
  {
  digitalWrite(pinled, HIGH);
  
      }else if(val=='Z')
      {
  digitalWrite(pinled, LOW);
      }
    
    }
  
    //print mph once a second
  displayMPH();
 delay(2000);
  }

GUI Code

import processing.serial.*;
int width = 800;
int height = 600;

int button1X;
int button1Y;
int button1Width = width/10;
int button1Height = height/20;
int button2X;
int button2Y;
int button3X;
int button3Y;
int button2Width = button1Width;
int button2Height = button1Height;
int button3Width = button1Width;
int button3Height = button1Height;
float buttonFont = button1Height/1.5;
float wordFont = button1Height;




Serial arduino;
color buttonColor, buttonHighlight, buttonPressed;

PFont font;

boolean button1Over = false;
boolean button2Over = false;
boolean button3Over = false;
void setup() {
  
  size(width,height);
  smooth();
  font = loadFont("CourierNew36.vlw"); 
  buttonColor = color(255);
  buttonHighlight = color(200);
  buttonPressed = color(50);
  button1X = width/10 - button1Width/2;
  button1Y = height/5 - button1Height/2;
  button2X = 2*width/10 - button1Width/2;
  button2Y = height/5 - button1Height/2;
    button3X = 3*width/10 - button1Width/2;
  button3Y = height/5 - button1Height/2;
  arduino = new Serial(this,"COM3", 9600);
}

void draw() {
  
  update(mouseX,mouseY);
  background(0);
  
  if(button1Over) {
    fill(buttonHighlight);
  } else {
    fill(buttonColor);
  }
  stroke(0);
  rect(button1X,button1Y, button1Width, button1Height);
  
  if(button2Over) {
    fill(buttonHighlight);
  } else {
    fill(buttonColor);
  }
  stroke(0);
  rect(button2X,button2Y, button2Width, button2Height);
  
  
    if(button3Over) {
    fill(buttonHighlight);
  } else {
    fill(buttonColor);
  }
  stroke(0);
  rect(button3X,button3Y, button3Width, button3Height);
  
  textFont(font, buttonFont);
  fill(0);
  text("On t",button1X + button1Width/3.9,button1Y + button1Height/1.3);
  text("On nt",button2X + button1Width/10.9,button1Y + button1Height/1.3);
    text("Off nt",button3X + button1Width/10.9,button1Y + button1Height/1.3);
  textFont(font, wordFont);
  fill(255);
  text("Accendi/Spegni Led ",button3X + button1Width + width/20,button1Y + button1Height/1.2);
}

///////////////////////////////////

void update(int x, int y) {
  
  if(overButton(button1X,button1Y,button1Width,button1Height)){
    button1Over = true;
  } else {
    button1Over = false;
  }
  if(overButton(button2X,button2Y,button2Width,button2Height)){
    button2Over = true;
  } else {
    button2Over = false;
  }
  if(overButton(button3X,button3Y,button3Width,button3Height)){
    button3Over = true;
  } else {
    button3Over = false;
  }
}

void mousePressed() {
  
  if(button1Over) {
    println("Button1 pressed");
    arduino.write('S');
    fill(buttonPressed);
    rect(button1X,button1Y, button1Width, button1Height);
  }
  if(button2Over) {
    println("Button2 pressed");
     arduino.write('N');
    fill(buttonPressed);
    rect(button2X,button2Y, button2Width, button2Height);
  }
  if(button2Over) {
    println("Button3 pressed");
     arduino.write('Z');
    fill(buttonPressed);
    rect(button3X,button3Y, button3Width, button3Height);
  }
}

boolean overButton(int x, int y, int width, int height) {
  
  if(mouseX >= x && mouseX <= x+width && mouseY >= y && mouseY <= y+height) {
    return true;
  } else {
    return false;
  }
  
}

Sarei grati se riuscireste a farmi visualizzare la velocità nella gui in modo live.Ringrazio tutti in anticipo

bhe in processing esiste una funzione che viene chiamata ogni volta che arrivano dati sulla seriale...

per esempio, per leggere i dati che arrivano da seriale:

void serialEvent(Serial p) { 
  inString = p.readString(); 
}

ricordati che i dati via seriale arrivano lettera per lettera, quindi sta a te ricostruire la parte che ti interessa. Una volta che hai letto la parte che ti interessa, è facile visualizzare il dato a video.

Ciò che non capisco e come prelevare i valori da un determinato pin analogico ad esempio A0. Potresti farmi un esempio di codice processing per la GUI?

non conosco firmdata, ma secondo me sul sito di procssing trovi molti più esempi

Nulla non trovo nulla per prelevare questa velocità...

tu stai gfià inviando la velocità via seriale con la funzione

displayMPH();

la funziona a quanto vedo scrive il numero seguito da un a capo

ora lato processing devi leggere la seriale mettendo i dati in una stringa ed estrarre il dato dalla stringa. Non esiste nulla di precotto, devi fartelo da te, ma sono 3 o 4 righe di codice...

Ho realizzato questo codice

      while (arduino.available () > 0) {
inByte = arduino.readStringUntil('\n'); 
if ( inByte != null ) {
  println(inByte);

        text(inByte,width/2, height/2);
          }

Ora la velocità me la legge solo che la scritta nella GUI va e viene.nel senso viene mostrata solo per quel istante in cui l'arduino aggiorna il valore.Come posso fare in modo che rimanda li e venga aggiornata senza che scompaia?

salva inByte come variabile gloabale, e la chiamata di stampa la ma tetti nella funzione draw():

text(inByte,width/2, height/2);

in pratica draw() è una funzione che viene chiamata quando viene ridisegnata la finestra. come puoi vedere viene cancellato tutto e poi ridisegnatao (non sempre è così però, tu cancelli tutto perchè chiami il metodo background(0) ), nel tuo caso alla fine del pain basta che stampi text e sei a posto. Ceto c'è il rischio che il valore di inByte venga cambiato mentre text viene stampato, ma è una possibilità remota e puoi fregartene, per completezza basta fare:

if ( inByte != null ) {
   syncronized(stringDaStampare){
      stringDaStampare = inByte;
   }
}

nel draw():

syncronized(stringDaStampare){
    text(stringDaStampare ,width/2, height/2);
}

Scusa l'ignoranza ma in stringaDastampare cosa dovrei mettere? scusami ma sono un pò confuso con le idee

:fearful: :fearful:
Prova a farmi un esempio tenendo presente il mio codice. E grazie per l'aiuto!

in stringaDastampare io ci metto il vaore da stampare. dato che il draw() è indipendendete dal loop() (parallelismo!) di processing, e che inByte può essere null, io salvo inByte solo se NON nullo in stringaDastampare, e poi nel draw() stampo stringaDastampare, in questo modo ho sempre un valore valido da stampare!

Ancora non capisco... stringaDastampare dovrebbe essere il mio arduino.readStringUntil('\n')?
Vedi se riesci a darmi il pezzo di codice da inserire direttamente o simile...che io me lo studio, perchè in qello che mi hai dato prima no ho capito molto bene.Scusami se non sono molto pratico

UP

DOWN (visto che non puoi apsettare 2 ore, ti rispondo tra altre 2 ore, nel frattempo prova a fare un pò di test usando la tua testa, tanto non rompi nulla sai)

credevo andasse troppo in basso e non venisse più letto... come succede in molti forum.Chiedo scusa.Sto facendo test da ieri sera. non ne viene nulla fuori.

stringaDastampare dovrebbe essere il mio arduino.readStringUntil('\n')

sì, ma sono se non è null :wink:

dovrebbe essere una cosa del genere?

      while (arduino.available () > 0) {
inByte = arduino.readStringUntil('\n'); 
if ( inByte != null ) {
  a= arduino.readStringUntil('\n'); 
   synchronized(a){
      a = inByte;
      }
  fill(125);
  synchronized(a){
        text(a,width/2, height/2);
        }
          }
}

togli a= arduino.readStringUntil('\n');

e

fill(125);

la text va messa nella funzione draw()

Così dunque:

import processing.serial.*;
int width = 800;
int height = 600;
String inByte;
String a;
int button1X;
int button1Y;
int button1Width = width/10;
int button1Height = height/20;
int button2X;
int button2Y;
int button3X;
int button3Y;
int button2Width = button1Width;
int button2Height = button1Height;
int button3Width = button1Width;
int button3Height = button1Height;
float buttonFont = button1Height/1.5;
float wordFont = button1Height;




Serial arduino;
color buttonColor, buttonHighlight, buttonPressed;

PFont font;

boolean button1Over = false;
boolean button2Over = false;
boolean button3Over = false;
void setup() {
  
  size(width,height);
  smooth();
  font = loadFont("CourierNew36.vlw"); 
  buttonColor = color(255);
  buttonHighlight = color(200);
  buttonPressed = color(50);
  button1X = width/10 - button1Width/2;
  button1Y = height/5 - button1Height/2;
  button2X = 2*width/10 - button1Width/2;
  button2Y = height/5 - button1Height/2;
    button3X = 3*width/10 - button1Width/2;
  button3Y = height/5 - button1Height/2;
  arduino = new Serial(this,"COM3", 9600);
    arduino.bufferUntil('\n'); // SerialEvent for new line 
  arduino.clear();
}

void draw() {
  
  update(mouseX,mouseY);
  background(0);
  
  if(button1Over) {
    fill(buttonHighlight);
  } else {
    fill(buttonColor);
  }
  stroke(0);
  rect(button1X,button1Y, button1Width, button1Height);
  
  if(button2Over) {
    fill(buttonHighlight);
  } else {
    fill(buttonColor);
  }
  stroke(0);
  rect(button2X,button2Y, button2Width, button2Height);
  
  
    if(button3Over) {
    fill(buttonHighlight);
  } else {
    fill(buttonColor);
  }
  stroke(0);
  rect(button3X,button3Y, button3Width, button3Height);
  
  textFont(font, buttonFont);
  fill(0);
  text("On t",button1X + button1Width/3.9,button1Y + button1Height/1.3);
  text("On nt",button2X + button1Width/10.9,button1Y + button1Height/1.3);
    text("Off nt",button3X + button1Width/10.9,button1Y + button1Height/1.3);

      while (arduino.available () > 0) {
inByte = arduino.readStringUntil('\n'); 
if ( inByte != null ) {
   synchronized(a){
      a = inByte;
      }
  synchronized(a){
        text(a,width/2, height/2);
        }
          }
}

  textFont(font, wordFont);
  fill(255);
  text("Accendi/Spegni Led ",button3X + button1Width + width/20,button1Y + button1Height/1.2);
}

///////////////////////////////////

void update(int x, int y) {
  
  if(overButton(button1X,button1Y,button1Width,button1Height)){
    button1Over = true;
  } else {
    button1Over = false;
  }
  if(overButton(button2X,button2Y,button2Width,button2Height)){
    button2Over = true;
  } else {
    button2Over = false;
  }
  if(overButton(button3X,button3Y,button3Width,button3Height)){
    button3Over = true;
  } else {
    button3Over = false;
  }
}

void mousePressed() {
  
  if(button1Over) {
    println("Button1 pressed");
    arduino.write('S');
    fill(buttonPressed);
    rect(button1X,button1Y, button1Width, button1Height);
  }
  if(button2Over) {
    println("Button2 pressed");
     arduino.write('N');
    fill(buttonPressed);
    rect(button2X,button2Y, button2Width, button2Height);
  }
  if(button2Over) {
    println("Button3 pressed");
     arduino.write('Z');
    fill(buttonPressed);
    rect(button3X,button3Y, button3Width, button3Height);
  }
}

boolean overButton(int x, int y, int width, int height) {
  
  if(mouseX >= x && mouseX <= x+width && mouseY >= y && mouseY <= y+height) {
    return true;
  } else {
    return false;
  }
  
}
void serialEvent (Serial arduino) {
  // get the byte:

  // print it:
 // println(inByte);
  // at the edge of the screen, go back to the beginning:
}

no allora chiariamo le cose.
Tu hai 2 thread, ovvero 2 "programmi" in parallelo su processing.
Uno ha il loop che si chiama appunto loop() come su arduino, che non stai usando (infatti manca mi pare, ma va bene così. Quà vanno messe tutte le operazioni logiche.
Uno si chiama draw() e viene chiamato quando bisogna aggiornare la finestra. Qua vanno messe SOLO le operazioni di disegno. Niente letture seriali o boiate del fenere.

In oltre ci sono degli eventi, ovvero funzioni che sono chiamate quando succede qualcosa. In questo caso "void serialEvent (Serial arduino) {"

quindi nell'evento seriale leggi la seriale e metti il risultato in una stringa (nel tuo caso "a").

il draw semplicemente stampa "a", nient'altro. se poi in "a" c'è un valore messo da seriale o il numero seriale di windows la fuunzione draw se ne deve fregare.

PERCHE?

perchè se la seriale si impalla (prova a staccare arduino), se fai come dico io la grafica è INDIPENDENTE dalla seriale e puoi chiudere/continuare ad usare il tuo programma... col tuo sistema anche la grafica si impalla e devi uccidere il programma da taskmanager.

altro esempio è se "a" fosse un'elaborazione pesante, l'immagine della finestra rimarrebbe congelata e non responsiva... non ti è mai capitato? bene, sappi che quello è un errore di strutturazione, o di architettura del programma.

kiss

Lesto ti chiederei troppo se ti chiedessi di fare i due pezzi di codice che mi servirebbero a prendere questi dati da arduino? Per piacere ne sto uscendo pazzo :astonished: :astonished: