12. Skin Electronics¶
Research¶
Skin Electronics – Summary
Over the past weeks, I have explored e-textiles and wearable technologies, learning how electronics can be integrated into fabrics and everyday clothing. This journey introduced me to foundational electronic skills—designing circuits, stitching conductive threads, embedding sensors, and creating interactive garments. Each step expanded my understanding of how technology can be worn, how it can sense the body, and how it can respond to movement, touch, or environment.
Now, I am taking a deeper step into the next frontier of wearable technology: skin electronics. Unlike wearables stitched onto clothing, skin electronics bring the interface even closer to the body. They are ultra-thin, flexible, stretchable devices that sit directly on the skin like a temporary tattoo or a soft patch. This week, I aim to explore how electronics can meaningfully interact with the skin, both functionally and safely.
Skin electronics combine materials science, digital fabrication, and biomedical principles. They can monitor real-time physiological signals such as temperature, hydration, heart rate, sweat composition, and muscle activity. Because they move with the skin, they feel natural. These technologies inspire new possibilities for health monitoring, sports performance, personal expression, and human–machine interfaces.
References & Inspiration¶
Week's Assignment¶
Tools and Materials¶
- [Arduino UNO](http://class.textile-academy.org)
- [Arduino IDE](http://class.textile-academy.org)
- Jumper wires
- Hall effect sensor
- Touch sensor
- Vibration sensor
- XIAO ESP32C3
- Phone
- LEDs
- Copper tape
- Connecting wires
- Insulating tape
Process and workflow¶
I used hall effect sensor to detect magnetic field. I wanted to use it in sensing position changes and speed detection using a magnet.
First I had to code it in ArduinO IDE and connecting the sensor to arduino UNO.
After connecting all the electronic components together, I linked the arduino UNO to my computer to get the readings and code. I had to ensure I was using the correct board port and I had to check in with my device manager.
Code¶
int sensorPin = 11; // Hall sensor signal pin
int ledPin = 7; // LED pin
int sensorValue; // current sensor state
int lastSensorValue = 1; // previous sensor state
int count = 0; // counts magnet passes
void setup() {
Serial.begin(1200);
pinMode(sensorPin, INPUT);
pinMode(ledPin, OUTPUT);
}
void loop() {
sensorValue = digitalRead(sensorPin); // Detect magnet pass (HIGH -> LOW transition)
if (sensorValue == 0 && lastSensorValue == 1) {
count++;
Serial.print("Magnet Pass Count: ");
Serial.println(count);
digitalWrite(ledPin, HIGH); // LED ON
}
// Turn LED OFF when magnet goes away
if (sensorValue == 1) {
digitalWrite(ledPin, LOW);
}
lastSensorValue = sensorValue;
delay(50);
When a magnet comes close → sensor outputs HIGH (1) When magnet moves away → sensor outputs LOW (0).
I also programmed it to count the number of passes when it detects the magnet.
I am to use this code on a car seat to know how far the seat has moved, to know proximity of the driver to the seat when in motion.
From the wearabes assignment, I also integrated a bit of skin electronic where when my thumb comes in contact with the touch sensor, the LEDs light. Continuous touch results in full light.
The following code generated by ChatGPT was used and it integrated web UI:
#include <WiFi.h>
#include <WebServer.h>
// ---------------- PINS ----------------
#define TOUCH_PIN 2
#define VIB_PIN 3
#define LED1 21
#define LED2 20
#define LED3 8
#define LED4 9
// ---------------- WIFI ----------------
const char* ssid = "SKIN";
const char* password = "12345678";
WebServer server(80);
// ---------------- SENSOR STATES ----------------
int touchState = 0;
int vibState = 0;
// vibration memory
unsigned long lastVibTime = 0;
int vibBurstCount = 0;
// ---------------- LIVING WEB UI ----------------
String page = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Living Skin</title>
<style>
body {
margin:0;
font-family: Arial;
color:white;
text-align:center;
transition:0.2s;
background:#0b0f14;
}
body.idle {
animation: breathe 4s infinite;
}
@keyframes breathe {
0% { background:#0b0f14; }
50% { background:#111a24; }
100% { background:#0b0f14; }
}
.touch { background:#123a2a !important; }
.flash { background:white !important; color:black !important; }
.stress {
animation: shake 0.1s infinite;
background:#2a0b0b !important;
}
@keyframes shake {
0% { transform:translate(0px,0px); }
25% { transform:translate(2px,-2px); }
50% { transform:translate(-2px,2px); }
75% { transform:translate(2px,2px); }
100% { transform:translate(0px,0px); }
}
.box {
margin:20px;
padding:20px;
border-radius:12px;
background:rgba(255,255,255,0.05);
}
.big { font-size:28px; }
</style>
</head>
<body id="body">
<h2>🧠 Living Skin System</h2>
<div class="box">🖐 Touch: <span id="touch">0</span></div>
<div class="box">⚡ Vibration: <span id="vib">0</span></div>
<div class="box big" id="state">IDLE</div>
<script>
let vibCount = 0;
let lastVibTime = 0;
function updateUI(touch, vib) {
let body = document.getElementById("body");
let state = document.getElementById("state");
body.className = "idle";
let now = Date.now();
if (touch == 1) {
body.classList.add("touch");
state.innerHTML = "🖐 AWARE";
}
if (vib == 1) {
body.classList.add("flash");
state.innerHTML = "⚡ REFLEX";
if (now - lastVibTime < 300) vibCount++;
else vibCount = 1;
lastVibTime = now;
}
if (vibCount > 4) {
body.className = "stress";
state.innerHTML = "🔥 STRESS";
}
if (touch == 0 && vib == 0) {
state.innerHTML = "🌬 BREATHING";
}
}
setInterval(() => {
fetch('/data')
.then(r => r.json())
.then(d => {
document.getElementById("touch").innerHTML = d.touch;
document.getElementById("vib").innerHTML = d.vib;
updateUI(d.touch, d.vib);
});
}, 150);
</script>
</body>
</html>
)rawliteral";
// ---------------- SERVER ----------------
void handleRoot() {
server.send(200, "text/html", page);
}
void handleData() {
String json = "{";
json += "\"touch\":" + String(touchState) + ",";
json += "\"vib\":" + String(vibState);
json += "}";
server.send(200, "application/json", json);
}
// ---------------- LED EFFECTS ----------------
void allOff() {
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
digitalWrite(LED4, LOW);
}
void wave() {
digitalWrite(LED1, HIGH); delay(60); digitalWrite(LED1, LOW);
digitalWrite(LED2, HIGH); delay(60); digitalWrite(LED2, LOW);
digitalWrite(LED3, HIGH); delay(60); digitalWrite(LED3, LOW);
digitalWrite(LED4, HIGH); delay(60); digitalWrite(LED4, LOW);
}
void flash() {
digitalWrite(LED2, HIGH);
digitalWrite(LED3, HIGH);
delay(50);
allOff();
}
void burst() {
for (int i = 0; i < 3; i++) {
digitalWrite(LED1, HIGH);
digitalWrite(LED2, HIGH);
digitalWrite(LED3, HIGH);
digitalWrite(LED4, HIGH);
delay(80);
allOff();
delay(80);
}
}
// ---------------- SETUP ----------------
void setup() {
Serial.begin(115200);
pinMode(TOUCH_PIN, INPUT);
pinMode(VIB_PIN, INPUT);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(LED4, OUTPUT);
WiFi.softAP(ssid, password);
Serial.println("WiFi Started");
Serial.println(WiFi.softAPIP());
server.on("/", handleRoot);
server.on("/data", handleData);
server.begin();
}
// ---------------- LOOP ----------------
void loop() {
touchState = digitalRead(TOUCH_PIN);
vibState = digitalRead(VIB_PIN);
server.handleClient();
// ---------------- PHYSICAL BEHAVIOR ----------------
if (touchState == HIGH && vibState == HIGH) {
burst();
}
else if (touchState == HIGH) {
wave();
}
else if (vibState == HIGH) {
flash();
}
delay(10);
}
Steps to follow to connect to web server for live streaming¶
-
Connect phone or PC to the wifi and change wifi name to ESP32-SKIN password:12345678
-
Open browser and insert the wifi IP address provided in the serial monitor and browse.
live touches,and vibration and real time system update will be displayed.





