The best tools to make your project dreams come true

Login or Signup

Motion Controlled Wearable LED Dance Harness

By Sparkfun Electronics

Courtesy of SparkFun

Introduction

Continuing on from the last time, we are going to add an accelerometer to detect basic movements and control a 12V non-addressable LED strip for Mark III! Make your LEDs breathe by fading in and out when laying on the floor. Turn off the LEDs when moving to your side. Or make the LEDs blink in a headstand!

Motion Controlled Wearable LED Dance Harness

Required Materials

To follow along with this tutorial, you will need the following materials listed below to build one motion controller. This is assuming that you have already soldered wires to LED strips and a harness from the first tutorial. You may not need everything, depending on what you have. Add it to your cart, read through the guides, and adjust the cart as necessary.

Wishlist for Motion Controlled Wearable LED Dance Harness SparkFun Wish List

Tools

You will need a soldering iron, solder, general soldering accessories, and tools to work with wire.

You will also need:

Suggested Reading

If you do not have a harness or LED strips prepared, make sure you start with this tutorial before continuing. This tutorial builds on the project that was used in the previous tutorial.

Prototype Wearable LED Dance Harness

Prototype Wearable LED Dance Harness FEBRUARY 8, 2018

A project tutorial to add an extra effect for dancers performing a choreographed piece. The harness can be added quickly under a costume.

If you aren’t familiar with the following concepts, we also recommend checking out these tutorials before continuing.

Understanding Your Circuit

Initial Circuit

For the scope of this tutorial, we will be focusing on the motion controller and using the LED strips and custom harness from the previous tutorial. Green and red were chosen to make yellow from the primary colors. A low-G, triple-axis, analog accelerometer (ADXL335) was added to sense the orientation of a dancer. A 3.3V Arduino was added to read the analog sensor data and control the LED strips based on the readings. Since the LED strips are powered at 9V and require more current than the Arduino's I/O pins can source, an n-channel MOSFET was chosen to safely control the LED strips. A 10kΩ pull-down resistor was added between the gate and ground so that the transistor is not floating.

Understanding Your Circuit-Initial Circuit

Having a hard time seeing the circuit? Click here for a closer look.

A 9V battery and custom made motion controller were used for each harness. Keep in mind that a 9V battery is not able to power all three colors simultaneously. However, using two colors was sufficient enough for the project and performance.

Note: An analog accelerometer was chosen for simplicity. However, any digital accelerometer can work with the setup as long as you adjust the connection and code to communicate with the sensor. Make sure that the accelerometer is low-G so that it is sensitive enough to detect motion.

Note: When testing the non-addressable LED strip, the pin labeled "G" was actually blue and the "B" was actually green. Depending on the manufacturer, the label may vary. Try testing the LED strip out with a power supply to determine see if the letter represents the color.

Complete Circuit

After successful tests on a breadboard, the circuit was condensed and soldered to a mini-solderable breadboard. Components were added to both sides of the breadboard to take advantage of the space provided. The front view is shown below to illustrate the circuit. Keep in mind that the transparent components are mirrored images of the Arduino Pro Mini and barrel jack. The top view for each of these components would be facing outward on the other side. Additionally, the wires are soldered between the boards.

Complete Circuit

Having a hard time seeing the circuit? Click here for a closer look.

The back view is shown below to illustrate the circuit. Again, the transparent components are mirrored images of the accelerometer, resistor, and n-channel MOSFET. The top view for each of these components would be facing outward on the other side.

back view

Having a hard time seeing the circuit? Click here for a closer look.

Hardware Hookup

When soldering the n-channel MOSFET to the solderable breadboard, a piece of electrical tape was added to the exposed drain on the back of the MOSFET. While it was not necessary, it was a reminder to not solder any circuits under the exposed drain where it could make contact via the plated through holes.

Hardware Hookup

If you have not already, solder straight male headers on your Arduino Pro Mini 3.3V/8MHz. Also, make sure to solder straight headers to your ADXL335 accelerometer. Then solder the pieces together on the solderable breadboard and create the same connections with stripped wire as explained earlier. Wires terminated with a female header were used to connect to the LED strip's male headers. There are a lot of connections that need to be soldered so we’ll just skip ahead to the completed circuit. Your circuit will look similar to the images below.

completed circuit

Securing the Controller

Secure the Wires

Add some hot glue to secure the wires and components to the board. Special attention was given to the sensitive joints where the wires or components may break.

Secure the Wires

Secure the Wires and Motion Controller To Harness

To secure the wires, we follow the same process as last time. The only difference is that we are using a motion controller instead of the power adapter. Plug in the jumper wires of your choice and add some electrical tape to secure the headers. Wrap some tape around the motion controller to protect and secure the board further. To be consistent with the code, make sure that the back of the board is facing toward the dancer and the wires are extending down the harness as shown in the image. A second board was placed in the image for reference.

Secure the Wires and Motion Controller To Harness

Note: At this point, you can secure a battery to the ribbon located above the motion controller.

secure a battery to the ribbon

Once again, the user can slide the harness on like a backpack, tie the ribbons across the chest and waist, and plug in the battery to test. The image below shows the battery just before being secured to the ribbon located above the motion controller. To diffuse, we'll added a translucent button-up shirt over the LEDs.

slide the harness on like a backpack

Example Code

Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE. Also, make sure to check out the following tutorials before uploading code: How to Install FTDI Drivers and Using the Arduino Pro Mini 3.3V.

To read the sensor readings and control the LEDs, we’ll need to program the Arduino. Head over to the GitHub repository to download the project code. Make sure to download and unzip the contents in order to view the example code located in the … Motion-Controlled-Wearable-LED-Dance-Harness > Firmware > Arduino folder.

GIBHUB MOTION CONTROLLED WEARABLE LED DANCE HARNESS

Heads up! The sensor readings were calibrated and read when the dancer is static and not moving. You may notice that the LEDs will react when the dance jumps or is in motion!

Calibrating the Accelerometer

There are some slight tolerances so the output will not be exactly the same number for each axis. To calibrate each low-G accelerometer, we simply use gravity! Initial tests of the circuit were done on a breadboard and wires before soldering the circuit to a prototyping board.

Calibrating the Accelerometer

Note: While you can try to mount the sensor to a flat surface (like the ADXL345 digital accelerometer), I was able to observe the values by holding the accelerometer with a hand. Just make sure that your hand is not moving too much. Small movements can cause the values to amplify when tilting the sensor or when your hand is shaking.

Note: This is one method of calibrating your accelerometer. There are other methods that are explained online that can use complex calculations with code to automate the ADXL335's calibration for accuracy. However, I found that it was sufficient enough in my case to just observe the data and perform a 6-point calibration through brute force on each sensor.

Initial Testing

The code in MinionAccelerometerV2.0.ino was used to calibrate the accelerometer after soldering the circuit and observe raw sensor readings when the dancer is:

  • Standing/Right Side Up
  • Upside Down
  • On the Right Side
  • On the Left Side
  • On the Stomach
  • On the Back

I decided to have the LEDs on when the dancer is right-side up, blinking when upside down, off when on their sides, and fading in/out when on their back/stomach. Feel free to adjust the effects as necessary for your application.

Head to the folder containing the example code ( … Motion-Controlled-Wearable-LED-Dance-Harness > Firmware > Arduino > MinionAccelerometerV2.0.ino ) and open it up using the Arduino IDE. Make sure to select the Arduino Pro or Pro Mini as the board, ATmega328P (3.3V/8MHz) as the processor, and the COM port that the FTDI enumerated on. Then upload the code to the Arduino. After uploading, open the serial monitor to check out the raw output for each axis.

Note: Headers were not soldered on to the board when uploading and testing code. As long as you have contact between the FTDI and Arduino, code can still be uploaded and tested. The following images show the header making contact with the board for each reading. If necessary, you can solder headers to the board.

+X Component Readings Standing/Right Side Up

Angle the motion controller so that the ADXL335's ↑ X silkscreen is pointing up to determine when the dancer is standing or right side up. The example code has the LEDs staying on.

StandingRight Side Up

When the ↑ X is pointing up, you will get a value close to about ~600. The other values will read an average of ~500. We’ll want to know the maximum when this happens to control the LEDs so the sensor will need to be tilted slightly to verify.

Copy Code
Start Reading Accelerometer
Analog xPin (A0) = 589
Analog yPin (A1) = 512
Analog zPin (A2) = 481

Analog xPin (A0) = 610
Analog yPin (A1) = 514
Analog zPin (A2) = 510

Analog xPin (A0) = 608
Analog yPin (A1) = 515
Analog zPin (A2) = 509

In this case, 610 appeared to be the maximum value for X while the sensor is not moving.

-X Component Readings Upside Down

Angle the motion controller so that the ADXL335's ↑ X silkscreen is pointing down to determine when the dancer is upside down. The example code has the LEDs blinking.

Upside Down

When the ↑ X silkscreen is pointing down, you will get a value close to about ~400. The other values will read an average of ~500 again. We will need to tilt the sensor slightly to verify the minimum.

Copy Code
Analog xPin (A0) = 409
Analog yPin (A1) = 502
Analog zPin (A2) = 501

Analog xPin (A0) = 402
Analog yPin (A1) = 504
Analog zPin (A2) = 497

Analog xPin (A0) = 403
Analog yPin (A1) = 506
Analog zPin (A2) = 499

In this case, 402 appeared to be the minimum value for X when the sensor is not moving.

+Y Component Readings On the Right Side

Angle the motion controller so that the ADXL335's ← Y silkscreen is pointing up to determine when the dancer is on their right side. The example code has the LEDs turning off.

On the Right Side

When the  ← Y silkscreen is pointing up, you will get a value close to about ~612. The other values will read an average of ~500. Tilt the sensor slightly to verify the maximum.

Copy Code
Analog xPin (A0) = 515
Analog yPin (A1) = 610
Analog zPin (A2) = 517

Analog xPin (A0) = 515
Analog yPin (A1) = 612
Analog zPin (A2) = 515

Analog xPin (A0) = 514
Analog yPin (A1) = 611
Analog zPin (A2) = 517

In this case, 612 appeared to be the maximum value for Y when the sensor is not moving.

-Y Component Readings On the Left Side

Angle the motion controller to its side so that the ADXL335's ← Y silkscreen is pointing down to determine when the dancer is on their left side. The example code has the LEDs turn off as well.

On the Left Side

When the ← Y silkscreen is pointing down, you will get a value close to about ~400. The other values will read an average of ~500 again. We will tilt the sensor once again slightly to verify the minimum.

Copy Code
Analog xPin (A0) = 506
Analog yPin (A1) = 403
Analog zPin (A2) = 515

Analog xPin (A0) = 512
Analog yPin (A1) = 402
Analog zPin (A2) = 514

Analog xPin (A0) = 508
Analog yPin (A1) = 404
Analog zPin (A2) = 515

In this case, 402 appeared to be the minimum value for Y when the sensor is not moving.

+Z Component Readings On the Back

Lay the sensor so that the ADXL335's • Z silkscreen is facing up to determine when the dancer is on their back. The example code has the LEDs fading in and out.

On the Back

When the • Z silkscreen is facing up, you will get a value close to about ~600. The other values will read an average of ~500 again. Tilt the sensor slightly to verify the maximum.

Copy Code
Analog xPin (A0) = 507
Analog yPin (A1) = 509
Analog zPin (A2) = 609

Analog xPin (A0) = 511
Analog yPin (A1) = 509
Analog zPin (A2) = 611

Analog xPin (A0) = 514
Analog yPin (A1) = 506
Analog zPin (A2) = 609

In this case, 611 appeared to be the maximum value for Z when the sensor is not moving.

-Z Component Readings On the Stomach

Lay the sensor so that the ADXL335's • Z silkscreen is facing down to determine when the dancer is on their stomach. The example code has the LEDs fading in and out.

-Z Component Readings On the Stomach

When the • Z silkscreen is facing down, you will get a value close to about ~400. The other values will read an average of ~500 again. Tilt the sensor slightly to verify the minimum.

Copy Code
Analog xPin (A0) = 494
Analog yPin (A1) = 516
Analog zPin (A2) = 406

Analog xPin (A0) = 495
Analog yPin (A1) = 515
Analog zPin (A2) = 403

Analog xPin (A0) = 495
Analog yPin (A1) = 514
Analog zPin (A2) = 404

In this case, 403 appeared to be the minimum value for Z when the sensor is not moving.

Adjusting Boundaries for Detecting Orientation

We’ll need to tweak those values to make sure that the accelerometer used matches the setup. Using the values obtained from calibration, the condition statements to control the LEDs were adjusted from the following lines of code:

Copy Code
  //X-X-X-X-X-X-X | READ xAxis | X-X-X-X-X-X-X
//LEDs ON
if (xRead > 605) {
//...

//LEDs Blinking
if (xRead < 411) {
//...

//Y-Y-Y-Y-Y-Y-Y | Read yAxis | Y-Y-Y-Y-Y-Y-Y
//LEDs OFF
if (yRead > 607 || yRead < 409 ) {
//...

//Z-Z-Z-Z-Z-Z-Z | read zAxis | Z-Z-Z-Z-Z-Z-Z
//
if (zRead > 610 || zRead < 425) {
//...

To the maximum and minimum values obtained for each component:

Copy Code
  //X-X-X-X-X-X-X | READ xAxis | X-X-X-X-X-X-X
//LEDs ON
if (xRead > 610) {
//...

//LEDs Blinking
if (xRead < 402) {
//...

//Y-Y-Y-Y-Y-Y-Y | Read yAxis | Y-Y-Y-Y-Y-Y-Y
//LEDs OFF
if (yRead > 612 || yRead < 402) {
//...

//Z-Z-Z-Z-Z-Z-Z | read zAxis | Z-Z-Z-Z-Z-Z-Z
//
if (zRead > 611 || zRead < 403) {
//...

Whew. That was a bit tedious. We’re not done yet though!

Solder, Rinse, Secure, Test, Code, Repeat...

Well, we have one accelerometer calibrated for one dancer. Which is great. Except there were a total of 8x dancers. The process outlined above needed to be repeated 7x more times.

Solder, Rinse, Secure, Test, Code, Repeat

I was not sure what to expect until after observing each accelerometer. Rather than having multiple sketches for each dancer, it was decided to make a condition statement that jumped to a modular function called calibrationADXL335() that contained each calibration just before uploading the code. Here’s part of the code written for the MinionAccelerometerV2.1.ino sketch.

Copy Code
//...
void calibrationADXL335() {
//function to calibrate ADXL335 accelerometers due to manufacturing tolerances
//read the values sent through the Arduino serial monitor to determine the values
//when calibrating. adjust the values accordingly. the values in the brackets are
//the min/max values used for the condition statements
if (calibration_M == 1) {
xUp = 540; //xRead > xUp, ...~ [550]-580 at REST
xDown = 488; //xRead < xDown, it's ~437-[488] at REST
yUp = 544; //yRead > yUp, it's ~[544]-580 at REST
yDown = 480; //yRead < yDown, it's ~445-[480] at REST
zUp = 608; //zRead > zUp, it's ~[608]-642 at REST
zDown = 435; //zRead < zDown, it's ~414-[435] at REST
}
else if (calibration_M == 2) {
xUp = 570; //xRead > xUp, ...~ [570]-607 at REST
xDown = 436; //xRead < xDown, it's ~405-[436] at REST
yUp = 610; //yRead > yUp, it's ~[610]-610 at REST
yDown = 430; //yRead < yDown, it's ~407-[430] at REST
zUp = 613; //zRead > zUp, it's ~[592]-619 at REST
zDown = 440; //zRead < zDown, it's ~410-[440] at REST
}
else if (calibration_M == 3) {
xUp = 590; //xRead > xUp, ...~ [590]-607 at REST
xDown = 436; //xRead < xDown, it's ~404-[436] at REST
yUp = 601; //yRead > yUp, it's ~[601]-610 at REST
yDown = 419; //yRead < yDown, it's ~405-[418] at REST
zUp = 592; //zRead > zUp, it's ~[592]-619 at REST
zDown = 430; //zRead < zDown, it's ~410-[430] at REST
}
else if (calibration_M == 4) {
xUp = 585; //xRead > xUp, ...~ [585]-604 at REST
xDown = 424; //xRead < xDown, it's ~407-[424] at REST
yUp = 598; //yRead > yUp, it's ~[598]-607 at REST
yDown = 420; //yRead < yDown, it's ~405-[420] at REST
zUp = 615; //zRead > zUp, it's ~[615]-622 at REST
zDown = 441; //zRead < zDown, it's ~421-[441] at REST
}

else if (calibration_M == 5) {
xUp = 590; //xRead > xUp, ...~ [590]-607 at REST
xDown = 437; //xRead < xDown, it's ~408-[437] at REST
yUp = 598; //yRead > yUp, it's ~[598]-610 at REST
yDown = 412; //yRead < yDown, it's ~407-[412] at REST
zUp = 600; //zRead > zUp, it's ~[600]-620 at REST
zDown = 431; //zRead < zDown, it's ~421-[431] at REST
}
else if (calibration_M == 6) {
xUp = 580; //xRead > xUp, ...~ [580]-610 at REST
xDown = 413; //xRead < xDown, it's ~404-[413] at REST
yUp = 601; //yRead > yUp, it's ~[595]-605 at REST
yDown = 411; //yRead < yDown, it's ~405-[411] at REST
zUp = 607; //zRead > zUp, it's ~[607]-625 at REST
zDown = 430; //zRead < zDown, it's ~418-[430] at REST
}
else if (calibration_M == 7) {
xUp = 585; //xRead > xUp, ...~ [585]-607 at REST
xDown = 429; //xRead < xDown, it's ~407-[429] at REST
yUp = 603; //yRead > yUp, it's ~[603]-611 at REST
yDown = 419; //yRead < yDown, it's ~407-[420] at REST
zUp = 605; //zRead > zUp, it's ~[605]-618 at REST
zDown = 434; //zRead < zDown, it's ~411-[434] at REST
}
else if (calibration_M == 8) {
xUp = 585; //xRead > xUp, ...~ [585]-607 at REST
xDown = 436; //xRead < xDown, it's ~405-[436] at REST
yUp = 593; //yRead > yUp, it's ~[593]-615 at REST
yDown = 420; //yRead < yDown, it's ~407-[420] at REST
zUp = 595; //zRead > zUp, it's ~[595]-614 at REST
zDown = 440; //zRead < zDown, it's ~411-[440] at REST
}
else {

xUp = 585; //xRead > xUp, ...~ [585]-607 at REST
xDown = 436; //xRead < xDown, it's ~405-[436] at REST
yUp = 601; //yRead > yUp, it's ~[601]-615 at REST
yDown = 419; //yRead < yDown, it's ~404-[419] at REST
zUp = 616; //zRead > zUp, it's ~[616]-642 at REST
zDown = 440; //zRead < zDown, it's ~410-[440] at REST
}

//
/*
* //calibration with tech support ADXL335.
//default calibration_M = 0
//default calibration for quick test of the adapter board
xUp = 605; //xRead > xUp, it's~[600]-604 at REST
xDown = 411; //xRead < xDown, it's ~399-[411] at REST
yUp = 607; //yRead > yUp, it's ~[607]-612 at REST
yDown = 409; //yRead < yDown, it's ~395-[409] at REST
zUp = 610; //zRead > zUp, it's ~[610]-618 at REST
zDown = 425; //zRead < zDown, it's ~ 410-[425] at REST
*/

}

It was interesting to see that most of the values were close to the first calibration. However, there were a few values that deviated slightly and needed to be adjusted with respect to the accelerometer. When testing the controller during a rehearsal, I noticed that the accelerometer was not positioned perfectly on each dancer. Depending on how tightly the harness was tied, the accelerometer was sometimes loose and not moving perfectly with the dancer. I also noticed that the dancer was not moving perfectly onto their sides as planned. The moves that I imagined to be on their side were actually more at a 45° angle with respect to where the sensor was attached. Certain patterns started triggering as if the dancer was on the left side, stomach, or right side.

With all these conditions in mind, I had to add some padding instead of using the exact maximum/minimum values to trigger the LEDs as expected. I also had to be aware of how tightly the harness was secured for each dancer. Whew, that was exhausting.

Stress Testing in the Field

Benchtop Tests

I tested the harnesses with the new motion controller using a benchtop power supply again for about 60 minutes. At 9V with the motion controller and 78x LEDs, the circuit pulled about ~452mA. At 9V with the motion controller and 90x LEDs (one of my students was a bit taller than the others), it pulled about ~485mA.

Studio Tests

I then tried it out at a studio with choreography using 9V batteries. As noted earlier, I had to add some padding and be aware of how tightly the harness was secured for each dancer so that the LEDs would trigger as expected. Here’s a quick demo of it in action.

choreography using 9V batteries

Dress Rehearsal

After testing and adjusting the code several times, everything went as planned during their dress rehearsal!

Dress Rehearsal

Dress Rehearsal2

Show Time!

With fresh batteries, everything went as planned during the show! I also had some extra batteries, multimeter, tape, and scissors in case I needed to do some last minute troubleshooting.

Show Time

While I am not able to share the performance with the music, here's some footage of the controller in action backstage! Just ignore my obnoxious voice screaming with excitement behind the camera.

INSTAGRAM: SHORT BACKSTAGE DEMO

Making It Better

There’s always room for improvement. I was only able to include the option for sensor control from the last time due to time constraints. I would probably explore additional upgrades and improvements on top of the initial list.

  • Once Sided Circuit – It was difficult working with the circuit on two sides of the prototyping board. While it was condensed, reworking parts of the board and wiring the circuit was tedious.
  • Printed Circuit Board – Stripping and soldering wires seemed pretty tedious. Designing and printing circuit boards would be faster if I decide to continue building the motion controller.
  • Calibration Methods – The 6-point calibration process seemed tedious. While it was interesting to view the data and differences between accelerometers, using a different calibration method and automating the process would have been better.
  • Combining the Accelerometer with a Gyro – While the accelerometer is good at determining the object's orientation when static, the reading was a bit noisy when the dancer was moving. I’d probably add a gyro to measure rotation to work with the accelerometer. Using both sensors combined make a inertial measurement unit (IMU) and should interpret the data better.
  • Using Different Sensors – Instead of using an accelerometer as the sensor, it would be neat to try a sound detector to trigger on beat.

For Mark IV and Mark V, I was able to explore some the following options.

  • Expanding to the Legs and Arms – Only the body was lit up. However, the arms and legs could use some lights. It would be cool to extend the LEDs on the arms and legs. This was actually easier to do in Mark IV using EL Wire.
  • Wireless Control – Using some XBees, it would be cool to wirelessly toggle between users or sensor control. This was explored in the Mark IV build.
  • Combining EL with LEDs – It was not until mark Mark V that I was able to add this feature.

Resources & Going Further

For more information, check out the resources below.

Key Parts and Components

Add all Digi-Key Parts to Cart
  • FQP30N06L-ND
  • CF14JT10K0CT-ND
  • 1568-1054-ND
  • 1988-1162-ND
  • 1568-1104-ND
  • 1568-1083-ND
  • 1568-1044-ND
  • WE1010NA-ND
  • K604-ND
  • MS543JVN-ND
  • 243-1324-ND
  • SMD2SWLF.0314OZ-ND