LEDs & gravity
Thursday, 1 October 2009
I thought it would be a nice touch if the LEDs in the Selleck Striker behaved more like the metal ringer in an old school mechanical hi-striker. So rather than rising up the scale in a linear way, what if it looked like the LED “ringer” was being pulled down by gravity (and friction, and air resistance) like the real thing?
So I figured an ascending object will decelerate in the same way a falling object will accelerate, since they’re both subjected to the same force (gravity). I found some formulas for acceleration due to gravity, particularly :
where d = distance, g = the gravitational constant, and t = time. I would calculate the trip from top to bottom as if the ringer was falling, then use that data in reverse.
The LEDs turn on in sequence, with a delay value in between to determine how long each one stays on (and how fast the “ringer” appears to move). So in order to determine that value I need to solve for t in the equation above. So:
I know that on Earth the gravitational constant — or g — is 9.8 m/s² (meters per second per second). I know the distance d between each LED is 1.37″, or .035m. So the time tx to get from the very top LED to the next one is:
So the first .035m step down from the top will take 59ms. In order to find tz for the second step, I need to find ty for the total distance from the top to the second step (.035m x 2 = .07m), then subtract tx for the first step:
So:
I need to do this for each of the 51 steps (50 LEDs plus the very top, the winner!). Actually, I’m not calculating this at all. I’ll let the Arduino do all the calculations, and save the delay value for each step in an array that it can quickly access when it needs to. Here’s how I did it in the Arduino script:
float gravity_constant = 9.8; // the constant of gravity, or G // we can adjust this to tweak the effect int gravity[50] = {}; // set up the gravity array for (int i = 1; i <= 51; i++) { // this will loop 51 times float distance_x = i * .035; // calculate the total distance from the top to the LED in question float distance_y = (i - 1) * .035; // same distance, minus one step float time_x = sqrt(distance_x / gravity_constant); // the time it takes for an object to fall distance_x meters float time_y = sqrt(distance_y / gravity_constant); // the time it takes for an object to fall distance_y meters float time = time_x - time_y; // the time it takes for an object to fall to our LED from the one before it, in seconds int time_ms = time * 1000; // convert to milliseconds gravity[i] = time_ms; // add this value to the gravity array }
The gravity array will look something like [59, 26, 16, 14, 13, 12, 11, 10, 9, etc…….], dropping rapidly at first and then slower until it levels off at 4ms or so. If we then light the LEDs in sequence, applying these delay values to each step:
int level = 48; // this is the level the person hit to // * entered manually for testing purposes, // in the final product this will be determined by // the force of the hammer strike for (int i = level; i > 0; i--) { digitalWrite(ledPins[level - i], HIGH); delay (gravity[i]); digitalWrite(ledPins[level - i], LOW); }
then we get something like this:
Note: the blinking at the beginning is the Arduino booting up, and the blinking at the end was added later to highlight the level of the hit.
No. 1 — December 31st, 2009 at 7:26 pm
It should be d = 1/2 g t^2
No. 2 — November 15th, 2010 at 8:14 am
Those floating point operations are not ideal.
You would be best using a spreadsheet to calculate the values and store them in array. It will speed things up nicely.