• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Задержки передачи данных

koldybins

New member
Подскажите, кто знает. Мне надо сделать простой но надежный мост UART <-> WiFi. У меня есть DevKit v1 ESP32. Он сконфигурирован как Клиент и связывается по WiFi с ноутбуком. Программку сделал в ардуино. Делаю такой тест: На DevKit каждую секунду прилетают 20 Байт с порядковым номером. Он их пересылает на ноут и ноут сразу же обратно. Первые минут 10-15 каждый ответ приходит с задержкой 200-300 миллисекунд. Но потом появляются задержки до полутора минут. Потерь данных вроде нету, после задержки все пакеты сыпятся один за другим без потерь. Но как убрать или хотя бы сократить задержки? Может надо какой-нибудь приоритет где-нибудь повысить?

Код:
void loop()
{
if(connection_status==connected_to_server)
    {
    //WiFi to UART Bridge
    while (SCCclient.available() || Serial.available())
        {   
        if(SCCclient.available())
            {
            char rx = SCCclient.read();
            Serial.write(rx);
            }
        if(Serial.available())
            {
            char tx = Serial.read();       
            SCCclient.write(tx);
            }
        }
    }
}
 

nikolz

Well-known member
Подскажите, кто знает. Мне надо сделать простой но надежный мост UART <-> WiFi. У меня есть DevKit v1 ESP32. Он сконфигурирован как Клиент и связывается по WiFi с ноутбуком. Программку сделал в ардуино. Делаю такой тест: На DevKit каждую секунду прилетают 20 Байт с порядковым номером. Он их пересылает на ноут и ноут сразу же обратно. Первые минут 10-15 каждый ответ приходит с задержкой 200-300 миллисекунд. Но потом появляются задержки до полутора минут. Потерь данных вроде нету, после задержки все пакеты сыпятся один за другим без потерь. Но как убрать или хотя бы сократить задержки? Может надо какой-нибудь приоритет где-нибудь повысить?

Код:
void loop()
{
if(connection_status==connected_to_server)
    {
    //WiFi to UART Bridge
    while (SCCclient.available() || Serial.available())
        {  
        if(SCCclient.available())
            {
            char rx = SCCclient.read();
            Serial.write(rx);
            }
        if(Serial.available())
            {
            char tx = Serial.read();      
            SCCclient.write(tx);
            }
        }
    }
}
это может быль причиной
Алгоритм Нейгла — Википедия
 

koldybins

New member
Спасибо за ответ. Но если это действительно виноват алгоритм нейгла, почему это случается только иногда? И задержки могут быть разные от трех до ста секунд. Такое впечатление, что когда требуются ресурсы для других более важных процессов, передача данных останавливается. Может такое быть?
Я только начал разбираться с esp32. Нет ли у него тонких настроек типа QoS?
QoS — Википедия
 

nikolz

Well-known member
Спасибо за ответ. Но если это действительно виноват алгоритм нейгла, почему это случается только иногда? И задержки могут быть разные от трех до ста секунд. Такое впечатление, что когда требуются ресурсы для других более важных процессов, передача данных останавливается. Может такое быть?
Я только начал разбираться с esp32. Нет ли у него тонких настроек типа QoS?
QoS — Википедия
алгоритм нейгла у вас влияет со стороны компа обычно это задержки порядка 200 ms. Но вы можете их убрать в настройках.
Более длительные задержки могут быть по иным причинам.
Но маловероятно что по нехватке ресурсов. Скорее это какие-то зависания или засыпания.
но угадать что у вас не так никто не может, телепатов нет.
 

koldybins

New member
Вот, посмотрите свежим взглядом. Может что-нибудь посоветуете:
Код:
#include <WiFi.h>
#include <Preferences.h>   // this library is used to get access to Non-volatile storage (NVS) of ESP32

//Digital INs/OUTs
#define BTN_AP_en           12   // digital input
#define PIN_LED_YELLOW      25    // digital input
#define PIN_LED_GREEN         26    // digital output
#define PIN_LED_RED           27    // digital input

//Version-Date
#define Date                  2
#define Month                  4
#define Year                  19

#define NetworkConnection_successfully      20
#define NetworkConnection_unsuccessfully      21
#define AP_modus_on                          22
#define hfm_connected_to_server             23

//****************************************************************************//
//*  global variables
//****************************************************************************//
int status = WL_IDLE_STATUS;
int connection_status=0;

//****************************************************************************//
//*  global objects of the classes
//****************************************************************************//
WiFiClient SCCclient;       // generate object of the class WiFiClient for SCC-Server
Preferences preferences;   // generate object of the class preference (Non-volatile storage)

//****************************************************************************//
//*  FUNCTION int WiFi_NetworkConnect(char* ch_SSID, char* ch_Password)
//*  Connect to network and return 1 (success) or -1 (no success)
//****************************************************************************//
int WiFi_NetworkConnect(char* ch_SSID, char* ch_Password)
{
Serial.println("Function WiFi_NetworkConnect()");
int success;
 
//connect to WiFi network see https://www.arduino.cc/en/Reference/WiFiBegin
WiFi.begin(ch_SSID, ch_Password);
 
//wait until connection is established or 10 seconds are gone
char WiFiConnectTimeOut = 0;
while ((WiFi.status() != WL_CONNECTED) && (WiFiConnectTimeOut < 100))
    {
    if(WiFiConnectTimeOut & 1)
        {
        digitalWrite(PIN_LED_RED, LOW);
        digitalWrite(PIN_LED_GREEN, HIGH);
        }
    else
        {
        digitalWrite(PIN_LED_RED, HIGH);
        digitalWrite(PIN_LED_GREEN, LOW);
        }
    if(WiFiConnectTimeOut & 2)Serial.print(".");
    delay(100);
    WiFiConnectTimeOut++;
    }

// not connected
if (WiFi.status() != WL_CONNECTED)
    {
    success = -1;
    }
else
    {
    success = 1;
    }

return success;
}

//****************************************************************************//
//*  FUNCTION void SwitchLED(void)
// Switch LEDs
// LED Color must be LED_GREEN, LED_RED, LED_YELLOW or LED_OFF
//****************************************************************************//
void SwitchLED(void)
{
if(connection_status==hfm_connected_to_server)
    {
    digitalWrite(PIN_LED_RED, HIGH);
    digitalWrite(PIN_LED_GREEN, LOW);
    digitalWrite(PIN_LED_YELLOW, HIGH);
    }
else if(connection_status==NetworkConnection_successfully)
    {
    digitalWrite(PIN_LED_RED, HIGH);
    digitalWrite(PIN_LED_GREEN, HIGH);
    digitalWrite(PIN_LED_YELLOW, LOW);
    }
else
    {
    digitalWrite(PIN_LED_RED, HIGH);
    digitalWrite(PIN_LED_GREEN, HIGH);
    digitalWrite(PIN_LED_YELLOW, HIGH);
    }
}


//****************************************************************************//
//*  FUNCTION void connect_to_server()
//****************************************************************************//
void connect_to_server(void)
{
// Open Preferences with WLAN_Config namespace. Each application module, library, etc
// has to use a namespace name to prevent key name collisions. We will open storage in
// RW-mode (second parameter has to be false). Note: Namespace name is limited to 15 chars.
// see https://github.com/espressif/arduino-esp32/blob/master/libraries/Preferences/examples/StartCounter/StartCounter.ino
preferences.begin("WLAN_Config", false); 
// takeout WLAN_Config Strings out of the Non-volatile storage
String eeprom_SSID = preferences.getString("SSID", "");
String eeprom_Password = preferences.getString("Password", "");
String eeprom_Server_IP = preferences.getString("Server_IP", "");
String eeprom_Server_Port = preferences.getString("Server_Port", "");

// convert String to char*, see https://coderwall.com/p/zfmwsg/arduino-string-to-char
char* ch_SSID = const_cast<char*>(eeprom_SSID.c_str());
char* ch_Password = const_cast<char*>(eeprom_Password.c_str());
char* ch_Server_IP = const_cast<char*>(eeprom_Server_IP.c_str());

Serial.println("Attempting to connect to WPA network...");  //
Serial.print("SSID: ");
Serial.println(eeprom_SSID);
Serial.print("Pass: ");
Serial.println(eeprom_Password);
Serial.print("Server_IP: ");
Serial.println(eeprom_Server_IP);
Serial.print("Server_Port: ");
Serial.println(eeprom_Server_Port);

// Connect to network
if(WiFi_NetworkConnect(ch_SSID, ch_Password)==1)    //NetworkConnection is successfully
    {
    connection_status=NetworkConnection_successfully;
    SwitchLED();
    Serial.println("Connected to wifi");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    // Connect to Server
    Serial.println("Starting connection to server...");
    SCCclient.connect(ch_Server_IP,eeprom_Server_Port.toInt());
    Serial.print("Status Connection: ");
    if (SCCclient.connected())   //Connection to Server open
        {
        connection_status=hfm_connected_to_server;
        Serial.println("connected to server");
        }
    else   // Connection to Server closed
        {
        Serial.println("Couldn't get a Server connection");
        Serial.println("Restarting");
        ESP.restart();
        }
    }
else    //NetworkConnection is unsuccessfully
    {
    connection_status=NetworkConnection_unsuccessfully;
    Serial.println("Couldn't get a wifi connection");
    Serial.println("Restarting");
    ESP.restart();
    }
}


//****************************************************************************//
//*  FUNCTION void setup()
//****************************************************************************//
void setup()
{
Serial.begin(115200);
Serial.println("Version 0.0.0");

//Digital INs/OUTs config
pinMode(PIN_LED_YELLOW, OUTPUT);
pinMode(PIN_LED_RED, OUTPUT);
pinMode(PIN_LED_GREEN, OUTPUT);
pinMode(BTN_AP_en, INPUT_PULLUP);
//attachInterrupt(digitalPinToInterrupt(BTN_AP_en), set_flag_check_btn_AP, FALLING);
SwitchLED();

connect_to_server();
}

//****************************************************************************//
//*  FUNCTION void loop()
//****************************************************************************//
void loop()
{
//WiFi to UART Bridge
if(connection_status==hfm_connected_to_server)
    {
    while (SCCclient.available() || Serial.available())
        {  
        if(SCCclient.available())
            {
            char rx = SCCclient.read();
            Serial.write(rx);
            }
        if(Serial.available())
            {
            char tx = Serial.read();      
            SCCclient.write(tx);
            }
        }
    }
}
 

koldybins

New member
Выставил Debug-Level на "Verbose", получаю иногда такую ошибку:
[E][WiFiClient.cpp:364] write(): 104
Но после этой ошибки данные больше не проходят. Никто с такой ошибкой не сталкивался?
 

nikolz

Well-known member

koldybins

New member
Спасибо за ссылку. Там правда ESP32 в режиме Access Point, но проблема похожа на мою. Решения проблемы так и не нашли. Очень жаль.
 

koldybins

New member
Получается никто на форуме не использует ESP32 для постоянного (24 часа в сутки) соединения? Если есть такие, бывают ли у вас обрывы соединения, задержки и потеря данных? И как вы с этим боретесь?
 

pvvx

Активный участник сообщества
Получается никто на форуме не использует ESP32 для постоянного (24 часа в сутки) соединения?
С WiFi это сделать непросто, т.к. надо правильно настроить всё внешнее оборудование и саму ESP32.
Если есть такие, бывают ли у вас обрывы соединения, задержки и потеря данных? И как вы с этим боретесь?
Самый простой путь - 'реконнектом' соединения через время или по любой ошибке.
По вашему описанию, если гадать, то скорее всего включается какой-то спящий режим у WiFi. Если он не отключен в настройках принудительно, то обычно включается автоматически по условию: если за время DTIM проходит менее N пакетов...
 

koldybins

New member
По вашему описанию, если гадать, то скорее всего включается какой-то спящий режим у WiFi. Если он не отключен в настройках принудительно, то обычно включается автоматически по условию: если за время DTIM проходит менее N пакетов...
Похоже задержки были из-за сети. Сама ESP32 не причем. Взял отдельный роутер без выхода в интернет, повесил на него ESP32 как клиент и ноутбук как сервер, задержки ушли. Обрывы правда есть каждые 3 часа 20 минут, подозрительно периодично, поэтому наверняка из-за роутера. Но это не страшно, обрывы будут по-любому рано или поздно. Пока делал так. Если подтверждение пакета не пришло 5 раз, перестартовываю ESP32командой ESP.restart(); Рестарт на удивление проходит быстро, 1-2 секунды. Вы предлагаете реконнект, но у меня почему-то после него соединение не восстанавливалось. Можно пожалуйста простой пример реконнекта привести?
С WiFi это сделать непросто, т.к. надо правильно настроить всё внешнее оборудование и саму ESP32.
Подскажите пожалуйста как именно, или где про это почитать.

Благодарю
 

pvvx

Активный участник сообщества
Обрывы правда есть каждые 3 часа 20 минут, подозрительно периодично, поэтому наверняка из-за роутера.
(3*60+20)*60=12000 сек.
Посмотрите в настройках роутера,
в DHCP: upload_2019-4-12_17-46-1.png
в WiFi: upload_2019-4-12_17-46-34.png

И если оно в "ротации сетевых ключей" то для Arduino подсказать что изменить на модуле будет сложно... Это уже кривость дров WiFi в ESP от её писателей.
DHCP запросто обходится фиксированным IP на модуле...
 
Сверху Снизу