Hallo, ich bin noch absoluter Neuling was das ESP8266 angeht… also bitte entschuldigt meine Unwissenheit. Also mein Ziel ist es eine bestehende UART Schnittstelle zwischen zwei AVR µC durch eine Wlan-Brücke zu ersetzten. Diese soll also für die AVRs komplett transparent sein AVR-UART <> ESP8266-WIFI <> WIFI-ESP8266 <>UART-AVR. Verwenden möchte ich zur Programmierung der ESP8266 die Arduino IDE. Das ist auch soweit eingerichtet und funktioniert. Ich kann mir vielleicht jemand einen Tipp geben ob es dafür vielleicht schon irgendwo ein Beispiel dazu gibt? Ich habe das Ganze auch schon selbst mit Abwandlung und Erweiterung davon https://blog.thesen.eu/telnet2serial-telnet-zu-rs232seriell-bruecke-mit-dem-esp8266-microcontroller/#comment-2437 probiert. Also ein ESP als Server und einen als Client. Leider ist es so dass die Latenzzeit für die Übertragung eines Befehls (7 Byte) von einem AVR zum anderen stark schwankt (100ms bis 600ms). Das führt dann zu einem Timeout in der Firmware der AVRs. Also brauche ich eine andere Lösung. Habt ihr einen Tipp?
Wie groß sind die Pakete zwischen den AVRs ? Hast du Steuerzeichen in deinem Protokoll ? Gruß JackFrost
Danke für die schnelle Antwort :) Die Pakete sehen prinzipiell so aus ~LIGHT1x und als Antwort z.B. ~ACKNOLx wobei das x CRC8 der vorangegangen 7 Byte ist, also 8Byte in Summe…
ich hatte auch mal was gelesen das die Übertagung über Websockets und dem ESP eine geringere Latenz hat, ich kann es aber leider nicht mehr ergooglen und es scheiter hier auch an den Grundlagen der Netzwerktechnik.
Wo tritt die Latenz auf , AVR1 -> AVR2 oder vom Start bis zum ACK ? Gruß JackFrost
>Leider ist es so >dass die Latenzzeit für die Übertragung eines Befehls (7 Byte) von einem >AVR zum anderen stark schwankt (100ms bis 600ms). Das führt dann zu >einem Timeout in der Firmware der AVRs. >Also brauche ich eine andere Lösung. Habt ihr einen Tipp? Ja, mach das Timeout länger oder zieh ein Kabel. Bei WLAN gibt es keine garantierten Latenzen. Was heute noch funktioniert könnte morgen schon wieder vorbei sein weil in der Nachbarschaft ein neuer Router dazugekommen ist.
Wie weit sind die ESP's denn von einander entfernt? Ich hatte zB selbst bei TCP von einem Laptop (HP Elitebook) zum ESP WLAN Latenzen von 3ms inklusive Bearbeitung des Paketes auf dem ESP. Dabei muss man allerdings sagen, dass ich ein NodeMCU Board hatte und dass es eben ein TCPServer auf dem ESP war, ebenfalls mit Arduino Firmware. Finde auch noch herraus, ob es sich um eine Latenz zwischen ESP und ESP oder ESP und AVR handelt (zB indem du ein einfaches ECHO System implementierst und ein ESP dann mittels den Systemticks die vergangene Zeit misst)
Hallo und danke für eure Hilfe. Das Echo System ist naheliegend aber leider hatte ich wohl ein Brett vorm Kopf hüst. Ich hab es umgesetzt und es ergibt sich eine maximale Latenz von ~300ms und durchschnittlich 180ms für den Weg AVR -> ESP -> ESP -> AVR und zurück. Das gleiche Echosystem ohne ESPs in der Leitung hat eine zu erwartende Latenz von unter 1ms. Die ESPs sind im Moment ~50cm voneinander entfernt. Mit 3ms wäre ich sehr zufrieden... Störungen durch externe Funkwellen kann ich hier in meinem Keller ausschließen. Hier herrscht ein absolutes Funkloch.
Also ich komme einfach nicht drauf. Ich hänge meinen Arduino Code mal an vielleicht könnt ihr euch mal ansehen ob ihr einen Fehler findet oder eventuell auch Testen ob es bei euch mit kürzerer Latenz funktioniert... Über die Einstellung WiFiMode wifi_mode = "WIFI_AP" oder "WIFI_STA" kann gewählt werden ob das Programm als Access-Point oder Client läuft. Besten Dank für eure Hilfe!
Warum nicht beide AVRs durch die ESP8266 ersetzen und die Daten auf einem gemeinsamen Server sammeln?
:
Bearbeitet durch User
Ein Problem könnte die verborgen verwendete String Klasse bei "Serial.write(client.read());" sein. Zum Einen blockiert sie bis zu einem Timeout, was deine Latenzen erklärt. Zum Anderen kann sie (wenn du Pech hast) bis zu ca. 5 Kilobyte Daten am Stück liefern, was ratz fatz zu einem Stack überlauf führt. Der Stack ist nämlich nur irgendwo zwischen 4 und 5kB klein! Das passiert vor allem, wenn sich WLAN mal Daten angestaut haben und dann alle zusammen "auf einmal" eintreffen. Die Art, wie du den seriellen Port verwendest, macht es noch träger. Denn der serielle Port hat nur einen kleinen Puffer (meist 64 Bytes). Wenn du mehr zu senden versuchst, als da rein passt, muss das Programm lange warten. Ändere deine Schleife so, dass sie niemals warten muss. Und zwar weder auf Netzwerk noch auf die serielle Schnittstelle. read() kannst du daher schonmal vergessen. Es gibt aber eine andere nicht blockierende read Funktion, die in ein char-array einliest und dir zurück liefert, wie viele Zeichen sie geliefert hat. Vor dem Schreiben kannst du abfragen, für wie viele Zeichen der Sende-Puffer frei hat. Wenn er nicht genug Platz hast, dann warte nicht, sondern sende nur so viel wie gerade geht und spare Dir den Rest für einen späteren Durchlauf der loop Schleife auf. Um das zu ermöglichen brauchst du wiederum große Puffer in deinem Sketch. Der Puffer sorgt dafür, dass du weniger häufig überschüssige Daten verwenfen musst. Du kannst sie später senden - sofern dein Puffer nicht überläuft. Das WLAN Netz hat im Gegensatz zur seriellen Schnittstelle eine sehr unregelmäßige Performance. Stell Dir vor, ein µC sendet mit 115200 Baud kontinuierlich so schnell er kann und dann stockt die Übertragung für eine halbe Sekunde (was durchaus normal ist). Dann stauen sich irgendwo etwa 6000 Bytes an. Nachdem die Übertragung wieder läuft, musst du nun diese 6000 Bytes seriell abliefern, aber gleichzeitig kommen genau so schnell neue Daten herein. Das ist ein Dilemma und das ist das Hauptproblem sämlticher Seriell/Netzwerk Adapter, die es gibt. Man muss funktional Abstriche in Kauf nehmen, und zwar entweder: a) Wenn über Netz mehr Daten rein kommen, als man seriell Senden kann, verwirft man Teile davon. oder b) Man verwendet sehr große Puffer und hofft, dass der Absender irgendwann mal eine Pause einlegt, in der man die angestauten Daten abarbeiten kann. Aber auc diese Puffer können überlaufen, dann musst du doch Daten verwerfen. Dein jetziges Programm verwirft auch Daten, das ist Dir eventuell nur noch nicht aufgefallen, weil die WLAN Schnittstelle etwa 5kB empfangene Daten puffern kann und der Sender notfalls einige male Wiederholt, falls etwas verloren geht. Doch das geht eben massiv auf die Latenz Zeit und dennoch können die Puffer überlaufen. Programme, die für serielle Kabel gedacht sind, erwarten jedoch eine kontinuierliche Lückenlose Übertargung ohne verlorene Teile. Deine WLAN Brücke kann nur dann zufriedenstellend funktionieren, wenn die seriellen Programme die stockende Übertragung im WLAN tolerieren und durch Soft-Handshake sicherstellen, dass sie die Puffer nicht überfüllen. Bei einer Halb-Duplex Kommunikation ergibt sich das von ganz alleine. Im fokgenden Beispiel sind (A) und (B) die seriellen Programme: (A) zu (B): Schalte mal das Licht an! (B) zu (A): Ist erledigt 1 Sekunde Pause (A) zu (B): Schalte das Licht wieder aus! (B) zu (A): Ist erledigt Hier haben wir ein Soft-Handshake. Der Befehlsgeber wartet immer auf die Rückmeldung, bevor er den nächsten Befehl sendet. Was könnte ohne Handshake passieren?: (A) zu (B): Schalte mal das Licht an! WLAN ist gestört, das Kommando kommt zunächst nicht an. 1 Sekunde Pause WLAN geht wieder, jetzt kommt das Kommando bei (B) an. (B) schaltet das Licht an. gleichzeitig kommt schon der nächste Befehl herein: (A) zu (B): Schalte das Licht wieder aus! (B) schaltet das Licht aus. Das Licht wurde ein und dann sofort wieder ausgeschaltet. Vermutlich flackert es nur kurz, falls man es überhaupt wahrnimmt. Dieses Ergebnis hatte A aber nicht gewollt. Gewollt war, dass das Licht eine Sekunde an ist. Versteht du das Problem jetzt?
> Mit 3ms wäre ich sehr zufrieden
Die bekommst du nur im Idealfall, quasi wenn du Netz gerade ganz für
Dich alleine hast. Und mit Netz meine ich nicht nur deine Fritz Box,
sondern die WLAN Funkfrequenzen, die Du Dir vermutlich mit einigen
Nachbarn teilst.
Es sei denn, du hast eine einsame Hütte im Wald.
Ich muss etwas korrigieren: > Ein Problem könnte die verborgen verwendete String Klasse bei > "Serial.write(client.read());" sein. Hier habe ich read() mit readString() verwechselt. Read kann nicht zu einem Speicherüberlauf führen.
Hallo, erstmal danke für eure umfängliche Hilfe und Mühe. Ich habe das Problem mittlerweile gelöst und möchte es euch (falls ihr so etwas auch benötigt) nicht vorenthalten. Die Latenz beträgt nun durchschnittlich 3ms und maximal 7ms für die oben genannten 8 Byte Befehle. Im Test wurden 8Byte übertragen und die Zeit bis zum kompletten Empfang des Echos gemessen. Das Problem lag daran das zu viele kleine Pakete über Wlan gesendet wurden. Nun warten die ESP8266 solang bis entweder der Serielle Eingangspuffer fast voll ist oder keine neuen Daten mehr ankommen. Das Folgende muss daher im Quelltext geändert werden
1 | .....
|
2 | /////////////////////
|
3 | //Client Serial --> Telnet
|
4 | /////////////////////
|
5 | int available_byts = Serial.available(); |
6 | if ((available_byts >= 50) || ((available_byts != 0) && (available_byts == Serial_couter))) |
7 | {//nur ausführen wenn keine neuen Daten auflaufen -> ab 50 Byte muss gesendet werden (Serial Buffer 64Byte -> sonst SERIAL_BUFFER_SIZE in RingBuffer.h ändern) |
8 | size_t len = Serial.available(); |
9 | Serial_couter = 0; |
10 | uint8_t sbuf[len]; |
11 | |
12 | Serial.readBytes(sbuf, len); |
13 | |
14 | if (client.connected()) |
15 | {
|
16 | client.write(sbuf, len); |
17 | }
|
18 | }
|
19 | else
|
20 | {//Datenzähler neu setzen + Pause |
21 | Serial_couter = available_byts; |
22 | delayMicroseconds(500); |
23 | }
|
24 | |
25 | ....
|
26 | |
27 | |
28 | /////////////////////
|
29 | //Server Serial --> Telnet
|
30 | /////////////////////
|
31 | int available_byts = Serial.available(); |
32 | if ((available_byts >= 50) || ((available_byts != 0) && (available_byts == Serial_couter))) |
33 | {//nur ausführen wenn keine neuen Daten auflaufen -> ab 50 Byte muss gesendet werden (Serial Buffer 64Byte -> sonst SERIAL_BUFFER_SIZE in RingBuffer.h ändern) |
34 | size_t len = Serial.available(); |
35 | Serial_couter = 0; |
36 | uint8_t sbuf[len]; |
37 | Serial.readBytes(sbuf, len); |
38 | |
39 | for (ii = 0; ii < MAX_NO_CLIENTS; ii++) |
40 | {
|
41 | if (pClientList[ii] && pClientList[ii].connected()) |
42 | {
|
43 | pClientList[ii].write(sbuf, len); |
44 | }
|
45 | }
|
46 | }
|
47 | else
|
48 | {//Datenzähler neu setzen + Pause |
49 | Serial_couter = available_byts; |
50 | delayMicroseconds(500); |
51 | }
|
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.