Week11

Assignment: Embedded Networking and Communication

Individual Assignment:

Creating network communication between 2 devices. In this assignment, I combine the Input device and the Output device to communicate.

ESP-NOW with Xiao ESP32-C3

Assignment Focus: This assignment explores short-range, connectionless communication using ESP-NOW, a proprietary communication protocol developed by Espressif. We will implement a peer-to-peer communication system using the Seeed Studio Xiao ESP32-C3 development board, demonstrating its capabilities for efficient, low-power data exchange in embedded systems.

Learning Objectives:

Why ESP-NOW?

Traditional Wi-Fi communication involves significant overhead with connection establishment, IP addressing, and protocol stacks. For applications requiring fast, direct data exchange between a few devices, ESP-NOW offers a simpler, more efficient alternative. It's ideal for:

Seeed Studio Xiao ESP32-C3

The Xiao ESP32-C3 is an excellent choice for this assignment due to its:

Tutorial Generated using Gemini:

You will be implementing a two-part system: an ESP-NOW Sender and an ESP-NOW Receiver.

Part 1: Setting up the Development Environment

  1. Install Arduino IDE: If you haven't already, download and install the Arduino IDE.
  2. Add ESP32 Board Support:
  1. Select the Correct Board: Go to Tools > Board > ESP32 Arduino and select "XIAO ESP32C3".
  2. Install Necessary Libraries: ESP-NOW functionality is built into the ESP32 core, so no additional libraries are typically needed beyond the standard ESP-NOW API.

Part 2: ESP-NOW Sender Implementation

Objective: Develop a program for one Xiao ESP32-C3 that periodically sends a small data packet (e.g., a simple counter or a short string) to a designated receiver using ESP-NOW.

Hardware:

Software Requirements:

  1. Include necessary headers: esp_now.h and WiFi.h.
  2. Define the Receiver's MAC Address: You will need to obtain the MAC address of your receiver Xiao ESP32-C3. This is crucial for direct communication.
  1. Initialize ESP-NOW:
  1. Pair with the Receiver: Add a peer using esp_now_add_peer(). This tells the sender where to send the data.
  2. Send Data:
  1. Periodic Sending: Implement a delay to send data at regular intervals (e.g., every 1-2 seconds).
  2. Serial Monitor Output: Print messages to the Serial Monitor indicating the status of data transmission (e.g., "Sending data...", "Send success", "Send failed").

Example Data Structure (Optional but Recommended):

C++

typedef struct struct_message {

    int id;

    float value;

    // Add more data fields as needed

} struct_message;

Part 3: ESP-NOW Receiver Implementation

Objective: Develop a program for another Xiao ESP32-C3 that listens for and receives data packets sent via ESP-NOW from the sender.

Hardware:

Software Requirements:

  1. Include necessary headers: esp_now.h and WiFi.h.
  2. Initialize ESP-NOW:
  1. Receive Data Callback:
  1. Serial Monitor Output: Print messages to the Serial Monitor indicating the received data, its length, and the sender's MAC address.

Part 4: Testing and Documentation

  1. Program Both Boards: Upload the Sender sketch to one Xiao ESP32-C3 and the Receiver sketch to another.
  2. Power Up: Power both boards.
  3. Observe Communication: Open the Serial Monitor for both boards (you might need two instances of the Arduino IDE or a terminal program that can handle multiple serial ports). Observe the data being sent and received.
  4. Troubleshooting:
  1. Document Your Work:

Video Link1

Video link 2

Master and Slave devices:

Master Input Device: Link

This input device has an MPU6050 added to the circuit, which can read the direction of turn. The turn direction is then sent to the slave output device, which can tilt itself with a command received from the master input device. Production details are added to the input week assignment. Follow the link to fabricate the PCB.

Code:

#include <esp_now.h>

#include <WiFi.h>

#include <Wire.h>

#define MPU_ADDR 0x68

#define Xreg 0x3B

#define Yreg 0x3D

// Structure to send

typedef struct {

  int8_t direction;  // Using smaller type

} Data;

Data data;

uint8_t receiverMac[] = {0xE4, 0xB3, 0x23, 0xC5, 0x6D, 0x4C};

// Calibration offset

int16_t xOffset = 0, yOffset = 0;

// Read axis function

int16_t readAxis(uint8_t reg) {

  Wire.beginTransmission(MPU_ADDR);

  Wire.write(reg);

  Wire.endTransmission(false);

  Wire.requestFrom(MPU_ADDR, 2, true);

  return (Wire.read() << 8) | Wire.read();

}

// Determine direction

int8_t getDirection(int x, int y) {

  if (abs(x) < 1000 && abs(y) < 1000) return -1; // Dead zone

  if (y < -1000) return 3; // Back

  else if (x < -1000) return 0; // Left

  else if (y > 1000) return 1; // Front

  else if (x > 1000) return 2; // Right

  else return -1;

}

// ESP-NOW send callback

void OnDataSent(const uint8_t *mac, esp_now_send_status_t status) {

  Serial.print("Send Status: ");

  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");

}

void setup() {

  Serial.begin(115200);

  // // Enable internal pullups if needed (optional)

  // pinMode(D4, INPUT_PULLUP); // SDA

  // pinMode(D5, INPUT_PULLUP); // SCL

  Wire.begin(D4, D5);

  WiFi.mode(WIFI_STA);

  WiFi.setSleep(false);

  // Initialize ESP-NOW

  if (esp_now_init() != ESP_OK) {

    Serial.println("ESP-NOW init failed");

    return;

  }

  esp_now_register_send_cb(OnDataSent);

  // Register peer

  esp_now_peer_info_t peerInfo = {};

  memcpy(peerInfo.peer_addr, receiverMac, 6);

  peerInfo.channel = 1;

  peerInfo.encrypt = false;

  peerInfo.ifidx = WIFI_IF_STA;

  if (!esp_now_is_peer_exist(receiverMac)) {

    if (esp_now_add_peer(&peerInfo) != ESP_OK) {

      Serial.println("Failed to add peer");

      return;

    }

  }

  // Wake up MPU6050

  Wire.beginTransmission(MPU_ADDR);

  Wire.write(0x6B); // PWR_MGMT_1

  Wire.write(0);    // Wake up

  Wire.endTransmission(true);

  delay(1000); // Allow MPU to stabilize

  // Get initial offsets

  xOffset = readAxis(Xreg);

  yOffset = readAxis(Yreg);

  Serial.printf("Offsets → x: %d, y: %d\n", xOffset, yOffset);

}

void loop() {

  int accX = readAxis(Xreg) - xOffset;

  int accY = readAxis(Yreg) - yOffset;

  data.direction = getDirection(accX, accY);

  Serial.printf("X: %d, Y: %d, Direction: %d\n", accX, accY, data.direction);

  esp_err_t result = esp_now_send(receiverMac, (uint8_t *)&data, sizeof(data));

  if (result == ESP_OK) {

    Serial.println("Send Success");

  } else {

    Serial.println("Send Error");

  }

  delay(500);

}

Slave Output Device: Link

Output device - Slave, collects input from the master device and moves the servo motor according to the direction of change.

Code: 

#include <esp_now.h>

#include <WiFi.h>

#include <ESP32Servo.h>

typedef struct {

  int8_t direction;

} Data;

const int servoPins[4] = {D0, D1, D7, D8}; // 0: LF, 1: RF, 2: LB, 3: RB

Servo servos[4];

void setServoDirections(int direction) {

  // Reset all servos to neutral first

  for (int i = 0; i < 4; i++) {

    servos[i].write(90);

  }

  switch (direction) {

    case 0: // Tilt Left → Move Right-side servos

      servos[1].write(180); // Right Front CW

      servos[3].write(180); // Right Back CW

      delay(100);

      break;

    case 1: // Tilt Front → Move Back servos

      servos[2].write(180); // Left Back CW

      servos[3].write(180); // Right Back CW

      delay(100);

      break;

    case 2: // Tilt Right → Move Left-side servos

      servos[0].write(180); // Left Front CW

      servos[2].write(180); // Left Back CW

      delay(100);

      break;

    case 3: // Tilt Back → Move Front servos

      servos[0].write(180); // Left Front CW

      servos[1].write(180); // Right Front CW

      delay(100);

      break;

    default:

      // Idle: all at neutral

      for (int i = 0; i < 4; i++) {

        servos[i].write(90);

      }

      delay(100);

      break;

  }

}

void OnDataRecv(const esp_now_recv_info_t *info, const uint8_t *dir, int len) {

  Data data;

  memcpy(&data, dir, sizeof(data));

  Serial.print("Direction: ");

  Serial.println(data.direction);

  setServoDirections(data.direction);

}

void setup() {

  Serial.begin(115200);

  WiFi.mode(WIFI_STA);

  WiFi.setSleep(false);  // Ensure ESP-NOW reliability

  Serial.print("Receiver STA MAC: ");

  Serial.println(WiFi.macAddress());

  if (esp_now_init() != ESP_OK) {

    Serial.println("ESP-NOW Init Failed");

    return;

  }

  esp_now_register_recv_cb(OnDataRecv);

  // Attach servos

  for (int i = 0; i < 4; i++) {

    servos[i].attach(servoPins[i]);

    servos[i].write(90);  // Neutral position

  }

}

void loop() {

  // Nothing in main loop – all handled via ESP-NOW callback

}

Working video


Working video


Working file link : LINK

<<Back to Home