Skip to content

WEEK 8 - WEARABLES

Last Update: Nov 14, 2021

November 8-14, 2021

This week I learned how to integrate circuitry onto fabrics with actuators - in this case, LEDs and fabric speakers. I also played with more various components to get more familiar with basic electronics.

Keywords: Arduino, Adafruit, Gemma, Neopixel, LED, LED strips, RGB, coding, programming, fabric speakers, magnet, electromagentic fields, conductive fabric, conductive thread, sewing, lights, breadboard, wires, alligator clips, embroidery, audio amplification, multimeter, capacitor, sensors, button, copper tape, transistor, resistor, electronics, programming, language


Quick Summary

💡 Tools/Resources Learned:

  • Inland DHT Sensor - Mde of two parts: a capacitive humidity sensor and a thermistor
  • Adafruit Audio Amplifier - reproduce input audio signals at sound-producing output elements, with desired volume and power levels

⚡️ Tools Refined:

  • Arduino Uno - a low-cost, flexible, and easy-to-use programmable open-source microcontroller board that can be integrated into a variety of electronic projects
  • Arduino IDE Version 1.8.16 - a cross-platform application that is written in functions from C and C++ typically to write programs for Arduino compatible boards
  • iMovie - iMovie is a video editing application developed by Apple Inc. for, and preinstalled on, macOS, iOS, and iPadOS devices

💭 What I still want to learn better:

  • Coding for Arduino IDE

Research

In terms of learning the fundamentals of electronics and the skills for building circuits, I give all my gratitude to Liza Stark and Emma Pareschi for their thorough guidance and knowledge sharing. In addition, I learned some basics from Adafruit Industries' Youtube Channel.

In terms of novel ideas, a huge source of inspiration for me this week was Kobakant

I also found interesting ideas and products from Instructables and Adafruit Industries. Some of their products such as an infinity mirror and LED trampoline inspired me to create fun products using common (ish) household items.

Side Note as of Nov 15: my inspiration and my actual outcome/assignment for this week do not match in caliber...yet. 😄

Setting up a Gemma Board

This week I used a Adafruit Gemma Board V2 as a microcontroller for sew-on neopixels (see next sections for neopixel integration). To set up the Gemma board, I plugged it to my laptop with a micro-USB to USB 2.0 cable and then through an adapter (see Problems below to see why this is so specific). I used Arduino IDE to create and upload code to the board. But to do this successfully, the board needs to be in Bootloader mode, which if not done already, can be done by pressing the little button on the board and waiting for a bright red light to lightly blink.

Neopixels

Individual

Following the Adafruit manual for neopixels (Flora ones, but it was roughly close enough). Once my Gemma board was ready to go, I uploaded the following code to it:

/*
  File name below: gemma-led1.ino
  Turns on an LED when a switch connected from #0 to ground is pressed

  This example code is in the public domain.

  To upload to your Gemma or Trinket:
  1) Select the proper board from the Tools->Board Menu
  2) Select USBtinyISP from the Tools->Programmer
  3) Plug in the Gemma/Trinket, make sure you see the green LED lit
  4) For windows, install the USBtiny drivers
  5) Press the button on the Gemma/Trinket - verify you see
     the red LED pulse. This means it is ready to receive data
  6) Click the upload button above within 10 seconds
*/

#define SWITCH 0
#define LED 2

// the setup routine runs once when you press reset:
void setup() {
  // initialize the LED pin as an output.
  pinMode(LED, OUTPUT);
  // initialize the SWITCH pin as an input.
  pinMode(SWITCH, INPUT);
  // ...with a pullup
  digitalWrite(SWITCH, HIGH);
}

// the loop routine runs over and over again forever:
void loop() {
  if (! digitalRead(SWITCH)) {  // if the button is pressed
    digitalWrite(LED, HIGH);    // light up the LED
  } else {
    digitalWrite(LED, LOW);     // otherwise, turn it off
  }
}

Once uploaded, I used conductive thread to sew it on to fabric and connect it to 2 individual Neopixel components.

Side Note: I originally used masking tape instead of a heat shrink tube to insulate intersecting connections but it didn't work as well as the heat shrink tube.

In the end, the LED lights were succesfully lit but were REALLY bright, I could barely look at it lol

Strip

While following Emma's tutorial on connecting Arduino board to LED strips and an online guide, I struggled to get the lights to turn on at all. Eventually I found out that I was connecting 10 LEDs in the strip to the board without a 1000uF capacitor, which I needed. (I haven't revisited this length of a strip yet, but I was able to successfully light a strip of 5 LEDs taped on paper. What I learned during this process however was that copper tape connected to the bottom of the strip didn't work because of the sticky adhesive still attached to the strip. Instead, I could peel back the waterproof silicone to provide a direct connection between the copperpins and the alligator clips.

The code I uploaded for this was the same sketch Emma provided for us (see Download Links below for Neopixels-Tutorial.ino). The only change I made was to the number of neopixels.

#define NUMPIXELS   5

Featherwing

Another Neopixel device I wanted to play with was the Featherwing board.

As of Nov 15 I still have to find the source problem and solution to why only 20 of the 32 LED lights are turning on.

Below is the code I used for this:

// A basic everyday NeoPixel strip test program.

// NEOPIXEL BEST PRACTICES for most reliable operation:
// - Add 1000 uF CAPACITOR between NeoPixel strip's + and - connections.
// - MINIMIZE WIRING LENGTH between microcontroller board and first pixel.
// - NeoPixel strip's DATA-IN should pass through a 300-500 OHM RESISTOR.
// - AVOID connecting NeoPixels on a LIVE CIRCUIT. If you must, ALWAYS
//   connect GROUND (-) first, then +, then data.
// - When using a 3.3V microcontroller with a 5V-powered NeoPixel strip,
//   a LOGIC-LEVEL CONVERTER on the data line is STRONGLY RECOMMENDED.
// (Skipping these may work OK on your workbench but can fail in the field)

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

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

// How many NeoPixels are attached to the Arduino?
#define LED_COUNT 32

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)


// setup() function -- runs once at startup --------------------------------

void setup() {
  // 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)
}


// loop() function -- runs repeatedly as long as board is on ---------------

void loop() {
  // Fill along the length of the strip in various colors...
  colorWipe(strip.Color(255,   0,   0), 50); // Red
  colorWipe(strip.Color(  0, 255,   0), 50); // Green
  colorWipe(strip.Color(  0,   0, 255), 50); // Blue

  // Do a theater marquee effect in various colors...
  theaterChase(strip.Color(127, 127, 127), 50); // White, half brightness
  theaterChase(strip.Color(127,   0,   0), 50); // Red, half brightness
  theaterChase(strip.Color(  0,   0, 127), 50); // Blue, half brightness

  rainbow(10);             // Flowing rainbow cycle along the whole strip
  theaterChaseRainbow(50); // Rainbow-enhanced theaterChase variant
}


// Some functions of our own for creating animated effects -----------------

// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

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

// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
  // Hue of first pixel runs 5 complete loops through the color wheel.
  // Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
  // means we'll make 5*65536/256 = 1280 passes through this outer loop:
  for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
    for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
      // Offset pixel hue by an amount to make one full revolution of the
      // color wheel (range of 65536) along the length of the strip
      // (strip.numPixels() steps):
      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
      // strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
      // optionally add saturation and value (brightness) (each 0 to 255).
      // Here we're using just the single-argument hue variant. The result
      // is passed through strip.gamma32() to provide 'truer' colors
      // before assigning to each pixel:
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show(); // Update strip with new contents
    delay(wait);  // Pause for a moment
  }
}

// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait) {
  int firstPixelHue = 0;     // First pixel starts at red (hue 0)
  for(int a=0; a<30; a++) {  // Repeat 30 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 increments of 3...
      for(int c=b; c<strip.numPixels(); c += 3) {
        // hue of pixel 'c' is offset by an amount to make one full
        // revolution of the color wheel (range 65536) along the length
        // of the strip (strip.numPixels() steps):
        int      hue   = firstPixelHue + c * 65536L / strip.numPixels();
        uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show();                // Update strip with new contents
      delay(wait);                 // Pause for a moment
      firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
    }
  }
}

Neopixels: Individual with Sensor

Humidity + Temperature Sensor

I expanded my circuit types by trying out a Inland DTH11 Temperature and Humidity Sensor and connecting it to LEDs as markers for temperature change.

To start, I prototyped with this sensor using a breadboard and some single LEDs. I followed this online guide and this one for the connections.

In this case, I programmed it so that a red LED would be turned on when the surrounding temperature was above 22 degrees C; a green LED would turn on when it was exactly 22 degrees; and a blue LED for temperatures below 22 degrees. (Note: This measurement was purely arbitrary).

Before uploading code, I had to download a new library called "DHT sensory library", along which I had to download another library.

I accessed by the code below by going to File > Examples > DHT sensory library > DHTtester and then modifying some areas including the LED light names and adding "Serial.begin(9600)" for monitoring data collection. I also commented out all the lines with "lcd" because I wasn't using a display for my circuit. It's also important to comment the specific DHT type being used (in this case, DHT11) - otherwise, the monitor will show and error "Failed to read from DHT Sensor!" (source: Random Nerd Tutorials).

/* Created by Ralph Nader on 1/10/19.
   Copyright  2019 Ralph Nader. All rights reserved.
   Made with  for everyone.
   Spread your knowledge.
   If you have any error or question, email me at "ralph@driple.co".
*/
#include <LiquidCrystal.h>             // Include the LiquidCrystal library.
#include "DHT.h"                       // Include the DHT library.

#define DHTPIN 8                       // Set the DHT Pin.
#define DHTTYPE DHT11                  // Set the DHT type.

LiquidCrystal lcd(1, 2, 4, 5, 6, 7);   // Creates a LiquidCrystal object. Parameters: (RS, Enable (E), d4, d5, d6, d7).
DHT dht(DHTPIN, DHTTYPE);              // Creates a DHT object. Parameters: (DHT Pin, DHT Type).

const int blueLED = 9;                  // Adds a led light (in that case, it is blue) to pin 9.
const int greenLED = 10;                // Adds a led light (in that case, it is green) to pin 10.
const int redLED = 11;                  // Adds a led light (in that case, it is red) to pin 11.

void setup() {
  //lcd.begin(16, 2);                    // Initializes the interface to the LCD screen, and specifies the dimensions (width and height) of the display.
  //lcd.setCursor(0, 0);                 // Set the cursor to column 0, line 0.
  Serial.begin(9600);
  Serial.println(F("DHT LED Test!"));

  pinMode(blueLED, OUTPUT);            // Change to output the blue pin.
  pinMode(greenLED, OUTPUT);           // Change to output the grene pin.
  pinMode(redLED, OUTPUT);             // Change to output the red pin.

  dht.begin();                         // Launch the DHT11 sensor.
  digitalWrite(blueLED,LOW);           // Turn off blue LED.
  digitalWrite(greenLED,LOW);          // Turn off green LED.
  digitalWrite(redLED, LOW);           // Turn off red LED.

  //lcd.print("Temperature:");           // Print "Temperature:" on LCD Screen.
  //lcd.setCursor(0, 1);                 // Set the cursor to column 0, line 1.
  //lcd.print("Humidity   :");           // Print "Humidity:" on LCD Screen.

}

void loop() {
  delay(1000);                         // Wait 0.5 seconds before updating the values.
  float T = dht.readTemperature();    // Read temperature in Celsius. If you want the Temperature in Fahrenheit, simply add "true" between the parentheses ==> float T = dht.readTemperature(True);
  float H = dht.readHumidity();       // Read humidity in percentage.

  if (isnan(H) && isnan(T)) {         // See if H (the Humidity variable) is NaN (Not A Number) && (Logical AND) See if T (the Temperature variable) is NaN to show error. 
    lcd.print("ERROR");               // Print error where there's the error.
    return;                           // Repeat the process with each update (each second).
  }

  if(T>22){                           // See if the temperature is higher than 22C.
    digitalWrite(redLED, HIGH);       // The red led will turn on.
    digitalWrite(blueLED, LOW);       // The blue led will turn off.
    digitalWrite(greenLED, LOW);      // The green led will turn off.

  }
  else if(T<22){                      // If the temperature is less than 22C.
    digitalWrite(blueLED, HIGH);      // The blue led will turn on.
    digitalWrite(greenLED, LOW);      // The green led will turn off.
    digitalWrite(redLED, LOW);        // The red led will turn off.
  }

  else if(T=22){                      // If the temperature is equal to 22C.
    digitalWrite(greenLED, HIGH);     // The green led will turn on.
    digitalWrite(redLED, LOW);        // The red led will turn off.
    digitalWrite(blueLED, LOW);       // The blue led will turn off.
  }

  //lcd.setCursor(1, 0);               // Set the cursor to column 12, line 0.
  //lcd.print(T);                       // Print the temperature.
  //lcd.setCursor(1, 1);               // Set the cursor to column 12, line 1.
  //lcd.print(H);                       // Print the humidity level.

  Serial.print(F("Humidity: "));
  Serial.print(H);
  Serial.print(F("%   Temperature:"));
  Serial.print(T);
  Serial.println(F("°C"));
}

Note: The actual temperature outside was 4 deg C and inside it was 23 deg C. It took 23 seconds for the sensor to read cooler temperatures and reach the 22 degree boundary, and 2:00min to warm back up to the 22 degree boundary.

Since I don't have a soldering iron, I will wait to put together a textile design with this component in (to be continued...).

Speakers

Various Iterations

Version #1: Due to tension and bobbin problems with my sewing machine, this method did not work well.

Version #2: Using an embroidery hoop, I hand stitched a spiral with conductive thread and used the muslin fabric as the insulator. The back piece was stitched on a separate piece of muslin (2 pieces total).

Version #3: Unfortunately the lab was inaccessible this week, so instead of laser cutting a spiral, I hand-cut a spiral out of copper fabric and then used an iron to attach fusible fabric to the spiral. To avoid the fusible adhesive material from getting on the ironing board or the iron itself, I placed a piece of organza on the opposite side of the spiral.

Note: After realizing Version #3 wasn't working, I thought maybe the organza was intefering with the EM waves, so I removed the organza with a seam ripper and scissors to reveal the copper fabric out of the organza covering.

Version #4: (Still be tested out) I am now in the process of creating another speaker using copper wire, sewn onto felt in a spiral form.

Connecting to Transistor and Arduino

Thanks to Emma's tutorial, I made a circuit using hard stock paper and copper tape along with a 10K Ohm resistor, a diode and an N-Channel MOSFET transistor.

I then connected this to two of the speakers I fabricated.

Unfortunately, neither speaker or circuit worked... to be continued...

Connecting to Audio Amplifier

In my attempt to integrate my fabric speakers in a different manner and check whether the previous problem was due to the speakers themselves or the circuit, I took apart an old set of iPhone earphones and connected it to an Adafruit Audio Amplifier and an external power supply (9V).

To determine which wires from the headphones I hacked to connect to the amplifier, I used an online guide from Circuit Basics

Unfortunately, neither speaker or circuit worked here either.. to be continued... :sad:

LEDs
Gemma and Neopixels (.ino)
Featherwing Strandtest (.ino)
DHT - no LED (.ino)
DHT - with LED indicators (.ino)

Sound
Audio Amplifier Test (.ino)
Tutorial-sounds (.ino)
Tutorial-melody (.ino)
Tutorial-melody - pitches.h file (.h)

Problem Areas

Arduino IDE Error 1

Problem
Seeing this error in the Arduino IDE after attempting to upload a code to an Arduino Uno board.

avrdude: ser_open(): can't open device "/dev/cu.usbmodem141301

Solution
Method #1: So far, the only solution that has worked best for me was to make sure that "/dev/cu.usbmodem141301" was checked under Tools > Port.

Method #2: The other solution was to change the adapter between the USB cable and the computer I was using.

Arduino IDE Error 2

Problem Seeing this error in the Arduino IDE after attempting to upload a code to a Gemma Board.

avrdude: Error: Could not find USBtiny device (0x1781/0xc9f)

Solution
First, make sure that the cable being used is a Micro-USB to USB 2.0 cord. Second, since I'm using a Macbook Pro with only 2 Thunderbolt ports, I found that the best adapter was a hub, as opposed to a single/direct adapter for USB to USB-C.

Failed to read DHT sensor

Problem
When trying to gather data and see them on the serial monitor, this error showed up.

Solution Inspired by Random Nerd Tutorials, the solution to this problem - at least in my case - was to make sure that my specific DHT sensor was the only one commented.

Other Resources and Sources of Inspiration

Lights

Sounds

Troubleshooting


Last update: 2022-02-08
Back to top