[TCP]ritardo loop connessione wifi (programmare ESP8266)

  1. se passi a UDP secondo me dovrai modificare il sever web per mandare una conferma di dati ricevuti per far sapere ad Arduino se i dati arrivano.

  2. ma hai molte serial.print() dal Serial monitor cosa vedi quando la connessione è lenta ? Dove sembra sia "fermo" il codice di Arduino ?

Ho inserito alcuni dei Serial.print proprio per capire cosa blocca il loop e quando la connessione è lenta si blocca per qualche secondo "random" (tra circa 3 e 8 secondi) praticamente ogni volta che il modulo wifi si connette al server, ovvero quando si crea la TCP, quando si inviano i dati, quando li si ricevono e quando si chiude la TCP.
Se non avete modo di scaricare la libreria vi posso scrivere la parte di codice relativa a queste funzioni se volete...

nid69ita:

  1. se passi a UDP secondo me dovrai modificare il sever web per mandare una conferma di dati ricevuti per far sapere ad Arduino se i dati arrivano.

Ma se parla di "server Web" e di "GET" si tratta di un server http (quindi Apache, IIS..) che è un protocollo TCP, quindi niente UDP. Se il server deve acquisire pacchetti UDP lo può fare solo implementando un servizio ad hoc che stia in ascolto. Il tutto è ovviamente più complicato del normale GET ma comunque provo a descriverti la cosa, poi vedi tu se può darti qualche spunto.

Che l'UDP sia connectionless è vero, ma si può sempre implementare un protocollino (provo ora a inventarlo) per cui il sistema A manda a B un pacchetto UDP col dato, e possibilmente con un identificativo univoco, anche solo un progressivo, e quando B lo riceve risponde con un altro pacchetto verso B con un "ACK" seguito dall'identificativo. Tipo (dove "001" è l'identificativo):

A UDP(B)"001DATO" ---- > B

A <----- UDP(A)"001ACK" B

A quel punto A può mandare anche 5 o 6 pacchetti, purché ne mantenga traccia in un qualche stack, dal quale rimuove i pacchetti dei quali ha ricevuto ACK. Memorizzando anche l'ora (o millis) di invio, è possibile di tanto in tanto verificare se qualche pacchetto non è stato ricevuto (ossia è ancora nello stack) e fare qualcosa, come inviare nuovamente il pacchetto, aggiornando il tempo di invio.
Una cosa del genere.

Tutto questo però implementando questa comunicazione anche sul server, per cui la soluzione migliore sarebbe ovviamente fare il GET ma serializzando le richieste (se devi aspettare la risposta) quindi vedendo come non far bloccare tutto lo sketch (Arduino non è multithread...)..

E quindi stai reinventando una versione da debuggare e testare di TCP che usa UDP? Un sacco di volte c'è la tentazione di fare ciò, ma non ha senso. Si usa UDP se e solo se perdere un pacchetto è accettabile e indolore, altrimenti su usa TCP, fine. Tutto il resto è cercarsi problemi, IMHO.

Il problema riscontrato, comunque, è normale. La connessione è sincrona e "in diretta", non viene effettuata in background, per cui c'è poco da fare, bisogna accettare il tempo che richiede. Non sei su una scheda con un sistema operativo che riceve i pacchetti dalle applicazioni, li bufferizza, accoda, invia, fa altrettanto con le risposte, ecc... Forse, e dico forse (non ho mai studiato i dettagli interni di funzionamento dell'ESP) l'hardware permetterebbe anche di farlo in background, ma non mi risulta che alcuna libreria attualmente esistente permetta questa possibilità.

Se sei disposto a perdere potenzialmente pacchetti, usare UDP sicuramente richiede meno tempo per l'invio ma, come dice docdoc, dovrai avere un servizio ad-hoc per la ricezione dall'altro lato, non potrai più usare HTTP.

In ogni caso, la libreria che stai usando a me non piace molto, preferisco WiFiEsp.

SukkoPera:
E quindi stai reinventando una versione da debuggare e testare di TCP che usa UDP?

Si, non è divertente? :slight_smile: Di protocolli (anche se in genere TCP ovviamente....) per lavoro mi sono sempre divertito a crearne, che ci trovi di male? E daje sukko, fattela 'na risata! :smiley:

Un sacco di volte c'è la tentazione di fare ciò, ma non ha senso. Si usa UDP se e solo se perdere un pacchetto è accettabile e indolore, altrimenti su usa TCP, fine. Tutto il resto è cercarsi problemi, IMHO.

Si, certo, ma in QUESTO caso se non hai un sistema multithread mi spieghi come gestisci tante richieste asincrone senza bloccare il processo del client? Visto che la libreria sembra fermarsi in attesa della risposta, la mia era solo una soluzione "non canonica" ad un problema che aveva esposto l'amico, ma che, seppure non perfetta/elegante, potrebbe risolvergli il problema non ti pare? :wink:

No, non mi pare. Se, come credo, hai studiato le reti ed i loro protocolli, sai benissimo quanti potenziali problemi ci sono da gestire (pacchetti persi, duplicati, ricevuti in ordine diverso da quello di invio, gli stessi problemi per gli ack, e quant'altro), e gestirli adeguatamente richiede la complessità e pesantezza di TCP. Per avere una soluzione approssimativa, tanto vale non averla, almeno secondo me, e rassegnarsi che qualche pacchetto vada perso.

Ho visto meglio il codice proposto dall'OP e, nel caso specifico, credo che la prima cosa da fare per velocizzare il tutto sia quella di evitare di aprire e chiudere la connessione per ogni singolo invio, come mi pare faccia. La aprirei all'inizio e la terrei aperta, in modo da dover fare solo la singola send() per ogni invio.

Eventualmente, si potrebbe anche vedere se si può disabilitare l'algoritmo di Nagle (TCP_NODELAY), ma non credo che intervenga in questo caso (I dati mi sembrano abbastanza corposi, e non so nemmeno se l'ESP lo implementi).

SukkoPera:
nel caso specifico, credo che la prima cosa da fare per velocizzare il tutto sia quella di evitare di aprire e chiudere la connessione per ogni singolo invio, come mi pare faccia. La aprirei all'inizio e la terrei aperta, in modo da dover fare solo la singola send() per ogni invio.

Quindi (sempre se il server accetta request multiple nella stessa sessione) una send senza verificare la risposta del server? Equivale a mandare un pacchetto UDP a quel punto..

Insomma, il problema come ho detto non è se TCP o UDP, è che se il problema è legato al fatto che il server potrebbe metterci vari secondi a dare conferma, Arduino, che non è multithreaded, deve stare ad aspettare.
Per cui la mia soluzione era quella di disaccoppiare la richeista dalla risposta, e gestire in uno stack le richieste per le quali non ha ancora ricevuto risposta, gestendo eventualmente i retry.

Per me, se ho compreso bene i requisiti del nostro amico, può funzionare, mentre con le soluzioni che di ci tu, no, anzi dici di rinunciare.
Beh, come si dice, le opinioni sono come le palle, ognuno ha le sue.. :wink:

E comunque se sei d'accordo, per me meglio lasciare spazio al problema specifico del nostro amico, inutile intasare il thread con discorsi sulla filosofia dei protocollo di rete. :smiley:

No, dico di fare solo la send, verificando il risultato in maniera magari asincrona (qua dipende da cosa permettono le librerie). Questo perché l'apertura della connessione è la parte più lenta, tra risoluzione DNS, handshake e quant'altro.

Per il resto i discorsi sul protocollo mi sembrano esattamente il centro della discussione, perché credi che intasino il thread? :wink:

Grazie a tutti dell'aiuto che mi state dando.

Premetto che nei vostri discorsi ogni tanto mi sono perso dato che non sono un esperto ma sono arrivato alla conclusione per prima cosa bisogna provare a cambiare la libreria come consigliato da @SukkoPera e se cambia qualcosa a parità di connessione e sketch.

Poi voglio avvisarvi che avevo già provato ad eliminare la parte dello sketch che si occupava della ricezione della risposta dal server che mi prendeva circa il 20% del ritardo da me lamentato senza compromettere nient'altro.

Ho anche provato come da voi consigliato ad aprire la connessione una volta senza chiuderla e mandare in sequenza le GET, questo funziona e va ancora più veloce però alla prima "caduta della connessione TCP" (perchè dopo qualche minuto cade) si blocca l'invio dei dati ovviamente.
Per risolvere credo si possa sfruttare una qualche funzione della libreria che verifica se la connessione c'è e ricreare la TCP qualora sia caduta con la speranza che la verifica con occupi un'eternità come la creazione stessa della TCP.

Poi per quanto riguarda l'UDP mi avete un pochino scoraggiato e quindi la lascerei da parte per adesso.

Quindi come detto farò queste prove nei giorni successivi ma se intanto avete qualcosa da aggiungere o da correggermi siete come sempre i benvenuti!
grazie

[WiFiEsp] Warning: Unsupported firmware

SukkoPera:
In ogni caso, la libreria che stai usando a me non piace molto, preferisco WiFiEsp.

Come consigliato da @SukkoPera ho provato a cambiare libreria ma qualsiasi esempio carico mi ritrovo con il seguente errore:
[WiFiEsp] Warning: Unsupported firmware

Infatti mi sono ricordato di aver già provato questa libreria e mi dava lo stesso errore.
Mentre con l'altra libreria ottengo ciò:
"FW Version:00200.9.4"

Questa è la mia schedina: https://www.dfrobot.com/product-1279.html
Come posso risolvere secondo voi?

Se funziona con l'altra libreria, probabilmente puoi semplicemente ignorare quel messaggio e andare avanti.

Ciao a tutti di nuovo.
Ho lasciato un po' "appeso" il problema che avevo quando ho scritto questo post perché mi sono reso conto che la strada da percorrere non era semplicissima e credevo che quel problema non fosse così importante ma non è così, mi sono infatti accorto di doverlo risolvere a tutti i costi.

Mi sono quindi messo a pensare a come risolvere e ho avuto 2 idee, una più semplice ed immediata anche se sicuramente più dispendiosa mentre l'altra un po' più complessa (sicuramente per me) e forse neanche fattibile. Per questo chiedo di nuovo aiuto a voi...

Prima soluzione:
Ho pensato di poter collegare un Arduino "economico", come ad esempio Arduino Uno, al mio Arduino Mega e lasciare che sia l'Uno ad effettuare la connessione e l'invio dati wifi. Infatti sarà il Mega a fare tutto il lavoro del mio progetto ma invece che effettuare lui la connessione wifi (che come ricorderete mi dava problemi di ritardi nell'esecuzione del loop) invierà semplicemente quei dati via Seriale all'Arduino Uno e data la semplicità e rapidità della Seriale sicuramente non avrà i ritardi della connessione TCP. Poi connetterò la solita scheda wifi basata su esp8266 (ESP8266 Wifi Bee (Arduino Compatible) - DFRobot) sull'Uno e procederò in tutta tranquillità all'invio dei dati in wifi.

Seconda soluzione:
Ho visto molte persone in rete che riescono a programmare l'ESP8266 con programmi ad hoc per le proprie esigenze e mi è venuto il dubbio che questo potesse venire a mio favore.
Quindi sostanzialmente ciò che vi chiedo in questo nuovo post è:

1)Posso programmare la mia ESP8266 in modo tale che riceva i dati dal Mega in seriale e si connetta al server tramite un processo interno alla scheda che non convolga l'Arduino Mega? Perché se la scheda si può programmare credo abbia un processore e qualche tipo di memoria all'interno...

Se la mia scheda specifica non va bene per quanto detto sopra, esiste un'altra scheda che possa far ciò?

Grazie ancora ragazzi

Sì, puoi fare come dici, programmando direttamente l'ESP per bufferizzare e "scaricare" i dati via wifi in maniera asincrona.

Fantastico... mi documenterò allora!!!

Salve di nuovo!

Vorrei aggiornarvi sui miei progressi riguardo il mio progetto.

Allora, come promesso mi sono documentato per capire come programmare la schedina esp8266 e credo di essere riuscito ad intuire come farlo tramite l'IDE di Arduino. Ci sono molti tutorial su come programmarla per fare le GET request al server senza l'uso di Arduino ed in parte è quello che mi serve però non ho trovato molto per quanto riguarda la comunicazione tra Arduino e l'ESP8266. Infatti non saprei come fare per memorizzare la stringa nella schedina ma considerando che sono in grado di far ciò tra 2 Arduino e considerando che l'esp8266 si può programmare nella stessa maniera e linguaggio di Arduino ho creduto che basta programmarla proprio come potrei fare con un qualsiasi Arduino almeno per quanto riguarda la memorizzazione della stringa...
Però prima di passare ai fatti e fare dei tentativi vi chiedevo se il mio ragionamento è giusto o se sono fuori strada...

Una buona soluzione è quella di usare un ring buffer.

Cosa sarebbe un ring buffer? :frowning: :o
E poi dici di usarlo nel programma per Arduino o per l'esp8266?

1simone0:
Cosa sarebbe un ring buffer? :frowning: :o

... io capisco i dubbi tecnici, per carità, però, dai ... un po' di spirito d'iniziativa NON guasta !!!

Se fai una piccola ricerca con Google per "Arduino Ring Buffer" ti vengono fuori SOLO 253'000 risultati, con spiegazioni, implementazioni, librerie già pronte, esempi, ecc. ecc. :smiley:

Guglielmo

Bè le mie ricerche me lo sono già fatte... :slight_smile:
Diciamo che la domanda principale era la seconda