|
ESP32-C6-WROOM-1U-N4Espressif Systems
|
x 1 | |
|
LIS2DW12TRSTMicroelectronics
|
x 1 | |
|
MCP73831T-2ATI/OTMICROCHIP(美国微芯)
|
x 1 | |
|
AT42QT1010-TSHRMicrochip
|
x 2 | |
|
B5819WS-TP-CNChipNobo(无边界)
|
x 1 | |
|
MIC5219-3.3YM5-TR |
x 1 |
|
arduino IDEArduino
|
LUNA ESSENCE: A Wearable Device Inspired by Morpho Butterfly
Click on the link to listen to his story: https://omersahingok.notion.site/LUNA-ESSENCE-e2fd9cfb7f834acf8f1824619350eb9f?pvs=4
Project Title: LUNA ESSENCE – A Wearable Device Inspired by the Elegance of the Morpho Butterfly
Introduction: LUNA ESSENCE is a wearable electronic device designed to combine functionality with aesthetics, inspired by the captivating beauty and transformation process of the Morpho butterfly. This project utilizes cutting-edge technologies to provide a versatile and engaging user experience.
Why Was This Project Created? The inspiration for LUNA ESSENCE stems from the graceful lifecycle of butterflies, particularly the Morpho species. The device aims to embody the delicate and transformative journey of these creatures while providing users with a practical, wearable platform for interaction and visual sharing.
Key Features:
ESP32 Core: The device is powered by the ESP32 microcontroller, ensuring efficient performance and seamless connectivity.
Sensors and Inputs: It includes:
1 Accelerometer for motion detection and dynamic interactions.
2 Touch Buttons for intuitive control.
4 Programmable LEDs to display dynamic patterns and statuses.
Rechargeable Design: LUNA ESSENCE features a built-in rechargeable battery for extended usability.
Visual Sharing: Displays real butterfly images and animations to enhance user engagement.
Wearability: Compact and lightweight, making it comfortable to wear and practical for everyday use.
How Does It Work? The device integrates its accelerometer, touch buttons, and LED system to create a responsive and interactive platform. Users can interact with the device through touch inputs and motion, triggering various LED animations or sharing visuals of the Morpho butterfly. The rechargeable design ensures sustainability and portability, allowing continuous use without frequent battery replacements.
Design Philosophy: The PCB design and component layout reflect the intricate structure of the butterfly, aiming to mirror the harmony found in nature. Each element of the design has been optimized for functionality while maintaining an aesthetic appeal, resonating with the butterfly's elegance.
Target Audience: LUNA ESSENCE is designed for enthusiasts of wearable technology, nature lovers, and individuals seeking unique, visually stunning devices that blend art and technology.
Future Plans: The project has the potential for expansion, including advanced features like BLE connectivity for data sharing, customizable LED patterns, and additional sensors for enhanced functionality.
Conclusion: LUNA ESSENCE is not just a wearable device; it's a tribute to the beauty of nature and the possibilities of technology. This project invites users to experience the seamless integration of form and function, inspired by the breathtaking transformation of the Morpho butterfly.
#include <Arduino.h>
#include <Wire.h>
#include <LIS2DW12Sensor.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <DNSServer.h>
#include <LittleFS.h>
// Wi-Fi Credentials
const char* ssid = "MORPHO";
const char* password = "DE18112018";
const char* domain = "morpho.love";
// DNS Server
DNSServer dnsServer;
const byte DNS_PORT = 53;
// Web Server
AsyncWebServer server(80);
// I2C Pins
#define SDA_PIN 0
#define SCL_PIN 1
// LED Pins
#define LED1 7
#define LED2 10
#define LED3 4
#define LED4 6
// Touch Sensor Pins
#define TOUCH_PIN_1 2
#define TOUCH_PIN_2 5
// Reset PIN
#define BUTTON 18
// IMU
LIS2DW12Sensor imu(&Wire, LIS2DW12_I2C_ADD_H);
volatile int32_t acceleration[3] = {0, 0, 0};
// Global Variables
volatile int counter = 0;
volatile bool sensor1Pressed = false;
volatile bool sensor2Pressed = false;
TaskHandle_t imuTaskHandle, controlTaskHandle;
// HTML template for the webpage
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
<title>For Morpho</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
background-color: #f0f0f0;
margin: 0;
padding: 20px;
}
.gallery {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
margin-top: 20px;
}
.photo-container {
position: relative;
cursor: pointer;
}
.photo {
max-width: 300px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
transition: transform 0.3s ease;
}
.photo-container:hover .photo {
transform: scale(1.05);
}
.download-text {
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 5px 10px;
border-radius: 5px;
font-size: 14px;
opacity: 0;
transition: opacity 0.3s ease;
}
.photo-container:hover .download-text {
opacity: 1;
}
</style>
</head>
<body>
<h1>For My Love</h1>
<div class="gallery">
%PHOTO_PLACEHOLDERS%
</div>
</body>
</html>
)rawliteral";
void initDNSServer() {
// Initialize DNS server to redirect all domains to our IP
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(DNS_PORT, domain, WiFi.softAPIP());
Serial.println("DNS server started with domain: " + String(domain));
}
void initWiFi() {
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
Serial.println("Wi-Fi Access Point Started");
Serial.print("IP Address: ");
Serial.println(WiFi.softAPIP());
Serial.print("Domain: http://");
Serial.println(domain);
}
// Updated function to generate photo placeholders with download links
String generatePhotoPlaceholders() {
String placeholders;
File root = LittleFS.open("/");
File file = root.openNextFile();
while (file) {
if (!file.isDirectory() && String(file.name()).endsWith(".jpg")) {
placeholders += "<div class=\"photo-container\">";
placeholders += "<a href=\"/";
placeholders += file.name();
placeholders += "\" download>";
placeholders += "<img src=\"/";
placeholders += file.name();
placeholders += "\" class=\"photo\" alt=\"Photo\">";
placeholders += "<span class=\"download-text\">Click to Download</span>";
placeholders += "</a>";
placeholders += "</div>";
}
file = root.openNextFile();
}
return placeholders;
}
// Function Prototypes
void imuTask(void *pvParameters);
void controlTask(void *pvParameters);
void handleLEDModes();
void lightLEDsBasedOnIMU();
void setAllLEDs(int brightness);
void blinkAllLEDs();
void blinkCrossLEDs();
void sequentialBlinkLEDs();
void sensor1ISR();
void sensor2ISR();
void buttonISR();
void setup() {
Serial.begin(115200);
// Initialize LittleFS
if (!LittleFS.begin(true)) {
Serial.println("An error occurred while mounting LittleFS");
return;
}
Serial.println("LittleFS mounted successfully");
// Initialize Wi-Fi
initWiFi();
// Initialize DNS Server
initDNSServer();
// Initialize Web Server with captive portal handling
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
String html = String(index_html);
html.replace("%PHOTO_PLACEHOLDERS%", generatePhotoPlaceholders());
request->send(200, "text/html", html);
});
// Handle captive portal requests
server.on("/generate_204", HTTP_GET, [](AsyncWebServerRequest *request) {
request->redirect("/");
});
server.on("/fwlink", HTTP_GET, [](AsyncWebServerRequest *request) {
request->redirect("/");
});
server.on("/connect", HTTP_GET, [](AsyncWebServerRequest *request) {
request->redirect("/");
});
// Serve static files from LittleFS
server.serveStatic("/", LittleFS, "/");
server.begin();
Serial.println("HTTP server started");
// Initialize I2C
Wire.begin(SDA_PIN, SCL_PIN);
// Initialize LEDs
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(LED4, OUTPUT);
// Initialize Touch Sensors
pinMode(TOUCH_PIN_1, INPUT);
pinMode(TOUCH_PIN_2, INPUT);
pinMode(BUTTON,INPUT);
// Attach interrupts to touch sensors
attachInterrupt(digitalPinToInterrupt(TOUCH_PIN_1), sensor1ISR, RISING);
attachInterrupt(digitalPinToInterrupt(TOUCH_PIN_2), sensor2ISR, RISING);
attachInterrupt(digitalPinToInterrupt(BUTTON), buttonISR, FALLING);
// Initialize IMU
if (imu.begin() != LIS2DW12_STATUS_OK) {
Serial.println("IMU initialization failed!");
while (1);
}
imu.Enable_X();
// Create FreeRTOS Tasks
xTaskCreate(imuTask, "IMU Task", 2048, NULL, 2, &imuTaskHandle);
xTaskCreate(controlTask, "Control Task", 2048, NULL, 1, &controlTaskHandle);
}
void loop() {
// Handle DNS requests
dnsServer.processNextRequest();
delay(1);
}
// Task 1: Continuously read IMU data
void imuTask(void *pvParameters) {
while (1) {
if (imu.Get_X_Axes((int32_t *)acceleration) == LIS2DW12_STATUS_OK) {
// IMU data updated in global variable
}
vTaskDelay(pdMS_TO_TICKS(50));
}
}
// Task 2: Check sensors and handle LEDs
void controlTask(void *pvParameters) {
while (1) {
if (sensor1Pressed && !sensor2Pressed) {
counter = 0;
while (sensor1Pressed && !sensor2Pressed) {
lightLEDsBasedOnIMU();
vTaskDelay(pdMS_TO_TICKS(50));
}
} else if (sensor2Pressed && !sensor1Pressed) {
while (sensor2Pressed && !sensor1Pressed) {
handleLEDModes();
vTaskDelay(pdMS_TO_TICKS(50));
}
}
vTaskDelay(pdMS_TO_TICKS(50));
}
}
// Interrupt Service Routine for TOUCH_PIN_1
void sensor1ISR() {
sensor1Pressed = true;
sensor2Pressed = false;
}
// Interrupt Service Routine for TOUCH_PIN_2
void sensor2ISR() {
counter = (counter + 1) % 5;
sensor2Pressed = true;
sensor1Pressed = false;
}
// Interrupt Service Routine for BUTTON
void buttonISR() {
Serial.println("ESP32 Restarting");
delay(500);
ESP.restart();
}
// Handle LED modes based on counter
void handleLEDModes() {
switch (counter) {
case 1:
setAllLEDs(255);
break;
case 2:
blinkAllLEDs();
break;
case 3:
blinkCrossLEDs();
break;
case 4:
sequentialBlinkLEDs();
break;
case 0:
setAllLEDs(0);
break;
}
}
void lightLEDsBasedOnIMU() {
int x = constrain(acceleration[0], -1000, 1000);
int y = constrain(acceleration[1], -1000, 1000);
if (abs(x) < 50 && abs(y) < 50) {
setAllLEDs(0);
return;
}
// Calculate brightness for LED1 (TOP LEFT)
if (x < -50 || y < -50) {
int proximityX2 = map(x, -1000, -50, 255, 0);
int proximityY2 = map(y, -1000, -50, 255, 0);
int combinedProximity2 = max(proximityX2, proximityY2);
analogWrite(LED1, combinedProximity2);
} else {
analogWrite(LED1, 0);
}
// Calculate brightness for LED2 (TOP RIGHT)
if (x < -50 || y > 50) {
int proximityX3 = map(x, -1000, -50, 255, 0);
int proximityY3 = map(y, 50, 1000, 0, 255);
int combinedProximity3 = max(proximityX3, proximityY3);
analogWrite(LED2, combinedProximity3);
} else {
analogWrite(LED2, 0);
}
// Calculate brightness for LED3 (BOTTOM RIGHT)
if (x > 50 || y > 50) {
int proximityX4 = map(x, 50, 1000, 0, 255);
int proximityY4 = map(y, 50, 1000, 0, 255);
int combinedProximity4 = max(proximityX4, proximityY4);
analogWrite(LED3, combinedProximity4);
} else {
analogWrite(LED3, 0);
}
// Calculate brightness for LED4 (BOTTOM LEFT)
if (x > 50 || y < -50) {
int proximityX1 = map(x, 50, 1000, 0, 255);
int proximityY1 = map(y, -1000, -50, 255, 0);
int combinedProximity1 = max(proximityX1, proximityY1);
analogWrite(LED4, combinedProximity1);
} else {
analogWrite(LED4, 0);
}
}
void setAllLEDs(int brightness) {
analogWrite(LED1, brightness);
analogWrite(LED2, brightness);
analogWrite(LED3, brightness);
analogWrite(LED4, brightness);
}
void blinkAllLEDs() {
setAllLEDs(255);
vTaskDelay(pdMS_TO_TICKS(500));
setAllLEDs(0);
vTaskDelay(pdMS_TO_TICKS(500));
}
void blinkCrossLEDs() {
analogWrite(LED1, 255);
analogWrite(LED3, 255);
analogWrite(LED2, 0);
analogWrite(LED4, 0);
vTaskDelay(pdMS_TO_TICKS(500));
analogWrite(LED1, 0);
analogWrite(LED3, 0);
analogWrite(LED2, 255);
analogWrite(LED4, 255);
vTaskDelay(pdMS_TO_TICKS(500));
}
void sequentialBlinkLEDs() {
int ledPins[] = {LED1, LED3, LED2, LED4};
for (int j = 0; j < 4; j++) {
analogWrite(ledPins[j], 255);
for (int k = 0; k < 4; k++) {
if (k != j) {
analogWrite(ledPins[k], 0);
}
}
vTaskDelay(pdMS_TO_TICKS(500));
}
}
LUNA ESSENCE: A Wearable Device Inspired by Morpho Butterfly
*PCBWay community is a sharing platform. We are not responsible for any design issues and parameter issues (board thickness, surface finish, etc.) you choose.
- Comments(0)
- Likes(1)
- (DIY) C64iSTANBUL Dec 27,2024
- 0 USER VOTES
- YOUR VOTE 0.00 0.00
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
More by Engineer
-
Build a Walking Robot: Theo Jansen Style 3D Printed Octopod
128 0 3 -
-
-
kmMiniSchield MIDI I/O - IN/OUT/THROUGH MIDI extension for kmMidiMini
141 0 0 -
DIY Laser Power Meter with Arduino
216 0 2 -
-
-
Box & Bolt, 3D Printed Cardboard Crafting Tools
187 0 2