Connecting wired and wireless communication
In thess week, our task was to setup wireless communication between circuit and internet page. I have decided to work on my project and setup communication between the esp32 and webpage, to be able to read running frequency from the microprocessor and display it on the webpage. To add something extra, I have also added option to change goal frequency, user wants to get close to. This way, the actuator doesn't vibrate with increasing frequency, but when the running frequency is getting further from the goal.
I have used this tutorial, to help me with the HTTP protocol. With the help of copilot, I have adjusted the code for my needs as you can see below:
#include "I2Cdev.h"
#include "MPU6050.h"
#include
#include
#include
// Display
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C // I2C address for SSD1306
// Frequency detection
#define SAMPLE_RATE 100
#define MAX_THRESHOLD 20384
#define MIN_THRESHOLD 12384
#define MA_WINDOW_SIZE 10
#define PEAK_WINDOW_SIZE 10
#define CLEARANCE_DELAY 2000
// Network
// Replace with your network credentials
const char* ssid = "Your wifi";
const char* password = "Your password";
// Set web server port number to 80
WiFiServer server(80);
unsigned long currentTime = millis();
unsigned long previousTime = 0;
const long timeoutTime = 2000;
// Variable to store the HTTP request
String header;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
MPU6050 mpu; // MPU6050 address is 0x68
hw_timer_t *timer = NULL;
volatile bool flag = false;
int MOTOR_PIN = D0; // PWM pin for motor control
int16_t ax, ay, az;
bool blinkState;
// MPU6050 offsets
int16_t ax_offset = -3107;
int16_t ay_offset = 1885;
int16_t az_offset = 837;
uint16_t currAccel;
uint16_t maBuffer[MA_WINDOW_SIZE];
unsigned int maIndex = 0;
uint32_t maSum = 0;
unsigned long peakBuffer[PEAK_WINDOW_SIZE] = {0};
unsigned int peakIndex = 0;
unsigned long periodSum = 0;
unsigned long currTimeDiff = 0;
unsigned long lastTime = 0;
uint16_t prevAvg = 0;
uint16_t currAvg = 0;
volatile bool highPeakFlag = false;
volatile bool computeAvg = false;
float currentFreq = 0.0;
float goalFreq = 0.0;
void IRAM_ATTR onTimer() {
flag = true;
}
void setup() {
/*--Start I2C interface--*/
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(115200);
delay(5000);
/*Initialize device and check connection*/
Serial.println("Initializing MPU...");
mpu.initialize();
Serial.println("Testing MPU6050 connection...");
if(mpu.testConnection() == false){
Serial.println("MPU6050 connection failed");
while(true);
}
else{
Serial.println("MPU6050 connection successful");
}
mpu.setDLPFMode(5);
Wire.begin(6, 7); // For Seeed XIAO ESP32
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
while (true);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Display Ready!");
display.display();
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 10000, true); // 100 Hz sampling
timerAlarmEnable(timer);
/* Setting accelerometer offsets */
Serial.println("Updating internal sensor offsets...\n");
mpu.setXAccelOffset(ax_offset);
mpu.setYAccelOffset(ay_offset);
mpu.setZAccelOffset(az_offset);
/*Configure board LED pin for output*/
pinMode(LED_BUILTIN, OUTPUT);
pinMode(MOTOR_PIN, OUTPUT);
// Fill sample buffer
for (int i = 0; i < MA_WINDOW_SIZE; i++) {
mpu.getAcceleration(&ax, &ay, &az);
currAccel = sqrt(ax * ax + ay * ay + az * az);
maBuffer[i] = currAccel;
maSum += currAccel;
delay(10);
}
prevAvg = maSum / MA_WINDOW_SIZE;
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
if (flag) {
flag = false;
unsigned long currentMillis = millis();
mpu.getAcceleration(&ax, &ay, &az);
currAccel = sqrt(ax * ax + ay * ay + az * az);
maSum = maSum - maBuffer[maIndex] + currAccel;
maBuffer[maIndex] = currAccel;
maIndex = (maIndex + 1) % MA_WINDOW_SIZE;
currAvg = maSum / MA_WINDOW_SIZE;
static int lastSlope = 0;
int slope = currAvg - prevAvg;
/* Detect peaks */
if (lastSlope > 0 && slope < 0 && prevAvg > MAX_THRESHOLD && !highPeakFlag) {
highPeakFlag = true;
currTimeDiff = currentMillis - lastTime;
periodSum = periodSum - peakBuffer[peakIndex] + currTimeDiff;
peakBuffer[peakIndex] = currTimeDiff;
if ((peakIndex + 1) % PEAK_WINDOW_SIZE == 0) {
computeAvg = true;
}
peakIndex = (peakIndex + 1) % PEAK_WINDOW_SIZE;
lastTime = currentMillis;
} else if (lastSlope < 0 && slope > 0 && prevAvg < MIN_THRESHOLD && highPeakFlag) {
highPeakFlag = false;
currTimeDiff = currentMillis - lastTime;
periodSum = periodSum - peakBuffer[peakIndex] + currTimeDiff;
peakBuffer[peakIndex] = currTimeDiff;
if ((peakIndex + 1) % PEAK_WINDOW_SIZE == 0) {
computeAvg = true;
}
peakIndex = (peakIndex + 1) % PEAK_WINDOW_SIZE;
lastTime = currentMillis;
}
/* Clear buffer when no peaks detected for CLEARANCE_DELAY ms */
if (currentMillis - lastTime > CLEARANCE_DELAY) {
computeAvg = false;
periodSum = 0;
memset(peakBuffer, 0, sizeof(peakBuffer));
peakIndex = 0;
}
/* Compute frequency */
if (computeAvg) {
uint32_t periodAvg = (2 * periodSum) / PEAK_WINDOW_SIZE;
currentFreq = 1000.0 / periodAvg;
Serial.println("Period sum: " + String(periodSum) + "\t" + "Period avg: " + String(periodAvg) + "\t" + "Frequency: " + String(currentFreq));
} else {
currentFreq = 0.0;
}
lastSlope = slope;
prevAvg = currAvg;
float freqDiff = abs(currentFreq - goalFreq);
int pwmVal;
if (currentFreq == 0.0) {
pwmVal = 0;
} else {
if (freqDiff > 0.05) {
pwmVal = (int)((freqDiff - 0.05) * (255.0-140.0) / (2.0 - 0.05) + 140.0);
//pwmVal = (int)((currentFreq - 1.2) * (255.0-140.0) / (3.0 - 1.2) + 140.0);
}
else {
pwmVal = 0;
}
}
if (pwmVal > 255) {
pwmVal = 255;
} else if (pwmVal < 140 && pwmVal > 0) {
pwmVal = 140;
}else if (pwmVal < 0) {
pwmVal = 0;
}
/* Write on display */
display.clearDisplay();
display.setCursor(0, 0);
display.printf("Running frequency:\n");
display.printf("%.2f steps per second\n", currentFreq);
display.printf("PWM %d\n", pwmVal);
display.display();
analogWrite(MOTOR_PIN, pwmVal);
// Web server logic
WiFiClient client = server.available(); // Listen for incoming clients
if (client) { // If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // Print a message out in the serial port
String currentLine = ""; // Make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) { // Loop while the client's connected
currentTime = millis();
if (client.available()) { // If there's bytes to read from the client,
char c = client.read(); // Read a byte, then
Serial.write(c); // Print it out the serial monitor
header += c;
if (c == '\n') { // If the byte is a newline character
// If the current line is blank, you got two newline characters in a row.
// That's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// Handle requests to increase or decrease goalFreq
if (header.indexOf("GET /increase") >= 0) {
goalFreq += 0.1; // Increase goalFreq by 0.1
Serial.println("Increased goalFreq: " + String(goalFreq));
} else if (header.indexOf("GET /decrease") >= 0) {
goalFreq -= 0.1; // Decrease goalFreq by 0.1
if (goalFreq < 0) goalFreq = 0; // Ensure goalFreq doesn't go below 0
Serial.println("Decreased goalFreq: " + String(goalFreq));
}
// Handle AJAX request for currentFreq
if (header.indexOf("GET /freq") >= 0) {
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE html>");
client.println("<html>");
client.println("<head>");
client.println(" <title>ESP32 Web Server</title>");
client.println(" <style>");
client.println(" body { font-family: sans-serif; background: #f0f0f0; text-align: center; padding: 20px; }");
client.println(" .box { background: #fff; padding: 20px; margin: auto; width: 90%; max-width: 300px; border-radius: 8px; box-shadow: 0 0 5px rgba(0,0,0,0.2); }");
client.println(" button { padding: 8px 12px; margin: 5px; border: none; border-radius: 4px; background: #007BFF; color: white; cursor: pointer; }");
client.println(" button:hover { background: #0056b3; }");
client.println(" span { display: block; text-align: left; margin-left: 5%; }");
client.println(" </style>");
client.println("</head>");
client.println("<body>");
client.println(" <div class='box'>");
client.println(" <h2>ESP32 Web Server</h2>");
client.println(" <p><span>Current Frequency:</span><span id='freq'>" + String(currentFreq, 2) + " Hz</span></p>");
client.println(" <p><span>Goal Frequency:</span><span id='goalFreq'>" + String(goalFreq, 2) + " Hz</span></p>");
client.println(" <button onclick=\"changeGoalFreq('increase')\">Increase Frequency</button>");
client.println(" <button onclick=\"changeGoalFreq('decrease')\">Decrease Frequency</button>");
client.println(" <script>");
client.println(" setInterval(() => {");
client.println(" fetch('/freq')");
client.println(" .then(response => response.text())");
client.println(" .then(data => { document.getElementById('freq').innerText = data + ' Hz'; });");
client.println(" }, 1000);");
client.println(" function changeGoalFreq(action) {");
client.println(" fetch('/' + action)");
client.println(" .then(() => {");
client.println(" const goalFreqElem = document.getElementById('goalFreq');");
client.println(" const currentGoalFreq = parseFloat(goalFreqElem.innerText);");
client.println(" const newGoalFreq = action === 'increase' ? (currentGoalFreq + 0.1).toFixed(2) : Math.max(0, (currentGoalFreq - 0.1).toFixed(2));");
client.println(" goalFreqElem.innerText = newGoalFreq + ' Hz';");
client.println(" });");
client.println(" }");
client.println(" </script>");
client.println(" </div>");
client.println("</body>");
client.println("</html>");
client.println(" ");
client.println("