Animated LED Clock

by BA_WE in Circuits > Clocks

3042 Views, 22 Favorites, 0 Comments

Animated LED Clock

IMG_20210320_115354.jpg
IMG_20210320_115321.jpg
LED clock display

EDIT: I've now uploaded a new & improved version using a 3D printed holder for the LED's, which can be found at: https://www.instructables.com/editor/EWQNKKSKW23YR7X/publish



Bored with Pandemic lockdown like the rest of us I started playing around with Arduino and LED strips.

I soon ran into the "ping pong ball LED clock" by thomasj152 at

https://www.instructables.com/Ping-Pong-Ball-LED-C...

and decided to give it a try.

Now after many (way too many!) hours of learning and messing around I thought I'd publish the changes I have made to it - while the concept and execution is roughly the same, I ended up rewriting much of the software so that it is (I think) more flexible and quite different.

Two major changes were made:

- I replaced the ping pong ball diffusers with cloth. The effect isn’t quite as funky but it’s easier and shows how the LED’s are on a grid, instead of making it look like a hex pattern

- The software was largely rewritten to make it more flexible and allow for sprite - based animations

I ended up coding not just a clock but something that is almost a 23x7 pixel full colour LED display, with a set of different animations. In hindsight this was absolute madness - I’m sure there is an Arduino library out there somewhere which would have accomplished the same hassle-free and more efficiently, but the point was to keep myself distracted while in lockdown.

This instructable relies heavily on thomasj's original for details, partly because I didnt change that much, partly because I forgot to take photos at the right time while assembling. I'm now working on a new version which will be more compact (higher density LED strip), have more pixels (24x12) and will be entirely in a 3D printed body, which should allow me to hide away the electronics a bit nicer. When (if) that is done I'll publish a new one.

Hope you all like the result and look forward to seeing what creative modifications there may be out there!

Supplies

- Triplex plate (I had some lying around spare, any flat background should do for mounting)

- Frame materials (I 3D printed these, but anything will do as long as it holds the cloth away from the LED’s)

- Semitranslucent cloth – I used some spare translucent curtain, an old t-shirt should work well too

- A 220V AC – 5V DC adapter I had lying around which I had stripped the wires bare

- Hotglue and a gluegun

- Arduino nano (clone): from China, ~1.50€)

- WS2812B LED strip (30 LEDs/meter, 5m, ~10)

- Wire, connectors, tools – I started out with an Arduino kit which had enough Dupont wires for my needs.

- Soldering iron and solder

Building the LED Backend

FET0509JTON6QF0.jpg
FQ8SWQKJTENB6UZ.jpg

Instead of writing this up I'd like to mention that I followed Thomasj's instructable almost to the letter but only steps 6,7, and 8 - so leaving out anything to do with the ping pong balls!

I first started cutting the LED strip into strips of 7 (plus two of 1 and one of 5) and soldering them together like in his instructions. This gave me a series of LED strips with flexible wiring interconnects, which I then mounted to a board of triplex. This part is pretty much identical to his, only he terminates the LED strip with 3 LEDs at the right end instead of the 1+5 arrangement he has at the left, and mine is exactly symmetrical.

The pictures here are from Thomasj's instructable, and only serve as a guidance to what you should end up with. The only difference in my case was that I used triplex wood instead of MDF. As I mentioned, I forgot to take decent pictures at this time, but it shouldn't be too difficult to figure out for yourself with thomasj's instructions.

I first drew out the configuration of the LED strips on the wood before cutting it up and mounting everything. I drew it out to end up with a grid of LED's in squares, but the vertical distance between strips doesnt matter all that much. The LED strip I'm using here has 30 LED/m (a spacing of 3.33cm between the individual LEDs) so I spaced the LED strips 3.3cm apart as well. I added rounded ends, could easily have been square (which would have probably made coding easier).

Making a Raised Ridge for the Cloth Diffuser

LED_Display_2021-Mar-15_07-32-47PM-000_CustomizedView24336350950.jpg
Screenshot 2021-03-15 203452.jpg
IMG_20210320_113133.jpg
IMG_20210320_113059.jpg
IMG_20210320_115130.jpg
IMG_20210320_113052.jpg
IMG_20210320_113047.jpg
IMG_20210320_115121.jpg

I wasn't in the mood for ordering >100 ping pong balls and waiting for them to arrive from China, so I messed around with various diffuser materials like paper and cardboard and ended up using a strip of white cloth (actually from a piece of semi-translucent curtain I had spare), folded double to make it a little more opaque.

Instead of making a wooden frame I decided to 3D print a ridge around the wooden board the LEDs are glued to, so it made a nice neat, raised edge around the wood. The 3D print design can be seen in the pictures, .stl files attached as well. I needed 2 of both endpieces (a top and a bottom, one on each side) and four of both midpieces. I recommend that if you are able to 3D model and 3D print you design some pieces specifically for your measurements, so these are just guidelines to what I did.

If you can't access a 3D printer a box design like thomasj's would probably work well, although it may be tricky to span the cloth wrinkle-free in the next step. I'd suggest experimenting for yourself to see what works best with the materials you have handy.

In the end I only 3D printed the semicircular end pieces and to save time made the sides from some laminate flooring trim I had lying around (see pictures), but 3D printing the edge pieces as in the schematics here should also work fine. The whole thing was hotglued together.

This places the LEDs in a shallow 'box' - roughly 1.5cm deep - over which I stretched the fabric (actually ended up using two layers). The whole thing is again hotglued together so it looks sort of OK-ish from the front. The back looks terrible, but you dont see that! If I did the whole thing again I’d add a 3rd later of textile and maybe 5mm extra clearance to diffuse the leds slightly better, the way it is now you can see the individual LEDs shine through slightly too much.

Electronics

IMG_20210320_115124.jpg
IMG_20210320_113359.jpg
IMG_20210320_113348.jpg
IMG_20210320_115127.jpg

The LED strip is hooked up to an arduino nano, everything soldered together. For soldering instructions you’ll need to look elsewhere, there are plenty of instructions on how to connect both WS2812B LED strips and DS3231 RTC modules to an Arduino. Again, I didnt take pictures and the whole thing is really messy but it works.

I ended up not having quite enough ground and power pins on the Arduino nano, so had to solder several wires to the ground pin at the same time – however the basic connections are the same as thomasj’s:

  • a 5v mains adapter wired to Vin and GND
  • a pushbutton between gnd and pin 7 (used to cycle the display)
  • a DS3232 RTC clock wired to pin 16 and 17 (which are I believe the SCL and SDA lines on a nano) and GND and 3.3V for power.
  • the WS2812B LED strip to GND and 5V and to pin6 for the data line.

The RTC I stuck to the back of the wood, and the nano and button I have put into a little 3D printed holder (which is then glued to the wood).

At this point the clock is very similar to thomasj’s except it uses a cloth diffuser instead of ping pong balls, and some minor construction differences (mine is much messier, but this is all hidden away by the cloth which wraps around the whole thing.)

Hey, it works! As mentioned in the introduction I plan to make a nicer tidy variant sometime in future, but for now as long as the mess is hidden away, I’m OK with the construction.

Downloads

Software

LED grid animation

First of all, I noticed that while thomasj152's clock looks like it has a hexagonal display, it is actually strips of LEDs in an antiparallel zigzag pattern. The ping pong balls make it look like a hexagonal grid.

While the original sketch codes the numbers 0-9 and displays the digits, it is actually a bit inflexible about how they are placed. The position of the LEDs to light up along the strip is hardcoded for each digit. I wanted to be able to move them left and right since they were not quite centred properly on my board, which is wider. However, because of the way it was wired (antiparallel or zigzag), moving them one ‘pixel’ across (basically subtracting or adding 7 to the LED position to light up) would actually turn the digits upside down. I decided I wanted to do things differently and be able to display things on a logical x, y grid.

I need to mention here that I have only recently started teaching myself to code, again because of lockdown-related boredom. It’s all from forums, Arduino.cc and Tutorialspoint.com and I have not had a single proper lesson in this stuff. This means that all of this is probably a) horrendously inefficient and b) buggy as heck. Any constructive comment would be much appreciated, but bear with me - in general I’ve traded efficiency simplicity/ease of understanding. When looking back at them I can see especially the earlier sketches have waay too many comments in there, all because I was uncertain of what I was doing. For the time being the Arduino nano has enough processing power for my purposes, so I find it fine as is – of anyone wants to massively expand the display size I expect code efficiency improvements will be needed!

In various sketches I've uploaded there will be unused variables from previous experiments, and in some cases I reuse whole subroutines for a slightly tweaked effect where it would be much more efficient to just change a single variable to modify an animation. I may someday get round to making it more efficient, or maybe not. Who knows! If anyone has any major improvements or fancy improved routines I'd love to see them, though.

My solution was to treat the clock as a 'virtual' 23 x 9 display, where the top and bottom rows are ‘overscan’ lines (so these don’t correspond to physical LEDs. This is useful to be able to hide away misbehaving pixels but is otherwise totally unnecessary), and a few LEDs on the side are also missing because of the rounded edges. Arbitrarily I chose coordinate 0,0 to be the top left – in hindsight it would have been more intuitive if it was bottom left. I set an RGB value for any pixel according to its x, y values on the virtual grid, and at runtime the sketch figures out which real LED on the LED strip corresponds to this virtual LED. This has the advantage of making it easy to implement things like sprites and move them around by adding and subtracting numbers to the x and y position. Disadvantage is increased processing and memory requirements, but I've not run into the limits yet.

Initially I tried implementing the translation using integer math but found this fussy – I would have needed to create a formula to account for both the reversing of the LED strip direction as well as for the shorter strips at the edges, which turned into a major hassle. In the end I have just put a big lookup table in an array “LEDarray” in the sketch which can be used to look up a real LED position for any x, y, value. This is not very memory efficient but may be a little quicker, and it will certainly make it easier in future to adapt to differently sized displays.

{virtLED to RealLED.ino} is the initial sketch used to test this out. It has three main parts, in sequence:

1. Light up the LEDs in sequential order on the strip – tests if they are all working

2. Light up the virtual LEDs in sequential order – left to right, top to bottom. Tests the translation routine.

3. Light up a single LED and then moves it around in various directions sequentially by adding and/or subtracting to the LED value, looping around when the LED goes off one of the edges

Result can be seen in the video embedded here.

Sprites

LED Sprite bounce test

Next I implemented a sprite system, so instead of lighting up a single LED it now loops the following subroutines:

1. Display a 3x3 sprite (an array defines the brightness values to be used). This starts with a LED x,y, coordinate and then in a loop calculates the brightness values for each virtual pixel of the sprite relative to the starting coordinate, looking them up from the sprite array. This brightness value is translated to a real LED position along the strip (as before, lookup in LEDarray) and then written

2. The sketch then calls FastLED.show() to actually display the values, after which they are immediately cleared again – the nice thing about FastLED is that it will only display the new values when you tell it to, so this isn’t visible, but it allows for an animation moving the sprite around.

3. The sprite x,y coordinates are moved around

This makes a sprite bounce around the display.

{xyspritebounce.ino} is my demo code, as in the embedded video.

Downloads

Backgrounds

I then wrote a couple of colourful background displays. This is where it's especially useful to be able to calculate pixels on an x,y, grid and not have to worry about the positions on the strip itself. I don't know how I'd do it otherwise.

Twirl

This defines an angle (theta) which is increased over time form a value of 0 (horizontal, right) to 255 (255 being full ciricle; 64 is vertical up, 128 is horizontal left and 192 is vertical down, etc). I used values from 0-255 instead of degrees since that makes the loop code easier. There is also an x,y centre point defined in software, which can be anything.

In this way there is an imaginary line emanating from the x,y, centre rotating over time with value theta.

Subsequently I scan across every virtual pixel on the display, calculating the angle made by a line drawn from tis pixel to the centre point at (x,y) and the (virtual) horizontal at theta=0 . I use some dot product math which gives the magnitude of the angle but not the sign, so I just do it once for all pixels above the horizontal line, and once for all pixels below (those are known to be te negative angles)

Finally for these pixels I calculate the difference between the value for theta at that point in time and the angle calculated above. If the difference is above a certain value, the pixel gets a colour; if it is below that value it gets a different colour.

This has the overall effect of having an animated 'pizza slice' rotating over time around the x,y, value I choose. The size of this slice can be varied by adjusting the difference value; it can be a small pizza slice or a half-circle.

Finally, the x,y, position (which is the centre of rotation) is moved around over time – I use a sine function for this, but the moving dot code in the previous example would work just as well.

Example sketches:

{twirlbounce_pizza}

{twirlbounce_halves} (here the difference angle is 128, corresponding to 180 degrees)

These routines could probably be quite easily adapted to simulate an analogue clock, if desired – just need to set the angles according to the time & make sure the time and minute are separately taken care of somehow. I may do this sometime, but not for now!

I also came up with some animated diagonal stripes, which I quite like. The thickness of these stripes can be set and they animate from right to left.

{background_stripes_colour_bands}

Time Display

I then adapted the original code to display the numbers of the time. This uses largely the original code to determine which number to display for each digit, and then draws four 5x3 sprites in order, looking up the sprite LED positions to light up in a 'digits' array.

This method is different to my original sprite in that the array storing the sprite values defines which LEDs to turn on, but does not give them brightness values (that would require a 3-dimensional array, which was too much for my brain to deal with). In this way it is actually much closer to thomasj’s implementation.

By defining the numbers as sprites you could animate their positions as well easily just by updating the position to draw them at, but I haven’t implemented this yet. This could be used for scrolling text, for example – although you’d probably run out of memory quickly on a nano if an entire font needed to be implemented, but a scrolling clock should be easy.

I also designed a new font as I didn’t like the legibility of thomasj’s digits when done without the ping pong balls. Easily tweaked by adapting the digits array.

Wrapping Up and Combining Everything

LED clock display

Finally, I combined most of the previous code into one sketch, see see {time_cyclebackgrounds1.0.ino}

Various backgrounds are displayed and can be cycled using the one button I attached to the clock. Instead of lighting up the digits in a particular colour for the time display I use the fastLED negative function:

leds[r] = -leds[r];

Which just inverts the RGB values of the background pixel. This gives some very colourful (but difficult to read) effects!

That’s all for now! I plan to make a second display using a higher density LED strip which will end up with slightly more pixels in a smaller display, but most of the code should be relatively easily recyclable. Would love to hear of any bugfixes or where I've done something stupid ‘programming-wise’, but for now hope this inspires some of you to make your own variants!