Pages: [1] 2   Go Down
Author Topic: Acquisire e processare stringhe da seriale  (Read 2000 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ciao a tutti,
Ho l'intenzione di leggere i valori di una stringa creata da processing su arduino. Fin'ora ho creato questo codice che ovviamente non fa cambiare i valori dei pin:
Code:
char serialin[] = "";

String motor1[] = "";
String motor2[] = "";
String motor3[] = "";
String motor4[] = "";

int motor1val = 0;
int motor2val = 0;
int motor3val = 0;
int motor4val = 0;

int i = 0;

void setup() {
  Serial.begin(9600);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
}
void loop() {
  if (Serial.available() > 0) {
    while (Serial.available() > 0) {
      serialin[i] = char(Serial.read());
      i++;
    }
    motor1 += int(serialin[0]);
    motor1 += int(serialin[1]);
    motor1 += int(serialin[2]);
   
    motor2[0] = serialin[4];
    motor2[1] = serialin[5];
    motor2[2] = serialin[6];
   
    motor3[0] = serialin[8];
    motor3[1] = serialin[9];
    motor3[2] = serialin[10];
   
    motor4[0] = serialin[12];
    motor4[1] = serialin[13];
    motor4[2] = serialin[14];
   
    motor1val = atoi(motor1);
    motor2val = atoi(motor2);
    motor3val = atoi(motor3);
    motor4val = atoi(motor4);
   
    Serial.flush();
    }
   
    analogWrite(3, motor1val);
    analogWrite(5, motor2val);
    analogWrite(6, motor3val);
    analogWrite(9, motor4val);
}

esattamente la stringa seriale che processing produce e invia è:
Code:
Ü,´,?,?
o qualcosa di simile, ovviamente i caratteri cambiano in base al numero di input dell'utente e devono essere convertiti mediante la tabella ascii per trovare l'esatto valore.

Qualcuno che sappia darmi una mano smiley?
Logged

0
Offline Offline
Shannon Member
****
Karma: 131
Posts: 10468
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
while (Serial.available() > 0) {
      serialin[i] = char(Serial.read());
      i++;
    }

così stai dando per scontato che tutta la stringa ti arrivi in blocco. Non è vero: per la seriale, ogni lettera (o meglio, ogni byte) è un discorso a parte. Certo SPESSO queste due cose coincidono, ma partire da una falsa assunzione è la via privilegiata per fare una brutta fine. Un pò come costruire una casa senza fondamenta, quando inizia a cascare c'è poco da fare. Quindi sta a te inventarti una lettera che indichi al tuo ciclo di lettura che la stringa è stata completata.

Da quì nasce il problema che arduino potrebbe leggere (per varie problematiche più rare delle precedenti) solo una parte della stringa: sta a te capire se una stringa è valida, o usando un carattere di "inizio stringa" oppure, se conosci a priori la lunghezza della stringa, a controllare che il numero di byte letti coincida.

poichè tu vuoi lavorare con i valori grezzi, e fregartene altamente delle tabelle ascii, non vedo perchè tiri in mezzo atoi: Ü per esempio, corrisponde ad un valore numerico, però se ci fai una atoi ottieni che Ü non corrisponde ad alcun numero, e quindi atoi ritorna un valore standard oppure un errore.

uhh se ti ho messo confusione  non fare problemi a chiedere. diciamo che il motivo principale per cui non funziona è il numero 3, ma anche gli altri 2 sono importanti e te ne accorgeresti quando risolvi il punto 3 e ti ritrovi con i motori che ogni tanto (o sempre, dipende dal baudrate impostato e dalla durata del loop) che impazziscono lo stesso
Logged

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

Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey ti devo fare un ringraziamento speciale per la fedeltà con cui mi aiuti smiley-grin smiley-grin
Comunque, non ho ben capito, la seriale per me è un po' incasinata... Comunque ho provato a cambiare l'output di processing portandolo a una cosa del genere:
Code:
207,213,215,244
ma tutti i pin rimangono a 0 volt :\
Logged

0
Offline Offline
Shannon Member
****
Karma: 131
Posts: 10468
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ah ok, passimo per i char. va bene però quando fai

Code:
motor1 += int(serialin[0]);
    motor1 += int(serialin[1]);
    motor1 += int(serialin[2]);

metti che arriva 207 succede che fai

motor1 += 2; //errore, se motor != 0!
motor1 += 0;
motor1 += 7;
motor1 quindi è = a 9!!

questo errore è su tutte le letture. considera che poi non stai mettendo 2 0 o 7, perchè quelli sono il corrispettivo ashii: sti mettendo il valore nella tabella ascii che corrisponde a 2, 0 o 7. è quì che dovresti usare atoi, non alla fine!

bhè, almeno per la virgola va bene che ti sei ricordato di saltarla
Logged

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

provincia di Forlì
Offline Offline
Full Member
***
Karma: 0
Posts: 119
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Non è esattamente quello di cui ho bisogno ma mi accodo sperando di poter capirci qualcosa sulla seriale, che davvero, è una parte davvero mistica/oscura per me....
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Allora, ho tolto quel pezzo di codice che hai preso in esame in quanto dava errore durante la compilazione(non chiedermi perchè). E sono rimasto con il codice che vedevi subito sotto al pezza da te esaminato.
Ora ho questo:
Code:
char serialin[] = "";

char motor1[] = "";
char motor2[] = "";
char motor3[] = "";
char motor4[] = "";

int motor1val = 0;
int motor2val = 0;
int motor3val = 0;
int motor4val = 0;

int i = 0;

void setup() {
  Serial.begin(9600);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
}
void loop() {
  if (Serial.available() > 0) {
    while (Serial.available() > 0) {
      serialin[i] = char(Serial.read());
      i++;
    }
    motor1[0] = atoi(serialin[0]);
    motor1[1] = atoi(serialin[1]);
    motor1[2] = atoi(serialin[2]);
   
    motor2[0] = atoi(serialin[4]);
    motor2[1] = atoi(serialin[5]);
    motor2[2] = atoi(serialin[6]);
   
    motor3[0] = atoi(serialin[8]);
    motor3[1] = atoi(serialin[9]);
    motor3[2] = atoi(serialin[10]);
   
    motor4[0] = atoi(serialin[12]);
    motor4[1] = atoi(serialin[13]);
    motor4[2] = atoi(serialin[14]);
   
    motor1val = int(motor1);
    motor2val = int(motor2);
    motor3val = int(motor3);
    motor4val = int(motor4);
   
    Serial.flush();
    }
   
    analogWrite(3, motor1val);
    analogWrite(5, motor2val);
    analogWrite(6, motor3val);
    analogWrite(9, motor4val);
}

tuttavia mi restituisce
Code:
error: invalid conversion from 'char' to 'const char*'

p.s. se non sai neanche le basi della seriale, se vuoi ho un buon video da consigliarti smiley-wink
Logged

provincia di Forlì
Offline Offline
Full Member
***
Karma: 0
Posts: 119
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Beh forse ho esagerato!
Scrivo sulla porta seriale cosa ritornano i componenti che uso e queste cose qua ma se devo inviare io qualcosa su porta seriale in modo da aggiorare una variabile su Arduino, beh, qui proprio zero!

Se mi vuoi linkare il video me lo guardo lo stesso, non si sa mai !
Logged

0
Offline Offline
Shannon Member
****
Karma: 131
Posts: 10468
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

a si, scusa, atoi vuole in input una stringa non una lettera.
se osservi la tabella ascii, per trasformare una lettera nel corrispettivo valore inttero basta sottrarre il valore asseganto al carattere 0.

altrimenti potresti "rompere" la tua megastringa in tante piccole stringhe da 4 caratteri (3 cifre + '\0', ovvero carattere di fine stringa) e darle in pasto ad atoi. in questo modo avresti:
char a[4];
a[0] = '2'; a[1]= '0';a[2] = '9'; a[3] = '\0';
int num = atoi(a);
Logged

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

Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
char serialin[] = "";

char motor1[4] = "";
char motor2[4] = "";
char motor3[4] = "";
char motor4[4] = "";

int motor1val = 0;
int motor2val = 0;
int motor3val = 0;
int motor4val = 0;

int i = 0;

void setup() {
  Serial.begin(9600);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
}
void loop() {
  if (Serial.available() > 0) {
    while (Serial.available() > 0) {
      serialin[i] = char(Serial.read());
      i++;
    }
    motor1[0] = serialin[0];
    motor1[1] = serialin[1];
    motor1[2] = serialin[2];
    motor1[3] = '\0';
    motor1val = atoi(motor1);

    motor1[0] = serialin[4];
    motor1[1] = serialin[5];
    motor1[2] = serialin[6];
    motor2[3] = '\0';
    motor2val = atoi(motor3);

    motor1[0] = serialin[8];
    motor1[1] = serialin[9];
    motor1[2] = serialin[10];
    motor3[3] = '\0';
    motor3val = atoi(motor3);

    motor1[0] = serialin[12];
    motor1[1] = serialin[13];
    motor1[2] = serialin[14];
    motor4[3] = '\0';
    motor4val = atoi(motor4);

    Serial.flush();
  }

  analogWrite(3, motor1val);
  analogWrite(5, motor2val);
  analogWrite(6, motor3val);
  analogWrite(9, motor4val);
}


Ho modificato il codice in questo modo ma pur dando via seriale 220,220,220,220 gli output dell'arduino rimangono a 0v :\
Logged

0
Offline Offline
Shannon Member
****
Karma: 131
Posts: 10468
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ok, ora la conversione dovrebbe essere giusta... ora dobbiamo assicurarci che i caratteri che arrivano via seriale siano giusti!

questo loop avviene con una velocità di (sparo un valore) 100microSec. un carattere con baud a 9600 impiega 1/960 secondi ad essere inviato.

quindi ogni loop sei fosrtunano se leggi anche solo UN carattere... come ti dicevo devi trovare un modo per rallentare il loop fino al ricevimento di tutta la stringa (non usare un delay, ma un carattere di fine stringa), oppure che aggiunge la lettera eventualmente letta ogni loop ad una stringa, e quando la stringa è abbastanza lunga (quindi completa) esegua la conversione.

in pratica immagina se io anzichè inviare solo questa risposta ti invii questa risposta in tanti messaggi da 3 o 5 o X caratteri a caso. Perchè tu possa ricavare un senso logico o aspetti che io finisca di scrivere e leggi tutto, oppure leggi pezzo per pezzo mano a mano che i messaggi arrivano e crei nella mente il significato.
Logged

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

Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

una cosa di questo tipo potrebbe andar bene?
Code:
char serialin[] = "";

char motor1[4] = "";
char motor2[4] = "";
char motor3[4] = "";
char motor4[4] = "";

int motor1val = 0;
int motor2val = 0;
int motor3val = 0;
int motor4val = 0;

int i = 0;

void setup() {
  Serial.begin(9600);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
}
void loop() {
  if (Serial.available() > 0) {
    while (Serial.available() > 0) {
      serialin[i] = char(Serial.read());
      i++;
    }
    if (sizeof(serialin) >= 15) {
    motor1[0] = serialin[0];
    motor1[1] = serialin[1];
    motor1[2] = serialin[2];
    motor1[3] = '\0';
    motor1val = atoi(motor1);

    motor1[0] = serialin[4];
    motor1[1] = serialin[5];
    motor1[2] = serialin[6];
    motor2[3] = '\0';
    motor2val = atoi(motor3);

    motor1[0] = serialin[8];
    motor1[1] = serialin[9];
    motor1[2] = serialin[10];
    motor3[3] = '\0';
    motor3val = atoi(motor3);

    motor1[0] = serialin[12];
    motor1[1] = serialin[13];
    motor1[2] = serialin[14];
    motor4[3] = '\0';
    motor4val = atoi(motor4);

    Serial.flush();
    }
  }

  analogWrite(3, motor1val);
  analogWrite(5, motor2val);
  analogWrite(6, motor3val);
  analogWrite(9, motor4val);
}


perchè ora i pin sono a 1v (non ci capisco più nullaaaaa D:)
Logged

0
Offline Offline
Shannon Member
****
Karma: 131
Posts: 10468
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

quasi, scordati sizeof che in questo caso ti da sì la dimensione dell'array, ma essendo un array in realtà un puntatore alla cella di ram che possiede il primo elemento, ti restituisce la dimensione in byte del puntatore, ovvero 16 byte. confuso? vabbè lascia perdere.

devi usare una variabile contatore: aumenta di 1 ogni lettera letta e aggiunta alla stringona, e viene azzerata quando la stringona cancellata. diciamo che non esiste un altro metodo (bugia bugia bugia! ma prima studiati i puntatori)
Logged

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

Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

perfetto, ora funziona smiley-grin Il problema è solo uno, dato che processing invia i valori relativi a una barra di selezione, è possibile che invii valori a una o due cifre il che incasina un po' tutto, come mi regolo :/?
Logged

0
Offline Offline
Shannon Member
****
Karma: 131
Posts: 10468
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

visto che i valori sono divisi da virgola, puoi fare un algoritmo che "smonta" i valori in base ad essa. oppure cambi l'algoritmo processing per fare in modo che invii sempre valori a 3 cifre, mettendo uno 0 davanti
Logged

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

Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Beh lesto, intanto grazie per la parte arduino smiley-grin
Stavo pensado di fare una serie di if che controllano la grandezza del numero facendo una cosa simile a:
se (numero minoreougualea 9) { numero = 00numero }
se (numero minoreougualea 99 && maggiore di 9) { numero = 0numero }
ma come faccio a unire un int a un'altro int? o meglio come faccio fisicamente a aggiungere due zeri?
Logged

Pages: [1] 2   Go Up
Jump to: