12. Skin Electronics#

assignment#

  • 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

introduction#

I want to make twinkle nails with NFC tags. Adafruit made NeoPixel Manicure before(without NFC tags), but I think this is not pretty. I trid to make it more sophisticated.

image source: Adafruit

Here is what I want to make.

preparation#

First, I read UID data from NFC tags.

After wiring arduino and an NFC reader as a schematic shown below, I uplaoaded DumpInfo.ino. The sketch will be in File > Examples > MFRC522 after installing the Arduino RFID Library for MFRC522.

image source: RANDOM NERD TUTORIALS

If wiring is right, you can see UID data on serial monitor as shown below(yellow underlined)

Here is five UIDs I used later prototyping.
Card UID1: 04 81 5D AA 61 3E 80
Card UID2: 04 A4 5D AA 61 3E 80
Card UID3: 04 5F 5D AA 61 3E 80
Card UID4: 04 3E 5D AA 61 3E 80
Card UID5: 04 82 5D AA 61 3E 80

prototyping#

Other than NFC tags, I bought nail tips and glue. reused Neopixels I modified in week 5.

I connected neopixels with a polyurethan insulated wire as I used in week 9.

It was painstaking job. I checked it worked properly before putting on my nails.

I glued LEDs on my nails with doublesided tapes.

Now I know why Adafruit’s NeoPixels Manicure went ugly

I put NFC tag embedded nail tips on LEDS. This is ugly…

Here is how naiLED works. I had a difficulty with letting LEDs glow once a tag’s UID is detected and a tag is apart from a sensor.
I naiLED it?

code#

#include <SPI.h>
#include <MFRC522.h>
#include <FastLED.h>

#define RST_PIN         9          // Configurable, see typical pin layout above
#define SS_PIN          10         // Configurable, see typical pin layout above

#define UID1 "04 BA 5E AA 61 3E 80"
#define UID2 "04 96 5E AA 61 3E 80"  
#define UID3 "04 5F 5D AA 61 3E 80"  
#define UID4 "04 3E 5D AA 61 3E 80"  
#define UID5 "04 82 5D AA 61 3E 80"


MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance
MFRC522::MIFARE_Key key;

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

// Which pin on the Arduino is connected to the NeoPixels?
// On a Trinket or Gemma we suggest changing this to 1
#define PIN            6

// How many NeoPixels are attached to the Arduino?
#define NUM_PIXELS      5

// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
// example for more information on possible values.

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, PIN, NEO_GRB + NEO_KHZ800);

int delayval = 500; // delay for half a second


void setup() {
  Serial.begin(9600);   // Initialize serial communications with the PC
  while (!Serial);    // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
  SPI.begin();      // Init SPI bus
  mfrc522.PCD_Init();   // Init MFRC522
  mfrc522.PCD_DumpVersionToSerial();  // Show details of PCD - MFRC522 Card Reader details
  Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));

  dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE);

  // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket
#if defined (__AVR_ATtiny85__)
  if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
  // End of trinket special code
  strip.begin(); // This initializes the NeoPixel library.
  strip.show(); // Initialize all pixels to 'off'
  strip.setBrightness(100);
}

void loop() {
  // Look for new cards
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    //return;   
  }

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    //return;
  }

    String strBuf[mfrc522.uid.size];
    for (byte i = 0; i < mfrc522.uid.size; i++) {
      strBuf[i] =  String(mfrc522.uid.uidByte[i], HEX);  // (E)using a constant integer
      if(strBuf[i].length() == 1){  
        strBuf[i] = "0" + strBuf[i];
      }
 }

 String strUID = strBuf[0] + " " + strBuf[1] + " " + strBuf[2] + " " + strBuf[3] + " " + strBuf[4] + " " + strBuf[5] + " " + strBuf[6];

if ( strUID.equalsIgnoreCase(UID1) ){  
      Serial.println("1");
      Serial.println(UID1);
        knightRider(1, 70, 8, 0xFF1000); // Cycles, Speed, Width, RGB Color (original orange-red)
  }
    else if ( strUID.equalsIgnoreCase(UID2) ){
      Serial.println("2");
      Serial.println(UID2);
  knightRider(1, 70, 8, 0x0000FF); // Cycles, Speed, Width, RGB Color (blue)
    }
    else if ( strUID.equalsIgnoreCase(UID3) ){
      Serial.println("3");
      Serial.println(UID3);
    knightRider(1, 70, 8, 0x00FF00); // Cycles, Speed, Width, RGB Color (green)
    }
    else if ( strUID.equalsIgnoreCase(UID4) ){
      Serial.println("4");
      Serial.println(UID4);
        knightRider(1, 70, 20, 0xFFFF00); // Cycles, Speed, Width, RGB Color (yellow)
    }
    else if ( strUID.equalsIgnoreCase(UID5) ){
      Serial.println("5");
      Serial.println(UID5);
      rainbowCycle(1);
    }


}

/**
 * Helper routine to dump a byte array as hex values to Serial.
 */
void dump_byte_array(byte *buffer, byte bufferSize) {
    for (byte i = 0; i < bufferSize; i++) {
        Serial.print(buffer[i] < 0x10 ? " 0" : " ");
        Serial.print(buffer[i], HEX);
    }
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

// Cycles - one cycle is scanning through all pixels left then right (or right then left)
// Speed - how fast one cycle is (32 with 16 pixels is default KnightRider speed)
// Width - how wide the trail effect is on the fading out LEDs.  The original display used
//         light bulbs, so they have a persistance when turning off.  This creates a trail.
//         Effective range is 2 - 8, 4 is default for 16 pixels.  Play with this.
// Color - 32-bit packed RGB color value.  All pixels will be this color.
// knightRider(cycles, speed, width, color);
void knightRider(uint16_t cycles, uint16_t speed, uint8_t width, uint32_t color) {
  uint32_t old_val[NUM_PIXELS]; // up to 256 lights!
  // Larson time baby!
  for(int i = 0; i < cycles; i++){
    for (int count = 1; count<NUM_PIXELS; count++) {
      strip.setPixelColor(count, color);
      old_val[count] = color;
      for(int x = count; x>0; x--) {
        old_val[x-1] = dimColor(old_val[x-1], width);
        strip.setPixelColor(x-1, old_val[x-1]); 
      }
      strip.show();
      delay(speed);
    }
    for (int count = NUM_PIXELS-1; count>=0; count--) {
      strip.setPixelColor(count, color);
      old_val[count] = color;
      for(int x = count; x<=NUM_PIXELS ;x++) {
        old_val[x-1] = dimColor(old_val[x-1], width);
        strip.setPixelColor(x+1, old_val[x+1]);
      }
      strip.show();
      delay(speed);
    }
  }
}

uint32_t dimColor(uint32_t color, uint8_t width) {
   return (((color&0xFF0000)/width)&0xFF0000) + (((color&0x00FF00)/width)&0x00FF00) + (((color&0x0000FF)/width)&0x0000FF);
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

references#