Inviare dati tramite PC alla scheda Arduino

Mi scuso se l’argomento è già stato trattato, ma non riesco a trovare niente che faccia al mio caso.
Il progetto iniziale era e resta quello di realizzare una macchina per il revorking di schede elettroniche. A piccoli passi e con gli aiuti ricevuti sono arrivato ad avere un termostato per alte temperature realizzato con una termocoppia K , il max 6675 un display e logicamente la scheda arduino che pilota un MOC e relativo Triac che controlla la resistenza. Per adesso ho messo da parte la regolazione PWM o PID e la sincronizzazione della commutazione con la tensione di rete ( zero crossing ) accontentandomi di un semplice ON/OFF vista anche l’inerzia della resistenza e un certo range di temperatura. Adesso dovrei inviare tramite PC dei dati per far sì che si raggiunga una certa temperatura e si possa controllare il tempo che il circuito rimane a questa temperatura e poi variare la temperatura e ancora impostare un nuovo tempo e così via.
Nel gergo di queste macchine questa operazione si chiama profilo e per rendere meglio l’idea allego una foto di uno di questi profili. Adesso il problema è : come faccio ad inviare tramite il PC una serie di dati che mi riproducano una simile curva ? Ho visto il processing ma non ci ho capito molto, vorrei sapere se quella può essere la strada giusta oppure è meglio utilizzare altri sistemi ? Mi potete fare qualche esempio pratico, visto che la mia conoscenza della programmazione è veramente molto lacunosa ?
Grazie !!!

profilo.jpg

processing è la via più usata ma per l'input da utente è un poco lacunosa, devi usare una libreria esterna. Però ci sono tantissimi tutorial, anche per la libreria grafica con pulsanti e texbox. Secondo me è la via più semplice e veloce

Altra scelta è quella di utilizzare visual studio express, ad esempio io avevo utilizzato visual c# con la libreria zedgraph per disegnare il grafico (esistono però un'infinità di librerie per i grafici)

Ciao se la tua esigenza è una rappresentazione grafica, ci sono altre strade oltre a Processing. In questo thread trovi qualche link di approfondimento: http://arduino.cc/forum/index.php/topic,51300.0.html

Grazie a tutti voi per i consigli e i link, però tenete conto che sono veramente agli inizi e mi resta difficile districarmi tra le varie possibilità. Fondamentalmente avrei bisogno di inviare i dati dal PC verso l’Arduino e non necessariamente in forma grafica. Il semplice sketch dal quale devo partire è questo

// prova termostato
// ver. 1.0 22-07-2011

#include <max6675.h>
#include <LiquidCrystal.h>

#define RESISTENZA 7 //Resistenza su D7
#define TMIN 100 //soglia intervento termostato
#define ISTERESI 2 //isteresi
#define ON 1
#define OFF 0

int Temperatura; //contiene la temperatura letta dal sensore
int thermoDO = 4;
int thermoCS = 5;
int thermoCLK = 6;
int vccPin = 3;
int gndPin = 2;

MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);

LiquidCrystal lcd(13, 8, 9, 10, 11, 12);

uint8_t degree[8] = {140,146,146,140,128,128,128,128};// realizza simbolo °

void setup() {
Serial.begin(9600);

pinMode(vccPin, OUTPUT); digitalWrite(vccPin, HIGH);
pinMode(gndPin, OUTPUT); digitalWrite(gndPin, LOW);
pinMode(RESISTENZA, OUTPUT); //D7 è la linea di uscita

lcd.begin(16, 2);
lcd.createChar(0, degree);

delay(500); // pausa per permettere al MAX6675 di stabilizzarsi
}

void loop() {

lcd.clear(); //inizializza il display
lcd.setCursor(0, 0); //posiziona il cursore sulla linea 0 riga 0
lcd.print(“Thermo 1.0 Test”); //scrive Thermo 1.0 Test test sul display

Temperatura=byte(thermocouple.readCelsius());//scrive in Temperatura il valore letto

if (Temperatura < TMIN) //se la temperatura è bassa attiva resistenza
digitalWrite(RESISTENZA, ON); //attiva il PIN 7
//Serial.print(“RESISTENZA ON”)
if (Temperatura >= TMIN+ISTERESI) //se la temperatura è alta disattiva resistenza
digitalWrite(RESISTENZA, OFF); //disattiva il PIN7
//Serial.print(“RESISTENZA OFF”)

lcd.setCursor(0,1); //posiziona il cursore sulla linea 1 riga 0
lcd.print(thermocouple.readCelsius()); //scrive sull’lcd il valore della temperatura
lcd.print(0, BYTE);
lcd.print("C ");

//Serial.print("C = ");
//Serial.println(thermocouple.readCelsius());

delay(1000);
}

In pratica avrei bisogno di inviare tramite il pc il valore della temperatura da raggiungere e mantenere per x tempo per poi inviare un altro valore di temperatura per altro x tempo e così via e se fosse possibile poter variare al “volo” questi valori in ogni momento. Se poi fosse possibile avere sul PC in forma grafica il ritorno dei dati dall’ arduino sarebbe il massimo !!! Mi servirebbe un esempio “Pratico” altrimenti difficilmente riesco ad andare avanti…
Ancora grazie sia per la disponibilità che per la pazienza !!!

un esempio grafico ma un poco avanzato è questo:

/**
 * 3d visualization of quaternion, and PID regulation
 * 27/07/2011by lesto
 */

import processing.serial.*;
import controlP5.*;

Serial myPort;  // Create object from Serial class


float [] Q = new float [4];
float [] Euler = new float [3]; // psi, theta, phi

int lf = 10; // 10 is '\n' in ASCII
byte[] inBuffer = new byte[22]; // this is the number of chars on each line from the Arduino (including /r/n)

PFont font;
final int VIEW_SIZE_X = 600, VIEW_SIZE_Y = 600;

Textfield inputP;
Textfield inputI;
Textfield inputD;
Textfield inputPorizon;
Textfield inputIorizon;
ControlP5 controlP5;

void setup() 
{
  size(VIEW_SIZE_X, VIEW_SIZE_Y, P3D);
  myPort = new Serial(this, "/dev/ttyUSB0", 19200);  

  font = loadFont("CourierNew36.vlw"); 

  controlP5 = new ControlP5(this);

  inputP = controlP5.addTextfield("p",400,100,100,20);
  inputI = controlP5.addTextfield("i",400,120,100,20);
  inputD = controlP5.addTextfield("d",400,140,100,20);
  inputPorizon = controlP5.addTextfield("P",400,160,100,20);
  inputIorizon = controlP5.addTextfield("I",400,180,100,20);

  // The font must be located in the sketch's "data" directory to load successfully



  delay(100);

  if (myPort != null) {
    myPort.clear();
    //myPort.write("start");
  }
  else {
    return;
  }
}


void readQ() {
  int num=0;
  while(myPort.available() > 0 && num < 1000) {
    String inputString = myPort.readStringUntil('\n');
    //    print("letto: ");
    //    println(inputString);
    if (inputString != null && inputString.length() > 0) {

      String [] inputStringArr = split(inputString, ' ');
      if(inputStringArr.length == 4) {
        try {
          float d[]=new float[4];
          d[0] = Float.parseFloat(inputStringArr[0]);
          d[1] = Float.parseFloat(inputStringArr[1]);
          d[2] = Float.parseFloat(inputStringArr[2]);
          d[3] = Float.parseFloat(inputStringArr[3]);
          for (int i=0; i < 4; i++) {
            Q[i]=d[i];
          }
          num++;
        }
        catch(Exception e) {
          //println(e);
          //println(inputString);
        }
      }
      else {
        if (inputString!=null) {
          if (!inputString.equals("\r\n") ) {
            print(inputString);
            //            println(inputString.length());
          }
        }
      }
    }
  }
  //if (num>0)
  //println("numero letture"+num);
}



void buildBoxShape() {
  //box(60, 10, 40);
  noStroke();
  beginShape(QUADS);

  //Z+ (to the drawing area)
  fill(#00ff00);
  vertex(-30, -5, 20);
  vertex(30, -5, 20);
  vertex(30, 5, 20);
  vertex(-30, 5, 20);

  //Z-
  fill(#0000ff);
  vertex(-30, -5, -20);
  vertex(30, -5, -20);
  vertex(30, 5, -20);
  vertex(-30, 5, -20);

  //X-
  fill(#ff0000);
  vertex(-30, -5, -20);
  vertex(-30, -5, 20);
  vertex(-30, 5, 20);
  vertex(-30, 5, -20);

  //X+
  fill(#ffff00);
  vertex(30, -5, -20);
  vertex(30, -5, 20);
  vertex(30, 5, 20);
  vertex(30, 5, -20);

  //Y-
  fill(#ff00ff);
  vertex(-30, -5, -20);
  vertex(30, -5, -20);
  vertex(30, -5, 20);
  vertex(-30, -5, 20);

  //Y+
  fill(#00ffff);
  vertex(-30, 5, -20);
  vertex(30, 5, -20);
  vertex(30, 5, 20);
  vertex(-30, 5, 20);

  endShape();
}


void drawCube() {  
  pushMatrix();
  translate(300, 350, 0);
  scale(5,5,5);


  // please, don't ask me why these angles are negated
  rotateZ(-Euler[2]);
  rotateX(-Euler[1]);
  rotateY(-Euler[0]);

  buildBoxShape();

  popMatrix();
}


void draw() {
  controlP5.draw();
  readQ();
  quaternionToEuler(Q, Euler);

  background(#000000);
  fill(#ffffff);

  textFont(font, 20);
  //float temp_decoded = 35.0 + ((float) (temp + 13200)) / 280;
  //text("temp:\n" + temp_decoded + " C", 350, 250);
  text("Q:\n" + Q[0] + "\n" + Q[1] + "\n" + Q[2] + "\n" + Q[3], 20, 50);
//  text("Euler Angles:\npsi  : " + degrees(Euler[0]) + "\ntheta: " + degrees(Euler[1]) + "\nphi  : " + degrees(Euler[2]), 200, 50);

  text("Euler Angles:\npsi  : " + Euler[0] + "\ntheta: " + Euler[1] + "\nphi  : " + Euler[2], 200, 20);
  float e[] = new float[3];
  quatToEuler( Q, e );
  Euler[0]=e[0];
    Euler[1]=e[1];
      Euler[2]=e[2];
      
  text("Euler Angles:\npsi  : " + degrees(e[0]) + "\ntheta: " + degrees(e[1]) + "\nphi  : " + degrees(e[2]), 400, 20);

  drawCube();

  text("p", 350, 120);
  text("i", 350, 140);
  text("d", 350, 160);
  text("O P", 350, 180);
  text("O I", 350, 200);  
  controlP5.draw();
}


// See Sebastian O.H. Madwick report "An efficient orientation filter for inertial and intertial/magnetic sensor arrays
void quaternionToEuler(float [] q, float [] euler) {
  euler[0] = atan2(2 * q[1] * q[2] - 2 * q[0] * q[3], 2 * q[0]*q[0] + 2 * q[1] * q[1] - 1); // psi
  euler[1] = -asin(2 * q[1] * q[3] + 2 * q[0] * q[2]); // theta pitch
  euler[2] = atan2(2 * q[2] * q[3] - 2 * q[0] * q[1], 2 * q[0] * q[0] + 2 * q[3] * q[3] - 1); // phi yaw?
}

void quatToEuler(float q1[], float euler[]) {
  //float[] euler = new float[3];
  //q1.normalize();
  double test = q1[0] * q1[1] + q1[2] * q1[3];
  if (test > 0.499) { // singularity at north pole
    euler[1] = (float) (2 * Math.atan2(q1[0], q1[3]));
    euler[2] = (float) (Math.PI / 2);
    euler[0] = 0;
    //return new Vector3f(euler);
    return;
  }
  if (test < -0.499) { // singularity at south pole
    euler[1] = (float) (2 * Math.atan2(q1[0], q1[3]));
    euler[2] = (float) -(Math.PI / 2);
    euler[0] = 0;
    //return new Vector3f(euler);
    return;
  }
  double sqx = q1[0] * q1[0];
  double sqy = q1[1] * q1[1];
  double sqz = q1[2] * q1[2];
  euler[1] = (float) Math.atan2(2 * q1[1] * q1[3] - 2 * q1[0] * q1[2], 1 - 2 * sqy - 2 * sqz);
  euler[2] = (float) Math.asin(2 * test);
  euler[0] = (float) Math.atan2(2 * q1[0] * q1[3] - 2 * q1[1] * q1[2], 1 - 2 * sqx - 2 * sqz);
  //return new Vector3f(euler);
}


void controlEvent(ControlEvent theEvent) {
  println("controlEvent: accessing a string from controller '"+theEvent.controller().name()+"': "+theEvent.controller().stringValue());
  if (theEvent.controller().stringValue().length() < 10) {
    try {
      Float.parseFloat( theEvent.controller().stringValue() );
      myPort.write("*"+theEvent.controller().name()+":"+theEvent.controller().stringValue()+"\n");
      println("Inviato:"+"*"+theEvent.controller().name()+":"+theEvent.controller().stringValue()+"\n");
    }
    catch(Exception e) {
      println("Non inviato:"+theEvent.controller().name()+":"+theEvent.controller().stringValue());
      //println(e);
      println("Non float o seriale non pronta");
    }
  }
  else {
    println("Non inviato:"+theEvent.controller().name()+":"+theEvent.controller().stringValue());
    println("Input too long");
  }
}

questo codice legge un quaternione (quattro numeri separati da : e poi a capo) e ruota un rettangolo di conseguenza. In oltre ci sono 6 texbox in cui settare un valore, al pèremere di invio il valore viene inviato all’arduino.

Questo è un programma che avevo fatto con Visual C#, semplicemente con lo sketch realizzato arduino riceve e reinvia i dati a PC. Il software può essere comunque utilizzato solo per la ricezione.

https://sites.google.com/site/circuitiarduino/home/comunicazione-arduino

mettiamola così: in processing puoi leggere e scrivere nella seriale esattamente come fa arduino (serial.begin etc etc..). L'unico sbattimento è rappresentato dall'input per l'utente, comunque problemi mooolto più grossi in praticamente tutti gli altri linguaggi.

Grazie Pitusso, lesto ypkdani !!! Ho provato a dare un'occhiata e a far girare lo sketch di lesto e onestamente non ci ho capito nulla... :D :D :D Per quanto riguarda l'esempio postato da ypkdani è più vicino a quello che mi occorre, ma avrei la necessità anche di inviare i dati tramite il PC Ho guardato anche i link suggeriti da pitusso e consiglio a tutti i principianti senza nessuna conoscenza come me di seguire il corso a puntate su youtube per processing. E' veramente ben fatto e spiega in maniera semplice molti rudimenti della programmazione.

Tornando al mio problema, qualcuno ha un po' di tempo da dedicarmi per tirare giu' un semplice sketch per processing da far girare insieme alllo sketch per arduino che ho postato che mi permetta di variare tramite due tasti della tastiera il valore di TMIN ? Questo mi servirebbe per capire come funziona la cosa e poi procedere con il passaggio successivo

Non conosco processing ed al momento sto imparando wpf quindi non ho tempo da dedicarti, qui però penso ci sia un tutorial che ti puo aiutare: http://jeremyblum.com/2011/02/07/arduino-tutorial-6-serial-communication-and-processing/ Ciao

Grazie ypkdani, provo a darci un'occhiata....

allora, se vuoi inviare un dato via processing, è abbastanza semplice.

in processing fai:

import processing.serial.*;

Serial myPort;  // Create object from Serial class

void setup() 
{
  size(200, 200);
  // I know that the first port in the serial list on my mac
  // is always my  FTDI adaptor, so I open Serial.list()[0].
  // On Windows machines, this generally opens COM1.
  // Open whatever port is the one you're using.
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600);
  //in alternativa, puoi "forzare" l'apertuyra di una porta seriale specifica, per esempio, per aprire la COM9:
  //myPort = new Serial(this, "COM9", 9600);
}

void draw()
{
  //legge un byte
  int val;
  if ( myPort.available() > 0) {  // If data is available,
    val = myPort.read();         // read it and store it in val
  }
  //scrive il valore letto indietro.
  myPort.write(val);
}

lato arduino il codie è praticamente lo stesso, solo che al posto di myPort usi "Serial", e il comando di inizializzazione nel setup è più semplice (Serial.begin(9600)). 9600 è il baudrate, ovvero il numero di byte scritti al secondo, più è alto più veloce è la trasmissione dei dati. Dato che devi leggere solo un byte il problema dovrebbe essere risolto così, se invece devi leggere più byte (esempio un intero o una stringa) il codice si complica.

ps. immaginavo che il mio codice processing non fosse per principianti, ma è l'unico che ho.

Grazie Lesto e complimenti per il tuo codice veramente un gran bel lavoro !!!

ho fatto una prova con l’esempio che mi hai fatto, ma mi esce l’errore come da foto “a”
Nella lezione in inglese ho copiato il codice ma mi esce l’errore come da foto “b”… =( =( =(

dove sbaglio ???

semplice leggi gli errori: foto A: la variabile VAL potrebbe essere non inizializzata. Quando non inizializzi una variabile (in C, visto che java rompe le balle e non compila, il C invece se ne frega e compila) al suo interno hai un valore casuale. Quindi SE entri nell'if, val avrà un valore e quindi tutto ok, ma se on ci entra val possiede un valore a caso (bel problema!) soluzioni: o inizializzi la variabile (val=0; per esempio) o metti la write dentro l'if, in modo che usi val solo quando è stata inizializzata dalla read!

foto B: "errore di sintassi, orse manca un punto e virgola(semicolon)?" ed infatti, se guardi la riga PRECEDENTE a quella evidenziata, manca il punto e virgola. Perchè è evidenziata la riga dopo? storie di compilazione, sappi che non devi fidarti ciecamente del debugger, altrimenti i programmatori a cosa servono? ;)

Grazie lesto !!! Grazie a te ho appreso altre due importanti regole e "vizi" del C.....

Sono ancora in panne…

Dunque, ho seguito ( a fatica ) una “lezione” in inglese presente su uno dei link che mi avete consigliato e copiando gli sketch per arduino e processing ho visto dal “vivo” l’interazione tra l’arduino e il PC .

I due semplici sketch sono questi

Arduino

int potpin = 0;

void setup()
{
Serial.begin(9600);
}

void loop()
{
int val = map(analogRead(potpin), 0, 1023, 0, 255);
Serial.println(val);
delay(50);
}

Processing

import processing.serial.*;
Serial port;
float brightness = 0;

void setup()
{
size(500,500);
port = new Serial(this, “COM3”, 9600);
port.bufferUntil(’\n’);
}
void draw()
{
background(0,0,brightness);
}

void serialEvent (Serial port)
{
brightness = float(port.readStringUntil(’\n’));
}

In pratica sulla scheda Arduino ho inserito un potenziometro da 10 Kohm con i capi laterali collegati uno alla massa e l’altro al 5 Volt. Il cursore centrale è collegato sul PIN 0 analogico dell’arduino.
In questo modo posso variare la tensione presente sull’ingresso analogico che viene campionata ( da 0 a 1023) e “convertita” in una scala da 0 a 254 . Questo valore viene utilizzato per far variare la luminosità di un rettangolo disegnato sullo schermo da nero a blu acceso. Funziona tutto perfettamente anche se ci sono diversi passaggi che non capisco e dovrò approfondire.
Ritornando al mio progetto iniziale, come posso fare per far “leggere” a processing il valore della temperatura ?

lo sketch per arduino è sempre il solito, è inutile che vada avanti se non riesco a fare questa operazione
che per i più sarà semplice ma per me è veramente complicata.

Arduino

// prova termostato
// ver. 1.0 22-07-2011

#include <max6675.h>
#include <LiquidCrystal.h>

#define RESISTENZA 7 //Resistenza su D7

#define TMIN 50 //soglia intervento termostato
#define ISTERESI 2 //isteresi

#define ON 1
#define OFF 0

int Temperatura; //contiene la temperatura letta dal sensore

int thermoDO = 4;
int thermoCS = 5;
int thermoCLK = 6;

MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
int vccPin = 3;
int gndPin = 2;

LiquidCrystal lcd(13, 8, 9, 10, 11, 12);

// make a cute degree symbol
uint8_t degree[8] = {140,146,146,140,128,128,128,128};

void setup() {
Serial.begin(9600);
// use Arduino pins
pinMode(vccPin, OUTPUT); digitalWrite(vccPin, HIGH);
pinMode(gndPin, OUTPUT); digitalWrite(gndPin, LOW);
pinMode(RESISTENZA, OUTPUT); //D7 è la linea di uscita

lcd.begin(16, 2);
lcd.createChar(0, degree);

// wait for MAX chip to stabilize
delay(500);
}

void loop() {

lcd.clear(); //inizializza il display
lcd.setCursor(0, 0); //posiziona il cursore sulla linea 0 riga 0
lcd.print(“MAX6675 test”); //scrive MAX6675 test sul display

thermocouple.readCelsius(); //Invia comando lettura temperatura
Temperatura=BYTE;

if (Temperatura < TMIN) //temperatura bassa attivare resistenza
digitalWrite(RESISTENZA, ON); //attiva il PIN 7
if (Temperatura >= TMIN+ISTERESI) //temperatura alta disattivare resistenza
digitalWrite(RESISTENZA, OFF); //disattiva il PIN7

lcd.setCursor(0,1); //posiziona il cursore sulla linea 1 riga 0
lcd.print(thermocouple.readCelsius());
lcd.print(0, BYTE);
lcd.print("C ");

delay(1000);
}

processing

Come faccio a leggere e scrivere la temperatura rilevata dalla sonda ???

Grazie ancora a tutti voi !!!

lato arduino Serial.println(thermocouple.readCelsius());

lato processing rimane identico, a meno che non vuoi visualizzare il dato come stringa... per stamparlo nel terminale di processing basta scrivere print(brightness); (se usi lo stesso codice di prima)

Grazie lesto !!! In effetti mi perdo da solo…avevo modificato lo sketch dell’arduino aggiungendo la riga di codice che mi hai suggerito te copiandola da quella che scrive la temperatura sul display

lcd.print(thermocouple.readCelsius());

e modificandola

Serial.println(thermocouple.readCelsius());

Lato processing non avevo modificato niente ma la schermata rimaneva nera…e mi usciva un messaggio di errore (vedi figura ) bastava aumentare la temperatura letta dalla termocoppia per avere la variazione di luminosità…Mi esce comunque il messaggio di errore…

Ho visto che l’altra riga che mi hai consigliato va a scrivere nel terminale di processing ( come mi hai detto ) ma in realtà avrei bisogno di scrivere a video nella finestra il valore della temperatura in formato numerico aggiornandolo al variare della temperatura ( ovvero non scrivendo di seguito tutti i valori letti ) e possibilmente disegnare una curva che indichi l’andatura della temperatura stessa.

b.jpg

l'errore che hai dipende da alcune librerie, ma non è un errore, è un warning

Grazie per la precisazione lesto, infatti lo sketch funziona comunque, nonostante la segnalazione