Skip to content

9. Wearables

goals of the week

  • Create a swatch using an attiny with one input and one output of your choice, using hard-soft connection solutions and battery.
  • Create 2 actuator swatches and test them with the Arduino or ATtiny. Learn how to program and ATTiny, add the libraries and links you used for your code.
  • Document the schematic and the programming code, libraries you had to add and calculations.
  • EXTRA POINT Integrate it to a project.


Here are some inspiring projects developed by previous participants:


VISUAL ACTUATOR

LEDs

Different colors = same voltages, but different forward voltages/voltage drops, which means they require different resistors

RGB LEDs - can combine three leads to create different colors.

NeoPixels (type of LED)

They have chips in them called drivers. Allows you to control each LED in specific.

You have to have them connected to a microcontroller, a battery is not enough.

Fiber Optics

Light shines in one end, travels down the strand, and emerges at the other end.

There is a clear internal core and an external coating called cladding.

LED intensity - depends on the intensity of the light source.

Type of Fiber - End Emitting (light only gets out at the end) / Side Emitting (thicker, cladding as not pronounce).

Taking the LED and attach to the Fiber. Connecting options:

  • Drilling a hole into the LED and placing the fiber
  • Tubing and glue
  • 3D printed enclosure and glue

Thermochromic Ink

Reacts to a heating surface.

Inks or pigments that changes in the presence of heat, the color of the ink goes away.

Heating elements:

  • Stainless steel conductive thread
  • Karl Grimm conductive thread (at leats 2.5 ohms)
  • Conductive Fabrics (tricky)
  • Nichrome wire or flexinol


SOUND ACTUATOR

Sound is a pressure wave created by an object when it vibrates.

Permanent Magnets - are objects that generate a magnetic field, which can attract and repel some metals. Every magnet as a north and a south pole.

Electromagnets - is a type of magnet that only works when electricity is flowing through it. The electromagnet force of a straight wire is not very strong at all but by coiling the wire, you can create a stronger field.

When you connect a battery and an audio signal to your electromagnet, it forms a magnetic field. The magnetic field fluctuates based on the electrical frequencies of the audio signal.

Variables:

  • Coil tightness - tighter the coil the louder it is
  • Material - stiff or less stiffer impact the sound
  • Magnet size - the bigger the louder
  • Magnet placement - the volume will be louder the closer the magnet is to the centre of the coil

Your speaker should:

  • Use conductive thread
  • Be a coil
  • Have a small space between the coil traces
  • Have two ends to connect to your circuit

You can make it by embroidery, weaving, folding, and vinyl cutting.


MOTION ACTUATOR

Shape Memory Alloy

Shape memory alloys, metals that change shapes when they are heated to a certain temperature.

  • Untrained flexinol will contract by 10% of its length when heat is applied.
  • Trained flexinol contracts by 10% but has been trained into a shape through a heating process. When heated, it will return to the shape you trained it to.

Variables:

  • Material Substrates — lighter material will yield best results, like cotton, paper, silk, (not polyester)
  • Diameter size — higher the diameter you will need more power
  • Length — the resistance increases when the length increases

You can make it by folding, curling, smoking

Connections: you cannot solder directly onto into, but you can use crimp beads to attach the flexinol to.

Flip Dots

Magnetic hematite bead flips back and forth when we run current through the coil. It creates an electromagnetic field that attracts or repeals the bead on the direction of the current.

  • Bead size - the bigger the bead the larger the EMF must be to flip it
  • Securing the bead - test the tension
  • Number of coils - at least 50
  • Gauge of wire - smaller gauge, more coils in less space
  • Coil wrapping material

Vibration Motors and Haptics

Haptic sensing involves both touch and kinesthesia (sometimes referred to as proprioception) which refers to sense of limb positioning and movement.

Unlike other senses, haptic sensing is bidirectional. The information we can extract about an object’s properties is linked to the movements made to perceive those properties

How it works:

  • Small motors that vibrate!
  • Voltage: 2V - 5V
  • 5V current draw: 100mA
  • 3V current draw: 60mA

There are two types of vibration motors: Eccentric Rotating Mass (ERM) and Linear Resonant Actuator (LRA). ERM vibe motors have an off-centre load that causes vibrations when it rotates.

You can use motor drivers to control the behaviour more precisely. You need one board for each motor.



research

inspiration

  1. ?
  2. GIVENCHY FALL 1999 RTW COLLECTION by ALEXANDER MCQUEEN
  3. AURORA LED NECKLACE
  4. MOVING TARGET 2007 by MAGGIE ORTH
  5. NASTIA PILEPCHUK
  6. PANGOLIN SCALES PROJECT by ANOUK WIPPRECHT
  7. ?
  8. Frison, PHILIPS DESIGN


neopixels

neopixel

We began the practical classes with some Arduino work to refresh our programming skills from E-Textiles week. It was a great refresher, and we had a lot of fun exploring various coding possibilities with Neopixels strips, including integrating an LDR sensor.

NeoPixels are RGB LEDs with built-in microcontrollers, allowing each light to display unique colors and brightness.

Before proceeding, we needed to install two essential libraries: one for controlling the NeoPixels and another for interfacing with the Servo Motor (which you'll see later on). Libraries are pre-written code collections designed to simplify hardware interfacing and specific tasks. They’re incredibly helpful, not only for beginners but for experienced developers as well.

In the image below, you’ll find a detailed view of the libraries we installed, including their versions and the initial code examples we used. Adafruit_NeoPixel.h 1.12.3 / ESP32Servo.h 1.2.1


arduino


In the image below, we have a breadboard circuit setup featuring a Seeed Studio XIAO ESP32S3, jumper wires, a NeoPixel strip with two LEDs, a 10k resistor, a 390-ohm resistor, and an LDR. This serves as a base circuit for the different approaches we made.

breadboardneopixel


schematic

Schematic by Michelle Vossen with Fritzing.


Building this Circuit on a Breadboard:

  • Connect the GND pin on the NeoPixel board to the GND pin on the microcontroller, and the 5V pin on the NeoPixel board to the 5V pin on the microcontroller.

  • Attach a 390Ω resistor to the Din pin on the NeoPixel board.

  • Connect the other end of the 390Ω resistor to pin A0 on the microcontroller.

  • Connect one leg of the LDR to GND and the other leg to A1.

  • Connect one leg of the 10KΩ resistor to 3.3V and the other one to pin A1 on the microcontroller.


BASE CODE:

/*
Map LDR input to neopixel output

Reads an analog input on pin A1, and maps it to neopixels. 
Also prints the result to the Serial Monitor.

Connect the data wire of the neopixel strip through a 300-500 Ohm resistor to pin A0
Connect the red wire of the neopixel strip to +3.3V (this is because when using battery power, there is no power on the 5V pin)
Connect the black wire of the neopixel strip to GND

Connect one leg of the LDR to pin A1. Also connect A1 through a 4.7k Ohm resistor to +3.3V (this way, 
we're making a voltage divider). Depending on the LDR value range you may need to increase 
or decrease the resistor value.
Connect the other leg of the LDR to ground

Other options for this code:
- Attach the center pin of a potentiometer to pin A0, and the outside pins to +3.3V and ground.

This example code is in the public domain.
20 Oct 2024
by Michelle Vossen

https://v0ss3n.github.io/projects/education/wearables 
*/

#include <Adafruit_NeoPixel.h>

// Pin Definitions
const int sensor_pin = A1;      // LDR connected to A0
const int neopixel_pin = A0;      // NeoPixel strip connected to A1

// NeoPixel Setup
const int numPixels = 2;   // Number of NeoPixels on the strip. Change according to the amount of NeoPixels. Keep the power budget in mind, see https://learn.adafruit.com/adafruit-neopixel-uberguide/powering-neopixels
Adafruit_NeoPixel strip = Adafruit_NeoPixel(numPixels, neopixel_pin, NEO_GRB + NEO_KHZ800);

int ldrValue;           // Variable to store LDR value

void setup() {
// Initialize the NeoPixel strip
strip.begin();
strip.show();  // Initialize all pixels to 'off'

// Initialize Serial Monitor for debugging
Serial.begin(115200);
}

void loop() {
// Read LDR value (range: 0 to 4095 on ESP32S3's 12-bit ADC)
ldrValue = analogRead(sensor_pin);
Serial.print("LDR Value before constraining and filtering: ");
Serial.println(ldrValue);
// Scale the LDR value down (because the values range from 650 to 1000 in my case). Change according to the values that you need.
ldrValue = constrain(ldrValue, 600, 2500);  // Constrain to the expected range
ldrValue = ldrValue / 10; // very rough filter, to remove some jitter

int mappedLdr = map(ldrValue, 60, 250, 0, 100);  // Map to percentage (0-100)

// Light up more NeoPixels based on the mapped LDR value (the closer, the more pixels)
int numLitPixels = map(mappedLdr, 100, 0, 0, numPixels);  // Map LDR to the number of NeoPixels

int ldrColor = map(mappedLdr, 0, 100, 0, 255);

// Light up the corresponding number of NeoPixels
for (int i = 0; i < numPixels; i++) {
    if (i < numLitPixels) {
    strip.setPixelColor(i, strip.Color(ldrColor, 0, 0));  // Set lit pixels to blue
    } else {
    strip.setPixelColor(i, strip.Color(0, 0, 0));    // Turn off the remaining pixels
    }
}

// Update the NeoPixel strip
strip.show();

// Output values to Serial Monitor for debugging
Serial.print("LDR Value: ");
Serial.print(ldrValue);
Serial.print(" | Lit Pixels: ");
Serial.println(numLitPixels);

// Add a small delay to avoid overwhelming the serial monitor and NeoPixel updates
delay(100);
}


CODE ALTERATIONS:

1ST Brighter to Darker

    int ldrColor = map(mappedLdr, 0, 100, 0, 255);

    // Light up the corresponding number of NeoPixels
    for (int i = 0; i < numPixels; i++) {
        if (i < numLitPixels) {
        strip.setPixelColor(i, strip.Color(ldrColor, 0, 0));  // Set lit pixels to blue
        } else {
        strip.setPixelColor(i, strip.Color(0, 0, 0));    // Turn off the remaining pixels
        }
    }

2ND Blue to Red

    int ldrBlue = map(mappedLdr, 0, 100, 0, 255); 
    int ldrRed = map(mappedLdr, 0, 100, 255, 0);

    // Light up the corresponding number of NeoPixels
    for (int i = 0; i < numPixels; i++) {
        if (i < numLitPixels) {
        strip.setPixelColor(i, strip.Color(ldrRed, 0, ldrBlue));  // Set lit pixels to blue
        } else {
        strip.setPixelColor(i, strip.Color(0, 0, 0));    // Turn off the remaining pixels
        }
    }

3RD Blue pair to Red pair

    int ldrBlue = map(mappedLdr, 0, 100, 0, 255); 
    int ldrRed = map(mappedLdr, 0, 100, 255, 0);

    strip.setPixelColor(0, strip.Color(ldrRed, 0, ldrBlue));
    strip.setPixelColor(1, strip.Color(ldrRed, 0, ldrBlue));

    (take OFF)  // // Light up the corresponding number of NeoPixels
    // for (int i = 0; i < numPixels; i++) {
    //   if (i < numLitPixels) {
    //     strip.setPixelColor(i, strip.Color(ldrRed, 0, ldrBlue));  // Set lit pixels to blue
    //   } else {
    //     strip.setPixelColor(i, strip.Color(0, 0, 0));    // Turn off the remaining pixels
    //   }
    // }

4TH 1 Red 1 Blue Reverse

    int ldrBlue = map(mappedLdr, 0, 100, 0, 255);
    int ldrRed = map(mappedLdr, 0, 100, 255, 0);

    strip.setPixelColor(0, strip.Color(ldrRed, 0, ldrBlue));
    strip.setPixelColor(1, strip.Color(ldrBlue, 0, ldrRed));

    (take OFF)  // // Light up the corresponding number of NeoPixels
    // for (int i = 0; i < numPixels; i++) {
    //   if (i < numLitPixels) {
    //     strip.setPixelColor(i, strip.Color(ldrRed, 0, ldrBlue));  // Set lit pixels to blue
    //   } else {
    //     strip.setPixelColor(i, strip.Color(0, 0, 0));    // Turn off the remaining pixels
    //   }
    // }

5TH 1 Red 1 Blue to Green pair

    int ldrBlue = map(mappedLdr, 0, 100, 0, 255); 
    int ldrRed = map(mappedLdr, 0, 100, 255, 0);


    strip.setPixelColor(0, strip.Color(ldrRed, ldrBlue, 0));
    strip.setPixelColor(1, strip.Color(0, ldrBlue, ldrRed));

    (take OFF) // // Light up the corresponding number of NeoPixels
    // for (int i = 0; i < numPixels; i++) {
    //   if (i < numLitPixels) {
    //     strip.setPixelColor(i, strip.Color(ldrRed, 0, ldrBlue));  // Set lit pixels to blue
    //   } else {
    //     strip.setPixelColor(i, strip.Color(0, 0, 0));    // Turn off the remaining pixels
    //   }
    // }


felt touchSensor

Issy and I decided to create a felt touch sensor that would change the colors of two NeoPixels. Initially, one NeoPixel would be red and the other blue, and upon touch, both would turn green. To start, we made a quick needle-felted sample with conductive fiber. You can find the step-by-step process for needle felting in my E-textiles week documentation.

We intentionally kept the sample soft and not too dense, allowing the NeoPixel lights to shine through the wool.

Since we already had both codes, one for controlling the NeoPixels and another for the felt touch sensor that I developed during E-textiles week, we focused on combining them and building the circuit on the breadboard. Using ChatGPT, we merged the two codes by providing all the necessary details, including our goal and the tools we had available.


touchsensor


Building this Circuit on a Breadboard:

  • Connect the GND pin on the NeoPixel board to the GND pin on the microcontroller, and the 5V pin on the NeoPixel board to the 5V pin on the microcontroller.

  • Attach a 390Ω resistor to the Din pin on the NeoPixel board.

  • Connect the other end of the 390Ω resistor to pin A0 on the microcontroller.

  • Use a jumper wire with an alligator clip to connect the touch sensor (felt sample) to Touch2 on the microcontroller.


CODE:

#include <Adafruit_NeoPixel.h>

// Pin Definitions
const int neopixel_pin = A0;       // NeoPixel strip connected to A0
const int touch_pin = T2;          // Pin that we're going to touch

// NeoPixel Setup
const int numPixels = 2;           // Number of NeoPixels on the strip
Adafruit_NeoPixel strip = Adafruit_NeoPixel(numPixels, neopixel_pin, NEO_GRB + NEO_KHZ800);

// Variables for touch sensor
int touchValue;                    // Variable to store touch sensor value
int threshold = 75000;             // Threshold for lighting up NeoPixels

void setup() {
// Initialize the NeoPixel strip
strip.begin();
strip.show();  // Initialize all pixels to 'off'

// Initialize Serial Monitor for debugging
Serial.begin(115200);
}

void loop() {
// Read touch sensor value
touchValue = touchRead(touch_pin);
Serial.print("Touch Value before constraining: ");
Serial.println(touchValue);

// Constrain the touch value range
touchValue = constrain(touchValue, 35000, 110000);

// Map the touch value to a percentage (0-100) for NeoPixel control
int mappedTouch = map(touchValue, 35000, 110000, 0, 100);

// Calculate color intensity based on mapped touch value
int touchBlue = map(mappedTouch, 0, 100, 0, 255);
int touchRed = map(mappedTouch, 0, 100, 255, 0);

// Set colors for each NeoPixel
strip.setPixelColor(0, strip.Color(touchRed, touchBlue, 0));  // First pixel fades red to blue
strip.setPixelColor(1, strip.Color(0, touchBlue, touchRed));  // Second pixel fades blue to red

// Update the NeoPixel strip
strip.show();

// Output values to Serial Monitor for debugging
Serial.print("Mapped Touch Value: ");
Serial.println(mappedTouch);

// Add a small delay to avoid overwhelming the serial monitor and NeoPixel updates
delay(100);
}



textile speaker

A textile speaker transforms electrical energy into sound waves using three key components: a permanent magnet, an electromagnet, and a vibrating membrane. These elements work together to move air and create sound. Electromagnetism forms the basis of this process. When an electric current flows through a wire, it generates a magnetic field. If you coil the wire, the magnetic field intensifies due to the increased surface area, resulting in a stronger electromagnetic force.

To produce the sound, the electromagnet (a coiled wire) is connected to a circuit powered by a battery and an audio signal. The audio signal carries varying electrical frequencies, causing the magnetic field of the coil to fluctuate in sync with the signal. When placed near a strong permanent magnet, the changing electromagnetic field interacts with the permanent magnet’s field, creating forces of attraction and repulsion. As the membrane vibrates, it pushes and pulls the surrounding air, generating sound waves that correspond to the original audio signal.


speakers

Issy and I teamed up to explore various speaker prototypes, experimenting with coils of different shapes, sizes, and materials. The goal was to evaluate how these variations affect performance and identify the most effective designs.

One critical aspect of the process was ensuring that the coil traces didn’t overlap or touch each other, as this could cause a short circuit and disrupt the electromagnetic field.

To power and test each speaker, we used the Adafruit PAM8302 Mono 2.5W Class D Audio Amplifier, connected to three AA batteries (providing 4.5V). An audio jack linked the setup to a laptop to deliver the audio signal.

This experiment allowed us to study how different parameters, such as coil geometry and material properties, influence the vibration of the speaker membrane and, ultimately, the sound quality.

  1. (circular coil) conductive thread hand sewn with non condcutive thread - less coil tightness; small diameter. Results: the sound was only audible when held close to the ears.
  2. (circular coil) conductive thread sewn with a sewing machine - medium coil tightness. Results: Both the circular and square coils produced similar results, delivering clear and audible sound.
  3. (square coil) conductive thread sewn with a sewing machine - medium coil tightness.
  4. (circular coil) conductive thread (copper wire) hand sewn - less coil tightness; small diameter. Results: Audible from a distance very well.
  5. (square coil) conductive tape - high coil tightness. Results: The sound quality was great, mainly due to the large conductive surface area.
  6. (circular coil) condcutive thread (copper wire) hand sewn with non condcutive thread; high coil tightness; large diameter. Results: The loudest design, not only projecting sound from afar but also handling bass frequencies very well.



servo motor

Servomotors are compact rotary or linear actuators commonly used for precise control of position, angle, or speed. They operate using a pulse-width modulation (PWM) signal, where the length of each pulse determines the motor's target movement.

The servomotors we worked with fell into two categories: fixed-range (180 degrees) and continuous rotation (360 degrees). In my examples, I am using a continuous rotation (360-degree) servomotor.

To control these servos, we used the Servo library in Arduino, that I showed above. This version was compatible with the Xiao ESP32S3 microcontroller, as newer versions of the library presented compatibility issues. We began our experimentation by uploading a basic example sketch called Sweep, which demonstrated how to smoothly rotate a servo back and forth across its range.


servomotorbreadboard


CODE:

/* Sweep
by BARRAGAN <http://barraganstudio.com>
This example code is in the public domain.

modified 8 Nov 2013
by Scott Fitzgerald

modified for the ESP32 on March 2017
by John Bennett

see http://www.arduino.cc/en/Tutorial/Sweep for a description of the original code

* Different servos require different pulse widths to vary servo angle, but the range is 
* an approximately 500-2500 microsecond pulse every 20ms (50Hz). In general, hobbyist servos
* sweep 180 degrees, so the lowest number in the published range for a particular servo
* represents an angle of 0 degrees, the middle of the range represents 90 degrees, and the top
* of the range represents 180 degrees. So for example, if the range is 1000us to 2000us,
* 1000us would equal an angle of 0, 1500us would equal 90 degrees, and 2000us would equal 1800
* degrees.
* 
* Circuit: (using an ESP32 Thing from Sparkfun)
* Servo motors have three wires: power, ground, and signal. The power wire is typically red,
* the ground wire is typically black or brown, and the signal wire is typically yellow,
* orange or white. Since the ESP32 can supply limited current at only 3.3V, and servos draw
* considerable power, we will connect servo power to the VBat pin of the ESP32 (located
* near the USB connector). THIS IS ONLY APPROPRIATE FOR SMALL SERVOS. 
* 
* We could also connect servo power to a separate external
* power source (as long as we connect all of the grounds (ESP32, servo, and external power).
* In this example, we just connect ESP32 ground to servo ground. The servo signal pins
* connect to any available GPIO pins on the ESP32 (in this example, we use pin 18.
* 
* In this example, we assume a Tower Pro MG995 large servo connected to an external power source.
* The published min and max for this servo is 1000 and 2000, respectively, so the defaults are fine.
* These values actually drive the servos a little past 0 and 180, so
* if you are particular, adjust the min and max values to match your needs.
*/

#include <ESP32Servo.h>

Servo myservo;  // create servo object to control a servo
// 16 servo objects can be created on the ESP32

int pos = 0;    // variable to store the servo position

int servoPin = A0;

void setup() {
    // Allow allocation of all timers
    ESP32PWM::allocateTimer(0);
    ESP32PWM::allocateTimer(1);
    ESP32PWM::allocateTimer(2);
    ESP32PWM::allocateTimer(3);
    myservo.setPeriodHertz(50);    // standard 50 hz servo
    myservo.attach(servoPin, 1000, 2000); // attaches the servo on pin 18 to the servo object 
    // using default min/max of 1000us and 2000us
    // different servos may require different min/max settings
    // for an accurate 0 to 180 sweep
}

void loop() {

    for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
        // in steps of 1 degree
        myservo.write(pos);    // tell servo to go to position in variable 'pos'
        delay(15);             // waits 15ms for the servo to reach the position
    }
    for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
        myservo.write(pos);    // tell servo to go to position in variable 'pos'
        delay(15);             // waits 15ms for the servo to reach the position
    }
}


Next, we integrated an LDR into the circuit, adding more interactivity. The LDR measures light intensity, and its readings are processed and mapped to control the servo motor's movements through Pulse Width Modulation (PWM).

By converting the light levels into PWM signals, the servo motor’s angle is dynamically adjusted in response to changes in ambient light. For instance, brighter light results in one range of motion, while dimmer light produces a different movement.


servomotorbreadboard


CODE:

/*
Map LDR input to servo motor output

Reads an analog input on pin A1, and maps it to servo motor angle (fixed angle versions) or speed (continuous rotation versions). 
Also prints the result to the Serial Monitor.

Ideally, we're powering a micro servo with a stand-alone power supply, but
with a micro servo and not too much weight, we can hopefully get away with powering it
like this :-)
Connect the orange wire of the servo motor to pin A0
Connect the red wire of the servo motor to +3.3V
Connect the black wire of the servo motor to GND

Connect one leg of the LDR to pin A1. Also connect A1 through a 4.7k Ohm resistor to +3.3V (this way, 
we're making a voltage divider). Depending on the LDR value range you may need to increase 
or decrease the resistor value.
Connect the other leg of the LDR to ground

Other options for this code:
- Attach the center pin of a potentiometer to pin A0, and the outside pins to +3.3V and ground.

This example code is in the public domain.
20 Oct 2024
by Michelle Vossen

https://v0ss3n.github.io/projects/education/wearables 
*/

// Include the servo library. If you're using a microcontroller with an AVR, SAM, SAMD, NRF52 or STM32F4 processor, use this library:
// #include <Servo.h>
// Use this one for ESP32 processors:
#include <ESP32Servo.h>


// Pin Definitions
const int servo_pin = A0;  // Servo connected to A1
const int sensor_pin = A1;    // LDR connected to A0

// Variables
Servo myServo;       // Create a Servo object
int ldrValue = 0;    // Variable to store LDR value
int servoAngle = 0;  // Variable to store servo angle

void setup() {
// Attach servo to the specified pin
myServo.attach(servo_pin);

// Initialize Serial Monitor for debugging
Serial.begin(115200);
}

void loop() {
// Read LDR value (0 to 4095 on RP2040 Xiao's 12-bit ADC)
ldrValue = analogRead(sensor_pin);
Serial.println(ldrValue);

// Scale the LDR value down (because the values range from 650 to 1000 in my case). Change according to the values that you need.
ldrValue = constrain(ldrValue, 3000, 4500);  // Constrain to the expected range
ldrValue = ldrValue / 10; // very rough filter, to remove some jitter

// Map LDR value to a range of 180 degrees for the servo (servoAngle: 0 to 180)
// Since I divided the values by 10, the min/max are divided by 10 too. This is not very elegant code :-)
servoAngle = map(ldrValue, 300, 450, 180, 0);
servoAngle = constrain(servoAngle, 0, 180);  // Ensure the angle stays between 0 and 180

// Set the servo to the mapped angle
myServo.write(servoAngle);

// Output values to Serial Monitor for debugging
Serial.print("LDR Value: ");
Serial.print(ldrValue);
Serial.print(" | Servo Angle: ");
Serial.println(servoAngle);

// Add a small delay to avoid overwhelming the serial monitor
delay(100);
}



final proposal

For this week’s final proposal, I decided to explore fiber optics, a material that truly captured my interest during the week. In our lab, we had access to end-emitting fiber optics, and I experimented with using sandpaper to carefully scrape the fibers to allow light to emit from their sides. It’s crucial to handle this process delicately, over-sanding the fibers can damage them and end up with no light output.

The initial design idea was to create a brooch flower made of multiple layers of felt. Fiber optic strands would emerge from the center of the flower and illuminate when the top layer of felt is touched.


final

I began the project by working on the needle felting, shaping rounded forms with wool to create the structure of the design. I integrated conductive fiber into one of the layers, intending to use it later as a touch sensor.

Next, I moved on to assembling the circuit on a breadboard. The circuit includes an LED, a 220-ohm resistor, and the touch sensor, which will allow the LED to light up when the conductive fiber is activated by touch.


Building this Circuit on a Breadboard:

  • Connect the positive leg of the LED to A1 on the breadboard.

  • Attach the negative leg of the LED to one end of a 220Ω resistor.

  • Connect the other end of the 220Ω resistor to GND on the microcontroller.

  • Use a jumper wire with an alligator clip to connect the touch sensor to pin T1.


CODE:

int LED_pin = A1;    // Pin the LED is attached to
int touch_pin = T1;  // Pin that we're going to touch

// change with your threshold value
int threshold = 60000;
// variable for storing the touch pin value
int touchValue;

// the setup function runs once when you press reset or power the board
void setup() {
// initialize serial communication at 115200 bits per second:
Serial.begin(115200);
// initialize LED_pin as an output
pinMode(LED_pin, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
touchValue = touchRead(touch_pin);
Serial.println(touchValue);

if (touchValue > threshold) {
// turn LED on
digitalWrite(LED_pin, HIGH);
Serial.println("LED on");
} else {
// turn LED off
digitalWrite(LED_pin, LOW);
Serial.println("LED off");
}
delay(50);

// while (touch_pin == 1) {
//   digitalWrite(LED_pin, HIGH);  // keep the LED on as long as touch pin 1 is touched (HIGH)
// }

// while (touch_pin == 0) {
//   digitalWrite(LED_pin, LOW);  // keep the LED off as long as touch pin 1 is not touched (LOW)
// }
}


troubleshooting

To translate the circuit into a wearable design, I began by using a piece of fabric as the base and created traces with conductive thread to connect the components. To simplify the assembly, I used pin headers on the microcontroller, making it easier to solder the droplet-shaped fabric to it, while enabling the traces to be sewn later.

The LED was placed at the center of the fabric, with a 220Ω resistor connected to it. I used a LiPo battery as the power source, along with a diode to prevent reverse current flow. The positive terminal of the diode was connected to the positive terminal of the battery, while the diode negative terminal was connected to 5V on the microcontroller.

Additionally, I incorporated a touch sensor by sewing a spiral trace with conductive thread onto the conductive felted layer and connecting it to the touch pin of the microcontroller.



Unfortunately, as shown in the video above, the circuit wasn’t functioning properly. During troubleshooting, I identified that the conductive thread I used had low conductivity, leading to poor connections. I attempted the process again with a different thread, but the circuit still failed to work. The issue could be due to the connections between components or the traces themselves.

To diagnose the problem, I followed these troubleshooting steps:

  • Measure all connections with a multimeter to ensure they are continuous and viable.
  • Test the circuit with USB power instead of battery power.
  • Check the touch values using the serial monitor in the Arduino IDE.
  • Verify that all components are oriented correctly.
  • Inspect for any short circuits or unintended connections.


final circuit

circuit

After troubleshooting the circuit for its use as a wearable, I finalized the circuit shown in the image on the right. For the conductive traces, I used conductive fabric, which I adhered to Vliesofix using a heat press. Once secured, I carefully cut the fabric into droplet-shaped traces.

Next, I positioned the traces on the denim fabric, ensuring that no conductive pieces overlapped. Using an iron, I fused the traces securely to the denim. To connect the LED and the 220-ohm resistor to the microcontroller, I used insulated wires.

The power source was a 3.7V LiPo battery, which I connected to the back of the microcontroller. The microcontroller's designated + (positive) and - (negative) terminals were used for this, and I ensured polarity by using matching wire colors, red for positive and black for negative, consistent with the LiPo battery's wires.

For the fiber optics, after sanding them, I bundled the fibers together, securing them with tape at the end. To improve aesthetics, I covered the taped section with black heat shrink tubing, leaving an exposed section at the end for the fiber optics to interface with the LED.


schematic

Due to unforeseen challenges during the week, I had to finalize this project over the Christmas break. I brought home all the necessary components and materials, but unfortunately, I forgot to pack the microcontroller with touch-sensitive pins, which I had planned to use to make my brooch flower function as a touch sensor.

To adapt, I revised my approach and implemented a basic blinking code to activate the LED, allowing me to achieve a final result despite the absence of the touch sensor functionality. As shown in my schematic, I marked the original idea of a touch sensor in red, leaving it as a future enhancement.


CODE:

// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
delay(1000);                      // wait for a second
digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
delay(1000);                      // wait for a second
}


brooch flower result

For the flower composition, I used three different felted circles. Two of these were layered on top to form the flower petals, while the third served as a backing piece to hide the denim fabric with the circuit.

The step-by-step composition of the final design is shown in the photos below. To add texture and dimension to the petals, I made a few quick stitches on the top layer, enhancing its resemblance to real flower petals. For the other layers, including the denim fabric with the circuit, I stitched them together at key points, ensuring stability while leaving a small opening to connect and disconnect the LiPo battery.

To attach the brooch flower to a garment, I used a pin secured to the back of the design. This allows for easy removal and versatility. For a more permanent option, you can simply hand-sew the flower directly onto the fabric!


composition


final


future improvements

I am truly happy with the outcome of the wearable. Although I wasn’t able to execute the circuit as originally envisioned, I’m pleased with the design’s final look and feel there is significant potential for improvement. Below are some improvements I’d like to pursue in the future:

  • My initial goal was to incorporate a touch sensor so the LED would light up when the flower petals were touched. To achieve this, I would need to replace the current microcontroller with one that has touch-sensitive pins. Using conductive thread on the circle with the conductive fibers, I could create the necessary connections and troubleshoot as needed.

  • Expanding this concept into a modular system could be very exciting. Imagine having multiple flowers on the body that interact with each other, where touching one flower could turn the lights on or off in another. This interaction could create a dynamic and fun wearable.

  • While felt worked wonderfully for this project, providing a way to completely hide the circuit from any angle, I’d like to experiment with other materials. Since discovering needle felting during E-Textiles week, I’ve become a bit obsessed with felt, but I believe incorporating other fabrics or materials could yield equally interesting results.

  • The fiber optics worked well, but they were challenging to manage, as they tended to lean in one direction and were difficult to control. Finding a more effective way to bundle and secure the fiber optics would significantly enhance the final result. This would require further research and testing to achieve a cleaner, more manageable design.