Skip to content

13∙ Skin Electronics

05th to 12 december 2023

Update
  • march 2024
Assignments
  • Document the concept, sketches, references also to artistic and scientific publications
  • Design a skin circuit:
  • Build your own version of the “Skin masquerade party” project or
  • Build your own version of the “Twinkle Nails” project
  • Document the project and included all source files and all materials used
  • Make a video with your skin electronic working
  • Make a performance of your project functioning
Ressources of the week

About this week

Matrix bracelet to generate patterns

For this week I made it one year later and had the super chance to make it with Marion Guillaud. I was super excited to met her universe. Some part of this documentation will be the same to her.

This week was all about electronics and the skin as interface. Katia Vega, an Associate Professor of Design in California, gave us a very interesting lecture. She invited us to revisit the notion of skin and to think of the body in a different way... like an interface with electronics.

A large part of the research done for this week is largely oriented towards the scientific field like medical, biology or work with bacteria. It was not easy for us to make the link with textiles and fashion.

Marion said so much well about the meeting of our mind during this week: "We both had ideas as farfetched as the other.😆"

References & Inspiration

We initially found mostly scientific, medical and biological references, like:

The work of Professors J. Rogers and Y. Huang on health technologies, focused on the search for an ultra-thin health monitor that sticks to the skin, can accompany you everywhere and transmit information to the relevant doctor for regular follow-up. But what about traceability and data transmission?

Like Louise Masssacrier made for her week, we were very interested by the MIT project and their temporary tattoos.

The work of this Australian research laboratory is just as interesting in terms of the use of electronics on the skin as a sensor and data receiver in the prevention of skin cancer.

We also found other informations in alumni works and projects to help us with our assignments:

Aswell the work of Eldy Lazaro, alumna Fabricademy 2017. Working with electronics and mycomaterials.

Process and workflow

First of all, we tested some circuits to understand how it's work with an Attiny and Arduino. We followed the circuit model presented by Emma Pareschi in her tutorial. Then we tested it with the matrix.

Slide 15

ATtiny

Materials:
- 5 crocodiles clips
- 5 male male jumpers
- 1 arduino UNO
- 1 USB cable
- 1 Attinyv85
- 1 Electrolytic Capacitor

Software
- Arduino
- Processing

Before testing with the Attiny, it's necessary to prepare the Arduino for being the programmer.
We followed the link of Instructables Website to program the Arduino.

Code example

/*Emma Pareschi - Fabricademy 2023
* I turn on a led and I turn it off
* The Led is connected to pin 3
*/

int led_pin = 3; //define the pin where the Led is connected

void setup() {
  pinMode(led_pin, OUTPUT); //define pin of the Led as an output
  //pinMode(pin, OUTPUT);

  //pinMode(pin, INPUT);
  //pinMode(pin, INPUT_PULLUP);
}

void loop() {
//turn the Led on   
  //analogWrite(pin, 0/255);d
  digitalWrite(led_pin, HIGH); 
  delay(500);                 
  digitalWrite(led_pin, LOW); 
  delay(500); 
}

Result

Matrix

Then we tested the matrix with a piezoresistive pressure sensor, the 3x3 paper matrix made with paper, copper tape and velostat.

Material:
- 6 crocodiles clips
- 6 male male jumpers
- 1 arduino UNO
- 1 USB cable
- 1 3x3 paper matrix

Software
- Arduino
- Processing

paper matrix

Code example with Arduino

//Emma Pareschi- Dec 2020
//Modify example from Pressure Sensor Matrix Code
//parsing through a pressure sensor matrix grid by switching individual
//rows/columns to be HIGH, LOW or INPUT (high impedance) to detect
//location and pressure.
//>> https://www.kobakant.at/DIY/?p=7443

#define numRows 3
#define numCols 2
#define sensorPoints numRows*numCols

int rows[] = {A0, A1};
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);
}

[Piezoresistive sensor Explanations of how piezoresistive sensor works, Screenshot form Kobakant website

Skin Electronics project

The main idea is to reuse the pattern machine that Marion created during her week 10. Creating patterns by interactions with the body matrix using a piezoresistive material like Velostat. Diane also tells us about Jessica Stanley's assignments of this week.

Skin touch sensor
Screenshot form Jessica Stanley's assignments

And we found more inspirations with the Kobakant project: Pressure Matrix code + circuit and the Stretchy touchpad

Materials & tools

Material Details
Machine laser cutter, Brother KH950 knitting machine, pattern machine
Tools Velostat,Conductive thread, thread, crocodiles clips, arduino UNO, USB cable, printing pastes and tools
Software Illustrator, Arduino, Processing
Fabrication files Pattern1 laser cutting, Pattern2 laser cutting, Pattern3 laser cutting

Process

First, we wanted to test it with pieces of silicone left over from my week 9 failed tests, with the idea that it would adhere better to the skin, in a 3x3 version.
But we realized that the copper tape didn't hold despite the glue. The velostat didn't connect properly when pressed between the two layers of silicone.

silicone test

Then, we did a test to knit a bracelet with connected yarn, like the paper matrix.

The Knitting machine

The use of this machine is not in the objectives of the week. But always fun to use it.

knitting machine

Piece 1
21 stitches in stockinette

40 rows in Tension 5 normal color thread
4 rows in Tension 2 conductive thread
6 rows in Tension 5 normal color thread
4 rows in Tension 2 conductive thread
6 in Tension 5 normal color thread
4 rows in Tension 2 conductive thread

Piece 2

4 rows in Tension 2, conductive thread
6 in Tension 5 normal color thread
4 rows in Tension 2 conductive thread
6 in Tension 5 normal color thread
4 rows in Tension 2 conductive thread

Knitting test

knitting test
On the left: Piece 1, on the right: Piece 2

Generative patterns and Processing

One of the lines knitted accidentetly with the conductive thread was cut.
We modified our code by notifying the number of rows: only 2 instead of 3.

Circle Code example

This is the first code we used to having circles.

//Emma Pareschi- Dec 2020
//Modify example from Pressure Sensor Matrix Code
//parsing through a pressure sensor matrix grid by switching individual
//rows/columns to be HIGH, LOW or INPUT (high impedance) to detect
//location and pressure.
//>> https://www.kobakant.at/DIY/?p=7443

#define numRows 2
#define numCols 3
#define sensorPoints numRows*numCols

int rows[] = {A0, A1};
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);
}
Result

The circle pattern

Ellipse and cross code example

We also tested to have cross and ellipse at the same time.

/*
Code based on Tom Igoe’s Serial Graphing Sketch

> http://wiki.processing.org/w/Tom_Igoe_Interview
Reads X analog inputs and visualizes them by drawing a grid
using grayscale shading of each square to represent sensor value.
http://howtogetwhatyouwant.at/
Working with a matrix
*/

String myString = null;
String inString = null;
int lf = 10;    // Linefeed in ASCII

Serial myPort; // The serial port
int rows = 2;
int cols = 3;
int maxNumberOfSensors = rows*cols;
float[] sensorValue = new float[maxNumberOfSensors]; // global variable for storing mapped sensor values,
float[] previousValue = new float[maxNumberOfSensors]; // array of previous values
int ellipseSize = 0;
int ellipseX;
void setup () {
  size(800, 800); // set up the window to whatever size you want
  ellipseSize = width/rows;

//println(Serial.list()); // List all the available serial ports
  String portName = Serial.list()[0]; // set the number of your serial port!
  myPort = new Serial(this, portName, 9600);
  myPort.clear();
  myPort.bufferUntil('\n'); // don’t generate a serialEvent() until you get a newline (\n) byte
  background(0, 0, 255); // set inital background
  smooth(); // turn on antialiasing
  ellipseMode(CENTER); //define the position of the ellipse from its center
  //ellipseMode(CORNER); //define the position of the ellipse from its corner
}

void draw () {
  background(255);
  for (int i = 0; i < maxNumberOfSensors; i++) {
    fill(sensorValue[i]-28, sensorValue[i]-28, sensorValue[i]-28); //Define first colour of the ellipse
    ellipse(ellipseX + ellipseSize/2, ellipseSize*(i%rows)+ellipseSize/2, ellipseSize*sensorValue[i]/255, ellipseSize*sensorValue[i]/255);
    push();
    translate(ellipseX + ellipseSize/2, ellipseSize*(i%rows)+ellipseSize/2);
    float d = ellipseSize*(1-sensorValue[i]/255)/2;
    line(-d, -d, d, d);
    line(d, -d, -d, d);
    pop();
    if ((i+1) % rows == 0) ellipseX += ellipseSize;
  }
  ellipseX=0;
}

void serialEvent (Serial myPort) {
  inString = myPort.readStringUntil(lf); // get the ASCII string
  println("test");
  if (inString != null) { // if it’s not empty
    inString = trim(inString); // trim off any whitespace
    int incomingValues[] = int(split(inString, "\t")); // convert to an array of ints

    if (incomingValues.length <= maxNumberOfSensors && incomingValues.length > 0) {
      for (int i = 0; i < incomingValues.length; i++) {
        // map the incoming values (0 to 1023) to an appropriate gray-scale range (0-255):
        sensorValue[i] = map(incomingValues[i], 0, 1023, 0, 255); // stretch 5×5, because sensor value = 255 at rest (without pressure)
        //incomingValue decreases with pressure because it is the resistance
        sensorValue[i] = constrain(incomingValues[i], 0, 255); // stretch 5×5
        println(sensorValue[i]); // print value to see
      }
    }

  }
}
Result

Final Cross code example

As we also wanted to try and generate a pattern with different cross sizes in each square, I reviewed the Processing code with the help to Marion husband (The Processing guy!).

Code for processing

/*
Code based on Tom Igoe’s Serial Graphing Sketch

http://wiki.processing.org/w/Tom_Igoe_Interview
Reads X analog inputs and visualizes them by drawing a grid
using grayscale shading of each square to represent sensor value.
http://howtogetwhatyouwant.at/
Working with a matrix
*/

String myString = null;
String inString = null;
int lf = 10;    // Linefeed in ASCII

Serial myPort; // The serial port
int rows = 2;
int cols = 3;
int maxNumberOfSensors = rows*cols;
float[] sensorValue = new float[maxNumberOfSensors]; // global variable for storing mapped sensor values,
float[] previousValue = new float[maxNumberOfSensors]; // array of previous values
int[] mins = new int[maxNumberOfSensors];
int[] maxs = new int[maxNumberOfSensors];
float[] Ns = new float[maxNumberOfSensors];

float ellipseSize = 0;

void setup () {
  size(1200, 800); // set up the window to whatever size you want
  ellipseSize = float(width)/float(cols);

  //println(Serial.list()); // List all the available serial ports
  String portName = Serial.list()[0]; // set the number of your serial port!
  myPort = new Serial(this, portName, 9600);
  myPort.clear();
  myPort.bufferUntil('\n'); // don’t generate a serialEvent() until you get a newline (\n) byte
  background(0, 0, 255); // set inital background
  smooth(); // turn on antialiasing

  for(int i = 0; i < maxNumberOfSensors; i++) {
    mins[i] = 1023;
    maxs[i] = 0;
    Ns[i] = random(3, 20);
  }
}

void draw () {
  background(255);
  for (int i = 0; i < maxNumberOfSensors; i++) {
    float X = (i % cols) * ellipseSize;
    float Y = (i / cols) * ellipseSize;

    //stroke(sensorValue[i]-28, sensorValue[i]-28, sensorValue[i]-28); //Define first colour of the ellipse
    push();
    translate(X, Y);
    float N = Ns[i];
    float d = ellipseSize/N * (sensorValue[i]/255.)/2.;
    for(int y = 0; y < N; y ++) {
      for(int x = 0; x < N; x ++) {
        push();
        translate(ellipseSize/Nfloat(x) + ellipseSize/2./N, ellipseSize/Nfloat(y) + ellipseSize/2./N);
        //strokeWeight(1);
        //rect(-ellipseSize/N/2.,-ellipseSize/N/2., ellipseSize/N, ellipseSize/N);

        strokeWeight(map(d, 0, ellipseSize/N, 0, 30));
        line(-d, -d, d, d);
        line(d, -d, -d, d);
        pop();
      }
    }
    pop();
  }
}

void serialEvent (Serial myPort) {
  inString = myPort.readStringUntil(lf); // get the ASCII string
  //println("test");
  if (inString != null) { // if it’s not empty
    inString = trim(inString); // trim off any whitespace
    int incomingValues[] = int(split(inString, "\t")); // convert to an array of ints

    if (incomingValues.length <= maxNumberOfSensors && incomingValues.length > 0) {
      for (int i = 0; i < incomingValues.length; i++) {
        // map the incoming values (0 to 1023) to an appropriate gray-scale range (0-255):
        if(incomingValues[i] > maxs[i]) maxs[i] = incomingValues[i];
        if(incomingValues[i] < mins[i]) mins[i] = incomingValues[i];

        sensorValue[i] = map(incomingValues[i], mins[i], maxs[i], 0, 255); // stretch 5×5, because sensor value = 255 at rest (without pressure)
        //incomingValue decreases with pressure because it is the resistance
        sensorValue[i] = constrain(incomingValues[i], 0, 255); // stretch 5×5
        println(sensorValue[i]); // print value to see
      }
    }
  }
}

Code for Arduino

//Emma Pareschi- Dec 2020
//Modify example from Pressure Sensor Matrix Code
//parsing through a pressure sensor matrix grid by switching individual
//rows/columns to be HIGH, LOW or INPUT (high impedance) to detect
//location and pressure.
//>> https://www.kobakant.at/DIY/?p=7443

#define numRows 2
#define numCols 3
#define sensorPoints numRows*numCols

int rows[] = {A0,A1};
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("");}
  }


Serial.println();
delay(10);
}
Results

But there seems to be a problem, perhaps in my code or in the formatting of the two knitting pieces. The starting grid already has patterns, whereas these should appear when the two fibers make contact with the velostat when it's pressed.

We chose to test one of the patterns generated by the bracelet with the cut-out. Processing view cross pattern1
cross pattern2

We used Illustrator for making vectorization, for preparing the file for the laser cutter. Be carefull to be in SVG file.
illustrator

illustrator

Laser cutting

Power Speed
95 40

More info here

Printing paste cross pattern

We tried the one with the "best" cut with printing pastes that I made for week 10.

Feeling it's a new dialog, story of language.


Last update: 2024-04-09