Skip to content

13. Skin Electronics

Research, References & Inspiration

This week I took time to understand how the ATtiny worked, which is a module that can store the Arudino code in a smaller component then the arduino. I had hread many time how it could be intergrated into project but never fully understood how so that was the higlight from this week. After the great lecture from Katia Vega I remembered a lecture I attended in DesginTalk's during Design March in Iceland. It was a couple called Neil Harbisson & Moon Ribas and they are cyborgs. A cyborg is an organism with both artificial and organic components and that is how they allow themselves to sense there environment in new ways, by intergrating sensors into they're bodies. I thought is was interesting learning about skin electronics and see how they have taken it even further and have electronice become a part of themselves, not just an add-on.

Here are two videos about they're work.

This is a project from Embodiment Lab where they are using pressure sensor matrix to map out a surface in the computer. I have also looked at this for my personal project where pressure sensor could be a tool to map a dancers movement. eTextile_NIME

Refrences


Tools

Process and workflow

First learned how to opperate and work with the ATtiny but for that we had to download new libraries to arduino to be able to clean the ATtiny from previous coding. Link to add to prefrences and paste it in the additional Board Manager URLs From there in libraries you can find Attiny by Davis A. Mellis and install it.

How to program Attiny

From Emma's lectur and Instructables 1. Connect the Attiny to your Programmer: - AVR programmer - Arduino UNO (make sure that the Arduino is uploaded with the ARduinoISP sketch) 2. In Arduino IDE: Select board (attiny85 (internal 8MHz)) and port 3. In Arduino IDE: Select programmer, Arduino as ISP or USBtinyISP 4. In Arduino IDE: If it is the first time YOU use the Attiny => Burn the bootloader 5. On Breadboard: connect the Attiny to your input/output devices 6. In Arduino IDE: Upload the code to the Attiny

ATtiny tutorial by Margrét Katrín Guttormsdóttir

Code 1

Led

/* Emma Pareschi, Nov 2019
 *  
 *  the led connected to pin 1. it blinks
*/

int led_pin = 1;  //pin of the Led

void setup() {
  // put your setup code here, to run once:
  pinMode(led_pin, OUTPUT);   // set the pin 1 as OUTPUT

}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(led_pin, HIGH);      //turn the Led ON
  delay(1000);                //wait
  digitalWrite(led_pin, LOW);       //turn the Led OFF
  delay(1000);                //wait
}

Code 2

/*
Emma Pareschi 2020
the Led turns on when the digital sensor is triggered
 */

// this constant won't change:
int sw_pin = 4;    // the pin that the pushbutton is attached to

int led_pin = 1; //pin of the led

// Variables will change:
int sw_status = 0;         // current state of the button

void setup() {
  // initialize input and output pins:
  pinMode(sw_pin, INPUT_PULLUP);
  pinMode(led_pin, OUTPUT);

}

void loop() {

  // read the pushbutton input pin:
  sw_status = digitalRead(sw_pin);

  // compare the switch status to its previous state
  if (sw_status == LOW) {   //if the sw is pressed
    digitalWrite(led_pin, HIGH);   //turn on the led (5V)
  } else {        //if the sw is not pressed
    digitalWrite(led_pin, LOW);   //turn off the Led (0V)
  }

}

Pressure sensor matrix

Interactive matrix by Margrét Katrín Guttormsdóttir

Processing is a softaware that works with interacting with the matrix I made. I downloaded the software and to start with I found a code on How to get what you want webpage using processing as an output from the interaction with the matrix. more codes are available at the Processing wbsite. I also used Louises documentation, a fabricademy alumni. She has a great documenttation of the different coding you can change and where to do it.

Arduino code for matrix

This1 is to code the arduino to further work in processing.

 /*
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[] = {7,6,5};
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); 
      } 

Processing code for matrix

This2 is the original code that I found on the kobakant page above. I worked on the code further, changed the shapes and color of the visuals, as you can see further down.

/*
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 rectSize = 0;
int rectY;
void setup () {
size(600, 600); // set up the window to whatever size you want
rectSize = width/rows;

println(Serial.list()); // List all the available serial ports
String portName = Serial.list()[1]; // 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(rectSize * (i%rows), rectY, rectSize, rectSize); //top left
if((i+1) % rows == 0) rectY += rectSize;
}
rectY=0;
}

void serialEvent (Serial myPort) {
String inString = myPort.readStringUntil('\n'); // 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
println(sensorValue[i]); // print value to see
}
}
}
}

Change color

You can find the a RGB color you can find codes for different colors on this webpage To change color you have to add numbers ranging from 0-255 in this field: From this being gray colors:

fill(sensorValue[i]);
To this being green to red/brown color:
fill(70,sensorValue[i], 0);

Design by Margrét Katrín

The whole code for color changing from gray to green

/*
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 rectSize = 0;
int rectY;
void setup () {
size(600, 600); // set up the window to whatever size you want
rectSize = width/rows;

println(Serial.list()); // List all the available serial ports
String portName = Serial.list()[1]; // 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(70,sensorValue[i], 0);
rect(rectSize * (i%rows), rectY, rectSize, rectSize); //top left
if((i+1) % rows == 0) rectY += rectSize;
}
rectY=0;
}

void serialEvent (Serial myPort) {
String inString = myPort.readStringUntil('\n'); // 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
println(sensorValue[i]); // print value to see
}
}
}
}

uncentered ellipse

Next I changed the form of the visuals from squares(rect) to circles(ellipse) changing every rect-something to ellipse-something.

Design by Margrét Katrín Guttormsdóttir

/*
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 ellipseSize = 0;
int ellipseX;
void setup () {
size(600, 600); // 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()[1]; // 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
ellipseMode(CORNER);
}

void draw () {
for (int i = 0; i < maxNumberOfSensors; i++) {
fill(70,sensorValue[i], 0);
//(rectSize * (i%rows), rectY, rectSize, rectSize); //top left
ellipse(ellipseX + ellipseSize/2, ellipseSize * (i%rows) + ellipseSize/2, ellipseSize*(1-sensorValue[i]/255), ellipseSize*(1-sensorValue[i]/255)); //top left
if((i+1) % rows == 0) ellipseX += ellipseSize;
}
ellipseX=0;
}

void serialEvent (Serial myPort) {
String inString = myPort.readStringUntil('\n'); // 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
println(sensorValue[i]); // print value to see
}
}
}
}

Centered ellipse

The codee above as you can see change from the side of the corner but I wanted it to change from the middle. To change that I typed in (CENTER) instead of (CORNER) for the ellipseMode.

Design by Margrét Katrín Guttormsdóttir

ellipseMode(CORNER);
to
ellipseMode(CENTER);
The whole code to changing visuals from squares to circles.
/*
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 ellipseSize = 0;
int ellipseX;
void setup () {
size(600, 600); // 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()[1]; // 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
ellipseMode(CENTER);
}

void draw () {
for (int i = 0; i < maxNumberOfSensors; i++) {
fill(70,sensorValue[i], 0);
//(rectSize * (i%rows), rectY, rectSize, rectSize); //top left
ellipse(ellipseX + ellipseSize/2, ellipseSize * (i%rows) + ellipseSize/2, ellipseSize*(1-sensorValue[i]/255), ellipseSize*(1-sensorValue[i]/255)); //top left
if((i+1) % rows == 0) ellipseX += ellipseSize;
}
ellipseX=0;
}

void serialEvent (Serial myPort) {
String inString = myPort.readStringUntil('\n'); // 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
println(sensorValue[i]); // print value to see
}
}
}
}

final code with different colors

After having tested out different colors and shapes I ened up finding colors that I liked for the final code3 as you can see below.

Design by Margrét Katrín Guttormsdóttir

/*
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 ellipseSize = 0;
int ellipseX;
void setup () {
size(600, 600); // 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()[1]; // 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(240,128,128); // set inital background
smooth(); // turn on antialiasing
ellipseMode(CENTER);
}

void draw () {
for (int i = 0; i < maxNumberOfSensors; i++) {
fill(255,sensorValue[i], 0);
//(rectSize * (i%rows), rectY, rectSize, rectSize); //top left
ellipse(ellipseX + ellipseSize/2, ellipseSize * (i%rows) + ellipseSize/2, ellipseSize*(1-sensorValue[i]/255), ellipseSize*(1-sensorValue[i]/255)); //top left
if((i+1) % rows == 0) ellipseX += ellipseSize;
}
ellipseX=0;
}

void serialEvent (Serial myPort) {
String inString = myPort.readStringUntil('\n'); // 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
println(sensorValue[i]); // print value to see
}
}
}
}


Fabrication files


Last update: 2023-02-07