From 777f32b3af9bff8ace6eadf0b895b5f5ee886e93 Mon Sep 17 00:00:00 2001 From: Sophie Schiller Date: Tue, 16 Feb 2021 14:41:12 +0100 Subject: [PATCH] add jumping balls --- src/main.ino | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 3 deletions(-) diff --git a/src/main.ino b/src/main.ino index 7023734..c7216a0 100644 --- a/src/main.ino +++ b/src/main.ino @@ -9,12 +9,12 @@ #define LED_PIN 7 -byte mode = 2; // 0 for acceleration, 1 for fire, 2 for waterfall, 3 pride, 4 glitter, 5 off -const byte NUM_MODES = 6; +byte mode = 5; // 0 for acceleration, 1 for fire, 2 for waterfall, 3 pride, 4 glitter, 5 pulse, 6 off +const byte NUM_MODES = 8; const byte debug = 3; const byte STRIPS = 6; const byte NUM_LEDS = 10; -const byte FRAMES_PER_SECOND = 30; +const byte FRAMES_PER_SECOND = 60; const float range = 0.5; //accelleration range in g const byte BRIGHTNESS = 50; @@ -23,6 +23,18 @@ const byte SPARKING = 50; uint8_t gHue = 0; +const float GRAVITY = -9.81; // Downward (negative) acceleration of gravity in m/s^2 +const float h0 = 1; // Starting height, in meters, of the ball (strip length) +const byte NUM_BALLS = STRIPS; // Number of bouncing balls you want (recommend < 7, but 20 is fun in its own way) + +float h[NUM_BALLS] ; // An array of heights +float vImpact0 = sqrt( -2 * GRAVITY * h0 ); // Impact velocity of the ball when it hits the ground if "dropped" from the top of the strip +float vImpact[NUM_BALLS] ; // As time goes on the impact velocity will change, so make an array to store those values +float tCycle[NUM_BALLS] ; // The time since the last time the ball struck the ground +int pos[NUM_BALLS] ; // The integer position of the dot on the strip (LED index) +long tLast[NUM_BALLS] ; // The clock time of the last ground strike +float COR[NUM_BALLS] ; // Coefficient of Restitution (bounce damping) + float accelerationHistory [STRIPS]; MPU6050 mpu(Wire); @@ -56,7 +68,18 @@ void setup() { Serial.println(F("Calculating offsets, do not move MPU6050")); delay(1000); mpu.calcOffsets(true,true); // gyro and accelero + + for (int i = 0 ; i < NUM_BALLS ; i++) { // Initialize variables + tLast[i] = millis(); + h[i] = h0; + pos[i] = 0; // Balls start on the ground + vImpact[i] = vImpact0; // And "pop" up at vImpact0 + tCycle[i] = 0; + COR[i] = 0.90 - float(i)/pow(NUM_BALLS,2); + } + Serial.println("Done!\n"); + } float calculateOrientationData() { @@ -201,6 +224,66 @@ void drawGlitter(){ leds[pos] += CHSV( gHue + random8(64), 200, 255); } +void drawPulse(){ + static int current_step; + float steps = 2000; + CRGB color; + for (int strip = 0; strip < STRIPS; strip++){ + //float f = 0.5-0.5*cos(360/steps*float(current_step) + 360/steps*360/float(STRIPS)*float(strip)); + float f = cos(360/steps*float(current_step) + 360/steps*360/float(2*STRIPS)*float(strip)); + if (f < 0) f = 0; + color = CHSV(gHue , 255, int(255*f)); + for( int j = 0; j < NUM_LEDS; j++) { + int pixelnumber = (strip * NUM_LEDS) + j; + leds[pixelnumber] = color; + } + } + current_step++; +} + +void drawKunsisLila(){ + static int current_step; + float steps = 2000; + CRGB color; + for (int strip = 0; strip < STRIPS; strip++){ + float f = cos(360/steps*float(current_step) + 360/steps*360/float(2*STRIPS)*float(strip)); + if (f < 0) f = 0; + color = CHSV(224 , 255, int(255*f)); + for( int j = 0; j < NUM_LEDS; j++) { + int pixelnumber = (strip * NUM_LEDS) + j; + leds[pixelnumber] = color; + } + } + current_step++; +} + +void bounceBalls(){ + for (int i = 0 ; i < NUM_BALLS ; i++) { + tCycle[i] = millis() - tLast[i] ; // Calculate the time since the last time the ball was on the ground + + // A little kinematics equation calculates positon as a function of time, acceleration (gravity) and intial velocity + h[i] = 0.5 * GRAVITY * pow( tCycle[i]/1000 , 2.0 ) + vImpact[i] * tCycle[i]/1000; + + if ( h[i] < 0 ) { + h[i] = 0; // If the ball crossed the threshold of the "ground," put it back on the ground + vImpact[i] = COR[i] * vImpact[i] ; // and recalculate its new upward velocity as it's old velocity * COR + tLast[i] = millis(); + + if ((vImpact[i] < 0.01 ) && (calculateOrientationData()>1.5)) { + vImpact[i] = vImpact0; // If the ball is barely moving, "pop" it back up at vImpact0 + } + } + pos[i] = round( h[i] * (NUM_LEDS - 1) / h0); // Map "h" to a "pos" integer index position on the LED strip + } + + for (int i = 0 ; i < STRIPS*NUM_LEDS ; i++) { + leds[i] = CRGB::Black; + } + //Choose color of LEDs, then the "pos" LED on + for (int i = 0 ; i < NUM_BALLS ; i++) leds[(i * NUM_LEDS)+pos[i]] = CHSV( uint8_t (i * 40) , 255, 255); + //Then off for the next loop around +} + void drawOff(){ fadeToBlackBy( leds, STRIPS*NUM_LEDS, 10); } @@ -234,6 +317,15 @@ void loop() { drawGlitter(); } else if (mode == 5) { + drawPulse(); + } + else if (mode == 6) { + drawKunsisLila(); + } + else if (mode == 7) { + bounceBalls(); + } + else if (mode == 8) { drawOff(); } FastLED.show();