Go Down

Topic: plot grafico tramite processing real time (Read 2 times) previous topic - next topic

aureliusss

ciao a tutti,
ho già scritto un post (sezione hardware) su un primo lavoro di tesi che sto facendo: rilevare la caratteristica corrente tensione di un alimentatore.http://arduino.cc/forum/index.php/topic,126840.0.html

dopo aver implementato questo circuito su breadboard


con il codice corrispondente per rilevare tensioni e corrente

Code: [Select]
#define RELAY_PIN 3 //digital pin to control the relay
#define c_pin A1    //capacitor analog pin
#define ps_pin A0   //power supply analog pin


void setup()
{
  pinMode(RELAY_PIN, OUTPUT);
  Serial.begin(9600); // open serial
  Serial.println("Press the spacebar to toggle relay on/off");
}


void loop()
{
  static int relayVal = 0;
  int cmd;
  float c_voltage, ps_voltage, current;
  static float res = 5.2;
 
  while (Serial.available() > 0)
  {
    cmd = Serial.read();
     
    switch (cmd)
    {
    case ' ':
      {
        relayVal ^= 1; // xor current value with 1 (causes value to toggle)
        if (relayVal)
          Serial.println("Relay on");
       
        break;
      }
    default:
      {
        Serial.println("Press the spacebar to toggle relay on/off");
      }
    }
     
    if (relayVal)
    {
      digitalWrite(RELAY_PIN, HIGH);
      delay(20);           // relay transition time
      do
      {
        c_voltage = analogRead(c_pin);
        ps_voltage = (analogRead(ps_pin));
       
        c_voltage = c_voltage *5 /1023;
        ps_voltage = ps_voltage * 5 / 1023;
        current = (ps_voltage - c_voltage)/res;
       
        Serial.print(ps_voltage);
        Serial.print("  ");
        Serial.print(c_voltage);
        Serial.print("  ");
        Serial.print(current);
        Serial.print("\n");
      }
      while(current >0.000001);
     
      Serial.println("Please wait for the capacitor to discharge");
      digitalWrite(RELAY_PIN, LOW);
      do
      {
        c_voltage = analogRead(A1);
        c_voltage = c_voltage * 5 / 1023;
       
        Serial.println(c_voltage);
        delay(50);  // just a delay to not print all the values
       
      }
      while(c_voltage > 0.001);
     
      relayVal = 0;  // reinitialze the relayVal
      Serial.println("\nThe relay is off, press the spacebar");
      Serial.println("again if you want to repeat the measure\n");
    } 
     

    }
}



vorrei riuscire a plottare in real time i dati che ricevo su corrente e tensione tramite processing.

ho letto tutti i vari post qui sul forum che riguardano processing  e visto anche qualche tutorial, ma non ho trovato come fare a prendere le due serie di dati e plottarli in un semplice grafico tipo questo ottenuto con excel



grazie per l'aiuto

pitusso

Ciao,
prova a dare un'occhiata a questo progetto:
http://code.google.com/p/arduinoscope/
dovresti trovare tutti gli strumenti che ti servono per realizzare il tuo progetto  :P

lucadentella

ciao

questo in c#, sorgenti su GitHub:
http://www.lucadentella.it/2011/11/08/analogdemo-plot-di-dati-e-invio-a-pachube-in-c/

bye
lucadentella.it

lesto

leggi i dati dalla seriale e li metti in un ArrayList. Questo arrayList va sempre usato in un blocco
syncronize(nomeArrayList){
   //ora puoi usare in sicurezza l'arrayList
}

Questo è necessario perchè l'acquisizione su seriale e il disegno sono su due thread diversi; usare una line per ogni valore seriale manderebbe in palla la grafica, che non riuscirebbe a disegnare abbastanza in fretta, mentre usare un array non sincronizzato può creare dei casini si concorrenza esagerati

ogni draw() scorri gli ultimi A valori dell'arraylist (dove X è la scala lungo l'asse X) e poi disegni delle righe col comando
line(X1, Y1, X2, Y2);

dove Y1 è il valore attuale, Y2 il prossimo valore, X1 e X2 un valore che si incrementa di Tot, dove tot è la larghezza della finestra diviso A

se vuoi disegnare più righe, basta ripetere questa parte del codice, sommando una costante ad Y per evitare che i dati si sovrappongano (se non vuoi la sovrapposizione)  facendo attenzione anche a non uscire dallo schermo!

sempre per non uscire dallo schermo, probabilmente dovrai usare uno zoom anche sull'asse Y, ovvero tutti i valori di Y moltiplicarli per B, esattamente come quelli di X li ai divisi per A
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

aureliusss

scusate ragazzi, il professore mi ha chiesto di mofificare lo sketch che ho sopra scritto, per avere più misure e visualizzare anche il tempo a cui vengono effettuate le misure, impostando come t=0 l'istante in cui inizio l'acquisizione dei dati?
coem faccio a impostare un cronometro? e che ''risoluzione'' può avere questo cronometro secondo voi?

lucadentella

guarda la funzione millis() di Arduino:
http://www.arduino.cc/en/Reference/Millis
lucadentella.it

aureliusss

secondo voi come potrei aumentare il numero di misure effettuate? esiste un modo per aumentare la frequenza dell'analogRead?

lesto

sì, diminuendo il prescaler. Però diminuisce anche la precisione della lettura, se non erro a 16 (il prescaler di defautl mi pare sia sui 128) ha una precisione a 8bit se non meno (cioè, i valori "reali" vanno da 0 a 255, il resto è rumore, anzichè i classici 10bit da 0 a 1023)
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

aureliusss

http://arduino.cc/forum/index.php/topic,6549.0.html
mi basta mettere il codice che trovo in questo post per aumentare la velocità dell'adc quindi?

lesto

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

aureliusss

ma con il codice che ho scritto, anzi esattamente questo segmento:
Code: [Select]
c_voltage = analogRead(c_pin);
          time1 = micros()-time0; //time c_voltage measurement
          ps_voltage = analogRead(ps_pin);
          time2 = micros() - time0; //time ps_voltage measurement


secondo voi time1 e time2 che poi andrò a stampare, sono esattamente il tempo in cui arduino prende la misura o sono posticipati?

lesto

#11
Oct 29, 2012, 04:11 pm Last Edit: Oct 29, 2012, 04:12 pm by lesto Reason: 1
posticipati, direi di circa 204microsecondi (200 microsecondi di lettura + 4 microsecondi per la nuova richiesta di micros)

essendo un valore fisso, di solito si può ignorare senza conseguenze, semplicemente il grafico è sballato di 200 micros sull'asse del tempo (se prendi come riferimento l'inizio lettura, se prendi la fine lettura sei quasi perfetto)
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

aureliusss

possibile che siano addirittura posticipati di 204 microsecondi? forse ho sbaglaito a non postarvi tutto il codice, perchè da quello che vedo io in output ad esempio, la prima misura sul c_voltage avviene al tempo di 20us
Code: [Select]
#define RELAY_PIN 3 //digital pin to control the relay
#define c_pin A1    //capacitor analog pin
#define ps_pin A0   //power supply analog pin
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif



void setup()
{
  // set prescale to 16
  sbi(ADCSRA,ADPS2) ;
  cbi(ADCSRA,ADPS1) ;
  cbi(ADCSRA,ADPS0) ;

  pinMode(RELAY_PIN, OUTPUT);
  Serial.begin(9600); // open serial
  Serial.println("How many measure do you want to take?");
}


void loop()
{
 
  int num_misure;
  float c_voltage, ps_voltage, current;
  static float res = 3.59;
  unsigned long time1, time2, time0;
  int i ;
 
 
  if(Serial.available() > 0)
  {
     num_misure = Serial.parseInt(); // Arduino stream function which receive a string on the serial port and then changes it int an integer
     if(num_misure > 0)
     {
     
      for(i = 1 ; i <= num_misure; i++)
     {
      Serial.print("Misura n.");
      Serial.println(i);
     
      digitalWrite(RELAY_PIN, HIGH);
      delay(20);            // relay transition time::::::: problema, ho impostato questo ritardo per aspettare la commutazione del ralay, ma questo non ha un tempo fisso
      time0 = micros();     // time the measure start
      do
      {
        c_voltage = analogRead(c_pin);
        time1 = micros()-time0; //time c_voltage measurement
        ps_voltage = analogRead(ps_pin);
        time2 = micros() - time0; //time ps_voltage measurement
       
        c_voltage = c_voltage *5 /1023;
        ps_voltage = ps_voltage * 5 / 1023;
       
        current = (ps_voltage - c_voltage)/res;
       
        Serial.println(ps_voltage);
        Serial.println(time1);
        Serial.println(c_voltage);
        Serial.println(time2);
        Serial.println(current);
        Serial.print('\n');
      }
      while(current >0.000001);
     
      Serial.println("Please wait for the capacitor to discharge");
      digitalWrite(RELAY_PIN, LOW);
      do
      {
        c_voltage = analogRead(A1);
        c_voltage = c_voltage * 5 / 1023;
       
        Serial.println(c_voltage);
        delay(50);  // just a delay to not print all the values
       
      }
      while(c_voltage > 0.001);
      Serial.print("\n\n");
       
     
     
    }   
  }
  }}
     

l'ho modificato rispetto a quello postato prima settando il prescaler a 16 come mi avevi descritto anche tu

l'output che ho è questo:(lo posto come codice èper renderlo leggibile)
Code: [Select]
How many measure do you want to take?
Misura n.1
2.65
32
1.01
48
0.46

2.74
1592
1.03
1612
0.48

2.83
3332
1.11
3352
0.48

3.83
25316
2.09
25336
0.49

5.00
59636
3.58
59656
0.39

5.00
93956
4.86
93976
0.04

5.00
128280
5.00
128296
0.00

Please wait for the capacitor to discharge
5.00
1.64
0.47
0.13
0.01
0.00

aureliusss

inoltre vorrei eliminare quella serie di Serial.print() per aumentare i ''punti'' di misura
avrei pensato alla costruzione di tre array PS_VOLTAGE[], C_VOLTAGE, CURRENT[], in cui storare i dati, e solo in una seconda parte stamparli, magari direttamente su excel o su matlab se riesco a trovare il modo di farlo, in maniera tale da poterli manipolare per grafici direttamente.

secondo voi riesco ad aumentare il  numero di misure che riesco a  prendere se li metto negli array invece che stamparli subito in output?

lesto

ah ok, se cambi il prescaler cambia la velocità dell'analogRead, e quindi è giusto che il tempo di "posticipazione" diminuisce.

per rendere il codice più veloce usa la write() invece che la pritn(): la print converte in caratteri ascii, ovvero 1 byte per ogni cifra; con la write scrivi in maniera binaria, quindi scrivi tanti byte quanto la dimensione della variabile.

Cole prescaler a 16 hai una precisione a 8 byte, quindi puoi prendere sono gli 8 byte più significativi (sui 10 che ti restituisce l'analogRead) e quindi aresti un byte per lettura.

Però devi inventarti un sistema per sincronizzare i dati.

a casa ho del codice sia per inviare che per ricevere, ma devo upparlo sul repo. Se hai facebook, ho postato del codice che fa 3 letture analogice (a scelta a 10 o 8 bit di precisione), nel caso di 8 bit le invio dirette al PC, nel caso di 10 bit, faccio la lettura dei 3 dati in un array, poi anzichè inviare 6byte (2 byte per letura, un int) unisco i dati per fare in modo di usare solo 4 byte (4*8=32bit, avanzano 2 bit a scrittura, in teoria facendo un array di 30 elementi guadagni un byte "a gratis" sfruttando anche quei due bit)

il trucco si sincronizzazione è che l'arduino andava in loop finchè processing,. quando pronto a ricevere, inviava un comando.

uesto perchè se inizi a legegre il flusso seriale in un momento a caso non sai il byte che stai leggendo a che misurazione si riferisce, e nel caso di invio di più di un byte a varibaile (da int in su) non sai nemmeno se il byte che hai letto è la parte bassa o la parte alta.
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Go Up