Networking & communication
Assignments
Our tasks for this week are:
- Group assignment: Send a message between two projects
- Individual assignment: Design, build, and connect wired or wireless node(s) with network or bus addresses
Group Assignment
Documentation of our group work can be found here.
For the group assignment we connected the heart side of the my teaching heart project to Tony’s pugboy gaming console project via the ESP NOW wireless protocol (both projects used the same board, the Xiao ESP32C3). The teaching heart was the receiving board and the pugboy was the sending board. We modified a program so that when the buttons on the pugboy were pressed, the ‘heartbeat’ rate of the teaching heart changes (increased or decreased).
Individual Assignment
For my final project I will use two pieces - a base, and the heart itself. I want the user to be able to pick up and move the heart around, investigate it, without being limited or tethered by wires. And I also want to be able to control the heartrate, the pace of the pattern of lights, via user inputs on the base.
Due to these constaints, I knew I’d need a wireless protocol to communicate between the two boards. I opted to use two SEEED Xiao ESP32C3 boards since we have them in the lab and that would allow me to use the ESP NOW wireless protocol that’s only available between ESP boards. Also, the Xiao ESP32C3 has built-in battery charging capabilities which make it attractive for use in the heart where I’ll need a battery to power the LED stands.
Programming
MAC Address
In order to set up my two boards as a sender and receiver using the ESP NOW protocol, I first needed to find the MAC (Media Access Control) address of the receiver board so it could be referred to in the sender board code. This is accomplished by running the following code on the Receiver board, in order for it to report its MAC address to me.
Random Nerd Tutorials has a bunch of helpful information and sample code to get up and running with ESP NOW, such as the snippet below:
Code:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/get-change-esp32-esp8266-mac-address-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <WiFi.h>
#include <esp_wifi.h>
void readMacAddress(){
uint8_t baseMac[6];
esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac);
if (ret == ESP_OK) {
Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
baseMac[0], baseMac[1], baseMac[2],
baseMac[3], baseMac[4], baseMac[5]);
} else {
Serial.println("Failed to read MAC address");
}
}
void setup(){
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.STA.begin();
Serial.print("[DEFAULT] ESP32 Board MAC Address: ");
readMacAddress();
}
void loop(){
}
Once I have the MAC address for the receiver board, I was able to refer to that board directly in the code for the sender board. I only need a one way communication rather than two way communication.
Sender board (in base)
The to download the Arduino IDE code I uploaded to the base microcontroller, or/and to see the design files for the board, please visit my Final Project page.
This code takes a value read by a potentiometer input device and sends it to the Receiver board as BPM via the ESP NOW protocol.
I’ve also included the code below if you want to copy and paste into a new Arduino IDE sketch:
#include <esp_now.h>
#include <WiFi.h>
#define POT_PIN D0 // Potentiometer connected to pin D1
// Define the structure for sending data
typedef struct struct_message {
int value;
} struct_message;
struct_message myData;
// Define the peer address (MAC address of the receiver)
uint8_t broadcastAddress[] = {0xD4, 0xF9, 0x8D, 0x00, 0xF9, 0x18}; // Replace with the receiver's MAC address
// Callback function that gets called when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("Last Packet Send Status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
// Global variables
int bpm = 60; // Default BPM
unsigned long lastToggleTime = 0;
unsigned long lastReadTime = 0;
const unsigned long readInterval = 500; // Delay for reading the potentiometer (in milliseconds)
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);
Serial.println("WiFi mode set to STA");
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
Serial.println("ESP-NOW initialized");
// Register the send callback
esp_now_register_send_cb(OnDataSent);
// Register peer
esp_now_peer_info_t peerInfo;
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;
}
Serial.println("Peer added");
}
void loop() {
// Get the current time
unsigned long currentTime = millis();
// Check if it's time to read the potentiometer and send data
if (currentTime - lastReadTime >= readInterval) {
// Read the analog value from the potentiometer
int analogValue = analogRead(POT_PIN); // Pin D1 corresponds to ADC1 (GPIO1)
// Map the analog value to the range 30 to 180
bpm = map(analogValue, 0, 4095, 30, 180); // Assuming a 12-bit ADC resolution
// Print the values for debugging
Serial.print("Analog Value: ");
Serial.print(analogValue);
Serial.print(" | Mapped Value: ");
Serial.println(bpm);
// Prepare data to send
myData.value = bpm;
// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
if (result == ESP_OK) {
Serial.println("Sent with success");
} else {
Serial.println("Error sending the data");
}
// Update the last read time
lastReadTime = currentTime;
}
}
Reciever board (in heart)
The to download the Arduino IDE code I uploaded to the heart microcontroller, or/and to see the design files for the board, please visit my Final Project page.
This code takes the BPM value received from the sender board in the base and uses it to update the pacing of two RGB LED strands mounted within the heart.
The code is also included below:
#include <esp_now.h>
#include <WiFi.h>
// Define the structure for receiving data
typedef struct struct_message {
int value;
} struct_message;
// Create a struct_message called myData
struct_message myData;
#include <FastLED.h>
// How many leds in your strip?
#define NUM_LEDS1 56
#define NUM_LEDS2 50
// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806, define both DATA_PIN and CLOCK_PIN
#define DATA_PIN1 D10
#define DATA_PIN2 D2
#define HALL_SENSOR D0
int BPM = 70;
// Define the array of leds
CRGB leds1[NUM_LEDS1];
CRGB leds2[NUM_LEDS2];
void setup() {
Serial.begin(115200);
Serial.println("resetting");
FastLED.addLeds<WS2812, DATA_PIN1, GRB>(leds1, NUM_LEDS1);
FastLED.addLeds<WS2812, DATA_PIN2, GRB>(leds2, NUM_LEDS2);
FastLED.setBrightness(84);
pinMode(HALL_SENSOR, INPUT_PULLUP);
WiFi.mode(WIFI_STA);
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Register for a callback function to receive data
esp_now_register_recv_cb(OnDataRecv);
}
void fadeall1() {
for (int i = 0; i < NUM_LEDS1; i++) { leds1[i].nscale8(230); }
}
void fadeall2() {
for (int i = 0; i < NUM_LEDS2; i++) { leds2[i].nscale8(230); }
}
void loop() {
// Pulse rate: 60 pulses per minute (1 pulse per second)
float delayTimeR = (((60.0/BPM)*1000.0) / (NUM_LEDS1)); // Delay time in milliseconds for each LED;
float delayTimeL = (((60.0/BPM)*1000.0) / (NUM_LEDS2)); // Delay time in milliseconds for each LED;
Serial.println(BPM);
Serial.println(BPM);
// First slide the LED in one direction for blue LEDs
for (int i = 0; i < NUM_LEDS1; i++) {
if (digitalRead(HALL_SENSOR) && i>11) {
leds1[i] = CRGB::Purple;
}
else{
leds1[i] = CRGB::Blue;
}
FastLED.show();
fadeall1();
fadeall2();
delay(delayTimeR);
}
//delay(500);
//First slide the LED in one direction for red LEDs
for (int i = 0; i < NUM_LEDS2; i++) {
leds2[i] = CRGB::Red;
FastLED.show();
fadeall2();
fadeall1();
delay(delayTimeL);
}
}
void OnDataRecv(const esp_now_recv_info *info, const uint8_t *incomingData, int len) {
memcpy(&myData, incomingData, sizeof(myData));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Received value: ");
BPM = myData.value;
Serial.println(BPM);
}
Hero shots
Reflections
I went into the week feeling intimidated by networking & communications but then when it came down to it, the local hands-on demo demystified the process considerably.
I was able to successfully and relatively painlessly implement the ESP NOW protocol between two Xiao ESP32C3 boards in order to send a value (beats per minute) from the Sender board in the Base to the Reciever board mounted in the heart. One thing I’ve noticed is that sometimes the pulse rate in the heart seems to lag behind the potentiometer, or isn’t sent successfully. I think there might be some unintentionally delay built into my code, either on the sending or receiving side, so I want to look into optimizing the code more to make the heart rate respond more quickly/intantaneously when the dial is turned by the user.
see below for some notes from the local class & exercises, as well as the global lecture
Notes for the week
- Wired & wireless networking
- networks & communication protocols used for:
- location flexibility - some operations happen offsite
- paralelism
- modularity
- interference - avoid interference b/w systems (5V sys and 3.3V sys)
Example: SAMD21, ESP21 connected to internet, input sensors Able to connect external sensors
Protocol vs Network
Network = group of computers connected among themselves through communication lines - Different topologies available: ring, mesh, star, fully connected, line, tree, bus Protocol = set of rules to specifiy message format
Choosing a network type
considerations:
- power consumption
- range
- bandwidth
- existing network vs adhoc
Serial vs Parallel
- Parallel interface:
- Serial interface: one cable, send data via pulses. More used now, more computational power
Synchronous vs Asynchronous communication
- asynchronous = data transferred w/out support from external clock signal. perfect for minimizing required wires
- synchronous = always come with data line(s) paired with a clock signal to in tell when to read
USB = Universal Serial Bus
Tx-Rx and Rx-Tx Most common way of serial communication 2 wires & GND asynchronous, so need to define read spead upfront (baud rate)
In Class Demo/Exercise: Wired communication
Barduino UART Board = ESP32S3 Dev Module Enable USB setting in tools to connect with serial over hardware
can do software serial vs hardware serial hardware is faster but software more flexible (but slower)
hardware exercise to communicate from my Barduino to Danni’s Barduino
now, software serial
serial - asynchronous
I2C protocol - synchronous includes a clock pin allows for several masters, several slaves 2 wires, 1028 devices - one bus parent communicates with children, children don’t communicate to each other SDA = data SCL = Clock can have a third line for voltage shared voltage is optional pull up resistor for both SDA & SCL lines (I2C protocols grounds the lines when sends data) many sensors work with I2C - check datasheet for address of sensor what if two sensors with same address? could either (1) multiplex or (2) use one of the other possible address options for the sensor (3) use another I2C port
On barduino, need SCL and SDA lines exposed
SPI protocol - 6 pins SCK = clock Reset pin VCC = voltage GND = ground MISO = Master In Slave Out MOSI = Master Out Slave In extra pins for each child pro: faster than I2C because can talk back and forth better for data tranfer
In class Demo: Wireless communication
can’t do with SAMD can do ESPs
Radio Frequency Spectrum Wavelength different protocols for different spectrums of frequencies
- lower the frequency, easier to go through buildings/things
- 5G wifi: less range, b/c higher frequency, but faster - sending information with frequencies of 5GHz
- 2.4 wifi: slow, but further range
- visible spectrum very small
- use low frequencies to communicate with submarines through water
- choose frequency depending on use case- how far want signal to carry, and how fast?
- visible light vs radio - higher freq vs lower - visible light gets stopped by wall but radio doesn’t
- certain parts of the spectum are illegal to use - reserved by governments/countries - confirm you’re using appropriate frequencies for your location
- need antennas to send these frequencies
- big topic in itself
- different types of antenna, have implications on signal/frequencies they produce
- different radiation pattern
-Radiation pattern: - ex: candle - radiate all around - ex: candle with mirror on one side to direct light to opposite light - can extend/stengthen/focus range on diffenent frequencies * Dipole - wire, (candle) * Patch (ESP32) (radiates better in one direction than another) * Omni * Helical
* Jamming Gun
Gain sending wifi 2.4 =/ wifi 5 antenna length of antenna depends on frequency of wavelength Range-power-frequency be careful with power (might not be legal) omni-direction: gain = 1 directional: gain = >1 dB = decibels, unit of measurement for gain non-linear, logarithmic scale increase by 3 dB, signal strenth (not range) doubles
AM-FM signal AM = amplitude modulation FM = frequency modulation
radio jamming = someone applying noise to the signal you’re trying to send, interferes
Antenna standards SMA male/female U.FL (fragile, don’t connect and disconnect a lot b/c will break the snap connector)
many protocol options for wireless communication
Barduino: ESP32-S3 wifi bluetooth low energy (=/ bluetooth) ESP-NOW (ESP-ESP protocol, not ESP-computer)
MQTT Protocol
- to send packages of information through a network (such as the internet)
- can connect to router (station)
- OR can connect to local devices (Soft Access Point)
- create MQTT-Broker (in center of start) to broker transfer of infomation
- can publish data from broker or
- used a lot in Smart Homes - to connect sensors (publishing data to broker)
- works with “topics” - tree diagram
Class demo with broker, button, neopixel Class demo with creating local access point (parent) with ESP32 Class demo with ESP-NOW -flexibility to set up different network patterns -use MAC address- unique for each ESP uC - 6 values - (another MAC address for bluetooth module)
ESP32-s3 has an antenna built in, length is calculatable
Bandwidth vs Range chart
-
bluetooth & wifi, quite short range
-
zigBee (protocol similar to bluetooth but a bit more range)
-
example where use only one LED to send and receive information to itself, wireless protocol
Neil Class Highlights
Wired
SPI
micropython libraries SD memory cards allows you to add GB of data to project, very fast, data stored (non-volatile) example: implement SPI in software memory card must be formatted with FAT file system
I2C
SCL, SDA both lines shared by the two processors pullup resistors on both lines, but boards pull down to talk I2C = Wire in arduino IDE many sensors/parts have I2C address built into them beware long cables - can get reflections, interference, complex impedence
I3C
emerging but not yet widely supported
ATP = Asynchronous Token Protocol
unclocked protocol fast-fast processors or also fast-slow processors because it has a status state, it doesn’t need to know what came before wire: low vs high token: is it valid or not pass data like a checkers piece moving on a board
USB
ethernet
Wireless
Radios
ARRL handbook
Antennas
If use a radio, need antennas tune
single chip radios
ESP23-C3 example: can serve a webpage from the xiao and interact from the browser example: bluetooth scanner app for phone allows it to interface w/ bluetooth devices blueart.py