Skip to content

9. Wearables

Research

Wearables week has been so anticipated! I spent most of e-textiles just trying to get my bearings so it is nice to be able to have a second go and really get to apply the things we have learnt and take them further. As I don't come from a fashion background the wearable element of this week is very exciting, I am interested in finding sleek solutions to hard soft connections and trying to make discreet circuits.

I am also SO excited to try motion outputs. I am interested in how I can align this with my interest in simple engineering mechanisms and automata to create kinetic sculptures.

moodboard

  1. Mika Satomi, Artificial Intelligence and it's false lies- an embroidered Artificial Neural Network.
  2. Casey Curran, Kinetic Fashion- Kinetic Fashion using pullies, hinges and gears.
  3. Maite Sosa Methol, Movimiento- : An interactive costume for amplified embodied performance through light output.
  4. Behnaz Farahi, Bodyscape-gyroscope recording shoulder movements controls LED output.
  5. Anastasia Pilepchuk, Kinetic Flower Mask-controlled by hand pulled strings.
  6. Casey Curran, White Sun Mask- I am inspired by the use of material in Curran's masks to make movement more dramatic.

In all these examples I am interested in the poetic connection between input and output and how electronic wearables can help draw attention to things that are embodied or invisible.

✙Documentation Workflow✙

This week we had to create:

  1. Wearable project which incorperates input and output in a fully integrated circuit.
  2. 2 actuator swatches.
Assignment Criteria: Week 8
  • Document your idea , sketches, references and research

  • 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

  • Upload a small video of your object working

  • EXTRA POINT Integrate it to a project

Top Tip!!!
  1. Make your pinout your desktop screensaver for the week....it helps!
Inspiration!!!
  • Anna Cain. Anna Cain's assignments for this week are just gorgeous! I ove how much she tried and that she also had time to make them aesthetically beautiful as well as functional!

  • Ninon Lizé Masclef. The fact this project was done in a week astounds me!

  • Riley Cox I love the concept behind this one!

✥WEARABLES WITH LIZA STARK✥

First of all we had our introductory lecture with Liza Stark in which she explained to us the different kind of actuators we could create. In e-textiles we had focused on inputs (buttons/sensors) but this week we would be focusing on how we can translate this into different kinds of output.

From Stark's introduction I was really interested in the idea that an electronic garment could be a form of playful communication, disrupting interaction and augmenting our senses in novel and silly ways. The relationship between input and output becomes a really creative space that could be fun, poetic or simply useful!

WHAT IS AN ACTUATOR?

An actuator is a component of a circuit that moves or controls another part based on input. These can be lots of things but this week we will focus on:

Visual:

moodboard

  1. LEDs: are ligth emitting diodes. They are easy to connect into a circuit and have many options for wearability and colour e.g through hole, RGB, Surface Mount, Sewable.

  2. Neopixels: come asstrips, rings, matrices or sewable neopixels. For more explaination see visual output section.

  3. Fiber Optics: have a clear internal core and an external coating called cladding. Light shines in one end, travels down the strand, and emerges at the other end. The intensity of glow depends on the intensity of the light source and they can either be end emitting or side emitting. They can be connected to the light source in various ways including drilling a hole, using glue or heat shrink.

  4. Thermochromic Ink: are pigments change state in the presence of heat. At a certain temperature they will become colourless or change colour. They can be mixed with substrates such as paint, gesso, glue etc. You can use the heat generated by electricity as the heating element.

Liza Stark demonstrates its behaviour in the video below:

Sound:

  1. Textile Speakers

Liza Stark takes you through different examples of textiles speakers in the video below. I will go into further detail on how they work in the Sound Output section of this documentation:

Motion

moodboard

Image from Liza Stark's Lecture Slides for Wearables (Fabricademy)

  1. Shape Memory Alloys: are metals that change shape when heated. They behave like regular metals when cool and return to preset shape when heated. This can create motions such as folding, curling or smocking. Examples of a SMA include Flexinol which can be trained (you can train the metal to return to a certain shape when heated) or untrained (will contract to 10% of its length when heated).

  2. Flip Dots: are magnetic beads connected to a coil. When current runs through the coil it creates an electromagnetic field that attracts or repels the bead based on the direction of the current.

  3. Haptics and Vibration Motors:is the use of touch feedback when you interact with your device. Vibration motors are small motors that vibrate. Most common vibration motors are ERM. ERM vibe motors have an off-centre load that causes vibrations when it rotates. This behaviour can be further controlled with the use of a driver.

I chose to explore each type of actuation in a swatch/ project:

✵VISUAL OUTPUT: NEOPIXELS✵

Neopixels are RGB LEDs with drivers embedded in them. This allows them to be individually addressable (controlled) and you can have many lights attached to only 1 pins on the microcontroller. So in terms of area on a wearable this is a very streamlined option.

Unlike LEDs they must be programmed through the microcontroller and you do need an EXTERNAL POWER SOURCE. You will have to calculate how much amperage you will need (to power via a wall supply or battery) depending on how many neopixels you are powering.

There are different types:

moodboard

Image taken from Lize Stark Slides for Wearables (Fabricademy).

  • Neopixel Strips
  • Neopixel Ring
  • Neopixel Matrices
  • Sewable Neopixels

◇Neopixel Adventures◇

First we needed to install the Neopixel Library in Arduino which gives us a range of example codes to learn with and adjust. We installed: Adafruit_NeoPixel.h 1.12.3.

Then we prepared our circuit.

Neopixels have 3 pins:

  1. Ground

  2. Data In / Data Out (neopixels have a direction)

  3. 5V

moodboard

We soldered jumper wires to the Ground, Data In and 5V pins.

We then set up the circuit and programmed the Arduino with a neopixel strip start up code as so:

moodboard moodboard

- Connect the neopixel in a breadboard to our Xiao ESP32S3 micro controller as in the schematic below:
- We connected Data in through a 390 ohm resistor to A0. We connected the ground on the neopixel to ground and the 5V on the neopixel to 3v3. 
- We also connected to A1 pin a LDR through a voltage divider created with a 10k ohm resistor. We then connected the LDR to ground and the 10k ohm resistor to 3v3.
    - /*
    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);
    }

Once we had the neopixel on we started to adapt the code to create different visual outputs.

Making the Neopixel dimmer and brighter via LDR:

- Connect the neopixel in a breadboard to our Xiao ESP32S3 micro controller as in the schematic below:
- We connected Data in through a 390 ohm resistor to A0. We connected the ground on the neopixel to ground and the 5V on the neopixel to 3v3. 
- We also connected to A1 pin a LDR through a voltage divider created with a 10k ohm resistor. We then connected the LDR to ground and the 10k ohm resistor to 3v3.
-  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
    }
    }
    - /*
    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, 500, 2500);  // Constrain to the expected range
    ldrValue = ldrValue / 10; // very rough filter, to remove some jitter

    int mappedLdr = map(ldrValue, 50, 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, 100, 0, 0, 255);

    // Light up the corresponding number of NeoPixels
    for (int i = 0; i < numPixels; i++) {
        if (i < numLitPixels) {
        strip.setPixelColor(i, strip.Color(0, 0, ldrColor));  // 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);
    }

Here is a video of this code working:

Turn neopixel from Blue to Pink via LDR:

- Connect the neopixel in a breadboard to our Xiao ESP32S3 micro controller as in the schematic below:
- We connected Data in through a 390 ohm resistor to A0. We connected the ground on the neopixel to ground and the 5V on the neopixel to 3v3. 
- We also connected to A1 pin a LDR through a voltage divider created with a 10k ohm resistor. We then connected the LDR to ground and the 10k ohm resistor to 3v3.
-  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
    }
    }
    - /*
        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, 500, 2500);  // Constrain to the expected range
        ldrValue = ldrValue / 10; // very rough filter, to remove some jitter

        int mappedLdr = map(ldrValue, 50, 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 ldrBlue = map(mappedLdr, 0, 100, 0, 255);
        int ldrRed = map(mappedLdr, 0, 100, 255, 0);

            strip.setPixelColor(0, strip.Color(ldrRed, 0, ldrBlue));  // Set lit pixels to blue
            strip.setPixelColor(1, strip.Color(ldrRed, 0, ldrBlue));  // Set lit pixels to blue

        // // Light up the corresponding number of NeoPixels
        // for (int i = 0; i < numPixels; i++) {
        //   if (i < numLitPixels) {

        // 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);

Cross fade neopixels between Blue and Pink:

- Connect the neopixel in a breadboard to our Xiao ESP32S3 micro controller as in the schematic below:
- We connected Data in through a 390 ohm resistor to A0. We connected the ground on the neopixel to ground and the 5V on the neopixel to 3v3. 
- We also connected to A1 pin a LDR through a voltage divider created with a 10k ohm resistor. We then connected the LDR to ground and the 10k ohm resistor to 3v3.
-      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
//   }
// }
- /*
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, 500, 2500);  // Constrain to the expected range
ldrValue = ldrValue / 10; // very rough filter, to remove some jitter

int mappedLdr = map(ldrValue, 50, 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 ldrBlue = map(mappedLdr, 0, 100, 0, 255);
int ldrRed = map(mappedLdr, 0, 100, 255, 0);

    strip.setPixelColor(0, strip.Color(ldrRed, 0, ldrBlue));  // Set lit pixels to blue
    strip.setPixelColor(1, strip.Color(ldrBlue, 0, ldrRed));  // Set lit pixels to blue

// // Light up the corresponding number of NeoPixels
// for (int i = 0; i < numPixels; i++) {
//   if (i < numLitPixels) {

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

Blue and Pink become green via LDR:

- Connect the neopixel in a breadboard to our Xiao ESP32S3 micro controller as in the schematic below:
- We connected Data in through a 390 ohm resistor to A0. We connected the ground on the neopixel to ground and the 5V on the neopixel to 3v3. 
- We also connected to A1 pin a LDR through a voltage divider created with a 10k ohm resistor. We then connected the LDR to ground and the 10k ohm resistor to 3v3.
-  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
//   }
// }
-/*
    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 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));

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

⚐ACTUATOR SWATCH⚐

Myself and Carolina then decided to make our first swatch based on this code. We adapted it so that we could use a Touch Sensor made from felted conductive wool to control the cross fade from Blue and Pink to Green.

We had learnt in E-textiles week how to use carding brushes to blend wool with small amounts of conductive fibres. This allowed us to create a needle felted conductive swatch that could function as a touch sensor. We used a embroidery hoop with stretched denim and a felting needle to make our sample. We then got to work connecting it into our neopixel circuit.

-  We set up the circuit as in all the other neopixel examples however we also connected our Conductive wool sample to the T2 pin on the Xiao ESP32S3:
- We used this code which we created by merging our touch sensor codes from E-textile week with the LDR/Neopixel Blue/Pink/Green Crossfade code we had just learnt. We did this with the kind help of Chat GPT:

#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);
}

moodboard moodboard moodboard

We were really pleased with the results of this swatch and the way the wool diffused the neopixel light. You can see how it worked in the video below:

☘︎SOUND OUTPUT: TEXTILE SPEAKERS☘︎

WHAT IS SOUND?

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

WHAT IS A SPEAKER?

To talk about speakers we need to talk about 2 different types of magnets:

  • Permenant Magnets :objects that generate a magnetic field which can attract and repel.

  • Electromagnetic Magnets: a type of magnet which works only when we have electricity flowing through it.

(When electric current runs through wire you get electromagnetism. If you coil the wire you get more surface area to amplify the magnetic field and you get a more powerful electromagnetic field)

To make a speaker you need a magnet, an electromagnet and a membrane that the sound wave can reverberate off of.

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

When you place that electromagnetic field next to a strong permenant magnet the electromagnetic field will attract and repel. This causes the membrane of your speaker (fabric, cone, object) to vibrate with the attraction and repulsion, causing the air to move and creating sound!

You can therefore make a textiles speaker by creating a electromagnet coil and a circuit to run current through it.

moodboard

Diagram by Kobakant, Fabric Speaker Swatch Example

Variables:

  • Coil tightness (tighter = stronger magnetic field = louder)
  • Material (stiffness and thickness of material impacts volume)
  • Magnet Size (Larger the magnet= louder the volume. Neodymium magnets are very powerful)
  • Magnet Placement (Closer the magnet to center of the coil= Louder)

The coil must have spaces between the traces and the trace has to be made of a CONDUCTIVE MATERIAL! But otherwise the way you create the coil is open to you.

Myself and Carolina decided to team up and make as many textile speakers as we could trying out different materials, shapes and tightnesses of coil.

moodboard

  1. Copper Thread Speaker, Hand couch stitched, loose round coil, small area.
  2. Conductive Tape, Medium Loose, Square coils, large area.
  3. Conductive Thread, Tight Square Coils, Embroidery Machined, large area.
  4. Conductive Thread, Tight Round Coils, Embroidery Machined, large area.
  5. Copper Wire, Very tight round coils, hand couch stitched, large area.
  6. Copper Wire, Loose round coils, hand stitched on fur. Small area.

We followed Liza Stark's Custom MonoAmp Tutorial for Textile Speakers for our set up. Each speaker was connected through the Adafruit PAM8302- Mono 2.5W Class D Audio Amplifier to 3 x AA batteries (4.5V) and an audiojack connected to a laptop. Through this set up we could use the speaker to amplify the audio we played on the laptop.

moodboard moodboard

Here is a video of the results. Unfortunately the quality of the audio recording doesn't convey the results accurately.

  1. No.1 didn't even make a sound that could be heard on camera.
  2. The conductive tape was actually really good and the area of the swatch helped with volume.
  3. About as loud as the conductive tape experiment. Audible without putting ear right to the speaker.
  4. Approximately as loud as the square coiled version.
  5. Very loud. Audible from a distance and carries bass very well.
  6. Also very loud. Heard without ear pressed to the speaker.

By far the best results were from No.5 This is owing to the copper wire, the tightness of the coils and large area. We had fun amplifying this speaker with a bowl and seeing how we could control the volume with the distance of the magnet from the coils center:

⚔︎MOTION OUTPUT: WEARABLE PROJECT WITH INTEGRATED INPUT/OUTPUT⚔︎

SERVO MOTOR:

A servomotors are small rotary or linear actuator. They are controlled by a pulse-width modulation (PWM) signal, which provides a series of pulses, the pulse lengths correspond to the desired position, angle or speed of the motor.

The ones we were using were either fixed (range of 180 degrees) or continuous (range of 360 degrees).

We started again with the Servo library in Arduino, we used Esp32 Servo 1.2.1 as newer versions of this library are incompatible with the Xiao ESP32S3. Here we uploaded an example sketch called Sweep. The code and set up is below:

- We set up our servo motor in a circuit. Connecting the Servo pin (yellow) to A0. Connect the servo ground (brown) to ground and servo power (red) to 3V3.
    -/* 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
    }
    }

moodboard moodboard

This established the basic motion of our servo motors.

LDR CONTROLLED SERVO MOTOR

Then we connected a LDR. The readings of the LDR are translated into Pulse Width Modulation which controls the angle of the Servo Motor.

moodboard moodboard

- For this we needed to make a voltage divider by connecting one leg of the LDR to pin A1. Also connect A1 through a 4.7k Ohm resistor to +3.3V.
    -/*
        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, 800, 2500);  // 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, 80, 250, 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);
        }

Here is a video of this set up in action:

✙INPUT/OUTPUT WEARABLE PROJECT✙

These experiments inspired my wearable project for this week. I knew I wanted to pair my interest in simple mechanics and automata with the servo motor to create interesting movements. I got to work sketching out some ideas and playing with paper, cardboard and wire to see what kind of movement I could create.

moodboard

Here is a short video of all the experiments I undertook. I first started with simple origami and then played with how I could create a pulley system.

I was really happy with a lot of these tests but only had time to flesh out one into a fully intergrated wearable project. I decided I wanted to create a sleeve with my robotic leaves pulley system. I wanted the wearer to be able to touch a sensor and effect the movement of the leaves on their arm.

I got to work trying to make this wearable.

  • I started by building my circuit on the breadboard. It would be exactly the same as our Servo motor/LDR experiments above in which the LDR readings are translated into PWM which determine the angle of the servo motor.

  • Then I drew out my connections with the FabriXiao board we were sent from FabLab Leon. These were roughly based on the Lilypad microcontrollers and are much more sewable and wearable than the basic Xiaoboards we had been using.

moodboard

  • I lasercut shapes out of fabric to mount my Fabrixiao board on. I sewed my conductive traces from each pin on the FabriXiao board that I needed. At the end of each trace I connected a snap button sewed to a peice of conductive fabric (to make an even stronger connection). This meant that anything I wanted connect just needed a snap button and it would connect well. This made my system modular for future wearable projects and adjustments to this system.

  • I similarly designed a snap button module with a LDR and 4.7k ohm resistor. This would be my Input/ Voltage Divider module which I wanted to sit on the shoulder of the wearer so they could easily touch the LDR.

  • I got sewing! Something I find incredibly hard and time consuming! So please forgive the ugliness and poor craftmanship you are about to see- its a working prototype OKAY!!

moodboard

moodboard

This was the result. I added a velcro strap so it could be fastened under the armpit, the battery falling behind and the LDR module falling forward over the shoulder.

  • I had to also make the motor wearbale. I decided to print a component from the Social Body Lab's Kinetic Wearable Toolkit to do this. I chose to 3D print their Servo Flex Base so that I could more easily attach the motor to the body (downloadable here)1

moodboard

I printed the base with 98A Fillimentum FlexFill on the Prusa i3 MK3S so that it would more easily bend to the body. With the power of hind sight I would make the bottom layers thinner so it had even more flex.

moodboard

I attached the servo with the base onto another velcro armband.

  • Now it was time to think about my robotic leaves. I wanted them to be 3D printed so I designed a model based on my cardboard trials in Rhino and then sliced them in Prusa Slicer. I ensured there were holes to sew them onto the garment and to thread the pulleys through them. You can download the gcode for this leaf below 2

moodboard

  • I printed this in 98A Fillimentum FlexFill and Transparent PLA to see which I could get to be the most flexible and light enough for the motor to pull. Here are the results:

moodboard

  • I sewed them onto a velcro armband also, making sure they were equidistant from each other.

moodboard

moodboard

Unfortunately, when I hooked this up to the motor with fishing line pulleys the motor could not pull the weight of the 3D printed leaves. I think this is a mixture of the leaves being to thick and rigid, the motor not being powerful enough and also the sewn connection between the leaf and the fabric arm band being too weak, especially when on the curve of the arm. This all made the motion I had achieve when they were made of cardboard and taped down on a flat table unmatchable.

  • In hope of getting some semblance of the motion I had achieved in my first experiments, I decided to attach the cardboard leaves to the motor and get the whole wearable system up and running.

moodboard moodboard moodboard

  • Then all that was left was to try it out!

Unfortunately the motion is still not as dramatic as it in my tabletop experiments. Some work will have to go into making the whole thing sturdy enough to move freely whilst attached to the curve of the arm. Similarly when not on a flat surface, the motor seemed to be weaker and the couldn't move the leaves as much. For this reason I plugged the whole system into my Laptop via USC cable to get the videos of the motion. The lypo battery is sufficient to move the leaves but the motion is less percievable.

I tried to overcome these details by changing the sensor values and the delay in the code in hopes to make the biggest motion I could based on the LDR readings. The code I ended up with is below:

        /*
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 <Servo.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, 440, 950);  // 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, 40, 90, 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(200);
}

And here is my final outcome by the end of the week. I really want to keep workshopping this project as it is now just a barely working protype but with a few adjustments I hope I can get even smoother, more dramatic movement.

There is so much to improve but this has been a ram-packed learning week and I am so excited about all the new possibilities wearables has given me.

Fabrication files