12. Skin electronics¶
This week we experimented with sensors that can function as skin, such as pressure sensors, which allow us to sense the movement of the joints or also information matrices that would even allow us to create artificial skin that has pressure sensitivity.
RESEARCH¶
REFERENCES & INSPIRATION¶
SKIN SENSORS FOR VITAL SIGNS¶
Wearable electronics are growing increasingly more comfortable and more powerful. A next step for such devices might include electronics printed directly onto the skin to better monitor and interface with the human body.
Scientists wanted a way to sinter—that is, use heat to fuse—metal nanoparticles to fabricate circuits directly on skin, fabric or paper. However, sintering usually requires heat levels far too high for human skin. Other techniques for fusing metal nanoparticles into circuits, such as lasers, microwaves, chemicals or high pressure, are similarly dangerous for skin.
In the IEEE Spectrum page you can read more.
I am delighted how we can use the skin as a conductor of valuable information, as shown in the example above, sensors that can tell us how our body feels.
BEAUTY TECHNOLOGY¶
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. DuoSkin
BEAUTY AND CONNECTIVITY¶
DuoSkin is a rapid prototyping and fabrication process using the skin - friendly material gold leaf to create wearable on - skin user interfaces , such as:
( a ) sensing touch input
( b ) displaying the user's mood using a thermochromic tattoo.
( c ) communicating and sharing data with other devices through NFC - all while maintaining body decoration aesthetics.
Here you can read their research DuoSkin Connectivity
EXAMPLES IN LAB¶
PRESSION SENSOR¶
In class with our teacher Citlalia Hernandez we were able to learn how to make a pressure sensor. For which we need the following materials.
CONSTRUCTION¶
To build the sensor it will be necessary to cut two conductive wires, cut some velostate and make a sandwich
Velostat or Linqstat is a pressure sensitive conductive material
1 conductive thread, velostate, 1 conductive thread.
Then we secure with tape so that the components do not move.
TEST¶
We connect an LED so that when the finger is flexed the pressure sensor sends the signal and the LED turns on. We can see the wiring and operation below.
int sensorPin = A0;
int sensorValue = 0;
int pinD = 8;
int b = 0;
void setup() {
// put your setup code here, to run once:
pinMode(pinD, OUTPUT);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
b = !b;
digitalWrite(pinD, b);
sensorValue = analogRead(sensorPin);
Serial.println(sensorValue);
delay(500);
if(sensorValue >= 115){
digitalWrite(13, HIGH);
}
else{
digitalWrite(13, LOW);
}
}
MATRIX SENSOR¶
We build a sensor in the form of a 9-point matrix, occupying the previous sensor logic.
For which we need the following materials.
CONSTRUCTION¶
For the construction it was necessary to cut a square of paper where we could accommodate our sensors.
-
We cut 3 pieces of conductive tape and glue them on top of the square, trying to keep the same distance between each of the lines.
-
We cut 3 strips of velostate and glued 3 pieces of conductive tape on top.
-
We need to connect wires to the terminals of each conductive tape so we proceed to solder.
-
After them we arrange the strips in the following way.
Make sure that the conductive tapes do not touch, that is why we use the velostat, Velostat or Linqstat is a pressure sensitive conductive material
TEST¶
We make the following connection to the arduino, very similar to the previous example
You must pay attention to the connection order of digital and analogue pins to have your data organized and know which box is 0, 1, etc. when you want to analyze this data.
Copy and paste in Arduino IDE the following code:
#define numRows 3
#define numCols 3
#define sensorPoints numRows * numCols
int rows[]= {A0, A1, A2};
int cols[]= {7, 8, 9};
int incomingValues[sensorPoints] = {};
void setup () {
for (int i = 0; i < numRows; i++) { pinMode(rows[i], INPUT);}
for (int i = 0; i < numCols; i++) { pinMode(cols[i], OUTPUT);}
Serial.begin(9600);
}
void loop ()
{
for (int colCount = 0 ; colCount < numCols; colCount++){
digitalWrite(cols[colCount], HIGH);
for (int rowCount = 0; rowCount < numRows; rowCount++){
incomingValues[colCount * numRows + rowCount] = analogRead(rows[rowCount]);
}
digitalWrite(cols[colCount], LOW);
}
for (int i = 0; i < sensorPoints; i++){
Serial.print(incomingValues[i]);
if( i < sensorPoints - 1)
Serial.print("\t");
}
Serial.println();
delay(10);
}
VISUAL INTERFACE¶
Next, we deal with the Processing program, which will help us create a graphical interface with the data collected by the Arduino.
Open processing and paste this code:
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()[2]; // 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++) {
println("Raw sensor value: " + incomingValues[i]);
sensorValue[i] = map(incomingValues[i], -50, 1000, 0, 255);
println("Mapped sensor value: " + sensorValue[i]);
}
}
}
}
You will have this result.
INTERACTIVE TATTOO¶
Something I wanted to integrate into this assignment was to be able to connect my body to the internet, some variable.
I wanted something portable and beautiful. The analog variable that I will manage will be my body temperature and the actuators will be microLEDs that will be connected to my skin.
STEP 1¶
I started drawing on my skin trying to arrange and design the connection paths of my electronic components.
STEP 2¶
I needed to use Arduino Cloud since creating the information API there also gave me the tool to be able to create a more attractive user interface than what would be done conventionally with a WEB server on ESP32.
We head to Arduino Cloud and create an account, this is completely free.
Then we proceed to create a new Thing and add the variables.
The variables that I will occupy are 3:
-
Temperature = this is an analog variable so I will save it with data type Float
-
LED1 = Boolean data - Light sequence #1 - this is so that when you press the button and it goes to TRUE state, light sequence #1 begins
-
LED2 = Boolean data - Light sequence #2 - this is so that when you press the button and it goes to TRUE state, light sequence #2 begins
STEP 3¶
We configure a new board, in my case I will be using the ESP32 WROOM 32 E
We need to configure this board and also the wifi network connection
After that you just need to go to the network settings and enter your Wi-Fi data.
STEP 4¶
Automatically when we see the Sketch option we can see that a code has been automatically generated.
It will be necessary to install some drivers that you can install by clicking on the LEARN MORE option.
After them, all that remains is to configure some communication data with the esp32 and we will be ready to upload the following code.
TEST 1¶
As a first test I want to see if any analog data goes up and updates correctly, so instead of a thermistor I first use a potentiometer.
I make the following electronic connection.
Copy the following code and upload it to the board from the Arduino Cloud web editor.
In the dashboard configuration we can design the control interface.
Download the Arduino Cloud IOT mobile app on your cell phone, enter your account and you can view the data.
The good thing about working with Arduino Cloud is that we have a backup of the data and its visualization in real time.
#include "thingProperties.h"
const int analogPin = 39;
int L1 = 13;
int L2 = 12;
int L3 = 27;
float value;
void setup() {
// Initialize serial and wait for port to open:
Serial.begin(115200);
pinMode(analogPin, INPUT);
pinMode(L1, OUTPUT);
pinMode(L2, OUTPUT);
pinMode(L3, OUTPUT);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
// Defined in thingProperties.h
initProperties();
// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
}
void loop() {
ArduinoCloud.update();
onLED1Change();
onLED2Change();
// Your code here
tEMP = analogRead(analogPin); // realizar la lectura analógica raw
Serial.println(tEMP);
delay(500);
}
void onLED1Change() {
// Add your code here to act upon LED1 change
if ( lED1 ) {
digitalWrite( L1 , HIGH ) ;
digitalWrite( L2 , HIGH ) ;
digitalWrite( L3 , HIGH ) ;
delay(1000);
digitalWrite( L1 , LOW ) ;
digitalWrite( L2 , LOW ) ;
digitalWrite( L3 , LOW ) ;
delay(500);
} else {
digitalWrite( L1 , LOW ) ;
digitalWrite( L2 , LOW ) ;
digitalWrite( L3 , LOW ) ;
}
}
/*
Since LED2 is READ_WRITE variable, onLED2Change() is
executed every time a new value is received from IoT Cloud.
*/
void onLED2Change() {
if ( lED2 ) {
digitalWrite( L1 , HIGH ) ;
digitalWrite( L2 , HIGH ) ;
digitalWrite( L3 , HIGH ) ;
} else {
digitalWrite( L1 , LOW ) ;
digitalWrite( L2 , LOW ) ;
digitalWrite( L3 , LOW ) ;
}
}
FINAL RESULT¶
After the final test I prepared the connection with the microleds and the thermistor.
Update the code as follows
#include "thingProperties.h"
float R1 = 42000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;
float ThermistorPin = 39;
float Vo;
int L1 = 13;
int L2 = 12;
int L3 = 27;
float value;
void setup() {
// Initialize serial and wait for port to open:
Serial.begin(115200);
pinMode(ThermistorPin, INPUT);
pinMode(L1, OUTPUT);
pinMode(L2, OUTPUT);
pinMode(L3, OUTPUT);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
// Defined in thingProperties.h
initProperties();
// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
}
void loop() {
ArduinoCloud.update();
onLED1Change();
onLED2Change();
// Your code here
Vo = analogRead(ThermistorPin);
R2 = R1 * (4095.0 / (float)Vo - 1.0);
logR2 = log(R2);
T = 1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2);
Tc = T - 273.15;
Tf = (Tc * 9.0) / 5.0 + 32.0;
tEMP = Tc; // realizar la lectura analógica raw
Serial.println(tEMP);
delay(500);
}
/*
Since LED1 is READ_WRITE variable, onLED1Change() is
executed every time a new value is received from IoT Cloud.
*/
void onLED1Change() {
// Add your code here to act upon LED1 change
if ( lED1 ) {
digitalWrite( L1 , HIGH ) ;
digitalWrite( L2 , HIGH ) ;
digitalWrite( L3 , HIGH ) ;
delay(1000);
digitalWrite( L1 , LOW ) ;
digitalWrite( L2 , LOW ) ;
digitalWrite( L3 , LOW ) ;
delay(500);
} else {
digitalWrite( L1 , LOW ) ;
digitalWrite( L2 , LOW ) ;
digitalWrite( L3 , LOW ) ;
}
}
/*
Since LED2 is READ_WRITE variable, onLED2Change() is
executed every time a new value is received from IoT Cloud.
*/
void onLED2Change() {
if ( lED2 ) {
digitalWrite( L1 , HIGH ) ;
digitalWrite( L2 , HIGH ) ;
digitalWrite( L3 , HIGH ) ;
} else {
digitalWrite( L1 , LOW ) ;
digitalWrite( L2 , LOW ) ;
digitalWrite( L3 , LOW ) ;
}
}
APLICATION¶
To design the circuit on my skin I used conductive fabric tape