Skin Electronics¶
What I Made This Week¶
- Paper Woven Pressure Matrix Sensors (2 Versions)
Research + Inspiration¶
I've often come across electronics that interface with and through the body but never truly thought of ways I could experiment with this work.
This week really opened me up more to the idea!
Prof. Katia Vega, Design professor at UC Davis, broke down skin electronics in a very understandable way.
I really liked the idea of embedding RF capability into nails, which could scan people into an event or the like with their nail vs. a paper ticket.
On a bit of a tangent, it reminds me of research Accenture Labs into functional and edible electronics. Here's more if you want to read about it!
Back to the subject at hand, I love make-up; make-up where you can really experiment with your face as your main canvas.
Make-up has a rich history, just like ink with indigenous peoples. When I made pigments during the Biochromes week, I was really inspired by how ink is used on the skin as a symbol of cultural heritage. Tattoos were condemned by colonizers but they bared a very sacred significance. Like the tattoos pictured below done by female tattoo artists in Micronesia, more specifically, the Marshalls island. Noble women who could afford them also wore tattoos on their shoulders called bwilak (from the tail of the frigate bird), chest, and a ‘secret’ tattoo on the vulva in a fashion similar to tattooing customs elsewhere in Micronesia (e.g., Palau, Pohnpei, Ulithi) and Fiji.
The Hybrid Body Lab does a lot of research and work into epidermal electronics and converting the skin as an interface. I really admire their project DuoSkin: Rapidly Prototyping On-Skin User Interfaces Using Skin-Friendly Materials. DuoSkin is a fabrication process that enables anyone to create customized functional devices that can be attached directly on their skin. Using gold metal leaf, a material that is cheap, skin-friendly, and robust for everyday wear, we demonstrate three types of on-skin interfaces: sensing touch input, displaying output, and wireless communication.
Weekly Assignment
- Document the concept, sketches, references also to artistic and scientific publications
- Design a “skin-circuit”, exploring the replication of the examples bwlow or:
- the Skin masquerade party project
- the Twinkle Nails project
- interactive tattoo
- Explore how to create a new skin electronics accessory.
- Document the project and included all source files and all materials used
- Upload your design files and source code
- Make a video with your skin electronic working
- Make a short performance/concept of your project functioning (extra credit)
What You'll Need
- Microcontroller (Arduino UNO, ATtiny, XIAO)
- Neopixels (sewable Flora neopixels)
- Capacitor (10uF)
- Threads (resistive/conductive threads)
- Inks (resistive/conductive inks for e-make up)
- RFID tags (RFID board and shield)
- E6000 Craft glue
- Liquid latex (for e-make up)
- Gold leaf sheet (for e-make up)
- Thermochromic ink (for e-make up)
- Actuators (mini vibration motors, speakers, jumper wires, alligator clips wires)
- Multimeter
- Soldering iron (Soldering station)
- Pliers, wire stripper, flush snips, tweezers
- Vinyl cutter
- Embroidery / Sewing machine
Prototyping¶
Using an ATtiny85¶
Okay, so, with anything, prototyping with electronics is an awesome first step.
Just an overview of things:
For prototyping you'll need:
-
a microcontroller, preferrably an Arduino Uno for its common rapid prototyping usage. This is your brain. This is what you program to then communicate with the components attached to it.
-
a breadboard. Breadboards are where you can connect your circuit together without having to solder. Certified cool tool. Remember rows in the breadboard are connected NOT columns. Only the rails labeled "+" and "-" are connected column-wise.
-
jumper wires which connect your circuit together on the breadboard.
-
an ATtiny85. This is a type of microcontroller. A tiny microcontroller. It doesn't have a USB connection so programming it through Arduino and its IDE is expected.
0 - 5 are digital pins meaning they read digital sensors (ON or OFF).
A pins are analog pins meaning they read analog sensors (like a volume knob).
PWM pins are pins that control a sensor in an analog manner.
- a 10 microFarad capacitor. Capacitors store energy very simply. They're connected in a circuit where you would like the energy being used to store for a longer period of time. For instance, if you have a capacitor (measured in microFarads) connected to an LED in a circuit that LED can continue being lit for longer due to the capacitor have stored charge while powered on. The larger the capacitor, the larger energy storage. Short leg goes to ground and long leg goes to power in your circuit.
Getting your ATtiny to Work in Arduino IDE
- Wire your breadboard circuit ONLY connecting the ATtiny to the Arduino and NOTHING else.
- Go to Arduino IDE. Navigate to Files > Examples > ArduinoISP.
- This will pop up as a sketch. "Upload" it to Arduino Uno.
- Arduino is now a programmer to program the ATtiny85.
- Go to Arduino IDE > Settings.
- Copy and paste the following URL where it says 'Additional Boards Manager URL's “https://raw.githubusercontent.com/sleemanj/optiboot/master/dists/package_gogo_diy_attiny_index.json”
- Click 'OK' and this will install the core files.
- Go to the Boards Manager on the left hand side of the IDE.
- Type 'ATtiny' into the search bar at the top left, you'll see "DIY ATtiny" and click Install.
- Go to Tools > Programmer > Arduino as ISP.
- Go to Tools > Board > DIYATtiny > ATtiny85.
- Go to Tools > Programmer > DIY ATtiny: Arduino as ISP and hit 'DIY ATiny: Arduino as ISP'
- Install the bootloader by simply going to: Tools > Burn Bootloader. If successful it will come up with a message saying 'done burning bootloader'
- Connect the rest of your components to the Arduino i.e. LED, capacitor, etc.
- Test the circuit with the following code. Remember to upload it by going to Sketch > Upload using Programmer.
Done! After burning the Bootloader, the ATtiny is now ready to be programmed.
//We will replace "LED_BUILTIN" with "4" since ATtiny does not have a built-in led! void setup() { // initialize digital Pin 3 of ATtiny 13(defined in hardware as 4) as an output. pinMode(4, OUTPUT); } // the loop function runs over and over again forever void loop() { digitalWrite(4, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(4, LOW); // turn the LED off by making the voltage LOW delay(1000); // wait for a second }
ATtiny85 Circuit
Pressure Matrix Sensor¶
I made a very simple paper + copper tape + velostat pressure matrix sensor using this tutorial.
The concept is we're making what's called a piezoresistive sensor. The piezoresistive effect is described as “a change in the electrical resistivity of a semiconductor or metal when mechanical strain is applied”. Meaning electrical resistance changes when you apply pressure (mechanical strain) in this case. And there's not only a change in resistance happening inside the material, but also between the electrodes and the material.
To get your pressure matrix sensor running, first wire up your matrix to the Arduino. Connect 3 of your rows A2, A1, and A0. Connect 3 of your columns 5, 6, and 7. It doesn't matter which is which.
Upload the arduino code to the IDE.
Arduino Code:
/*
Matrix: Kapton + Copper
A simple pressure sensor matrix made from two Kapton film sheets with
7×7 copper tape traces and a piece of Velostat or Eeonyx piezoresistive
material in between.
parsing through this grid by switching individual rows/columns to be
HIGH, LOW or INPUT (high impedance) to detect location and pressure.
>> http://howtogetwhatyouwant.at/
*/
#define numRows 3
#define numCols 3
#define sensorPoints numRows*numCols
int rows[] = {A0, A1, A2};
int cols[] = {5, 6, 7};
int incomingValues[sensorPoints] = {};
void setup() {
// set all rows and columns to INPUT (high impedance):
for (int i = 0; i < numRows; i++) {
pinMode(rows[i], INPUT_PULLUP);
}
for (int i = 0; i < numCols; i++) {
pinMode(cols[i], INPUT);
}
Serial.begin(9600);
}
void loop() {
for (int colCount = 0; colCount < numCols; colCount++) {
pinMode(cols[colCount], OUTPUT); // set as OUTPUT
digitalWrite(cols[colCount], LOW); // set LOW
for (int rowCount = 0; rowCount < numRows; rowCount++) {
incomingValues[colCount * numRows + rowCount] = analogRead(rows[rowCount]); // read INPUT
}// end rowCount
pinMode(cols[colCount], INPUT); // set back to INPUT!
}// end colCount
// Print the incoming values of the grid:
for (int i = 0; i < sensorPoints; i++) {
Serial.print(incomingValues[i]);
if (i < sensorPoints - 1)
Serial.print("\t");
}
Serial.println();
delay(10);
}
The download the program called Processing. It uses Javascript which is a programming language that programs moving and responsive visuals/interfaces.
Upload the following processing code into your new Processing sketch. Make sure you change the portname in the sketch to the port where your Arduino is connected. My Arduino is connected to /dev/tty.usbmodem141201. So change that to your port name! :)
Processing Code:
import processing.serial.*;
Serial myPort;
int rows = 3;
int cols = 3;
int maxNumberOfSensors = rows * cols;
float[] sensorValue = new float[maxNumberOfSensors];
int lf = 10; // linefeed
int cellSize;
void setup() {
size(600, 600);
cellSize = width / cols;
// ---- SERIAL ----
println(Serial.list()); // see available ports
String portName = "/dev/tty.usbmodem141201"; // change to your actual port
myPort = new Serial(this, portName, 9600);
myPort.clear();
myPort.bufferUntil('\n');
background(0);
smooth();
ellipseMode(CENTER);
}
void draw() {
background(0);
for (int i = 0; i < maxNumberOfSensors; i++) {
int col = i / rows;
int row = i % rows;
float val = sensorValue[i];
fill(val);
float d = map(val, 0, 255, cellSize, 5);
ellipse(
col * cellSize + cellSize / 2,
row * cellSize + cellSize / 2,
d,
d
);
}
}
void serialEvent(Serial myPort) {
String inString = myPort.readStringUntil(lf);
if (inString != null) {
inString = trim(inString);
int[] incomingValues = int(split(inString, "\t"));
if (incomingValues.length == maxNumberOfSensors) {
for (int i = 0; i < incomingValues.length; i++) {
float mapped = map(incomingValues[i], 0, 1023, 0, 255);
sensorValue[i] = constrain(mapped, 0, 255);
println(i + ": " + sensorValue[i]);
}
println("----");
}
}
}
Capactive Sensor¶
We did a pressure sensor before this in matrix form. Now we're moving to capacitive!
Hackster.io really summarized capacitors quite well: "A capacitor is simply two conductors with an insulator in between. This allows for a charge to be stored and then discharged. This also lets changes in its capacitance be sensed, such as a finger coming into contact with a copper pad."
A capacitive sensor has a send and receive pin separated by a high resistance resistor. The higher the resistance the more sensitive your sensor.
Send Pin: This pin is set to rapidly change its state (charge and discharge). It provides the signal for the measurement.
Receive Pin: This pin measures the time it takes for the voltage to change in response to the signal from the send pin. The time taken to charge the pin's inherent capacitance is what the library measures to detect a touch.
Here's a circuit with 2 capacitive sensors and 2 LEDs. The resistors for the LEDs are 220 ohms and 1 Megaohm for each of the capacitive sensors.
Arduino Code for Capacitive Sensing
#include <CapacitiveSensor.h>
CapacitiveSensor cs_4_2 = CapacitiveSensor(4, 2);
CapacitiveSensor cs_4_6 = CapacitiveSensor(4, 6);
int bluePin = 10;
int redPin = 12;
long thr = 1000; // adjust threshold
void setup() {
Serial.begin(9600);
pinMode(bluePin, OUTPUT);
pinMode(redPin, OUTPUT);
}
void loop() {
long total1 = cs_4_2.capacitiveSensor(30);
long total2 = cs_4_6.capacitiveSensor(30);
Serial.print(total1);
Serial.print(",");
Serial.println(total2);
delay(10);
if(total1 > thr && total2 < thr) {
digitalWrite(bluePin, LOW);
digitalWrite(redPin, HIGH);
} else if(total1 < thr && total2 > thr) {
digitalWrite(bluePin, HIGH);
digitalWrite(redPin, LOW);
} else if(total1 > thr && total2 > thr) {
digitalWrite(bluePin, HIGH);
digitalWrite(redPin, HIGH);
} else {
digitalWrite(bluePin, LOW);
digitalWrite(redPin, LOW);
}
}
On Skin¶
Triangle Pattern Capacitive Sensor¶
I first started making a design on Fusion360.
I wanted to go ahead and use the tattoo paper + gold leaf + vinyl method.
Here's what I did (because, boy, was this confusing. My brain could not register.)
-
I bought what's called removable vinyl. You remove the vinyl from its paper to stick onto something else. You can remove it once you stick it somewhere. Hence, removable vinyl. There are 2 sides to this - the vinyl and the grid paper underneath it that can be separated from vinyl. Like a sticker.
-
I used a Silhouette Cameo 5 to cut my vinyl stencil from the design I made. It's a desktop vinyl cutter. I want to cut through the vinyl entirely so I chose vinyl (matte) as my material and set my settings as follows:
-
Blade Depth: 8-9
- Force: 15-17%
-
Passes: 2
-
I loaded the vinyl onto the cutting mat, into the machine, and cut my stencil. I removed the grid paper underneath the vinyl and stuck the vinyl onto temporary tattoo paper. Tattoo paper also has 2 sides - a somewhat glossy side and a side that's a lot like cardstock texture. Stick the vinyl on the glossy side.
- Now, you should have a vinyl stencil, on top of tattoo paper! Spray a little spray adhesive (repositioning) on the stencil and wait for the glue to be a bit tacky. Place 1 layer of gold leaf on top. I used a paper towel to press the gold leaf down. I then spray a little more adhesive on top and placed a 2nd layer of gold leaf on top.
-
Now, I couldn't successfully transfer my gold leaf design from the tattoo paper it was glued to on to my skin. So, I ended up use a pretty wet paper towel and placing it on the non-goldleaf side of the tattoo paper at this point. When you do this, the outline of your design appears as sort of an orange color.
-
Normally the stencil should transfer as I've researched but it didn't work for me. So, once wet, I carefully separated the gold leaf + vinyl stencil from the tattoo paper. There should be a thin sticky film on the gold leaf. I used scissors to cut along the outline. As carefully as I could. Very delicate process since it's sticky and fragile.
- Once I cut out the design, I stick it to my skin and apply a little more water on top if it starts peeling. This will allow more skin adhesion.
I experienced a lot of trial and error with this sensor in particular. Capactive sensors are based on touch so when you put the gold leaf on your bare skin it's almost as if you're always touching the sensor. Not to mention, your body is an energy cell. Eventually your skin becomes one large electrode that, despite having multiple capactive pads, have those sensors act as one.
I eventually moved my skin circuit from my bare skin, placed a sheet of tegaderm on top of my skin (which is a transparent wound dressing), and then placed my capacitive pads on top.
The gold leaf started to crack so I placed some copper tape to keep the continuity just in case.
I got one capacitive touch pad to work!
Code
#include <CapacitiveSensor.h>
CapacitiveSensor cs_4_2 = CapacitiveSensor(4, 2); // pin 4 is send pin, pin 2 is receive pin
int led1 = 11;
long thr1 = 3900; // adjust this for sensitivity based on values you see in serial monitor :)
void setup() {
Serial.begin(9600);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
}
void loop() {
long total1 = cs_4_2.capacitiveSensor(30);
Serial.print(total1);
Serial.print(",");
// LED 1
if (total1 > thr1) {
digitalWrite(led1, HIGH);
} else {
digitalWrite(led1, LOW);
}
delay(10);
}
Woven Paper Pressure Sensors¶
As I was finishing my foray into skin electronics, I came across this really cool paper from the Hybrid Body Lab called SkinPaper on using paper as an interface for body electronics. I was mesmerized by it honestly. It made me want to experiment with paper, beeswax, origami paper, velostat, tegaderm, and conductive fabric I had.
I prototyped with some cardstock paper first. I cut 8 strips of cardstock. I then coated these strips with beeswax.
How I coated the paper with beeswax: 1. I cut a piece of parchment paper and placed it on top of an old rag. I plugged in my iron and let it heat up. 2. I sprinkled a couple of bits of beeswax on the parchment paper and folded it. 3. I placed my now hot iron on top of the folded parchment paper to heat it up the wax in between. 4. Once the wax was melted, I placed my strips inside and applied the iron again. I tried moving the wax around gently with my iron to evenly coat the paper strips as much as possible.
I tried applying spray adhesive on the wax paper to adhere the conductive fabric but it wasn't strong enough and of course wax paper was no help with that. So I ended up using copper tape.
I wove a twill weave matrix. I then cut small squares of velostat and put them in areas of the woven matrix where conductive fabric are face to face.
Again, we have to remember, a simple pressure sensor like this is velostat sandwiched between 2 conductive mediums.
There were a couple of things to keep in mind here. At least what I learned. - Copper tape makes for an uneven pressure matrix. Really, handmade pressure matrices are not symmetric. - Wax paper adds to the uneveness - The function "INPUT_PULLUP", which turns on a built-in resistor in the microcontroller, inside the Arduino microcontroller so it doesn't read high or low due to noise. One row often has slightly higher resistance in a handmade matrix. Pullups exaggerate the difference allowing the weakest row to drop off. That's why you'll see one of my rows is totally inactive. - You need to create a voltage divider circuit with the digital pins (which don't use INPUT-PULLUP which means they don't have a resistor) to limit current, protects the pins on the Arduino, and allow for smoother readings. So, I wired every digital pin (6-3) to a 10K ohm resistor (one leg of the resistor in GND) and then connected each of those pins to each of the 4 columns in my matrix.
Processing Code for Wax Paper Pressure Matrix Sensor:
import processing.serial.*;
/*
4x4 Pressure Matrix Visualization
Matches Arduino column-major scan order:
index = col * rows + row
*/
Serial myPort;
int rows = 4;
int cols = 4;
int maxNumberOfSensors = rows * cols;
float[] sensorValue = new float[maxNumberOfSensors];
int cellSize;
int lf = 10; // ASCII linefeed
void setup() {
size(600, 600);
cellSize = width / cols;
// CHANGE THIS TO YOUR PORT
String portName = "/dev/cu.usbmodem143301";
myPort = new Serial(this, portName, 9600);
myPort.clear();
myPort.bufferUntil('\n');
rectMode(CENTER);
textAlign(CENTER, CENTER);
textSize(12);
background(65, 65, 255);
}
void draw() {
background(65, 65, 255);
for (int col = 0; col < cols; col++) {
for (int row = 0; row < rows; row++) {
int index = col * rows + row; // IMPORTANT
float v = sensorValue[index];
v = constrain(v, 0, 255);
fill(v - 28, v - 28, v - 28);
stroke(0);
float x = col * cellSize + cellSize / 2;
float y = row * cellSize + cellSize / 2;
float s = cellSize * (1 - v / 255.0);
rect(x, y, s, s);
// Debug index overlay (optional — comment out if not needed)
fill(255, 0, 0);
text(index, x, y);
}
}
}
void serialEvent(Serial myPort) {
String inString = myPort.readStringUntil(lf);
if (inString != null) {
inString = trim(inString);
int[] incomingValues = int(split(inString, '\t'));
if (incomingValues.length == maxNumberOfSensors) {
for (int i = 0; i < incomingValues.length; i++) {
sensorValue[i] = map(incomingValues[i], 0, 1023, 0, 255);
sensorValue[i] = constrain(sensorValue[i], 0, 255);
}
}
}
}
Arduino Code for Wax Paper Pressure Matrix Sensor:
/*
Matrix: Kapton + Copper
4x4 Pressure Sensor Matrix - Corrected Scanning Logic
*/
#define numRows 4
#define numCols 4
#define sensorPoints numRows * numCols
int rows[] = {A0, A1, A3, A4}; // Row pins (analog as digital)
int cols[] = {6, 5, 4, 3}; // Column pins
int incomingValues[sensorPoints] = {};
void setup() {
// Set all pins to high-impedance input initially
for (int i = 0; i < numRows; i++) {
pinMode(rows[i], INPUT_PULLUP); // Use INPUT_PULLUP for rows
}
for (int i = 0; i < numCols; i++) {
pinMode(cols[i], INPUT);
}
Serial.begin(9600);
}
void loop() {
// Iterate through each column
for (int colCount = 0; colCount < numCols; colCount++) {
pinMode(cols[colCount], OUTPUT);
digitalWrite(cols[colCount], LOW); // Activate column by pulling LOW
// Read all rows for this column
for (int rowCount = 0; rowCount < numRows; rowCount++) {
incomingValues[colCount * numRows + rowCount] = analogRead(rows[rowCount]);
}
// Deactivate column and return to input
pinMode(cols[colCount], INPUT);
}
// Send all 16 values, tab-separated, newline-terminated
for (int i = 0; i < sensorPoints; i++) {
Serial.print(incomingValues[i]);
if (i < sensorPoints - 1) {
Serial.print("\t");
}
}
Serial.println();
delay(10);
}
I then made an origami paper matrix sensor. This paper is very fiber-like. I cut strips of it along with strips of conductive fabric and adhered them together this time using spray adhesive.
I added the velostat pieces as before and stuck it onto my leg using tegaderm.
This didn't exhibit the same problems the previous sensor did and that's maybe because of the copper tape? I don't know, but hope to do more experiments!
Processing Code for Woven Origami Paper Pressure Matrix Sensor:
import processing.serial.*;
/*
4x4 Pressure Matrix Visualization (ELLIPSES)
Ellipses disappear when sensor is not pressed
Matches Arduino column-major order
*/
Serial myPort;
int rows = 4;
int cols = 4;
int maxNumberOfSensors = rows * cols;
float[] sensorValue = new float[maxNumberOfSensors];
int cellSize;
int lf = 10; // ASCII linefeed
void setup() {
size(600, 600);
cellSize = width / cols;
// CHANGE THIS TO YOUR SERIAL PORT
String portName = "/dev/cu.usbmodem143301";
myPort = new Serial(this, portName, 9600);
myPort.clear();
myPort.bufferUntil('\n');
ellipseMode(CENTER);
background(255, 75, 17);
}
void draw() {
background(255, 75, 17);
for (int col = 0; col < cols; col++) {
for (int row = 0; row < rows; row++) {
int index = col * rows + row;
float v = sensorValue[index];
v = constrain(v, 0, 255);
// Higher pressure → bigger ellipse
float d = map(v, 0, 255, cellSize, 0);
// Only draw if visible
if (d > 0.5) {
fill(v, v, v);
noStroke();
float x = col * cellSize + cellSize / 2;
float y = row * cellSize + cellSize / 2;
ellipse(x, y, d, d);
}
}
}
}
void serialEvent(Serial myPort) {
String inString = myPort.readStringUntil(lf);
if (inString != null) {
inString = trim(inString);
int[] incomingValues = int(split(inString, '\t'));
if (incomingValues.length == maxNumberOfSensors) {
for (int i = 0; i < incomingValues.length; i++) {
sensorValue[i] = map(incomingValues[i], 0, 1023, 0, 255);
sensorValue[i] = constrain(sensorValue[i], 0, 255);
}
}
}
}
Arduino Code is the same as the previous woven matrix sensor! :)
I had a lot of fun with this! Like I said, I hope to keep exploring!
E-Make-Up¶
So I wanted to make a skin circuit using gold leaf + electric paint + LEDs.
Here are a couple of simple designs I drafted on Fusion for this e-makeup circuit.
I used electric paint as a line near my eyes and used the division on the bridge of my nose to connect + and - of a battery.
I tried tacking on the LEDs to my cheeks with latex glue but I thought it may be interfering with the connection. I also used copper tape to place them on my cheeks as well but to no successful avail.
The gold leaf was also splitting in some areas so that's where I would use copper tape to patch them up.
I like the look! If only it worked... hopefully next time!
Oh! I also tried electric paint with tegaderm underneath it but the circuit didn't work. I removed the tegaderm and tried layering as much electric paint as I could along my lines to close up any cracks. Nevertheless, the circuit did not power up.
One of the main challenges with e-makeup and sensors on skin is that your body conducts electricity. It's one giant electrode which is why insulation is so important. But I'd love to continue investigating in this realm. It's a cool challenge!




























