Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!




How to double the b...
 
Share:
Notifications
Clear all

How to double the bouncy ball effect?

Page 2 / 3

 Hans
(@hans)
Noble Member Admin
Joined: 9 years ago
Posts: 2187
 

Woops, pressed ENTER too fast.

So the idea is: a ball in the original bouncing balls code is 1 LED.
To make it more visible, I added a function "DrawBall", which draws an individual ball at a given location.
The position on the LED strand is the center of the ball.

We additionally pass it the ball colors (red, green, blue), how much the additional LEDs should dim in brightness, and the amount of extra LEDs we'd like to add left and right of the original center LED.

void DrawBall(int ballPosition, byte red, byte green, byte blue, byte dimming, byte ExtraSidePixelCount);

For an example of the picture in the previous post;

DrawBall(Position,colors[0],colors[1],colors[2], 220, 2);

1) The ball is drawn with "Position" as the center.
2) We use the red, green and blue values "colors[0],colors[1],colors[2]".
3) All LEDs, except the center LED, will be dimmed by 220, which seemed like a nice value - but feel free to play with it. As far as I know, 250 will most likely make the LED go OFF.
4) We add 2 LEDs on the left and on the right of the center LED.

If I'd want to make it totally perfect then I gradually dim the extra LEDs, instead of taking just one value, but while testing I kind-a already liked it this way.

Hope this results in a better effect - I assume you'd try with adding 2 LEDs as in the code below, but you could most certainly try more.

Please note that this will only work with the FastLED library since we need to have the fadeLightBy function:

The full code:

#include "FastLED.h"
#define NUM_LEDS 60 // Total strip length
#define HALFLEDS 30 // One half LED count
CRGB leds[NUM_LEDS];
#define PIN 6 
void setup()
{
  FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
}
// REPLACE FROM HERE
void loop() {
  byte colors[3][3] = { {0xff, 0,0}, 
                        {0xff, 0xff, 0xff}, 
                        {0 , 0 , 0xff} };
  BouncingColoredBalls(3, colors);
}
void BouncingColoredBalls(int BallCount, byte colors[][3]) {
  float Gravity = -9.81;
  int StartHeight = 1;
  
  float Height[BallCount];
  float ImpactVelocityStart = sqrt( -2 * Gravity * StartHeight );
  float ImpactVelocity[BallCount];
  float TimeSinceLastBounce[BallCount];
  int Position[BallCount];
  long ClockTimeSinceLastBounce[BallCount];
  float Dampening[BallCount];
  
  for (int i = 0 ; i < BallCount ; i++) {   
    ClockTimeSinceLastBounce = millis();
    Height = StartHeight;
    Position = 0; 
    ImpactVelocity = ImpactVelocityStart;
    TimeSinceLastBounce = 0;
    Dampening = 0.90 - float(i)/pow(BallCount,2); 
  }
  while (true) {
    for (int i = 0 ; i < BallCount ; i++) {
      TimeSinceLastBounce = millis() - ClockTimeSinceLastBounce;
      Height = 0.5 * Gravity * pow( TimeSinceLastBounce/1000 , 2.0 ) + ImpactVelocity * TimeSinceLastBounce/1000;
  
      if ( Height < 0 ) {                      
        Height = 0;
        ImpactVelocity = Dampening * ImpactVelocity;
        ClockTimeSinceLastBounce = millis();
  
        if ( ImpactVelocity < 0.01 ) {
          ImpactVelocity = ImpactVelocityStart;
        }
      }
      Position = round( Height * (HALFLEDS - 1) / StartHeight);
    }
  
    for (int i = 0 ; i < BallCount ; i++) {
      // Leftside; (chnage 220 for dimming, and 2 for number of extra LEDs on each side)
      DrawBall(Position,colors[0],colors[1],colors[2], 220, 2);
      // Rightside;
      DrawBall(NUM_LEDS-Position-1,colors[0],colors[1],colors[2], 220, 2);
    }
    
    showStrip();
    setAll(0,0,0);
  }
}
void DrawBall(int ballPosition, byte red, byte green, byte blue, byte dimming, byte ExtraSidePixelCount) {
  // LEDs before the center LED
  for(int counter=1; counter<=ExtraSidePixelCount; counter++) {
    if(ballPosition-counter>=0) { 
      setPixel(ballPosition-counter,red,green,blue); 
      leds[ballPosition-counter].fadeLightBy( dimming ); 
    }
  }
  
  // Center LED    
  setPixel(ballPosition,red,green,blue);
  
  // LEDs after the center LED
  for(int counter=1; counter<=ExtraSidePixelCount; counter++) {    
    if(ballPosition+counter<HALFLEDS) { 
      setPixel(ballPosition+counter,red,green,blue); 
      leds[ballPosition+counter].fadeLightBy( dimming ); 
    }
  }
}
// REPLACE TO HERE
void showStrip() {
 #ifdef ADAFRUIT_NEOPIXEL_H 
   // NeoPixel
   strip.show();
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   FastLED.show();
 #endif
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
 #ifdef ADAFRUIT_NEOPIXEL_H 
   // NeoPixel
   strip.setPixelColor(Pixel, strip.Color(red, green, blue));
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H 
   // FastLED
   leds[Pixel].r = red;
   leds[Pixel].g = green;
   leds[Pixel].b = blue;
 #endif
}
void setAll(byte red, byte green, byte blue) {
  for(int i = 0; i < NUM_LEDS; i++ ) {
    setPixel(i, red, green, blue); 
  }
  showStrip();
}

ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 9 years ago
Posts: 2187
 

p.s. since the last example would only work with FastLED anyway, I removed some of the extra code and made it 100% just for FastLED as well - maybe a little easier to read. This is the same in essence as the previous example.

#include "FastLED.h"
#define NUM_LEDS 60 // Total strip length
#define HALFLEDS 30 // One half LED count
CRGB leds[NUM_LEDS];
#define PIN 5 
void setup()
{
  FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
}
void loop() {
  byte colors[3][3] = { {0xff, 0,0}, 
                        {0xff, 0xff, 0xff}, 
                        {0 , 0 , 0xff} };
  BouncingColoredBalls(3, colors);
}
void BouncingColoredBalls(int BallCount, byte colors[][3]) {
  float Gravity = -9.81;
  int StartHeight = 1;
  
  float Height[BallCount];
  float ImpactVelocityStart = sqrt( -2 * Gravity * StartHeight );
  float ImpactVelocity[BallCount];
  float TimeSinceLastBounce[BallCount];
  int Position[BallCount];
  long ClockTimeSinceLastBounce[BallCount];
  float Dampening[BallCount];
  
  for (int i = 0 ; i < BallCount ; i++) {   
    ClockTimeSinceLastBounce = millis();
    Height = StartHeight;
    Position = 0; 
    ImpactVelocity = ImpactVelocityStart;
    TimeSinceLastBounce = 0;
    Dampening = 0.90 - float(i)/pow(BallCount,2); 
  }
  while (true) {
    for (int i = 0 ; i < BallCount ; i++) {
      TimeSinceLastBounce = millis() - ClockTimeSinceLastBounce;
      Height = 0.5 * Gravity * pow( TimeSinceLastBounce/1000 , 2.0 ) + ImpactVelocity * TimeSinceLastBounce/1000;
  
      if ( Height < 0 ) {                      
        Height = 0;
        ImpactVelocity = Dampening * ImpactVelocity;
        ClockTimeSinceLastBounce = millis();
  
        if ( ImpactVelocity < 0.01 ) {
          ImpactVelocity = ImpactVelocityStart;
        }
      }
      Position = round( Height * (HALFLEDS - 1) / StartHeight);
    }
  
    for (int i = 0 ; i < BallCount ; i++) {
      // Leftside; 
      DrawBall(Position,colors[0],colors[1],colors[2], 220, 2);
      // Rightside;
      DrawBall(NUM_LEDS-Position-1,colors[0],colors[1],colors[2], 220, 2);
    }
    // Show colored balls
    FastLED.show();
    // revert back to all black
    for(int i = 0; i < NUM_LEDS; i++ ) {
       leds.setRGB(0, 0, 0); 
    }
    FastLED.show();
  }
}
void DrawBall(int ballPosition, byte red, byte green, byte blue, byte dimming, byte ExtraSidePixelCount) {
  // LEDs before the center LED
  for(int counter=1; counter<=ExtraSidePixelCount; counter++) {
    if(ballPosition-counter>=0) { 
      leds[ballPosition-counter].setRGB(red,green,blue); 
      leds[ballPosition-counter].fadeLightBy( dimming ); 
    }
  }
  
  // Center LED    
  leds[ballPosition].setRGB(red,green,blue);
  
  // LEDs after the center LED
  for(int counter=1; counter<=ExtraSidePixelCount; counter++) {    
    if(ballPosition+counter<HALFLEDS) { 
      leds[ballPosition+counter].setRGB(red,green,blue); 
      leds[ballPosition+counter].fadeLightBy( dimming ); 
    }
  }
}

I've attached the .ino file as well.

Please let me know what you think ... 


ReplyQuote
 ohno
(@ohno)
Active Member
Joined: 5 years ago
Posts: 16
Topic starter  

I am going to install this new code right now and make another video shortly, as the sun sinks.

My cuz wasnt motivated to help last night, he has a programming degree that he has never used to make anything.  You seem to be the opposite, ha!

I just pasted in the dropbox link and your website did the rest.  You can keep my videos.  I'll try handbraking the next one, 90% reduction is very good.


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 9 years ago
Posts: 2187
 

Oh don't worry compressing videos, I can grab them from your Dropbox and do it for you, no problem ...
Just excited and curious if this did the job for you ....


ReplyQuote
 ohno
(@ohno)
Active Member
Joined: 5 years ago
Posts: 16
Topic starter  
Sorry for the delay, got handbrake working.  I had to shovel my driveway... twice, since sun went down.

ReplyQuote


 Hans
(@hans)
Noble Member Admin
Joined: 9 years ago
Posts: 2187
 

Oh nice! I'd call that an improvement - definitely recommend playing with the size / dimming see if you can get a setting you like best.
What do you think? 

By lack of my own roof and LED strands, I can only test 1 meter of 60 LEDs at a time 

Shoveling the driveway ... man I miss that, retarded as that may sound.
I've been in Houston the past 6 months and can't get used to the lack of seasons. Winter has to have snow ... and 110 degrees is not what I'd call cold and chilly 


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 9 years ago
Posts: 2187
 

Uploading the video here as well, for those who'd like to see how things are developing ... 

P.s. to compress even further, I use the following settings (since the picture is almost a still image):

- Constant Quality, RF = 27
- Encoder options Preset = Fast
- Encoder options Tune = Still Image
- Set Audio to "None"


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 9 years ago
Posts: 2187
 

Strangely enough, when I edit a message, the video does NOT get embedded, so here a new try:

https://www.tweaking4all.com/wp-content/uploads/2017/03/balls2.mp4


ReplyQuote
 ohno
(@ohno)
Active Member
Joined: 5 years ago
Posts: 16
Topic starter  

I think it looks good as is.  I'll turn the balls green and this is ready for the St Patty's Day show.  I'll make a final video and post any final code tweaks in case anyone else is doing led holidays. 

My American football team is green&white so I will reuse this code with one white ball each game day when the season starts.  

This is the type of profile holding my LEDs.  In the daytime it disappears so nobody sees anything is on my roofline.  https://www.aliexpress.com/item/30m-30sets-x1m-Aluminum-led-channel-Aluminum-channel-led-for-Aluminium-profile-led-strip-AP1307/32607495574.html

I also tiled some into my shower, because no shower is complete without electricity.  No led shows in the shower though they are just dumb 12v rgb leds.


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 9 years ago
Posts: 2187
 

Haha, well, I'm glad it worked out well ... 
I've been renting for the past decades, as soon as I have my own home, I'll be ordering miles of LED strands to do lighting inside and outside. Thanks for the tip on the profile. I'll be doing some experiments, like I did with toilet paper, just a little better resistant against wear and tear hahah ... 

Oh and ... Happy Saint Patty's Day laddy 


ReplyQuote


 ohno
(@ohno)
Active Member
Joined: 5 years ago
Posts: 16
Topic starter  
I increased the # of balls to 8.  I installed the show and found that theory didn't translate well into reality. 
There are some strange issues.  LED1 is on the right side, and LED300 is on the left.
Here are the anomalies:
- the last ~ 20 LEDs are dead but the first 20 are fine
- there are color flashes, but only on the left side
- the color anomalies happened with the original 3 ball code but it was usually just with 1 ball on the left side

My initial guess is that the Arduino uno is running out of memory or cpu.  If it is a cpu issue, then it's a problem but if it is a memory issue I can install a larger Arduino into the show.


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 9 years ago
Posts: 2187
 

Hi Ohno!

The video you posted on DropBox is not doing anything (screen remains black and plackback time is zero seconds).

As for odd effects, I can imagine that I might have goofed up in the DrawBall function and values might overshoot.
I'd have to see the effect ... can you try to upload the video again?


ReplyQuote
 ohno
(@ohno)
Active Member
Joined: 5 years ago
Posts: 16
Topic starter  

I had used the m4v codec in handbrake by using the "for web" option.  Seems that your pc may not have that codec for playback so lets try mp4.

https://dl.dropboxusercontent.com/u/11518517/colorError1.m4v


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 9 years ago
Posts: 2187
 

Oh I see what might be happening with the video; Google Chrome doesn't seem to want to play it in the browser.
You could try (for a next time) to rename the file from m4v to mp4.

Anyhoo ... as far as the color error; you mean the red-ish color on the far left? or the flashing white on the left?


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 9 years ago
Posts: 2187
 

(so I downloaded from the link you posted and VLC plays the file)


ReplyQuote


Page 2 / 3

Like what you see and you'd like to help out? 

The best way to help is of course by assisting others with their questions here in the forum, but you can also help us out in other ways:

- Do your shopping at Amazon, it will not cost you anything extra but may generate a small commission for us,
- send a cup of coffee through PayPal ($5, $10, $20, or custom amount),
- become a Patreon,
- donate BitCoin (BTC), or BitCoinCash (BCH).

Share: