Introduction: The Suit (programmable, Interactive)

About: Hello! I’m a DevOps engineer working for a major German telecommunications provider. Alongside my professional responsibilities, I am dedicated to training the next generation of talent in our field. In my fre…

Last year I had the crazy idea to construct a suit with leds around my body. It should be programmable and interactive, so I started in November last year and here I show you the result.

Step 1: Requirements

materials:

- 2 * black Morphsuits

- 15 m WS2812B rgb led stripes ( 60 led´s / m )

- Arduino zero

- Prototype PCB for Arduino

- 2 * accelerometer sensors MPU-6050

- 0,96 I2C Serial-128X64 white blue OLED-LCD-LED

- sound detection module

- logic level converter

- 3 * 7,2V NiMH 5000mAh accu

- 3 * 5V 3A step down voltage regulator

- rotary encoder

- wires

- Tamiya plugs

- screws

- PLA filament

- heat shrink tube

- duck tape

- 3 * 4 pol plugs/sockets

- 5 pol plugs/sockets

tools:

- 3D printer

- soldering iron

- screwdrivers

- pincers

Step 2: The Suit With the Led´s

I wanted to have 4 led stripes per body part, so I measured the girth of all 4 positions on all 9 body parts. Together I had a length of 15 m. I cutted the led stripes, so that they fit to my body. I soldered the power pins parallel together and the data pins in a serial connection ( dataOut --> dataIn,dataOut --> dataIn, dataOut --> dataIn, and so on ... ) I used hot glue to protect the soldered pins.

One morphsuit is used to create the loops for all 36 led stripes. I got some help to sewing all the loops to the other morphsuit. My plan was to fix the loops on the inside of the morphsuit, but my sewer fixed it on the outside, so I had to improvise. I burned a little hole at the end of the 4. loop into the suit, so I was able to put the wires into the suit. I pushed the led stripes into the loops.

Step 3: The Controller Unit ...

Total I had 891 leds. The microcontroller spends 3 byte for every led, 1 byte for every color (RGB). So I need minimum 2673 byte of dynamic memory ( 3Byte * 891 led´s) + the memory for the variables.

https://www.arduino.cc/en/Products/Compare

There are not so many arduino boards which have more then 3kbyte of sram, so I decided to use the arduino zero. The zero works with 3.3V, the most parts (rotary encoder, 0.96 display, accelerometer sensors, sound detector) are working with 3.3V, only the leds are needing 5V, so I used a logic level shifter to controll the leds.

On picture 1 you can see the wiring of the controller. For all parts exists very good tutorials.

I used a prototype PCB to get a robust connection between arduino and parts, I used plugs and sockets to easily connect and remove the parts.

Connection of rotary encoder:

VCC --> 3.3V Zero
GND --> GND Zero
clkPin --> Pin 2 Zero
dtPin --> Pin 3 Zero
switchPin --> Pin 4 Zero

Connection of level shifter:

LowVCC --> 3.3V Zero
LowGND --> GND Zero
LowChannel 2 --> Pin 5
HighVCC --> 5V Stepdown
HighGND --> GND Stepdown
HighChannel 2 --> Led Stripe DataIN

Connection of MPU6050 & 0.96 Display:

VCC --> 3.3V Zero
GND --> GND Zero
SDA --> SDA Zero
SCL --> SCL Zero

The AD0 Pin of the second MPU6050 is connected to VCC, so that this unit get another I2C adress ...

Connection of sound detector:

VCC --> 3.3V Zero
GND --> GND Zero
AnalogOut --> Pin A0 Zero

With Fusion 360 I created a case which fits to my arm, in pic 2&3 you can see it fully assambled ...

Step 4: Programming: the Controller Part

If you have a lot of sensors and actors, you should never use "delay" to pause some action, during "delay" nothing will happen, it is better to do some kind of time control, like this:

last_do_this = millis();
last_do_that = millis();

void loop
{
  do_this();
  do_that();
  
  delay(1); // to get your arduino a pause to cool down ...
}

void do_this()
{
  if ( millis() - last_do_this < 50 )
  {
    return;
  }
  
  // do something

  last_do_this = millis();
}

void do_that()
{
  if ( millis() - last_do_that < 250 )
  {
    return;
  }
  
  // do something

  last_do_that = mills();
}

function do_this() runs every 50 ms and function do_that() every 250ms ... if one function needs more time, the other had to wait ...

Use of rotary encoder:

I searched for while before I found a good solution to use the encoder...

https://github.com/MajicDesigns/MD_REncoder

The most solutions did not work in high load cases, but this library works really good and if you take a look into the examples, you will see it is really easy to use ...

Use of MPU-6050:

http://playground.arduino.cc/Main/MPU-6050

https://github.com/jrowberg/i2cdevlib/tree/master/...

I read only the raw data of the Y axis and if the Y value exceed a threshold I trigger some action ...

Use of 0.96 inch display:

https://github.com/adafruit/Adafruit_SSD1306

This library works good and is easy to handle ...

display.setTextColor(WHITE);
display.setCursor(0,0);
display.setTextSize(2);
display.println( "mainmenue" );
display.display();

after a lot of problems I checked that the display.display() function needs 180 ms to update the display, so do not use this function to many times ...

Use of sound decoder:

This was the easiest thing, I read only the analog value from pin A0. Without any noise the value was 416/417, depending on the noise the value changed between 250 <-> 580. In depending of this values I active leds´s or not ...

Step 5: Programming: the Led Part

Use of the led stripe:

http://fastled.io/

https://github.com/FastLED/FastLED

All led stripes are connected together, so it is one big led stripe with 891 leds. I created an array with start and end addresses of every led stripe:

// the led addresses for every led stripe
const int ledblocks[][2] = { {0,16},  // 0 right lower arm 4
                    {17,31},          // 1 right lower arm 3
                    {32,45},          // 2 right lower arm 2
                    {46,56},          // 3 right lower arm 1
                    {57,78},          // 4 right upper arm 4
                    {79,97},          // 5 right upper arm 3
                    {98,115},         // 6 right upper arm 2
                    {116,132},        // 7 right upper arm 1
                    {133,166},        // 8 right upper leg 4
                    {167,195},        // 9 right upper leg 3
                    {196,222},        // 10 right upper leg 2
                    {223,248},        // 11 right upper leg 1
                    {249,270},        // 12 right lower leg 4
                    {271,291},        // 13 right lower leg 3
                    {292,309},        // 14 right lower leg 2
                    {310,324},        // 15 right lower leg 1
                    {325,358},        // 16 left upper leg 4
                    {359,387},        // 17 left upper leg 3
                    {388,414},        // 18 left upper leg 2
                    {415,440},        // 19 left upper leg 1
                    {441,462},        // 20 left lower leg 4
                    {463,483},        // 21 left lower leg 3
                    {484,500},        // 22 left lower leg 2
                    {501,515},        // 23 left lower leg 1
                    {516,532},        // 24 left lower arm 4
                    {533,547},        // 25 left lower arm 3
                    {548,561},        // 26 left lower arm 2
                    {562,572},        // 27 left lower arm 1
                    {573,594},        // 28 left upper arm 4
                    {595,613},        // 29 left upper arm 3
                    {614,631},        // 30 left upper arm 2
                    {632,648},        // 31 left upper arm 1
                    {649,708},        // 32 torso 5
                    {707,765},        // 33 torso 4
                    {766,826},        // 34 torso 3
                    {827,890} };      // 35 torso 2

so I am able to active every led stripe with the position number of the array, as example ledblocks[10] gives me the start and end adress of the right upper leg ... and a for loop do the rest ...

void enableLEDBlock(int ledbl )
{
  for(int i = ledblocks[ledbl][0]; i <= ledblocks[ledbl][1]; i++)
  { 
    leds[i] = CRGB::White;
  }
}

The clavilux mode:

In depending of the soundvalue of the sound detector I activate different led stripes ...

  if ( soundSensorValue < ( soundMinValue - ( 1 * soundMultiValue ))  || soundSensorValue > ( soundMaxValue + ( 1 * soundMultiValue )) )
  {
    enableLEDBlockGreen( 33 ); // torso 4
    enableLEDBlockGreen( 35 ); // torso 2
  }
  
  if ( soundSensorValue < ( soundMinValue - ( 2 * soundMultiValue ))  || soundSensorValue > ( soundMaxValue + ( 2 * soundMultiValue )) )
  {
    enableLEDBlockGreen( 32 ); // torso 5
    enableLEDBlockGreen( 8 ); // right upper leg 4
    enableLEDBlockGreen( 16 ); // left upper leg 4
  }
  
  if ( soundSensorValue < ( soundMinValue - ( 3 * soundMultiValue ))  || soundSensorValue > ( soundMaxValue + ( 3 * soundMultiValue )) )
  {
    enableLEDBlockGreen( 4 ); // right upper arm 4
    enableLEDBlockGreen( 28 ); // left upper arm 4
    enableLEDBlockGreen( 9 ); // right upper leg 3
    enableLEDBlockGreen( 17 ); // left upper leg 3
  }
  // and so on ...

The walking mode:

I read the raw Y value from both sensors which are mounted in the lower legs.

  accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  accelgyro2.getMotion6(&a2x, &a2y, &a2z, &g2x, &g2y, &g2z);

if the value over 25000 i set the first value of a shifting array to 1, I use some time magic to prevent bouncing ...

  //if the right leg moving, initiate a led wave
  if ( gy > 25000 )
  {
    gforce = gy;

    if ((millis() - last_right_tick) > 300 )
    {
      rightBody[0] = 1;
      last_right_tick = millis();
    }
  }
  
  //if the left leg moving, initiate a led wave
  if ( g2y < -25000 )
  {
    gforce2 = g2y;
    if ((millis() - last_left_tick) > 300 )
    {
      leftBody[0] = 1;
      last_left_tick = millis();
    }
  }

if the "walk mode" enabled I call every 75 ms a function which shift the array to left ...

// rotate the led shift register
void rotateArrays()
{
  for ( int i = 18; i >= 0; i-- )
  {
    leftBody[i + 1] = leftBody[i];
    rightBody[i + 1] = rightBody[i];
  }
  
  leftBody[0] = 0;
  rightBody[0] = 0;
}

so the following will happend:

{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
// and so on

in depending of the "1" in the array I active the related led stripe ... more than one wave at the same time is possible ...

The starlight mode:

this is just a simple function which randomly activate 50 led´s ...

void runFlash()
{
  blackall();
  for ( int i = 0; i <= 50; i++ )
  {
    leds[random(NUM_LEDS)] = CRGB::White;
  }
  FastLED.show();
  delay(1);
}

Step 6:

Make it Glow Contest 2016

Participated in the
Make it Glow Contest 2016

Sensors Contest 2017

Participated in the
Sensors Contest 2017