ESP8266 отправляет данные GPS через ESP сейчас

У меня есть проект, включающий два модуля ESP8266 и один GPS-модуль NEO-6M. Я хочу отправить данные GPS на другой микроконтроллер через ESP-NOW, но он не отправляет данные, хотя и отображает координаты. Я просто хочу понять, как отправить данные через ESP-NOW. Я пробовал размещать два микроконтроллера рядом друг с другом, но статус всё ещё отображается как «Fail». Код отправителя:

#include <TinyGPS++.h>
#include <ESP8266WiFi.h>
#include <espnow.h>
#include <SoftwareSerial.h>

SoftwareSerial ss(5, 4); 
TinyGPSPlus gps;

int baud = 9600;
uint8_t receiverMAC[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

typedef struct struct_message {
  float latitude;
  float longitude;
  float altitude;
} struct_message;

struct_message myData;

void setup() {
  Serial.begin(baud); 
  ss.begin(baud);  
  WiFi.mode(WIFI_STA);
  delay(100);
  if (esp_now_init() != 0) {
    Serial.println("ESP-NOW initialization failed!");
    while (true);
  }
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  if (esp_now_add_peer(receiverMAC, ESP_NOW_ROLE_SLAVE, 1, NULL, 0) != 0) {
    Serial.println("Failed to add peer");
    return;
  }
}

void loop() {
  while (ss.available() > 0) {
    if (gps.encode(ss.read())) {
      if (gps.location.isValid()) {
        myData.latitude = gps.location.lat();
        myData.longitude = gps.location.lng();
        myData.altitude = gps.altitude.meters();
        displayInfo();
        sendData();
      }
    }
  }
    esp_now_register_send_cb(OnDataSent);
}

void OnDataSent(uint8_t * mac_addr, uint8_t sendStatus) {
  Serial.print("ESP-NOW Send Status: ");
  if (sendStatus == 0) {
    Serial.println("Delivery success");
  }
  else {
    Serial.println("Delivery fail");
  }
}

void displayInfo() {
  Serial.print("Latitude: ");
  Serial.println(myData.latitude, 6);
  Serial.print("Longitude: ");
  Serial.println(myData.longitude, 6);
  Serial.print("Altitude: ");
  Serial.println(myData.altitude, 2);
}

void sendData() {
  delay(100);
  uint8_t result = esp_now_send(receiverMAC, (uint8_t *) &myData, sizeof(myData));
  if (result != 0) {
    Serial.println("Error sending data");
  }
}

В то время как код приемника для другого микроконтроллера показан ниже

#include <ESP8266WiFi.h>
#include <espnow.h>

typedef struct struct_message {
  float latitude;
  float longitude;
  float altitude;
} struct_message;

struct_message myData;

void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
  Serial.println("Data received!");
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Latitude: ");
  Serial.println(myData.latitude, 6);
  Serial.print("Longitude: ");
  Serial.println(myData.longitude, 6);
  Serial.print("Altitude: ");
  Serial.println(myData.altitude, 2);
}

void setup() {
  Serial.begin(9600);
  WiFi.mode(WIFI_STA);
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
}

, 👍0

Обсуждение

1) Для приемника ESP-Now он должен находиться в режиме точки доступа с помощью WiFi.mode(WIFI_AP);, WiFi.disconnect();. 2) Для передатчика ESP-Now не нужно повторно регистрировать обратный вызов в цикле, строку esp_now_register_send_cb(OnDataSent); следует перенести в setup(). 3) Для sendData() удалите uint8_t result = и оператор if, состояние sendData предоставляется в функции обратного вызова., @hcheung

Извините за поздний ответ и спасибо за ответ. Я попробовал выполнить ваши рекомендации, однако функция OnDataSent всё ещё выдаёт ошибку. Я не знаю, почему это происходит., @mizuto0

1) Добавьте WiFi.disconnect(); в код передатчика, чтобы убедиться, что он не подключен к WiFi. 2) Сопоставляете ли вы receiverMAC[] с фактическим MAC-адресом вашей платы приемника? 3) Вам не обязательно использовать фактический аппаратный MAC-адрес платы приемника, вы также можете назначить приемнику [локально управляемый MAC-адрес](https://serverfault.com/a/40720) и убедиться, что вы используете его как на передатчике, так и на приемнике, как показано в моем [примере кода](https://www.e-tinkers.com/2024/10/fix-a-wireless-doorbell-with-esp-now/)., @hcheung

Спасибо за предложение, я попробовал применить ваши рекомендации, и, похоже, всё заработало, поскольку данные отправляются на приёмник ESP8266. Однако отправка данных занимает некоторое время., @mizuto0

Определение «некоторое время» основано не на моём [опыте] (https://www.e-tinkers.com/2020/05/esp-01-range-test-with-esp-now-protocol/), где обычно требуется 500 мкс на полный оборот, а на дальних дистанциях оно варьируется от 2000 мкс до иногда 20 000 мкс. Поскольку в вашем наброске есть GPS, «некоторое время» связано с приёмом GPS или с работой ESP-NOW?, @hcheung

Успешная отправка данных заняла около двух секунд; за это время уже были получены данные GPS. Следовательно, соединение, вероятно, было установлено благодаря ESP-NOW. У меня нет количественной оценки доли успешных попыток (в микросекундах), но, возможно, стоит добавить это значение для проверки., @mizuto0

Данные NMEA GPS публикуются с частотой 1 Гц (то есть каждую секунду), поэтому интервал составляет не менее 1 секунды. Что касается передачи и приёма ESP-Now, проблема решена, поэтому я собрал всю предоставленную мной информацию и добавил её в качестве ответа, а также код для измерения времени прохождения сигнала туда и обратно. Буду благодарен, если вы примете это как ответ на благо будущих читателей., @hcheung


2 ответа


Лучший ответ:

0

Есть несколько моментов, связанных с неправильной настройкой ESP-Now.

  1. Для приемника ESP-Now он должен находиться в режиме точки доступа с помощью WiFi.mode(WIFI_AP) и убедиться, что он не подключается к WiFi с помощью WiFi.disconnect().
  2. Для передатчика ESP-Now он должен находиться в режиме STA (это сделано правильно) и он НЕ ДОЛЖЕН подключаться к WiFi, поэтому добавьте WiFi.disconnect() сразу после WiFi.mode(WIFI_STA).
  3. Вам не нужно регистрировать обратный вызов повторно в цикле, строку esp_now_register_send_cb(OnDataSent); следует перенести в setup(). 4. Для sendData() удалите оператор uint8_t result = и if, состояние sendData предоставляется в функции обратного вызова.
  4. Чтобы адрес receiveMAC[] в передатчике совпадал либо с фактическим MAC-адресом приёмника ESP8266, либо с локально управляемым MAC-адресом. Преимущество использования локально управляемого MAC-адреса заключается в следующем: а) вам не нужно писать скетч для определения MAC-адреса, как показано в другом ответе; б) если в будущем вы замените приёмник ESP8266 на другой, вам не нужно будет перепрошивать передатчик для изменения MAC-адреса.

Ниже приведен пример кода (без кода GPS) для передатчика ESP8266 ESP-Now и приемника ESP-Now с примером использования локально администрируемого MAC-адреса.

Передатчик ESP-Now

#include <ESP8266WiFi.h>
#include <espnow.h>

typedef struct gps_message_s {
  float latitude;
  float longitude;
  float altitude;
} gps_t;

// *** следующие переменные должны соответствовать настройкам приемника ***
uint8_t receiverMAC[] = {{0x82, 0x88, 0x88, 0x88, 0x88, 0x88};
gps_t myData;
const unit8_t channel = 1;
// *********************************************************************

unsigned long sendStartTime;

void OnDataSent(uint8_t * mac, uint8_t sendStatus) {

  unsigned long sentEndTime = micros();

  Serial.printf("< Device: %02x:%02x:%02x:%02x:%02x:%02x\n",
                 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  Serial.printf("< Status: %s\n", 
                 (sendStatus == 0 ? "Success" : "Failed"));'
  Serial.printf("Round-trip in uS: %4lu, ", sentEndTime - sentStartTime);
}

void setup() {
  Serial.begin(115200); 

  WiFi.persistent(false); // отключить постоянный Wi-Fi
  WiFi.mode(WIFI_STA);    // Передатчик ESP-Now должен быть в режиме STA
  WiFi.disconnect();      // Не подключаться к WiFi

  if (esp_now_init() != 0) {
    Serial.println("ESP-NOW initialization failed!");
    while (true);
  }

  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_add_peer(receiverMAC, ESP_NOW_ROLE_SLAVE, channel, NULL, 0);
  esp_now_register_send_cb(onDataSent);
}

void loop() {

    // фиктивные данные для структуры myData, заменяем их фактическими данными
    myData.latitude = 1.72;
    myData.longitude = 1.03;
    myData.altitude = 13.0;
    Serial.printf("Sending Lat=%.2f, Long=%.2f; Alt=%.2f\n",
                   myData.latitude, myData.longitude, myData.altitude);
    sentStartTime = micros();
    esp_now_send(receiverMAC, (uint8_t *) &myData, sizeof(myData));
    delay(1000);   // отправить снова через 1 секунду
}

Приёмник ESP-Now

#include <ESP8266WiFi.h>
#include <espnow.h>

typedef struct struct_message {
  float latitude;
  float longitude;
  float altitude;
} struct_message;

// *** следующие 3 настройки должны соответствовать настройкам передатчика ***
uint8_t mac[] = {0x82, 0x88, 0x88, 0x88, 0x88, 0x88};
const uint8_t channel = 1;
struct_message myData;
// ***********************************************************************

void OnDataRecv(uint8_t * tmac, uint8_t *incomingData, uint8_t len) {
  Serial.println("Data received!");
  memcpy(&myData, incomingData, len);
  Serial.printf("From: %02x:%02x:%02x:%02x:%02x:%02x, ",
                 tmac[0], tmac[1], tmac[2], tmac[3], tmac[4], tmac[5]);
  Serial.print("Latitude: ");
  Serial.println(myData.latitude, 6);
  Serial.print("Longitude: ");
  Serial.println(myData.longitude, 6);
  Serial.print("Altitude: ");
  Serial.println(myData.altitude, 2);
}

void setup() {
  Serial.begin(115200);

  WiFi.persistent(false); // отключить постоянный Wi-Fi
  WiFi.mode(WIFI_AP);     // Приемник ESP-Now должен быть в режиме точки доступа
  WiFi.disconnect();      // Не подключаться к WiFi
  wifi_set_macaddr(SOFTAP_IF, mac); // если используется локально администрируемый MAC-адрес

  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
}

Вот две мои записи в блоге о проекте дверного звонка ESP-Now и тесте дальности и времени отклика

,

0

Ваш receiverMAC в настоящее время равен {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}. Это недопустимый MAC-адрес. Получите правильный MAC-адрес принимающего ESP8266, выполнив следующий код:

    void setup() {
    Serial.begin(115200);
    WiFi.mode(WIFI_STA);
    Serial.print("ESP8266 MAC: ");
    Serial.println(WiFi.macAddress());}
    void loop() {}

Более подробную информацию можно найти в этом руководстве: https://randomnerdtutorials.com/get-change-esp32-esp8266-mac-address-arduino/. Определите правильный MAC-адрес и обновите его в коде. Если вы хотите изготовить печатные платы для своего проекта, здесь вы найдете информацию о стоимости. https://www.allpcb.com/blog/pcb-ordering/pcb-cost-per-unit.html

,