Skip to content

12. Skin Electronics

References & Inspiration

Inspo

  1. DuoSkin is a metallic temporary tattoo material that serves as an on-skin interface with connected devices.
  2. A biosensor made of fluorescent proteins embedded in the shell of microscopic marine algae called diatoms that could help detect chemicals in water samples. (Sciencedaily)
  3. Magnetic skin that can be used to control a variety of devices using a simple magnetic sensor. (hackster.io)
  4. Ultra-thin flexible electronics with a display. (MHealthSpot)
  5. A new stretchable transparent touchpad can be used to write words and play electronic games. (Futuristech)

Tools

  • Processsing
  • alligator clips
  • copper film
  • gold leaf
  • vinyl
  • breadboard
  • jumper wires
  • ESPXIAO_S3

NFC

We tested the Near-field communication (NFC), which is is a set of communication protocols that enables communication between two electronic devices over a distance of 4 cm (1+1⁄2 in) or less. In the side video you can see me uploading the url on the NFC through the NFC Tools app.

  • Open your application: Read > Scan your NFC
  • Menu > Write > Add a record > URL / URI (Add a URL record) > paste your URL > OK
  • Write > Write / 24 Bytes
Now you can use you NFC!

Sensitive Matrix

We already prepared our Sensitive *Matrix for the afternoon workshop.

A matrix is a grid whose intersection nodes are sensors. In our application, pressure sensors. It allows you to use fewer pinouts but still have many pressure points.

Resistor → an electric component that can impede the amount of current. The analog sensor can act as a valuable resistor

Resistors what is it Unit of measure Testing Voltage devider
---------------- an electric component that can impede the amount of current Ohm multimeter in resistance-measurement mode two resistors in a series
can act as a valuable resistor ---------------- ---------------- Vout = [ R2/ (R1 + R2)] x Vin

Pull-up resistor → present in the pin of the microcontroller. To use it, you need to specify it in the code.

You can use a pin as an output, but you need to specify it in the code

Sensitive Matrix

I first tried building my matrix on textile but the visuals I was obtaineing where not really cliear. So I attempted again with paper, it was slighlty more reliable but not 100% working,

Arduino IDE

int row0 = A0;  //first row pin
int row1 = A1;  //second row pin
int row2 = A2;  //third row pin

int col0 = 9;    //first column pin
int col1 = 8;    //second column pin
int col2 = 7;    //third 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() {

  // FIRST BLOCK OF READINGS----------------------------
  //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
}

Processing

Processing is a free graphics library and integrated development environment (IDE) built for the electronic arts, new media art, and visual design communities with the purpose of teaching non-programmers the fundamentals of computer programming in a visual context. (reference). Processign interface is similar to Arduino IDE.

/*
The sensors values are not calibrated.

*/

/*
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/
*/

import processing.serial.*;

Serial myPort; // The serial port
int rows = 3;
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 rectSizeX = 0;
int rectSizeY = 0;
int rectY;


void setup () {
  size(1000, 1000); // set up the window to whatever size you want
  rectSizeX = width/rows;
  rectSizeY = height/cols;


  println(Serial.list()); // List all the available serial ports
  String portName = Serial.list()[7]; // 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(255); // set inital background
  smooth(); // turn on antialiasing
  rectMode(CORNER);
}

void draw () {
  for (int i = 0; i < maxNumberOfSensors; i++) {
    fill(sensorValue[i]);
    rect(rectSizeX * (i%rows), rectY, rectSizeX, rectSizeY); //top left
    if((i+1) % rows == 0) {
      rectY += rectSizeX;
    }
  }
  rectY=0;
}


void serialEvent (Serial myPort) {
  String inString = myPort.readStringUntil('\n'); // get the ASCII string
  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], 000, 900, 0, 255); // stretch 5×5
        sensorValue[i] = constrain(incomingValues[i], 0, 255);
        //println(sensorValue[i]); // print value to see
        //println(incomingValues[i]);
      }
    }
  }
}
If you start the sketch in Processing and your serial monitor and plotter are running, it won’t work!

My sketches are ...

This schematic 1 was obtained by..

This tutorial 2 was created using..

footnote fabrication files

Fabrication files are a necessary element for evaluation. You can add the fabrication files at the bottom of the page and simply link them as a footnote. This was your work stays organised and files will be all together at the bottom of the page. Footnotes are created using [ ^ 1 ] (without spaces, and referenced as you see at the last chapter of this page) You can reference the fabrication files to multiple places on your page as you see for footnote nr. 2 also present in the Gallery.

Sensitive tattoo

Tattoo I decided to work with sensitive tattoo. I designed this model on Adobe Illustrator.

Cricut1

I first use the Cricut to cut the design. I connected the cutting maching via cable and I already had the softaware installed in my laptop. I saved the file ans an .svg and I uploaded it. I attached these pieces to the bioplastics I made during the Textile as Scaffold week.

Cricut2

I also tried making a gold leaf tattoo, but it didn’t go very well. At first, I applied the gold leaf to the wrong side of the transferable tattoo paper. When I tried a second time, the glue wouldn’t stick to the other side because it has a waterproof surface. I wasn’t able to complete this part. Perhaps I should try using a different type of glue next time.

Coding

Visuals

Code

I used this code to obtain values that I couls use in processing to obtain visual (screen fading from white to black)

#define TOUCH_PIN_1 A0
#define TOUCH_PIN_2 A1
#define TOUCH_PIN_3 A2
#define TOUCH_PIN_4 A3

void setup () {

Serial.begin (115200);

}

void loop() {

int t1 = touchRead (TOUCH_PIN_1);
int t2 = touchRead (TOUCH_PIN_2);
int t3 = touchRead (TOUCH_PIN_3) ;
int t4 = touchRead (TOUCH_PIN_4) ;

Serial.print(" 1: ");
Serial.print(t1);
Serial.print(" 2: ");
Serial.print(t2);
Serial.print(" 3: ");
Serial.print(t3);
Serial.print(" 4: ");
Serial.println(t4);

delay (100);
on Bioplastic

Processing

We tried adapting the Matrix code to my 4 copper stickers. Sadly it did not work quite right.

import processing.serial.*;

Serial myPort; // The serial port
int rows = 1;
int cols = 4;
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 rectSizeX = 0;
int rectSizeY = 0;
int rectY;


void setup () {
  size(1000, 1000); // set up the window to whatever size you want
  rectSizeX = width/rows;
  rectSizeY = height/cols;


  println(Serial.list()); // List all the available serial ports
  String portName = Serial.list()[3]; // 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(255); // set inital background
  smooth(); // turn on antialiasing
  rectMode(CORNER);
}

void draw () {
  for (int i = 0; i < maxNumberOfSensors; i++) {
    //fill(sensorValue[i]);
    //rect(rectSizeX * (i%rows), rectY, rectSizeX, rectSizeY); //top left
    //if((i+1) % rows == 0) {
      //rectY += rectSizeX;
    //}
  }
  //rectY=0;
}


void serialEvent (Serial myPort) {
  String inString = myPort.readStringUntil('\n'); // get the ASCII string
  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], 70000, 180000, 0, 255); // stretch 5×5
        if (sensorValue[i] > 100000){
          fill(0,0,0);
        }
        else {fill(255,255,255);
        }
        rect(rectSizeX * (i%rows), rectY, rectSizeX, rectSizeY); //top left
    if((i+1) % rows == 0) {
      rectY += rectSizeX;
        //sensorValue[i] = constrain(incomingValues[i], 0, 255);
        println(sensorValue[i]); // print value to see
        println(incomingValues[i]);
      }
    }
    rectY=0;
  }
}
}

MP3

I tested the copper stickers with this code to test to obtain some values from the serial monitor

On Bioplastic

#define TOUCH1 4   
#define TOUCH2 5  

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("Touch test on GPIO4 & GPIO5...");
}

void loop() {
  int v1 = touchRead(TOUCH1);
  int v2 = touchRead(TOUCH2);

  Serial.print("Pad1: ");
  Serial.print(v1);
  Serial.print("   Pad2: ");
  Serial.println(v2);

  delay(150);
}
When the copper stickers are not being touched, the readings are approximately 80000 for Pad 1 and 9000 for Pad 2. When they are touched, the readings increase to approximately 500000 for Pad 1 and 600000 for Pad 2.

MP3 diagram

I tried connecting my sensor to an MP3, above you can find the diagram I used.

  • copper stickers -> D4 - D5
  • TX -> D7 (RX)
  • RX -> D6 (TX)
  • MP3 VCC -> 5V
  • MP3 GRD -> GRD
  • SPK_1 and SPK_2 -> buzzer

This is the code I used

#define TOUCH_PIN1 4   
#define TOUCH_PIN2 5   

int threshold1 = 200000;   
int threshold2 = 100000;   

HardwareSerial MP3(1);   // use UART1

void setup() {
  Serial.begin(115200);

  MP3.begin(9600, SERIAL_8N1, 6, 7);

  Serial.println("Touch + MP3 ready");
}

void loop() {
  int val1 = touchRead(TOUCH_PIN1);
  int val2 = touchRead(TOUCH_PIN2);

  Serial.print("Pad1: "); Serial.print(val1);
  Serial.print("   Pad2: "); Serial.println(val2);

  if (val1 > threshold1) {  
    Serial.println("Pad 1 touched → play 0001.mp3");
    playTrack(1);
    delay(500);            
  }

  if (val2 > threshold2) {
    Serial.println("Pad 2 touched → play 0002.mp3");
    playTrack(2);
    delay(500);
  }

  delay(50);
}

void playTrack(uint8_t track) {
  uint8_t cmd[10] = {0x7E,0xFF,0x06,0x03,0x00,0x00, track, 0x00, 0x00, 0xEF};
  MP3.write(cmd, 10);
}
Sadly, it did not work. I think maybe the power is not enough to feed the mp3 and the buzzer, as no light was turning on in the mp3 player.

Directly on skin

I tried attaching directly the copper tattoo on my skin but the values I was obtaining on my serial monitor where not really usable. They would onky oscillate between 39000 and 42000 being only kind of stable around 42000 when I'd touch the copper

on skin

#define TOUCH_PIN 5  // D5 → GPIO5 → Touch1

void setup() {
  Serial.begin(115200);
}

void loop() {
  // Lower numbers = more touch
  uint16_t touchValue = touchRead(TOUCH_PIN);

  Serial.println(touchValue);
  delay(50);
}

Results

Fabrication files


  1. File: xxx 

  2. File: xxx