13. Skin Electronics

This week has been very interesting to learn and experiment some new techniques to embed electronics within fashion industry. As an electronics engineer, I find this super interesting to dig-deeper and explore more into "Skin Electronics"!!

Introduction

With the advacement of different feilds of electronics and materials, it is now possible to embed electronics into skin. From wearable electronics and health care instruments to beuaty productucs and makeup, skin electronics demonstartes a mind blowing feild to explore and experiment with different materials and applications.

Interesting Projects & Research Papers

  • Adafruit Industries Projects:

Find more about these projects in the links here from Adafruit learning resources: (LED Masquerade Masks,Space Face LED Galaxy Makeup, NeoPixel Tiara and Candle Flicker Hair Bow).

The Assignment of the Week

Design and implement skin electronics circuit.

Project #1: Crystaled Hair Band

For this project, I have designed a hair band from tulle that is crystaled = has LED crystals.

  • Ispiration:

I got the ispiration from this project to grow crystals on LEDs and E-textiles.

Also, I would like to thank Loes Bogers from Textile Lab Amsterdam for the very interesting expirementation to grow alum crystals over conductive thread :)

  • The Circuit:

I have designed a simple circuit for LEDs connected in parallel with a coin cell battery. As the SMD LEDs are very small and not easy to embed into a fabric, I have designed a small sewable PCBs to solder the LEDs and to make it handy. The following image shows Eagle schematics and PCB design that I have developed (for the sewable connector, I have downloaded the LilyPad library from SparkFun Eagle library).

I have used Roland MDX-50 milling machine to mill the small boards and then soldered the SMD LEDs and resistors as follows.

Then I sewed and tested the sewable LED boards as follows.

I have applied nail varnish to all metals and conductors to avoid corrosion. Also, I left two terminals of conductive thread exposed for the positive and negative battery terminal connections. In order to avoid short circuit between positive and negative terminals of the battery, I have stitched the conductive thread with regular thread to fix it in place.

  • The Process:

I followed this recipe to make the solution to form alum crystals.

- My Crystalization Failed!!

I had the alum for few days with the LEDs circuit dipped into it without any proper crystals being formed. I jus got very small tiny crystals not forming what I wanted to achieve.

  • Using Artificial Crystals:

I decided to use artificial crystalsover the LEDs.

I used Digispark Attiy85 development board that I have used earlier in Week 10. I uploaded a very simple code to fade the brightness of the LEDs.

int led = 1;           // the pin that the LED is attached to
int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by

// the setup routine runs once when you press reset:
void setup() {
  // declare pin 9 to be an output:
  pinMode(led, OUTPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  // set the brightness of pin 9:
  analogWrite(led, brightness);

  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;

  // reverse the direction of the fading at the ends of the fade:
  if (brightness == 0 || brightness == 255) {
    fadeAmount = -fadeAmount ;
  }
  // wait for 30 milliseconds to see the dimming effect
  delay(30);
}

I have soldered the 6V battery holder to VIN and GND pins in the Attiny85 development board and then attached the battery holder at the back of the Attiny85 development board using glue gun.

It seems working!!

My friend Katya wanted to try it on :)

Project #2: Pedometer

I have designed a pedometer that will track the walked steps and will alert the user about the status of the daily activities through LEDs and a vibration motor.

I referred to the following video to understand how to use the accelerometer and gyroscope module MPU6050 (Datasheet) to acquire data for motion.

Also refer to this useful guide from Arduino learning resources and this tutorial to understand more about MPU6050 interfaced with Arduino board and how to write the sketch/ code.

  • Circuit:

The circuit consist of Arduino Nano board, MPU6050 accelerometer and gyroscope module, neopixel strip and vibration motor. I have designed the following figure using Fritzing to demonistrate the connection.

  • Logic and Code:

I have used MPU6050 module to count the walked steps. I referred to link 1 and link 2 to understand how MPU6050 can be used for steps counting. The following video explains how to manipulate the data acquired data from MPU6050 to track the number of walked steps.

I used the same logic for counting the steps and also I have obtained the walked distance in meters from the number of walked steps using simple equation. Added to this, I program the Arduino to blink the neopixel strip and to vibrate the motor when the healthy daily number of steps is achieved. In the following code, I am adding comments to further explain how the logic is translated in Arduino language.

#include <Wire.h>

// Adafruit NeoPixel library
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

#define PIN        6 // NeoPixel connected to pin D6 in Arduino
#define NUMPIXELS 7 // the number of NeoPixels in the strip attached to the Arduino

Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
#define DELAYVAL 500 // Time (in milliseconds) to pause between pixel

// Defining variables 

int Vib = 5; // Vibration motor connected to pin D5 in Arduino
long accelX, accelY, accelZ; // Defining accelerometer output variables in the X,Y and Z directions
float gForceX, gForceY, gForceZ; // Defining gravitational forces in the X,Y and Z directions
long gyroX, gyroY, gyroZ; // Defining gyroscope output output variables in the X,Y and Z directions
float rotX, rotY, rotZ;  // Defining rotation output variables in the X,Y and Z directions

unsigned long previousMillis = 0;
const long interval = 1000;
long count = 0;
unsigned long currentMillis;
int flag = 0; 

// In the setup function, the serial communication is started, MPU is setted up, neopixel strip is initialized and also vibration motor is defined as an output device
// setup() function -- runs once at startup --

void setup() {
  Serial.begin(9600);
  Wire.begin();
  setupMPU();
   // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif
  // END of Trinket-specific code.

  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)

  pinMode (Vib, OUTPUT); // Defining vibration motor as an output device
}

// loop() function -- runs repeatedly as long as board is on --
// In the void loop function, functions for MPU6050 are called to acquire the motion data and number of steps continously
void loop() {
  recordAccelRegisters();
  recordGyroRegisters();
  stepCount();
  delay(100);
}


// void setupMPU function is responsable for defining the shift registers to store the data acquired from MPU6050 module. This is quite advanced topic! 
//If you are interested to understand the full details watch the video (https://www.youtube.com/watch?time_continue=142&v=M9lZ5Qy5S2s&feature=emb_logo) and read the datasheet (https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf). 

void setupMPU(){
  Wire.beginTransmission(0b1101000); //This is the I2C address of the MPU (b1101000/b1101001 for AC0 low/high datasheet sec. 9.2)
  Wire.write(0x6B); //Accessing the register 6B - Power Management (Sec. 4.28)
  Wire.write(0b00000000); //Setting SLEEP register to 0. (Required; see Note on p. 9)
  Wire.endTransmission();  
  Wire.beginTransmission(0b1101000); //I2C address of the MPU
  Wire.write(0x1B); //Accessing the register 1B - Gyroscope Configuration (Sec. 4.4) 
  Wire.write(0x00000000); //Setting the gyro to full scale +/- 250deg./s 
  Wire.endTransmission(); 
  Wire.beginTransmission(0b1101000); //I2C address of the MPU
  Wire.write(0x1C); //Accessing the register 1C - Acccelerometer Configuration (Sec. 4.5) 
  Wire.write(0b00000000); //Setting the accel to +/- 2g
  Wire.endTransmission(); 
}

// The following function, acquires the accelerometer data and stores it into registers. Each axis has a separate register to store the data. 

void recordAccelRegisters() {
  Wire.beginTransmission(0b1101000); //I2C address of the MPU
  Wire.write(0x3B); //Starting register for Accel Readings
  Wire.endTransmission();
  Wire.requestFrom(0b1101000,6); //Request Accel Registers (3B - 40)
  while(Wire.available() < 6);
  accelX = Wire.read()<<8|Wire.read(); //Store first two bytes into accelX
  accelY = Wire.read()<<8|Wire.read(); //Store middle two bytes into accelY
  accelZ = Wire.read()<<8|Wire.read(); //Store last two bytes into accelZ
  processAccelData();
}

// The following function, manipulates the accelerometer data to obtain the gravitational force in different directions. The number in the numerator defines the sensetivity of the accelerometer reading. 

void processAccelData(){
  gForceX = accelX / 1500.0;
  gForceY = accelY / 1500.0; 
  gForceZ = accelZ / 1500.0;
}

// The following function, acquires the gyroscope data and stores it into registers. Each axis has a separate register to store the data. 

void recordGyroRegisters() {
  Wire.beginTransmission(0b1101000); //I2C address of the MPU
  Wire.write(0x43); //Starting register for Gyro Readings
  Wire.endTransmission();
  Wire.requestFrom(0b1101000,6); //Request Gyro Registers (43 - 48)
  while(Wire.available() < 6);
  gyroX = Wire.read()<<8|Wire.read(); //Store first two bytes into accelX
  gyroY = Wire.read()<<8|Wire.read(); //Store middle two bytes into accelY
  gyroZ = Wire.read()<<8|Wire.read(); //Store last two bytes into accelZ
  processGyroData();
}

// The following function, manipulates the gyroscope data to obtain the rotation in different directions. The number in the numerator defines the sensetivity of the accelerometer reading. 

void processGyroData() {
  rotX = gyroX / 131.0;
  rotY = gyroY / 131.0; 
  rotZ = gyroZ / 131.0;
}

// Theater-marquee-style chasing lights. Pass in a color (32-bit value,
// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)
// between frames.
void theaterChase(uint32_t color, int wait) {
  for(int a=0; a<10; a++) {  // Repeat 10 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      strip.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in steps of 3...
      for(int c=b; c<strip.numPixels(); c += 3) {
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show(); // Update strip with new contents
      delay(wait);  // Pause for a moment
    }
  }
}

// The following function count the number of walked steps

void stepCount(){
  if (gForceY > 0.4)
  {
    flag = 1;
    Serial.print ("Inside greater, flag = ");
    Serial.println(flag);
    previousMillis= millis(); // the function millis() is used to do real time monitoring. Defining the duration. 
    currentMillis= millis();
    delay (200);
  }

  if((currentMillis - previousMillis <= interval)&&(flag))
  {
    Serial.println("Inside time loop");
    if (gForceY< -0.4)
    {
      count++;
      flag = 0;
      Serial.print("Inside lesser, flag = ");
      Serial.print(flag);
      delay (200);
    }
  }

  currentMillis = millis();

  if (currentMillis - previousMillis > interval)
  {
    flag = 0; 
    Serial.print ("Inside clear, flag= ");
    Serial.println(flag);
    delay (200);

  }

  if (count > 250) // After each 250 steps, celebrate :) 
  {
    count = 0;

    digitalWrite(Vib, HIGH);
    delay (1000);    
  // Do a theater marquee effect in various colors...
    theaterChase(strip.Color(0,   127,   0), 50); // Green, half brightness
        digitalWrite(Vib, LOW);

    delay(5000); // Pause before next pass through loop
  }
    float dis=count*0.70;

  Serial.print ("Steps = ");
  Serial.println(count);
  Serial.print ("Distance (m) =  ");
  Serial.println(dis);
  Serial.print("Y = ");
  Serial.println(gForceY);
  delay (200);

  }
  • Testing the Circuit with the Code:
  • Electronics PCB Design and Production:

I have used Autodesk Eagle software to design an Arduino Nano shield with rest of components connected to it as follows.

Then I prepared the milling and drilling files for the milling machine using FabModules.

Refer to Fab Academy Handout designed by me pages (43-53) for electronics production tutorial and detailed instructions on how to use FabModules and Roland MDX-50 milling machine to mill a PCB :)

As the figures above illustrate, milling the copper traces and pads will be processed first by the machine then drilling the holes and finally cutting the outline. I have used VPanel software to send the RML files acquired from FabModules [Refer to the booklet for more details].

Then, I soldered and tested the PCB.

  • Case Design and Fabrication:

For the final design, I wanted to use wooden textile scaffolding but using silicon rubber instead of textile. To do this, I designed a triangular pattern using Rhinoceros to be laser cut and applied over a silicon rubber sealing the cover of the pedometer. For the pedometer, I designed a simple case with a clip from the back side to attached it belt.

I designed a small clip and enclosure box with a hole for power and another hole for screw to hold the case with the clip.

I cut basswood of 2mm thickness for the wooden patterns using laser cutter.

I cut an acrylic cover with the laser machine and I used Dragon Skin 20 silicon rubber for to stick the wooden pieces and to seal the cover.

  • Final Result:

Project #3: Textile Electrodes

This project is directly related to my final project whic deals with designing and using textile electrodes to acquire biometric signals from the human body. These textile electrodes should be in a direct contact with the skin to obtain the body signals. Refer to my project documentation here where I have expiremented different materials to build textile electrodes and refert to this link to see how I embeded them onto the fabric along with other systems.

Future Improvements

Working on the assignment of this week, has revealed to me the importance of design and modeling for electronics engineers. I believe I need to work a lot to improve my 3D modeling design skills and also assembly and electronics PCB fitting into case. I know that my design is not the best, but for me I feel proud to construct such a project within one week. For future, I need to practice using Rhinoceros a lot for 3D modeling and need to learn how to fit electronics with some fixing points for screws.

I found some interesting links provided by Instructables and TinkerCAD to learn how to embed 3D printig with electronics circuit.

Design Files

Please check the Drive folder to download the 3D models and PCB design.