9. WEARABLES¶
In this week of WEARABLES, we are building on our knowledge of E-TEXTILES and using a micro controller to integrate electronics into a wearable device of some kind.
RESEARCH & INSPIRATION¶
There are some really cool Wearables being done by a few different fashion companies. I have a few examples below
Stone Island is ahead of the game with their Thermochromatic fabrics and garments
Junya Watanabe also has experimented with adding electronics into his work
I also looked into what is a growing industry of making garments or wearables that obfuscate surveillance systems.
one of which was a visor that disrupts AI ability to read faces.
TOOLS¶
- FABRIXIAO (seeed studio XIAO RP2040)
- NEOpixels
- Arduino Big Sound Sensor
- Gravity I2C 16x2 Arduino LCD with RGB Font Display (Black) V1.0
- Arduino Joystick
- ThermoChromatic pigment
- Brother Digital Embroidery Machine
ELECTRONIC PIN OUTS¶
SOFTWARE¶
- Arduino IDE
- Inkscape
- InkStich Extension
PROCESS AND WORKFLOW¶
I managed to fry my AdaFruit Flora somehow and so this week i switched to the FabriXiao
I first had to solder the micro controller to the board and learn the differences between the two different boards.
LED JOYSTICK¶
My First sample was a NEOpixel strip that I was controlling with a arduino joystick.
Depending on how I move the joystick it will change the Color and brightness of the LEDS.
If I click the button of the joystick it will also flash the LEDS and switch to a different mode where the LEDS blink while also still having the same color changing properties of the joystick.
CODE EXAMPLE 1¶
#include <Adafruit_NeoPixel.h>
// Define pin and number of pixels
#define PIN D5 // Pin for the 4-LED NeoPixel strip
#define NUMPIXELS 4 // Number of pixels in the strip
// Define joystick analog input pins
#define JOY_X A0 // X-axis pin of the joystick
#define JOY_Y A1 // Y-axis pin of the joystick
#define JOY_BTN D9 // Button pin of the joystick
// Create NeoPixel object
Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
// Define color states for the button press
int colorState = 0; // Used to cycle through colors when button is pressed
// Variables to store the actual center position of the joystick
int centerX = 512;
int centerY = 512;
// Flag to track the current mode
bool isMode1 = true; // Default to Mode 1 (Joystick controls RGB)
// Deadzone value (tolerance for joystick drift)
int deadzone = 100; // You can adjust this value for higher tolerance
// Color cycling states (you can add more colors here)
unsigned long colors[] = {
0xFF0000, // Red
0x00FF00, // Green
0x0000FF, // Blue
0xFFFF00, // Yellow
0xFF00FF, // Magenta
0x00FFFF // Cyan
};
void setup() {
// Initialize the NeoPixel strip
strip.begin();
strip.show(); // Clear the strip initially
// Set the joystick button pin as input
pinMode(JOY_BTN, INPUT_PULLUP); // Use the internal pull-up resistor
// Calibrate the joystick center
calibrateJoystick();
}
void loop() {
// Read the joystick X and Y axis values (0 to 1023)
int xValue = analogRead(JOY_X); // Read X-axis (left-right)
int yValue = analogRead(JOY_Y); // Read Y-axis (up-down)
// Check if the joystick button is pressed (button is LOW when pressed)
if (digitalRead(JOY_BTN) == LOW) {
// Toggle between Mode 1 and Mode 2 when the button is pressed
toggleMode();
delay(500); // Simple debounce to prevent multiple presses
}
if (isMode1) {
// In Mode 1, control RGB based on joystick movement
controlRGBWithJoystick(xValue, yValue);
} else {
// In Mode 2, control the color cycling with joystick
controlColorCycling(xValue, yValue);
}
delay(50); // Smooth transition delay
}
// Function to set color and brightness for all LEDs in the strip
void setStripColor(int r, int g, int b, int brightness) {
for (int i = 0; i < NUMPIXELS; i++) {
// Apply brightness scaling
int scaledR = r * brightness / 255;
int scaledG = g * brightness / 255;
int scaledB = b * brightness / 255;
strip.setPixelColor(i, strip.Color(scaledR, scaledG, scaledB));
}
strip.show(); // Update the strip with the new colors
}
// Function to control RGB blending using joystick (Mode 1)
void controlRGBWithJoystick(int xValue, int yValue) {
// Apply deadzone to eliminate small unwanted movements
if (abs(xValue - centerX) < deadzone) xValue = centerX;
if (abs(yValue - centerY) < deadzone) yValue = centerY;
// Calculate joystick movement with dead zone tolerance
int xMovement = abs(xValue - centerX); // Calculate absolute movement from center
int yMovement = abs(yValue - centerY);
// Calculate total movement (sum of X and Y) to determine brightness
int totalMovement = xMovement + yMovement;
// Map the total movement to brightness (0-255)
int brightness = map(totalMovement, 0, 1023, 0, 255);
brightness = constrain(brightness, 0, 255); // Ensure brightness is within 0-255
// Map X-axis to red and green channels, Y-axis to blue channel
int red = map(xValue, 0, 1023, 0, 255); // X-axis controls red
int green = map(yValue, 0, 1023, 0, 255); // Y-axis controls green
int blue = map(abs(xValue - yValue), 0, 1023, 0, 255); // Combined movement for blue
// Set the color and brightness of the NeoPixel strip
setStripColor(red, green, blue, brightness);
}
// Function to control color cycling using joystick (Mode 2)
void controlColorCycling(int xValue, int yValue) {
// Use the joystick's X and Y axis to adjust the color state
int xMovement = abs(xValue - centerX);
int yMovement = abs(yValue - centerY);
int totalMovement = xMovement + yMovement;
// Map movement to switch color states
int colorChangeRate = map(totalMovement, 0, 1023, 0, 5); // Adjust rate of color change
if (colorChangeRate > 0) {
colorState = (colorState + colorChangeRate) % 6; // Cycle through the colors
}
// Set all pixels to the color corresponding to the current state
setStripColor(
(colors[colorState] >> 16) & 0xFF, // Red
(colors[colorState] >> 8) & 0xFF, // Green
colors[colorState] & 0xFF, // Blue
255
);
}
// Function to toggle between Mode 1 and Mode 2 when the button is pressed
void toggleMode() {
isMode1 = !isMode1; // Toggle the mode
if (isMode1) {
// Clear strip when switching back to Mode 1
strip.clear();
strip.show();
}
}
// Function to calibrate the joystick center position
void calibrateJoystick() {
// Read the joystick values when it's at rest (before beginning the loop)
centerX = analogRead(JOY_X);
centerY = analogRead(JOY_Y);
// Add some delay to make sure we get the stable readings
delay(500); // Calibrate for half a second
Serial.print("Calibrated Center - X: ");
Serial.print(centerX);
Serial.print(" Y: ");
Serial.println(centerY);
}
DECIBLE COUNTER AND DISPLAY¶
My second sample was a decible counter connected to an LCD screen.
The big sound sensor is basically acting as a microphone to pick up noise from the surroundings.
The LCD screen then displays the decible level.
It also changes the backlight color at different decible levels.
CODE EXAMPLE 2¶
#include <Wire.h>
#include <DFRobot_RGBLCD1602.h> // Library for Gravity I2C LCD
#define SOUND_SENSOR_PIN A0 // Analog pin for Big Sound Sensor
const int sampleWindow = 50; // Time window for sound measurement (ms)
// LCD setup: Set I2C address (default: 0x27)
DFRobot_RGBLCD1602 lcd(/*RGBAddr*/0x60 ,/*lcdCols*/16,/*lcdRows*/2);
void setup() {
Serial.begin(9600);
// Initialize the LCD
lcd.init();
lcd.setRGB(0, 0, 255); // Set LCD backlight to blue (quiet)
lcd.setCursor(0, 0);
lcd.print("Decibel Meter");
delay(2000);
lcd.clear();
}
void loop() {
unsigned long startMillis = millis(); // Start of sampling window
unsigned int signalMax = 0;
unsigned int signalMin = 4095; // RP2040 ADC is 12-bit (0-4095)
// Measure sound level
while (millis() - startMillis < sampleWindow) {
int sample = analogRead(SOUND_SENSOR_PIN);
if (sample < 4096) { // Ensure value is within ADC range
if (sample > signalMax) signalMax = sample;
if (sample < signalMin) signalMin = sample;
}
}
unsigned int peakToPeak = signalMax - signalMin;
double voltage = (peakToPeak * 3.3) / 4095.0; // Convert ADC value to voltage
double decibels = 20 * log10(voltage / 0.00631); // Approximate dB calculation
// Update LCD
lcd.setCursor(0, 0);
lcd.print("dB: ");
lcd.print((int)decibels); // Display decibels as an integer
lcd.print(" "); // Clear trailing characters
// Change backlight based on decibel levels
if (decibels < 0) {
lcd.setRGB(0, 0, 255); // Blue (Quiet)
} else if (decibels < 10) {
lcd.setRGB(0, 255, 0); // Green (Moderate)
} else if (decibels < 16) {
lcd.setRGB(255, 105, 180); // Pink (Loud)
} else if (decibels < 25) {
lcd.setRGB(128, 0, 128); // Purple (Very Loud)
} else {
lcd.setRGB(255, 0, 0); // Red (Extremely Loud)
}
// Optional: Print to Serial Monitor
Serial.print("dB: ");
Serial.println(decibels);
delay(100); // Short delay for stability
}
THERMOCHROMATIC INK¶
For my third sample, I created a embroidery with conductive thread and coated it in thermochromatic ink.
Using the InkStich Extension for Inkscape I converted my logo into an embroidery file.
One issue I had was that I mistakenly used a fill function as inkscape was not treating my logo as a single line vector.
This caused my embroidery to be too densly packed with conductive thread, making the circut not complete / infinite.
With no clear start and end point the current takes the path of least resistance.
Even with the above problems I was able to get a pretty good effect with the thermocromatic ink
FUTURE¶
A quick sketch showing how I might iterate both electronic wearables into a garmet.
Left side: LED epaulette controlled by joystick integrated into breast pocket
Right side: decible counter LCD with electronics integrated into breast pocket