ESPNow Receiving data incorrectly

Hello all,

This is my first post here and I have tried to follow the "getting the best out of this forum". If there is anything that I am missing or can improve dont hesitate to let me know.

I am relatively new to using different protocols in order to send data to various controllers and am having some trouble sending over data using ESPNow in a many- to- one configuration (2 senders and 1 receiver). I originally followed this RNT tutorial as a guide to set it up.

For some project context, I am using 2 cameras that are detecting a cup using an edge AI model I trained. The cameras are running eloquent Arduinos EloquentEsp32Cam From here, I am sending out the diameter and height data in order to find an approximate volume on receiver esp32. This data will then be displayed on an epaper display.

Issue that I am having:
The data is being sent correctly from each individual module to the receiver. When I try to use the diameter, it seems to have a random incorrect value and it is this random value that is being used for the math/display, Although the correct value seems to be sent as I can see it in the serial print. (This is not an issue for the height data, only diameter).

  • Through trouble shooting, I know that the value on the sender side is being sent correctly through serial monitor prints. On the receiver side, the issue seems to be the way it gets/handles the data as when i print the diameter it has said random value.

IMAGE OF EPAPER ISSUE:

IMAGE OF SERIAL MONITOR:

This data that is incoming is numerically correct, but the way it is being displayed is not.

Questions:

  • From what I have read online, the structure created to hold and send the values have to be the exact same on both sender and receiver sides, which I do not have because each individual cameras are sending different data respectively. Do I have to create 2 different structures to handle the different data that the cameras are sending since they are not the same?

HARDWARE BEING USED:
2x Freenove ESP32-S3-WROOM Board camera modules (senders)
1x DOIT Esp32 DEV MODULE (receiver)
1x 2.9 inch e-paper display

The following is the receiver code:

#include <esp_now.h>
#include <WiFi.h>

// ************ Structure example to receive data, put the data type that we will recieve ************//
typedef struct struct_message {
  int ID;
  int height;
  int width;
}

struct_message;

// ****************************** Structure for recieved data ******************************//
struct_message boundingBox;

// ****************************** Setting up sender IDs (cameras) ******************************//
struct_message board1; //height
struct_message board2; //diameter

// ****************************** Creating Receive array for sender boards ******************************//

struct_message boardsStruct[2] = { board1, board2 };
//struct_message boundingBox;

// ****************************** Funtion for recieved data ******************************//
void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) {
  char macStr[18];
  Serial.print("Packet received from: ");
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  Serial.println(macStr);
  memcpy(&boundingBox, incomingData, sizeof(boundingBox));
  Serial.printf("Board ID %u: %u bytes\n", boundingBox.ID, len);

  // ******************************Update height and diameter structures with the new incoming data******************************// 
  boardsStruct[boundingBox.ID-1].height = boundingBox.height;
  boardsStruct[boundingBox.ID-1].width = boundingBox.width;
  Serial.printf("Height value: %d \n", boardsStruct[boundingBox.ID-1].height);
  Serial.printf("Diameter value: %d \n", boardsStruct[boundingBox.ID-1].width);
  Serial.println();
}

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);

  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

 // ****************************** Calling function to read read recived data ******************************//
  esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
}

void loop() {
  // ****************************** Accessing board data ******************************// 
  int board1Height = boardsStruct[0].height;
  int board2Diameter = boardsStruct[1].width;
  Serial.println(board1Height);
  Serial.println(board2Diameter);
  delay(1000);

This is sender code for cup height:

#include <esp_now.h>
#include <WiFi.h>

#include <Vertical_Cam_inferencing.h>
#include <eloquent_esp32cam.h>
#include <eloquent_esp32cam/edgeimpulse/fomo.h>

using eloq::camera;
using eloq::ei::fomo;

//**************************************************************ESPNOW Setup**************************************************************//

// ************** RECEIVER MAC Address **************//
uint8_t broadcastAddress[] = { 0x4C, 0x11, 0xAE, 0x66, 0x2F, 0xA4 };


//************** Data to be sent**************//
typedef struct struct_message {
  int ID;  // must be unique for each sender board
  int height;
  //int width;
} struct_message;

//************** Creating ESP peer interface **************//
struct_message boundingBox;

// Create peer interface
esp_now_peer_info_t peerInfo;

//************** Call function for data to be sent **************//
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

//**************************************************************Camera Setup**************************************************************//

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

  // **************Set device as a Wi-Fi Station **************//
  WiFi.mode(WIFI_STA);

  // ************** Init ESP-NOW **************//
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  //************** Packet Status **************//
  esp_now_register_send_cb(OnDataSent);

  // **************Register peer **************//
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;

  // **************Add peer **************//
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }


  // **************Camera parameters **************//
  camera.pinout.freenove_s3();
  camera.brownout.disable();
  camera.pixformat.rgb565();
  camera.resolution.yolo();

  // **************init camera**************//
  while (!camera.begin().isOk())
    Serial.println(camera.exception.toString());

  // **************no object is detected**************//
  fomo.daemon.whenYouDontSeeAnything([]() {
    // do nothing
  });

  // **************Cup detected**************//
  fomo.daemon.whenYouSee("Coffee Cup", [](int i, bbox_t bbox) {
    Serial.printf(
    "Coffee Cup found at (x = %d, y = %d) (size %d x %d).\n",
      bbox.x,
      bbox.y,
      bbox.width,
      bbox.height
);
});


  // start daemon
  fomo.daemon.start();

  Serial.println("Camera OK");
  Serial.println("Put object in front of camera");
}



void loop() {
  //************** Set values to send**************//
  //boundingBox.height = 0;
  boundingBox.ID = 1;
  boundingBox.height = fomo.first.height;

  // **************Send message via ESP-NOW**************//
  if (fomo.first.height == boundingBox.height) {
    fomo.first.height = 0;
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&boundingBox, sizeof(boundingBox));
    if (result == ESP_OK) {
      Serial.print("Sent with success 1");
    } else {
      Serial.println("Error sending the data");
    }
    delay(1000);
  } else if (fomo.first.height != boundingBox.height) {
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&boundingBox, sizeof(boundingBox));
    if (result == ESP_OK) {
      Serial.println("Sent with success 2");
    } else {
      Serial.println("Error sending the data");
    }
    delay(2000);
  }
}

This is the sender code for the daimeter

#include <esp_now.h>
#include <WiFi.h>

#include <Diameter_Cam_inferencing.h>
#include <eloquent_esp32cam.h>
#include <eloquent_esp32cam/edgeimpulse/fomo.h>

using eloq::camera;
using eloq::ei::fomo;

//**************************************************************ESPNOW Setup**************************************************************//

// ************** RECEIVER MAC Address **************//
uint8_t broadcastAddress[] = { 0x4C, 0x11, 0xAE, 0x66, 0x2F, 0xA4 };


//************** Data to be sent**************//
typedef struct struct_message{ 
  int ID;  // must be unique for each sender board
  //int height;
  int width; 
} struct_message;

//************** Creating ESP peer interface **************//
struct_message boundingBox;

// Create peer interface
esp_now_peer_info_t peerInfo;

//************** Call function for data to be sent **************//
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

//**************************************************************Camera Setup**************************************************************//

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

  // **************Set device as a Wi-Fi Station **************//
  WiFi.mode(WIFI_STA);

  // ************** Init ESP-NOW **************//
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  //************** Packet Status **************//
  esp_now_register_send_cb(OnDataSent);

  // **************Register peer **************//
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;

  // **************Add peer **************//
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }


  // **************Camera parameters **************//
  camera.pinout.freenove_s3();
  camera.brownout.disable();
  camera.pixformat.rgb565();
  camera.resolution.yolo();

  // **************init camera**************//
  while (!camera.begin().isOk())
    Serial.println(camera.exception.toString());

  // **************no object is detected**************//
  fomo.daemon.whenYouDontSeeAnything([]() {
    // do nothing
  });

  // **************Cup detected**************//
  fomo.daemon.whenYouSee("Coffee Cup", [](int i, bbox_t bbox) {
    Serial.printf(
    "Coffee Cup found at (x = %d, y = %d) (size %d x %d).\n",
      bbox.x,
      bbox.y,
      bbox.width,
      bbox.height

);
});


  // start daemon
  fomo.daemon.start();

  Serial.println("Camera OK");
  Serial.println("Put object in front of camera");
}



void loop() {
  //************** Set values to send**************//
  //boundingBox.width = 0; 
  boundingBox.ID = 2;
  boundingBox.width = fomo.first.width; 

  // **************Send message via ESP-NOW**************//
  if (fomo.first.width == boundingBox.width) {
    fomo.first.width = 0;
    Serial.println(boundingBox.width);
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&boundingBox, sizeof(boundingBox));
    if (result == ESP_OK) {
      Serial.println(boundingBox.width);
      Serial.println("Sent with success 1");
      
    } else {
      Serial.println("Error sending the data");
    }
    delay(1000);
  } else if (fomo.first.width != boundingBox.width) {
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&boundingBox, sizeof(boundingBox));
    if (result == ESP_OK) {
      Serial.println("Sent with success 2");
    } else {
      Serial.println("Error sending the data");
    }
    delay(2000);
  }
}

What do you expect to see and what is it you are seeing. I am thinking a decimal point maybe?

You don't want that delay (2000)
at the end of your receiver loop ()
( or anywhere else in it )

1 Like

Thanks for the reply. I am expecting to see 8 in the diameter and 21 as the height.

Appreciate the tip, let me remove those and see what the outcome is.

Sorry thought i'd come back and give a bit more clarity to the issue.

I am expecting to see 8 in the diameter and 21 as the height. There should be no decimal point as the value is always a whole number. I am seeing that the values are being sent, but it seems like they are being forced into the boundingBox.Height variable, which is being printed in as the height in the serial monitor. When i print the diameter value, it gives a static number that is random and printed in the serial monitor as the width.

Let me know if this clears things up a bit more.

Here's the sum of my ESPNOW knowledge --

I suggest to get data transmission working properly with example data, after stripping out all the camera and other unrelated code. Then go back and fix the original.

Consider that when a receiver is listening for ESP-Now messages, you may get broadcast messages from other devices that have no idea you're listening. You can't blindly act upon bytes that have been flying through the air. Verifying the sender's MAC is one way to handle this, but is not that flexible. Ideally you can verify the type of payload by examining it in isolation; some combination of

  • payload size
  • type identifier
  • checksum or hash

The answer to your question is Yes: if they type are different enough, it makes sense to have different structs.

However, this case is pretty simple. Your redundantly typedefed (and poorly named) receiver type is

12 bytes, which are blindly copied into

regardless of actual

int len

number of bytes received. Each sender sends

only 8 bytes; either the above or below

so the "received" width is always random(-ish). And for the latter, the diameter ends up as the height.

Better to keep the struct the same for senders and receiver, and setting the missing value to zero, or some other indicator value like -1, which could double as a type indicator.

is it possible the ESP32 and ESP32S3 are packing the structure differently?
I also tend to specify integer to be a specific size, e.g.

struct __attribute__((packed)) Data {
  byte NodeID;  // ID of transmitting node
  int16_t seq;  // sequence number
  int32_t distance;
  int32_t height;
} struct1;

works OK between two ESP32s
EDIT: just tried sending

struct Data {
  byte NodeID;  // ID of transmitting node
  int seq;  // sequence number
  int distance;
  float voltage;
  char text[50];
} struct1 = { nodeID, 0, 56, 3.14159, "hello " };  // sample data

between ESP32 and ESP32S3 and worked OK packing etc is the same

Looking at the EloquentCAM library, the variable types for the parameters received from fomo.daemn.whenYouSee are 16-bit unsigned int (uint16_t) variables. However, the struct where you are storing the values uses int which is a signed 16-bit value.

It is best not to mix signed and unsigned datatypes.

You probably also need to use %u rather than %d in your sprintf statements to ensure correct encoding.

maybe worth having a read thru Nick Gammon's How to process incoming serial data and SerialTransfer library for transferring packetized data

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.