12. Skin Electronics¶
Research¶
Basic concepts¶
Skin electronics refers to ultra-thin, flexible and stretchable electronic systems designed to be worn directly on the skin and create body-centric interfaces.
Credit to Katia Vega
Main applications include physiological monitoring (health & wellness like muscle activity) and human-Machine interfaces (electronic tattoos, tactile patches).
Adafruit microcontroller¶
The Adafruit SADM21 QT Py is a tiny microcontroller ideal for e-textile/e-skin projects. Easy to program with Arduino, it was my first time experimenting with something other than the Arduino Uno and more compact platform.
Credit to Adafruit official website
Alumni pages that inspired me¶
-
Face Mask: Riley Cox - Textile Lab Amsterdam
-
Skin electronics research: Julija Karas - Fab Lab BCN
-
Neopixel project: Diane Wakim - Le Textile Lab
-
Health related idea: Sophia di Matteo - GreenFabric Bruxelles
References & Inspiration¶
- Political Lace by Melissa Coleman is an elegant detachable lace collar embedded with a subtle LED light that pulses every 7.5 minutes: a solemn reminder of the tragic frequency at which young women die during childbirth.
- Kinisi by Katia Vega transforms the skin into a digital interface: subtle FX cosmetics, conductive makeup and hidden sensors let facial gestures (a blink, a wink, a smile or raised eyebrow) trigger light patterns on the skin and hair.
- The following Kenzo spot highlights Margaret Qualley’s expressive face and body movements, which inspired me with their fluidity and presence for e-skin project.
- Kinesiology tape is a therapeutic elastic tape applied directly to the skin to support muscles and reduce pain. The tape allows free movement while providing gentle support and sensory feedback.
Final Result¶
This week's assignments required building a circuit adapted to the skin.
As a result, I developed a wearable prototype consisting of three contact-based sensors integrated on kinesio strips, connected to an Adafruit microcontroller with an embedded NeoPixel to provide visual feedback.
Due to some difficulties with the original configuration, the final prototype was positioned on a different part of the body and tested with a single color change. For more details, see here.
Process to get there¶
This week was full of new things and exploration for me. The process below will unfold step by step through tests and small discoveries, just like my learning week.
Tutorial with Emma Pareschi¶
In this tutorial we explored matrix-based pressure and capacitive sensors using Arduino and Processing.
Material
- Microcontroller (Arduino UNO or XIAO board)
- Alligator clips
- Jumper wires
- Copper tape
- Velostat
- Aluminum foil
- Tape
- Baking paper
- High value resistor (500K - 1M - 2M Ohm)
- Paper
- Pencil or pen
- Ruler
- Scissor
Matrix is a grid whose intersection nodes are sensors. In our application, pressure sensors.
Test and detailed setup
We also used Processing to display visual changes while pressing the matrix.
Capacitive sensor detects changes in capacitance caused by the body approaching without needing pressure.
Test and detailed setup
A quick test with aluminum foil: while approaching the material the values changed as visible in the serial plotter view.
Experimenting¶
For my project, I had the idea of using kinesio tape, since it can be applied directly to the skin, as a patch to detect and provide feedback on the movement of a specific body part, such as the neck, where I often experience pain.
I tested several components to provide feedback (e.g., a vibration motor and a temperature sensor) but eventually I decided to focus on light. As a side note, this weekend in Lyon it was La Fête des Lumières, which I took as a sign.
Phase 1: coding configuration¶
I explored three different hardware and coding configurations. Tests 1 and 2 are exploratory prototypes, while Test 3 is the final and official configuration used for the wearable e-skin system. If you want to jump directly to the final setup, go to Test 3.
Test 1: Single sensor/single LED (exploratory)
The goal of this first test was to validate a basic interaction: when two conductive areas placed on kinesio tape touch each other, an LED turns on.
I create a quick and dirty prototype to then built the circuit by using the following material and Arduino configuration (Arduino Code used):
- Kinesio tape (mine is light colored/pink)
- Silver conductive tape
- Alligator clips and wires
- LilyPad LED
- Arduino Uno.
Wiring in Arduino UNO:
- Silver tape A: pin 7
- Silver tape A: GND
- LilyPad LED: digital pin 9 for anode (+) and GND for cathode (-)
Test 2: Three sensors/three LEDs (exploratory)
This second test expands the previous configuration by introducing three independent sensors and three corresponding LED outputs, with the goal of tracking multiple body movements. Arduino code used.
Test 3: Final wearable configuration (Adafruit QT Py + NeoPixel)
I was looking for a smaller solution and in the lab I found Adafruit SADMI (QT PY). While activating this small microcontroller I found a neopixel already embedded, tested it and decided to use it instead of sewable LEDs in order to reduce the number of components.
Adafruit configuration and test in Arduino IDE
-
Add the Adafruit SAMD package URL. Go to Arduino IDE > Preferences and add this line to the Additional Boards Manager URLs: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
-
Install the Adafruit SAMD boards: Open Tools > Board > Boards Manager, search for “Adafruit SAMD”, and click Install.
-
Select the QT Py board. Go to Tools > Board, scroll to Adafruit SAMD (32-bit ARM Cortex-M0+) Boards, and select: “Adafruit QT Py M0” (or your specific QT Py version, e.g., QT Py ESP32-S2, QT Py RP2040, etc.).
-
Install required libraries. Open Tools > Manage Libraries, search for and install any libraries needed for your project (in my case, Adafruit NeoPixel). Then connect your board and select the correct Port.
In this final wearable configuration, each sensor controls one color of the embedded NeoPixel: when the sensor is activated, the corresponding light turns off.
- Sensor 1 → BLUE light: + to A0, - to GND
- Sensor 2 → RED light: + to A1, - to GND
- Sensor 3 → GREEN light: + to A3, - to GND
Arduino code used to provide a light feedback.
Further exploration A fourth interaction logic was explored, where the light would turn white when two sensors were touched simultaneously. This test was not successful and requires further debugging, so it is not included in the final configuration.
Phase 2: prototype configuration¶
The prototype configuration consists of a central kinesio strip hosting the microcontroller, connected to three stretch sensors placed around it.
Each sensor is built using two kinesio strips (one for the positive pole and one for the negative pole), resulting in a total of six kinesio elements for the sensing system. An adhesive conductive tape is applied on top of each kinesio strip, and conductive threads coming from the microcontroller pins are laid along the tape forming the electrical connections.
When specific movements are performed, the positive and negative conductive paths come into contact, closing the circuit and triggering the light feedback. Three movements were selected to be tested with this configuration, as shown in the image below.
Credit: Pinterest
Phase 3: sewing the circuit elements¶
Note: During later iterations, I improved the insulation between the conductive threads connected to the positive pins to prevent false contacts, by adding an extra layer of kinesio tape.
For each sensor, I recreated the configuration described in Phase 2, which consists of two kinesio components: one connected to GND and one connected to a positive pin. When the two conductive paths come into contact, the circuit is closed and a light is activated.
The final sewn configuration visually resembles a spider with six legs, corresponding to the six kinesio elements used for the three sensors.
The video below shows the three sensor combinations and their corresponding light colors when activated.
Phase 4: application to the body¶
The main kinesio strip was applied along the center of the neck as the base for the sensors. The individual patches were positioned as follows:
- Sensor 1: positive on the sternum, negative on the chin.
- Sensor 2: positive on the temple, negative on the left wrist (touching the temple while laterally stretching the neck).
- Sensor 3: positive on the forehead, negative on the right hand (hands resting on the forehead to release the shoulders).
When I started applying the kinesio tape patches to my body, I realized that the wires were too long and that the intersections could cause false positives if each individual connection was not insulated, as confirmed by the recorded video.
Note: my DSLR camera stopped working as soon as I tried to use it, resulting in a low-quality video recorded on my phone.
Adjusting and recording the neck configuration was challenging. For clarity and due to time constraints, I recorded a different setup, applying the larger kinesio tape strip on the arm and two patches on the hands, creating an on/off mechanism and testing only the green light: when the hands touch, the light turns on.
The system was tested with a wired connection to the computer, as I didn’t have the battery or the correct connector to make it fully autonomous.
What's next: more to explore¶
While working on the taping coding and configuration, I was very interested in applying the system to the face and exploring how lights could respond to movements. However, when I tested with small pieces of kinesio tape, it was difficult to allow the conductive straps to make contact during gestures like blinking.
Images: Martina Muroni unless otherwise stated.
Code Example¶
/*
The analog sensor is connected between pin A0 and pin 4
*/
int row0 = A0; //first row pin
int row1 = A1; //first row pin
int row2 = A2; //first row pin
int col0 = 4; //first column pin
int col1 = 5; //first column pin
int col2 = 6; //first column pin
int incomingValue0 = 0; //variable to save the sensor reading
int incomingValue1 = 0; //variable to save the sensor reading
int incomingValue2 = 0; //variable to save the sensor reading
int incomingValue3 = 0; //variable to save the sensor reading
int incomingValue4 = 0; //variable to save the sensor reading
int incomingValue5 = 0; //variable to save the sensor reading
int incomingValue6 = 0; //variable to save the sensor reading
int incomingValue7 = 0; //variable to save the sensor reading
int incomingValue8 = 0; //variable to save the sensor reading
void setup() {
// set all rows to INPUT (high impedance):
pinMode(row0, INPUT_PULLUP);
pinMode(row1, INPUT_PULLUP);
pinMode(row2, INPUT_PULLUP);
//set the firt column as output
pinMode(col0, OUTPUT);
pinMode(col1, OUTPUT);
pinMode(col2, OUTPUT);
//open serial communication
Serial.begin(9600);
}
void loop() {
//set the col0 to low (GND)
digitalWrite(col0, LOW);
digitalWrite(col1, HIGH);
digitalWrite(col2, HIGH);
//read the three rows pins
incomingValue0 = analogRead(row0);
incomingValue1 = analogRead(row1);
incomingValue2 = analogRead(row2);
//set the col1 to low (GND)
digitalWrite(col0, HIGH);
digitalWrite(col1, LOW);
digitalWrite(col2, HIGH);
incomingValue3 = analogRead(row0);
incomingValue4 = analogRead(row1);
incomingValue5 = analogRead(row2);
//set the col2 to low (GND)
digitalWrite(col0, HIGH);
digitalWrite(col1, HIGH);
digitalWrite(col2, LOW);
incomingValue6 = analogRead(row0);
incomingValue7 = analogRead(row1);
incomingValue8 = analogRead(row2);
// Print the incoming values of the grid:
Serial.print(incomingValue0);
Serial.print("\t");
Serial.print(incomingValue1);
Serial.print("\t");
Serial.print(incomingValue2);
Serial.print("\t");
Serial.print(incomingValue3);
Serial.print("\t");
Serial.print(incomingValue4);
Serial.print("\t");
Serial.print(incomingValue5);
Serial.print("\t");
Serial.print(incomingValue6);
Serial.print("\t");
Serial.print(incomingValue7);
Serial.print("\t");
Serial.println(incomingValue8);
delay(10); //wait millisecond
}
#include <CapacitiveSensor.h>
/*
* Modified example from CapitiveSense Library Demo Sketch (Paul Badger 2008)
* Uses a high value resistor e.g. 10M between send pin and receive pin
* Resistor effects sensitivity, experiment with values, 50K - 50M. Larger resistor values yield larger sensor values.
* Receive pin is the sensor pin - try different amounts of foil/metal on this pin
*/
CapacitiveSensor cs_4_2 = CapacitiveSensor(4,2); // 10M resistor between pins 4 & 2, pin 2 is sensor pin, add a wire and or foil if desired
void setup()
{
cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF); // turn off autocalibrate on channel 1 - just as an example
Serial.begin(9600);
}
void loop()
{
long total1 = cs_4_2.capacitiveSensor(30);
Serial.println(total1); // print sensor output 1
delay(50);
}
int sensorPin = 7;
int ledPin = 9;
void setup() {
pinMode(sensorPin, INPUT_PULLUP); // legge HIGH quando aperto
pinMode(ledPin, OUTPUT);
}
void loop() {
int val = digitalRead(sensorPin);
if (val == LOW) { // LOW quando i patch si toccano
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}
}
// === Arduino UNO - 3 Sensors → 3 LEDs ===
// Sensors: two conductive tape points close → circuit closes
// LEDs: independent output for each sensor
// Connections: digital pins as inputs/outputs
// ------------------- PIN ASSIGNMENTS -------------------
int sensor1Pin = 2; // Sensor 1 input (digital)
int sensor2Pin = 3; // Sensor 2 input
int sensor3Pin = 4; // Sensor 3 input
int led1Pin = 5; // LED 1 output (e.g., blue)
int led2Pin = 6; // LED 2 output (e.g., white)
int led3Pin = 7; // LED 3 output (e.g., green)
// ------------------- SETUP -------------------
void setup() {
// configure sensor pins as input with internal pullup
pinMode(sensor1Pin, INPUT_PULLUP);
pinMode(sensor2Pin, INPUT_PULLUP);
pinMode(sensor3Pin, INPUT_PULLUP);
// configure LED pins as OUTPUT
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
pinMode(led3Pin, OUTPUT);
}
// ------------------- MAIN LOOP -------------------
void loop() {
// read sensors (LOW means circuit closed)
int sensor1State = digitalRead(sensor1Pin);
int sensor2State = digitalRead(sensor2Pin);
int sensor3State = digitalRead(sensor3Pin);
// control LEDs based on sensor state
digitalWrite(led1Pin, sensor1State == LOW ? HIGH : LOW);
digitalWrite(led2Pin, sensor2State == LOW ? HIGH : LOW);
digitalWrite(led3Pin, sensor3State == LOW ? HIGH : LOW);
// small delay to avoid bouncing issues (optional)
delay(20);
}
#include <Adafruit_NeoPixel.h>
// neopixel interno
#define NUMPIXELS 1
Adafruit_NeoPixel pixels(NUMPIXELS, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
// sensori
int sensor1Pin = A0; // sensore 1
int sensor2Pin = A1; // sensore 2
int sensor3Pin = A3; // sensore 3
void setup() {
// neopixel
pixels.begin();
pixels.setBrightness(255);
// sensori con pullup
pinMode(sensor1Pin, INPUT_PULLUP);
pinMode(sensor2Pin, INPUT_PULLUP);
pinMode(sensor3Pin, INPUT_PULLUP);
}
void loop() {
bool s1 = (digitalRead(sensor1Pin) == LOW);
bool s2 = (digitalRead(sensor2Pin) == LOW);
bool s3 = (digitalRead(sensor3Pin) == LOW);
if (s1) {
// BLUE
pixels.setPixelColor(0, pixels.Color(0, 0, 200));
}
else if (s2) {
// WHITE
//pixels.setPixelColor(0, pixels.Color(180, 180, 180));
//RED
pixels.setPixelColor(0, pixels.Color(200, 0, 0));
}
else if (s3) {
// GREEN
pixels.setPixelColor(0, pixels.Color(0, 150, 0));
}
else {
// OFF
pixels.setPixelColor(0, pixels.Color(0, 0, 0));
}
pixels.show();
delay(20);
}












