Skip to content

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

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.

lace

  • 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.

kine

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.

Getting ready for the training
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

In this screenshot, column 0 is the one set to LOW and allowing the code reading. Same option is repeated for the other two columns later in the code.

Final configuration with Arduino Pins.

We also used Processing to display visual changes while pressing the matrix.

Code used to test this sensor.

Capacitive sensor detects changes in capacitance caused by the body approaching without needing pressure.

Test and detailed setup

Theoretical concepts during the training

A quick test with aluminum foil: while approaching the material the values changed as visible in the serial plotter view.

Code used to test this sensor.

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.

Dense circuit featuring three LEDs and three sensor prototypes

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
  1. 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

  2. Install the Adafruit SAMD boards: Open Tools > Board > Boards Manager, search for “Adafruit SAMD”, and click Install.

  3. 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.).

  4. 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.

ada1 ada2

Note: click on the image to see it bigger.

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

Microcontroller and conductive thread sewn to the main kinesio band

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.

Images explain the two movements (microcontroller was unplugged, so the light was off)

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);
}
Note: ChatGPT was used to improve the codes.

Tools & Resources