Far comunicare GRBL e arduino uno

Ciao!
dopo svariate ore passate a leggere forum e documentazioni varie, prima di cadere nella demoralizzazione, vorrei chiede a qualche buon anima se mi puo' aiutare a risolvere il mio problema !

Scenario: (scusate ma sara' un post lungo !)
Ho un atmega 328 standalone con caricato Grbl 0.9e (funzionante e testato , sempre utilizzato inviando i dati tramite pc in seriale..)
Ho poi un arduino uno sul quale sto cercando di sviluppare questo sw che mi fa dannare..
Questo secondo "giocattolo" lo chiamero' "master", mentre il 328 con grbl lo chiamero' "grbl" per cercare di spiegare..

Ora mi sono intestardito di voler utilizzare il master (che poi se tutto funzionera' diventera' un altro 328 standalone) per inviare i dati al "Grbl" tramite seriale prendendoli da una SD.

Ho fatto la parte hw, ho messo anche un lcd 16x2 per un debug immediato, visto che la seriale poi sara' dedicata solo alla comunicazione tra i 2 e non disponibile per il pc..
Fin qui tutto ok, se leggo le linee una ad una dalla SD e le "stampo" sull lcd , nessun problema, tutto corretto..
Se inoltre le invio via seriale (collegata per test/debug) al pc simulando di essere io tramite pc il grbl a ricevere/rispondere anche qui tutto ok !
Ho verificato con un programma di connessione seriale (su pc) con visualizzazione ascii ed esadecimale dei dati da e verso "grbl" ed escono corretti al byte, MA (!!) se collego tra loro i 2 questi si scambiano 1 o massimo 2 linee e poi si ferma il tutto miseramente !!
Il grbl restituisce degli errori come se i comandi fossero "malformati" anche se in realta' le linee di comando sono perfette ( provato piu' volte ad inviare le stesse da pc e le accetta benissimo..)
Pensavo fossero degli errori di comunicazione, dovuti a disturbi o velocita', (i 2 sono a 10 cm)
Ho provato ad abbassare la velocita', ma non cambia nulla
Mi sono messo col pc "sniffando" una alla volta le linee TX del grbl e del master usando un convertitore usb2ttl collegando solo la massa e la RX, in modo da non influire sulle comunicazioni, e la sequenza di byte che vedo passare in entrambi i sensi e' esattamente quella che mi aspetto mentre comunicano tra loro, MA QUALCOSA NON VA !!!
...Sto impazzendo (il caldo non aiuta..)

Per chi non lo conoscesse grbl e' un piccolo interprete di codice "G" che poi pilota i motori di varie cose, da stampanti 3d, pantografi cnc etc..
Da un certo punto di vista e' molto semplice.. alla partenza invia in seriale una stringa di "benvenuto" e poi sta li ad aspettare dei comandi via seriale, appunto !
Semplificando moltissimo il suo funzionamento, ad ogni CR (o LF, indifferentemente) inviatogli lui risponde con un "ok"+CR+LF ad indicare che lo ha ricevuto

poi se si invia una stringa tipo "G0 x1 y2" +CR (o LF e' indifferente) lui la prende in "carico" e risponde il solito "ok"+CR+LF
di queste stringhe ne accetta un tot, fino a riempire un buffer, ed il risultato e' che ad un certo punto inviandone una lui non ci restituira piu' il solito ok+... finche non avra' "smaltito" quelle gia' presenti nel buffer
A quel punto ci mandera' il solito ok e noi potremmo sparare in seriale altre stringhe e via dicendo..

Ho anche provato a fere un programmino molto ridotto eliminando al minimo le cose per cercare di uscirne, ma anche senza lettura da SD, dichiarando 5 stringhe di test scritte a mano e perfettamente testate e funzionanti ancora non vuole andare.
Ho introdotto ritardi di test ovunque, ma piu' ci sbatto e meno capisco..

Qualcuno mi aiuterebbe ??

Grazie !

Ah,
allego il codice ridotto all' osso della parte master..

funziona egregiamente se lo si testa tra master e pc, ma appena si collegano master e grbl invia una o 2 stringhe e poi grbl da errori come se la stringa inviata fosse "sbagliata" e poi si ferma tutto..

#include <Wire.h>              
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR  0x38  // indirizzo i2c del pcf..
#define BACKLIGHT_PIN     7 
int lineNo = 0;

// stringhe di comandi di prova..
char* ComandoG[]={"g0 z10.00","G00 X0.000 Y0.000","G00 X-3.00 y0.00 Z5.000","G00 X-3.00 y0.00 Z0.000","G01 X-3.00 y0.00 Z-4.00 F250","X-0.00 Y-0.00 Z-4.00","g0 z5.00","g0 x0 y0"};

String RxString;
LiquidCrystal_I2C lcd(I2C_ADDR, BACKLIGHT_PIN, POSITIVE);  // Set the LCD I2C address

void setup()
{
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.begin(16,2);        // inizilizzo l' lcd a 16 colonne per 2 righe
  lcd.setBacklight(HIGH);
  lcd.clear();
  lcd.print("Attesa GRBL..");
  
  delay(5000); // aspetto alcuni sec prima di iniziare ad inviare
  
 // Open serial communications and wait for port to open:
  Serial.begin(57600); // velocita' di trasmissione seriale
  
  // sveglio GRBL :
  Serial.println(); // invio cr+lf (risponde con 2 ok di fila)
  delay(1000); // attendo un sec per la risposta
  Serial.flush();  // per sicurezza svuoto il buffer di ricezione

  lcd.clear();
  lineNo= 0 ;
    while (lineNo < 8)  // mi preparo ad inviare le 8 stringhe di test
      {
        Serial.print(ComandoG[lineNo]); // invio la stringa
        Serial.write(0x0A);      // seguita solo da /n (LF)
        lcd.print(ComandoG[lineNo]); // per debug la scrivo sull lcd
        lineNo++;
        delay(1000); // attesa per lettura informazioni su lcd

        // lettura della risposta da seriale e stampa su lcd della stessa..

        while (Serial.available() <=0) // Attendo che il buffer di ricezione contenga qualcosa in risposta
        	{
             delay(5);
                }

        while (Serial.available()) // legge tutti i caratteri nel buffer
          {
          RxString += char(Serial.read()); // creo una stringa con i caratteri ricevuti
          delay(10);
          }

        lcd.print(String(lineNo) + "<" + RxString); // su lcd la stringa di risposta ricevuta
        delay(1000); // tempo per leggerla
        RxString="";

      } // file lettura risposta
  
  // dopo aver inviato le 8 stringhe, fine trasmissione
    lcd.clear();
    lcd.print("Fine invio !!");  
}

// fine programma

void loop()
{
delay(100);
// loop infinito che non fa niente !!
}

Ti invitiamo a presentarti qui: Re: Presentazioni nuovi iscritti, fatevi conoscere da tutti! (Part 1) - Generale - Arduino Forum
e a leggere il regolamento: [REGOLAMENTO] Come usare questa sezione del forum - Italiano - Arduino Forum

Ciao
Ho fatto ulteriori prove..
con un altro arduino ho lo stesso risultato, MA utilizzando la software serial al posto di quella HW invece la cosa cambia parecchio...
FUNZIONA !!!!
..Al primo colpo, senza grosse modifiche..

Adesso pero' il problema mi rimane..
Io vorrei usare la seriale hardware per vari motivi (buffer, flessibilita' etc..)
Cosa potrebbe essere a causare il difetto ?
E' come se i dati venissero inviati "sbagliati" o disturbati o "non sincronizzati" (o chissa cos' altro..), anche se dal pc risultano arrivare in ordine..
Forse il pc e' piu' "flessibile". ?!
E' possibile che la parte dell' adattatore ttl2usb (il 16u2) dell arduino in quialche modo possa disturbare la comunicazione dei "pin" 0 e 1 essendo pratica,mente collegato assieme ad essi ?

Qualcuno mi puo' dare qualche consiglio o work-around ?

Grazie
Axel

Vediamo se ho capito.
Tu usi una UNO con il programma che hai inviato per trasmettere lo G-code ad uno "stand alone".
Non vedo il programma ricevente: probabilmente è la sede dell'inghippo.

Ciao cyberhs,
Grazie per avermi risposto, innanzitutto !

Il programma "ricevente" , il grbl in questione non lo posto perche' e' parecchio "ingombrante" ed articolato.
NON e' (purtroppo) farina del mio sacco, io mi limito ad utilizzarlo..
E' comunque open source e lo si trova qui:
https://github.com/grbl/grbl/tree/dev
lo si puo' comodamente consultare anche senza scaricarlo, direttamente dal web, giusto epr darci un occhiata..

Non mi sono addentrato a cercare di fare modifiche li' dentro perche' non credo di esserne in grado e per non peggiorare la cosa..

Se a passatempo o per curiosita' ci vuoi dare una sbirciata, per formulare qualche ipotesi che mi possa aiutare, mi faresti un gran regalo..
Grazie
Axel

Ma la UNO è collegata al PC via USB quando lanci il programma?

Ciao
No, assolutamente no !
quando provo a farli comunicare tra loro la usb sulla UNO e' libera, e il "grbl" ha i tx e rx ovviamente collegati incrociati alla UNO e basta !

Fornisco alimentazione alla UNO tramite un alimentatore esterno da 9v DC che ho verificato con l' oscilloscopio non dare glitch e spurie varie..
Dalla UNO alimento anche la GRBL portando i +5 e gnd (anche sulla grbl ci sono i cond di filtro e livellamento vicinissimi al chip)

Ho appena fatto un ulteriore prova, ho messo su una breadbord SOLO il mega328 della UNO, un quarzo da 16 Mhz e i 2 relativi cond da 22pf
Ho collegato l' LCD per debug immediato via I2C (solo i pin SDA e SCL), alimentazione, condensatore di filtro da 100nf + uno di stabilizzazione da 22uF.
Ah, ovviamnete la resistenza di pullup per il reset.
Ho collegato il tx del 328 (ex UNO) al rx del grbl e tx del 328(ex UNO) al rx del grbl... null' altro !

IL RISULTATO NON CAMBIA...
Sull lcd dove vedo la risposta del grbl, mi arriva sempre errore ad ogni invio, per poi fermarsi..

Quindo ho escluso anche eventuali disturbi dovuti al 16u2... c'e dell' altro che mi sfugge !

Ah, ovviamente ho fatto la prova a SOSTITUIRE il grbl con il pc per vedere cosa arriva in seriale ed arriva tutto perfettamemnte come mi aspetterei !!!

Ancora, con questo hardware (2 mega328 standalone) se sul master (leggi il chip della UNO) carico lo sketch che utilizza la sw serial i due parlano beati come due vecchie signore !!! (ovviamente usando come tx e rx della UNO due pin diversi da quelli dedicati alla seriale hw)

IDEE ???

L'errore credo sia nella String RxString.
Inizializzala usando tanti spazi quanti la lunghezza massima della stinga che devi ricevere più qualcosa.
String RxString = " ";

ciao
..dici ??
Dopo provo e ti faccio sapere..
sarebbe bello se cosi' potessi risolvere..

Io cominciavo ad ipotizzare che non fosse un problema di "cosa" spara in seriale, ma "quando" !
..nel senso che potrebbe inviare correttamente, ma che l'altro facesse la lettura in tempi "sbagliati" o troppo presto, o troppo tardi, prendendo come dato una parte incompleta del comando inviatogli.

per capirci se invece di prendere "g0 z10.00" cominciasse a "catturare" tardi lo stream e prendesse "0 z10.00" (senza la G iniziale per capirci) ci starebbe l'errore che restituisce, di comando errato
Anche se troncasse la fine dello stream (non prendendo che ne so il \n terminante) magari potrebbe rimanere nel buffer la striga che sommata alla successiva darebbe origine ad un comando senza senso..
Questo potrebbe essere il motivo per cui la comunicazione "si ferma".
Non sentendo il fine riga, lui non manda l' "ok" di avvenuta ricezione e l'altro non manda altro nell' attesa dell "ok"..
Ci sta'.. !
Un po tirato, faccio fatica a crederlo essendo hardware, ma ci potrebbe stare..

che ne pensi ?
Intanto provo il tuo work-around..
grazie ancora
ciao

Ho provato ad inizializzare la stringa come mi hai suggerito.. ho contato il comando piu' lungo tra quelli nell' array e la ho inizializzata alcuni caratteri piu' lunga..

niente.. stesso risultato..
Ho notato pero' che se modifico l' array di stringhe da inviare, mettendone una con un solo carattere , per esempio il "\n" (LF), il grbl a quella mi risponde subito con l' "ok", come dovrebbe essere, se solo aggiungo pochi caratteri es "G0X10\n" appena il master la invia, non ricevo nessuna risposta, gia' la comunicazione si ferma.
A questo punto ho provato ad inserire una piccola routine che fa in modo che se non ottengo nessuna risposta entro 3 secondi dopo l'invio di un comando , invio un altro "\n" (LF)...
Risultato:
l'invio del solo carattere \n ottiene immediatamente risposta, senza far subentrare la nuova routine, l'invio di stringhe appena piu' lunghe non ottinene risposta, dopodiche' passati i 3 secondi la routine invia un altro \n ed ottengo immediatamente come risposta un errore di comando non valido.

In realta' dovrei ottenere come risposta ben due "ok", uno per il primo LF (quello a terminazione del comando) e uno per quello dopo i 3 secondi inviato dalla routine..

Questo mi conferma che il comando non viene ricevuto come dovrebbe..
Come dicevo, "sniffando" su quella linea (il TX del master (UNO) coillegato al RX del grbl) i dati che passano, mi vedo passare esattamente cio' che mi aspetto..

per esempio inviando "G0X10\n" mi vedo passare : 47 30 58 31 30 0A
ma non ho risposta dal grbl,... dopo i 3 sec mi vedo passare un nuovo 0A (sparato dalla routine), a quel punto come risposta mi arriva un errore di comando non corretto.
Inutile dire che provando ad inviare da pc lo stesso comando (e anche usando la soft serial con lo stesso identico sketch) il comando viene accettato tranquillamente e ricevo il mio bel ed atteso "ok"..

Mi sembra di essere il Dottor House..

Altro ?

C'è un aspetto che varrebbe la pena verificare.
A 57600 occorre necessariamente un sistema di handshaking per una corretta trasmissione e quello adottato è una versione di Xon/Xoff.
Il ricevente quando riempie il suo buffer invia un carattere di Xoff (0x13 = 19) per fermare la trasmissione e ne invia un altro Xon (0x11 = 17) per farla riprendere.
Prova a vedere se ricevi Xoff od altro.
Poi tu mandi la stringa seguita da LF (0x0A = 10) mentre normalmente si invia la sequenza CR + LF: sei sicuro che questa sia la normale sintassi?

Hai perfettamente ragione sul sistema di handshaking..
Anche io speravo che ci fosse, ma da quello che vedo transitare non arriva null' altro che i comandi e' la terminazione con "CRLF"

Per la tua giusta osservazione riguardo alla terminazione col solo LF invece che CRLF come sarebbe piu' standard,
io mi sono rifatto allo script in python che forniscono gli stessi sviluppatori del grbl per fare il "porting" sull' arduino UNO da usare per inviare i comandi da pc al grbl.
Sono pochissime righe in python , se ci dai un occhio tanto per verificare se ho capito male io mi faresti una cortesia..

https://github.com/grbl/grbl/blob/master/script/simple_stream.py

lo riporto qui essendo molto breve..
Qui usano i 9600 ma nelle faq c'e scritto chiaramente che si puo' utilizzare tranquillamnte fino a 115200 solo cambiano la velocita' della seriale

import serial
import time

Open grbl serial port

s = serial.Serial('/dev/tty.usbmodem1811',9600)

Open g-code file

f = open('grbl.gcode','r'); ### file che contiene i comandi, uno per riga

Wake up grbl

s.write("\r\n\r\n")
time.sleep(2) # Wait for grbl to initialize
s.flushInput() # Flush startup text in serial input

Stream g-code to grbl

for line in f:
l = line.strip() # Strip all EOL characters for consistency
print 'Sending: ' + l,
s.write(l + '\n') # Send g-code block to grbl --- comando terminato da 'n' (LF)
grbl_out = s.readline() # Wait for grbl response with carriage return
print ' : ' + grbl_out.strip()

Wait here until grbl is finished to close serial port and file.

raw_input(" Press to exit and disable grbl.")

Close file and serial port

f.close()
s.close()

oppure uno sempre di loro provenienza un po piu' elaborato (ma comunque molto comprensibile e breve..) ma a parte la gestione del buffer e qualche contgrollo in piu' il succo e' quello..

https://github.com/grbl/grbl/blob/master/script/stream.py

Di seguito riporto la comunicazione fatta da pc al grbl, tanto per non lasciare nulla al caso..
All' accensione collegandosi in seriale si riceve :

9A 0D 0A 47 72 62 6C 20 30 2E 39 65 20 5B 27 24 27 20 66 6F 72 20 68 65 6C 70 5D 0D 0A

i caratteri spampabili sono : Grbl 0.9e ['$' for help]
a questo punto invio un LF e ricevo immediatamente in cambio

6F 6B 0D 0A

il mio ok seguito da cr+lf

Adesso invio il comando "G0X10" seguito da LF
ed immediatamente risponde

6F 6B 0D 0A

Altri caratteri esadecimali non ne vedo passare, quindi credo che non ci sia un handshaking..

ho provato con stringhe di comando molto piu' lunghe ma mi restituisce sempre e solo l' "ok"
altri codici hex che non siano caratteri stampabili oppure 0D o 0A non ne vedo..

Se adesso provo ad inviare il comando di prima terminando la riga con CRLF anziche solo LF
questa e' la risposta:
quote]6F 6B 0D 0A 6F 6B 0D 0A[/quote]

2 ok di fila ! (con crlf a seguito per ogniuno)

Se invece invio il comando terminandolo con CR ricevo comunque il mio "ok"
Dunque lui accetta sia CR sia LF come terminazione di comando

Mettendoli ambedue semplicemente mi risponde 2 volte, accettandoli entrambi !

Hai provato a scendere a 9600 baud?

ciao
ho provato a ricompilare il grbl per andare a 9600 e di conseguenza settato il master a 9600...
Il risultato e' un pochino migliore, nel senso che non si blocca immediatamente, ma un paio di invii corretti li fa..
Se i comandi sono brevi anche 3 o 4 di fila, poi ricado nello stesso problema..

Mi pare di capire quindi che il problema e' proprio qualcosa legato alla temporizzazione delle 2 seriali..
..a sapere cosa pero' !..
Quello che non capisco e' perche' da pc il problema non si evidenzia..
Da pc va bene a 9600 a 57600 a 115200 anche inviando file di 500k.. non perde un colpo..
mistero !

La controprova è quella di ridurre ulteriormente il baud rate a 4800 e provare.
Proverei anche a ridurre un po' i due buffer RX_BUFFER_SIZE e TX_BUFFER_SIZE nel caso il problema fosse la memoria RAM dello stand alone (vedi riga 29 del serial.h).
Comunque, alla riga 205 di config.h c'è opzione che abilita il protocollo Xon-Xoff, anche se il commento indica che forse non funziona.

ok
per primo provo a ridurre a 4800 e vediamo..

come ulteriore prova ridurro' il buffer

e come ultimo poi provero' abilitando il "xon/off" ma avevo letto in giro che era molto problematico di suo
comunque una prova la faccio

..vediamo..

ciao
non ho ancora provato quelle due cose, perhce sono ancora in giro, ma mi e' venuto in mente una cosa..

Il grbl ha un risonatore ceramico, mentre il "master" ha un quarzo +i soliti 2 condensatori..
Potrebbe essere una differenza di oscillazione (dalla quale il software calcola i tempi) a darmi il problema ??
Che ne pensi ?

Certo il risonatore ceramico è meno preciso del quarzo, ma perché, allora, lo stesso GRBL funziona con il PC?

bella domanda..
me lo chiedo anche io..
comunque ho fatto le prove che mi hai indicato..

abilitando xon e xoff si comporta come sopra.. glielo mando ma non lo "sente"
..e' come se il grbl avesse problemi di "ricezione", nonostrante sul suo rx i dati arrivino corretti..

Ho provato a ridurre il buffer di ricezione e non cambia nulla
Ho provato a 4800 e migliora un pochino, ma la solfa e' quella..

Hoi anche provato ad alimentare il tutto a batteria, ma anche li' nessun miglioramento

Adesso voglio provare ad invertire i 2 chip (e relativi programmi caricati) per vedere se i problemi di ricezione me li ritrovo nel "master"