Front view of the turn stability tracker in its ready status.
This project helps me to be more accountable in my dance turn technique training by giving me audible and visual cues when I am off center in a turn. This device's main components are an accelerometer that tracks the turn axis (x, y, and z) and an active buzzer to notify the user when they are off center in the turn. A potentiometer is also included to adjust the sensitivity of the accelerometer, and the LED strip aesthetically updates according to the turn's status.
An overall picture of the device for proportion and scale; it is in a ready status, shown by the bright blue.
All of the electronic components mounted onto the belt using zip ties, along with them being connected to a battery pack.
A close-up of the finished electronic parts of my project. I decided to solder about half of the components in order to ensure movement affects them as little as possible
A look at the device when it is in a "turning" state, with the LED strip glowing in rainbows based on the accelerometer position.
In this video, I demonstrate how the device works the potentiometer and active buzzer. Being off a certain axis will trigger the LED strip to go into flashing rainbow colors, as it usually stands for being in a turn. Then, the LED strip will flash red if the active buzzer was going off at any time during the turn, and green otherwise.
The first round of wiring with the accelerometer and potentiometer, with the potentiometer controlling the threshold of the accelerometer's values.
Testing with the accelerometer and potentiometer to determine suitable baseline values and a threshold.
Wiring up the battery pack to the main device after fulling incorporating the active buzzer.
Mounting everything onto the physical belt, including the LED strip that was wired back to the original mechanism.
An aspect that was quite challenging for me wiring up the battery pack & LED correctly and mounting everything onto a piece of wearable tech. For a while, I kept accidentally disabling my computer's USB port because my code included a section that took more power from the Arduino than it had (the LED strip section), making my port go into safe mode for a few minutes at a time. As for powering the LED strip, I actually melted a battery pack in the process because I placed the batteries inside then left it in a position where the red and black wires' tips touched. Moreover, determining the dimensions and where the components would be best mounted was pretty difficult and required a lot of trial and error.
At large, I'm pretty satisfied with the process and how my project turned out in the end. I ran into many challenges throughout the process, and I was really exposed to the difficulties of creating a wearable device, such as controlling the wiring and mounting everything onto a physical object to sustain movement.
In the in-class crit, I received a response saying "a screen with a simple statement suggesting an improvement would be cool." I agreed and felt that way too; I actually had an LCD screen on one of my very first prototypes, but I ultimately felt that it was just too much to mount with everything else. Another response I received was, "I see how making a casing around the electronics now would make it bulky but I agree with the point of making your electronics more compact in future iterations." I also agree with this point, and I originally wanted to create a 3D printed encasing for the electronic components. However, it ultimately seemed to be difficult, especially for a wearable piece of tech.
I learned a lot about being outside the comfort zone of my abilities on this project. With it being a wearable device, using battery packs, and including some components that I haven't previously worked with, I really had to push my limitations and adapt to all the new material. I found some of the programming aspects to be challenging as well, especially with coding the accelerometer and LED strip to behave exactly how I want them to. The logic behind the accelerometer connecting to the active buzzer and the LED strip was complicated, especially with the conditionals involved with the different light conditions.
As for my next steps, I don't think I would build another iteration of this project. However, if I were to create a new iteration I would try implementing some form of a flexible housing for my electronic components. I would also try to store all of the parts in a more compact way.
/*
60-223 Introduction to Physical Computing, Spring 2026
Project 2 - Assistive Device: Turn Stability Tracker
Author: Genie Tang
This sketch connects to an accelerometer and an LED to measure vibration and generate
an output to the LED in response to it. Its function is to measure the movemente of the
accelerometer relative to its original position, map that vibration to a level from 1 to 10,
and control the brightness of the LED based on how strong vibration is.
Pin mapping:
Arduino pin | role | details
------------------------------
A0 input XPin
A1 input YPin
A2 input ZPin
A3 input Potentiometer Pin
3 output LED Pin
6 output Buzzer Pin
*/
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
// set up pin assignments
const int XPIN = A0;
const int YPIN = A1;
const int ZPIN = A2;
const int POTPIN = A3;
const int BUZZERPIN = 6;
const int LEDPIN = 3;
const int NUMPIXELS = 28;
Adafruit_NeoPixel strip(NUMPIXELS, LEDPIN, NEO_GRB + NEO_KHZ800);
// baseline values when upright
int xCenter = 415;
int yCenter = 355;
int zCenter = 385;
// turn timer vars
bool turning = false;
unsigned long turnStartTime = 0;
unsigned long turnEndTime = 0;
unsigned long stableStartTime = 0;
float turnTimeSeconds = 0.0;
// led strip vars
bool wasTurning = false;
bool flashResultActive = false;
bool flashGreen = false;
unsigned long flashStartTime = 0;
unsigned long lastFlashToggle = 0;
bool flashOn = false;
int rainbowOffset = 0;
bool offCenterDuringTurn = false;
void setup() {
pinMode(XPIN, INPUT);
pinMode(YPIN, INPUT);
pinMode(ZPIN, INPUT);
pinMode(POTPIN, INPUT);
pinMode(BUZZERPIN, OUTPUT);
digitalWrite(BUZZERPIN, LOW);
strip.begin();
strip.setBrightness(30);
strip.show();
Serial.begin(9600);
}
// helper fxns
void setAllPixels(uint32_t color) {
for (int i = 0; i < NUMPIXELS; i++) {
strip.setPixelColor(i, color);
}
strip.show();
}
uint32_t wheel(byte pos) {
pos = 255 - pos;
if (pos < 85) {
return strip.Color(255 - pos * 3, 0, pos * 3);
}
if (pos < 170) {
pos -= 85;
return strip.Color(0, pos * 3, 255 - pos * 3);
}
pos -= 170;
return strip.Color(pos * 3, 255 - pos * 3, 0);
}
// shows blue on led strip
void showBlueReady() {
setAllPixels(strip.Color(0, 0, 255));
}
// shows rainbow wave on led strip
void showRainbowWave() {
for (int i = 0; i < NUMPIXELS; i++) {
int pixelIndex = (i * 256 / NUMPIXELS + rainbowOffset) & 255;
strip.setPixelColor(i, wheel(pixelIndex));
}
strip.show();
rainbowOffset = (rainbowOffset + 6) & 255;
}
// led strip flashes green or red depending on turn quality
void startResultFlash(bool success) {
flashResultActive = true;
flashGreen = success;
flashStartTime = millis();
lastFlashToggle = millis();
flashOn = true;
}
void updateResultFlash() {
if (!flashResultActive) return;
// toggle flash every 150 ms
if (millis() - lastFlashToggle >= 150) {
lastFlashToggle = millis();
flashOn = !flashOn;
}
if (flashOn) {
if (flashGreen) {
setAllPixels(strip.Color(0, 255, 0));
} else {
setAllPixels(strip.Color(255, 0, 0));
}
} else {
setAllPixels(strip.Color(0, 0, 0));
}
// flash for about 1.2 seconds, then return to blue
if (millis() - flashStartTime >= 1200) {
flashResultActive = false;
showBlueReady();
}
}
void loop() {
int xValue = analogRead(XPIN);
int yValue = analogRead(YPIN);
int zValue = analogRead(ZPIN);
int potValue = analogRead(POTPIN);
// sensitivity threshold controlled by potentiometer
int threshold = map(potValue, 0, 1023, 10, 80);
// original tilt amount for LED/buzzer feedback
int tiltAmount = abs(xValue - xCenter) + abs(yValue - yCenter);
int zThreshold = 25;
// z axis movement for turn timing
int zAmount = abs(zValue - zCenter);
// test prints to control
Serial.print("X: ");
Serial.print(xValue);
Serial.print(" Y: ");
Serial.print(yValue);
Serial.print(" Z: ");
Serial.print(zValue);
Serial.print(" Pot: ");
Serial.print(potValue);
Serial.print(" Threshold: ");
Serial.print(threshold);
Serial.print(" Tilt: ");
Serial.print(tiltAmount);
Serial.print(" Zdiff: ");
Serial.print(zAmount);
if (zAmount > zThreshold) {
if (!turning) {
turning = true;
turnStartTime = millis();
offCenterDuringTurn = false;
}
stableStartTime = 0;
} else {
if (turning) {
if (stableStartTime == 0) {
stableStartTime = millis();
}
if (millis() - stableStartTime > 300) {
turning = false;
turnEndTime = millis();
turnTimeSeconds = (turnEndTime - turnStartTime) / 1000.0;
}
}
}
// feedback logic
if (tiltAmount > threshold) {
Serial.println(" OFF CENTER");
digitalWrite(BUZZERPIN, HIGH);
offCenterDuringTurn = true;
} else {
Serial.println(" STABLE");
digitalWrite(BUZZERPIN, LOW);
}
// detect the moment a turn just finished
if (wasTurning && !turning) {
startResultFlash(!offCenterDuringTurn);
}
// choose led behavior by state
if (turning) {
flashResultActive = false;
showRainbowWave();
} else if (flashResultActive) {
updateResultFlash();
} else {
showBlueReady();
}
wasTurning = turning;
delay(50);
}