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

[Solved] How to double the bouncy ball effect?

34 Posts
2 Users
0 Reactions
7,863 Views
 ohno
(@ohno)
Eminent Member
Joined: 8 years ago
Posts: 16
Topic starter  

Just wondering if it is possible to have bouncy balls on both ends of the LED strip simultaneously, instead of just one side?

What I am trying to do:
The front of my house has a roofline like this    ^
I have 300 ws2812b leds connected into one long strip along that roofline.
It would look cool to have the green bouncy balls on both sides, shooting up toward the roof peak for St Patricks day!

I can figure out how to do one side, and then the other, thanks to the other posts on this forum.  How could I do both ends simultaneously?


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

Hi Ohno!

Ehm ... I guess the question is; do they need to run identical? I mean; symmetric?
In that case I'd use two strips, one for each side, and set try if both strips can be connected in parallel. Now granted, I never tested this, so it might not work, but I suspect it actually might work.

If they do not need to be symmetric, then I'd consider getting an additional Arduino. They are pretty cheap these days.
They could share the same Power Supply ... So you'd keep things easy for just a few extra bucks.


   
ReplyQuote
 ohno
(@ohno)
Eminent Member
Joined: 8 years ago
Posts: 16
Topic starter  

First thing, thanks for posting your advanced code.  Also, for giving support for its use.  You are a scholar and a gentleman.

Your idea is good, keeping it simple.  That would work perfectly to solve my problem, since I do not need the effects to be symmetrical on each side and I have the hardware required.

But here is why that solution doesn't quite work for me:

1. winter in Canada- not a great time for roof work (the *lowest* point of my roof is 16' from the ground)

2. I would have to cut my string into two pieces and reverse one string.  This would ruin the other effects, especially cyloning and shooting stars, which are cool to see on 32' roof line.

I don't mean to complain!  Just saying that the KISS principle wont work for me on this project.  I will make a video tonight of the green multicolored bouncy balls- it is a work in progress.

Is there a way I can get bouncy balls on both ends of one 300 LED, 32' long string without having to cut apart my permanent installation?  The code you wrote is way above my head already, but I can do some basic editing to make effects run.


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

Hi Ohno!

You're most welcome, and I like to share the knowledge - I truly wish I could make it my day-time job.
Having lived in Wisconsin for 13 years (which I actually loved), I can totally relate to not wanting to do this in winter.

So, point well taken. Let me quickly look at the code and see if I can make it bounce in 2 halves...


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

Would you mind if both sides are symmetrical? If you wouldn't mind then this might work (I have not been able to test this);

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;
  
  int Halfway = NUM_LEDS/2; // determine number of leds per side
  
  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 * (Halfway - 1) / StartHeight); // One side
    }
  
    for (int i = 0 ; i < BallCount ; i++) {
      setPixel(Position,colors[0],colors[1],colors[2]);
      setPixel(NUM_LEDS-Position,colors[0],colors[1],colors[2]); // mirror to other side
    }
    
    showStrip();
    setAll(0,0,0);
  }
}

The idea is to split the entire strip in two virtual strips. One strip counts from 0 to the middle (Halfway variable). The second strip counts from the last LED up to the middle, say we have 10 LEDs, then this would look like this:

1,2,3,4,5 (middle) 6,7,8,9,10

now becomes:

1,2,3,4,5 (middle) 5,4,3,2,1

So the position of any ball can only exist (initially) in the left half, so we bounce between 0 and Halfway.
The right side will bounce identical, so we just copy the position of the ball on the left side and just make sure that we start counting from the last LED back to the middle (NUM_LEDS-Position).

Not sure if this is an acceptable answer ... 
However, when we'd make a function to make both side work individually/independent, then we'd need to repeat a lot of the code and I'd probably need to start experimenting to see how well this would work. But I do like the idea ...


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

I couldn't resist, so I did test this slightly modified code.
Mind you the definition of the HALFLED in the beginning, the principle is the same as the previous code - I just pasted the entire code this time;

#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++) {
      setPixel(Position,colors[0],colors[1],colors[2]);
      setPixel(NUM_LEDS-Position-1,colors[0],colors[1],colors[2]);
    }
    
    showStrip();
    setAll(0,0,0);
  }
}
// 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
 ohno
(@ohno)
Eminent Member
Joined: 8 years ago
Posts: 16
Topic starter  

Exciting!  I wish I could see my LEDs in the daytime because I will post the video as soon as mother nature allows me to make it.  Your code using two halves is exactly what I was hoping.  I have the Arduino and pc case that powers everything in a kitchen cabinet and I run 25' of wire for the data line and I inject power from the pc case at both ends of the 32' led string.  The leds are mounted in aluminum profiles with acrylic milky covers.  Works really well and I don't have to go outside to change my outdoor led show.  This is the video that made me buy LED's in the first place:  https://www.youtube.com/watch?v=z5dfpe_-Lgg

I also built some Arduino controlled relays so I can turn on and off outdoor xmas effects.  So far I have only used it to blink my outdoor LED trees in sequence at xmas.  I only run my led show on holidays.

And you probably could do this full time if you started up a business.  I am always coming up with ideas, lol.  What I was thinking was installing LEDs on to businesses so they can run holiday or other theme shows.  It is a nicer way to make ppl look than those ungodly bright LED signs everyone is putting up in my city.  With your coding skills I am sure you can make impressive results.  I saw you did a boblight setup on an 80" tv, I did an ambilight setup on an 80" tv also with apa102 since the colors on the ws2812b are so far off.  I used 4 pieces of electrical conduit to mount the LEDs on, and I can rotate them to aim the LEDs. 


   
ReplyQuote
 ohno
(@ohno)
Eminent Member
Joined: 8 years ago
Posts: 16
Topic starter  

Hey I've got it installed and it is working on both ends!  I have a video uploading to my HTPC, 40mb. (edit: reduced to 4Mb with HandBrake, and hosted at Tweaking4All.com).  

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

Looks like something is wrong, there are a bunch of gaps between the LEDs.  Like the balls are wiffle balls, if you remember those?
Maybe it is because to move that fast, some of the LEDs are skipped.  eg... instead of the ball going from 1,2,3,4,5,6 it goes 1,3,6 and skips over some LEDs.
At the end of the video, I zoomed in so if you pause you can see the gaps.  My cousin is coming over for UFC tonight, he has java programing experience. 
If we figure it out I'll post the mod. 
I am guessing that changing the gravity on line 21 may make it run smoother.  
 float Gravity = -9.81;

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

That inspirational video is mind blowing .... WOW.

Well, doing lighting as a fulltime business would work just fine in the US and Canada, but probably not so much in Europe. There will be the occasional client, but not as much as out here (I'm from the Netherlands, lived 13 years in Wisconsin, and right now live in Houston for my job). It kind-a reminds me of the first houses that had an iPad installed to control lighting, music, alarm, etc. Pretty quickly these companies had to compete with cheap Chinese knock-offs. Granted they do not work as well, but ... it's a customer lost.

I like your video! Nice start! I'll try to download and convert it so I can permanently embed it here (so it won't use your DropBox account that much and you can safely remove it later on) - with your permission of course. 

I do see what you mean with the gaps. Let me take a look and see what the best point would be to make things smoother.


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

Did you try changing "float Gravity = -9.81;" to another value?

I'm beginning to think that it goes a little too fast or that the one-led balls are too small ...


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

OK, I managed to reduce your video to 4 Mb with HandBrake.
Just wondering; how did you get the video in the post to begin with hahah ... (I assume you just pasted the link?)
I've always used attachments, but I like embedding better.


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

For some odd reason I lost your post, while trying to post the video (the 4Mb version):

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

So here your text again:

Hey I've got it installed and it is working on both ends! I have a video uploading to my HTPC, 40mb. (edit: reduced to 4Mb with HandBrake, and hosted at Tweaking4All.com).  

Looks like something is wrong, there are a bunch of gaps between the LEDs. Like the balls are wiffle balls, if you remember those? Maybe it is because to move that fast, some of the LEDs are skipped. eg... instead of the ball going from 1,2,3,4,5,6 it goes 1,3,6 and skips over some LEDs. At the end of the video, I zoomed in so if you pause you can see the gaps. My cousin is coming over for UFC tonight, he has java programing experience.  

If we figure it out I'll post the mod. I am guessing that changing the gravity on line 21 may make it run smoother.  

 float Gravity = -9.81;


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

Java experience should most certainly help - since Java is very similar to C/C++. 
I'm curious what he comes up with!

An alternative might be by using 2 or 3 LEDs as "ball" size, for example the 1e and 3e LED the same color as led number 2 , just more dimmed. You'd have replace the for-loop with for example:

   for (int i = 0 ; i < BallCount ; i++) {
      // Leftside, for each ball, LED 1-2-3
      if(Position-1>=0) { setPixel(Position-1,colors[0],colors[1],colors[2]); }
      setPixel(Position,colors[0],colors[1],colors[2]);
      if(Position+1<HALFLEDS) { setPixel(Position+1,colors[0],colors[1],colors[2]); } // Rightside, for each ball, LED 1-2-3
      if(Position-2>=0) { setPixel(NUM_LEDS-Position-2,colors[0],colors[1],colors[2]); }
      setPixel(NUM_LEDS-Position-1,colors[0],colors[1],colors[2]);
      if(Position<HALFLEDS) { setPixel(NUM_LEDS-Position,colors[0],colors[1],colors[2]); }
    }

I tested this and it works as expected. I'm trying to see if I can dim LED 1 and 3 of each ball. This might look better on your house too - much more visible.

As for the Gravity value:
The closer to zero (for example -1) the slower it gets. But that will not be as nice.

Also think about it that in the same time frame, a LED can bounce all the way or just a little bit, limiting the number of lit up LEDs for long distance bounces.


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

OK, managed to get faded first and third LED for each ball to work as well,example code below.

To be clear, the previous example and this example replace this part of the code you tested:

    for (int i = 0 ; i < BallCount ; i++) {
      setPixel(Position,colors[0],colors[1],colors[2]);
      setPixel(NUM_LEDS-Position-1,colors[0],colors[1],colors[2]);
    }

Replace it with (if you'd like I can post the entire code):

    for (int i = 0 ; i < BallCount ; i++) {
      // Leftside; LEDs 1,2,3 for each ball
      if(Position-1>=0) { 
        setPixel(Position-1,colors[0],colors[1],colors[2]); 
        leds[Position-1].fadeLightBy( 220 ); 
      }
      setPixel(Position,colors[0],colors[1],colors[2]);
      if(Position+1<HALFLEDS) { 
        setPixel(Position+1,colors[0],colors[1],colors[2]); 
        leds[Position+1].fadeLightBy( 220 ); 
      }
      // Rightside; LEDs 1,2,3 for each ball
      if(Position-2>=0) { 
        setPixel(NUM_LEDS-Position-2,colors[0],colors[1],colors[2]);
        leds[NUM_LEDS-Position-2].fadeLightBy( 220 ); 
      }
      setPixel(NUM_LEDS-Position-1,colors[0],colors[1],colors[2]);
      if(Position<HALFLEDS) { 
        setPixel(NUM_LEDS-Position,colors[0],colors[1],colors[2]); 
        leds[NUM_LEDS-Position].fadeLightBy( 220 );
      }

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
 

OK, so I could really not resist and made you this code, where I created a function to draw a ball, any width you'd like.


   
ReplyQuote
Page 1 / 3
Share: