How to force a value to be an integer

I am trying to get a 24 pixel WS2812 ring to display time I started with the code from another forum entry as a starting point so thanks to robhixkg for providing a starting point, I decided to use rgb values.
I have run into two problems, the hours display fine, but the min and sec value after 23 disappear. I have tried dividing the value by 2.5 which gives each segment a value of 2.5 seconds or minutes. But this doesn’t really work . As it jumps a pixel. When I divide by 2 it displays on each pixel. Is there a way to force a value to be an integer so 2.5 would display as 3 and 4.2 would be 4.

Here is the code

var sec = 0.0;
var min = 0.0;
var hour = 0;

export function render(index) {

var secColor = 1;
var minColor = 1;
var hrColor = 1;

var pixelSet = false;

sec = clockSecond();
min = clockMinute();
hour = clockHour();

// Set the pixel for the hour, minute, and second
if (index == (sec / 2)){
rgb(secColor, 0, 0);
pixelSet = true;
} else if (index == (min / 2)){
rgb(0, minColor, 0);
pixelSet = true;
} else if (index == (hour)){
rgb(0, 0, hrColor);
pixelSet = true;

}


// Turn the pixel off if it is not supposed to be on
if (!pixelSet)
rgb(0, 0, 0);
}

Since you don’t want the clock jumping ahead, you always want to round down, so use floor()
That always will give you the integer part. (Unless it’s a negative number, then it rounds down [which is up cause it’s negative], as we discussed elsewhere earlier this week)

That said, trying to get 60 seconds or minutes to smoothly fit into 24 pixels? It’ll “stutter” a bit due to not being an even division. If it was twelve, you’d change the seconds hand/dot every 5 seconds right? So twice as many dots means you have to change dots every 2.5 seconds.
Since you don’t have a half second in your measurements, it’ll never fall smoothly.

You might be better off doing division by 5, so you will have 12 dots, and then make the dots before and after glow much less, and then at 2-3 (you’ll be early at 2, late at 3) seconds swap over to the next pixel (and partly light the two next to it), giving you a “sweep” effect that the eye will feel/see as more natural. Actually you could even increase the brightness on a second by second basis… That would look nice, like the light was sliding from pixel to pixel… I started to try to explain but it’ll be easier to do it in code. I’ll reply later. (Also want to grab a circle led to test it… and guess what, my solution isn’t smooth either… working on it now…)

Minutes you won’t notice as much, of course … but second hand sweeps are quick enough for the eye to see irregularities.

1 Like
// smooth clock by ScruffyNerf
// written for https://forum.electromage.com/t/how-to-force-a-value-to-be-an-integer/814

export var sec = 0;
export var min = 0;
export var hour = 0;

export var secpixel = 0; 
export var secpixel2 =  0;
export var minpixel =  0;
export var hourpixel =  0;

// pick your colors
var hrColor = array(3);
hrColor[0] = 1
export function rgbPickerHoursColor(r, g, b){
  hrColor[0] = r
  hrColor[1] = g
  hrColor[2] = b
}

var minColor = array(3);
minColor[1] = 1
export function rgbPickerMinutesColor(r, g, b){
  minColor[0] = r
  minColor[1] = g
  minColor[2] = b
}

var secColor = array(3);
secColor[2] = 1
export function rgbPickerSecondsColor(r, g, b){
  secColor[0] = r
  secColor[1] = g
  secColor[2] = b
}


export function render(index) {
	
	// what time is it?
	sec = clockSecond(); // values from 0-59
	min = clockMinute(); // values from 0-59
	hour = clockHour();  // values from 0-23

	//let's convert these to fit 24 pixels nicely

	  // hours would seem easy, except we don't want a 24 hour clock, we want a 12 hour clock	
	hourpixel = (hour%12) * 2
	  //that will fold it in half, mod12 aka %12 turns 12 into 0, 13 into 1, etc...  
    // our pixels start at 0, but we need to light pixel 2 for 1 o'clock, pixel 4 for 2 o'clock, etc. so double it
	if (min > 29) {
		// if we are past 29 minutes, add one more, so the hour hand/pixel will move on the half-hour
		hourpixel++
		if (hourpixel>23) { hourpixel = 0} // catch the wrap around exception at 24/0
	}
	
	// seconds and minutes have to fit 60 into 24... or every 2.5 minutes
	minpixel = floor(min/2.5)  // floor rounds down
	if (min%5 == 2 && sec > 29) {
		// if we're in minute 2 out of every five, and more than 30 seconds, add one, to shift on time.
		minpixel++
		if (minpixel>23) { minpixel = 0} // catch the wrap around exception at 24/0
  }

    //seconds is the hard one... 
    //the eye can see the sweep 'stutter' irregularly
    // we don't have 60 pixels to get 1 per second
    // but can we fake smoothly 60 seconds with 24 pixels? 
    // not well with the clock functions it seems...
  
  secpixel = floor(sec/2.5) // floor rounds down, this is actual seconds
  secpixel2 = floor(time(.015*60)*24) // this is the time function, which is close but NOT exact
  
  mainbrightness = 1;
  secondbrightness = .25;

  // Set the pixel for the second, then the minute, then the hour

  if (index == hourpixel) {
	  rgb(hrColor[0],hrColor[1],hrColor[2]);
  } else if (index == minpixel) {
    rgb(minColor[0],minColor[1],minColor[2]);
  } else if (index == secpixel2) {
    rgb(secColor[0]*secondbrightness,secColor[1]*secondbrightness,secColor[2]*secondbrightness);
  } else if (index == secpixel) {
    rgb(secColor[0]*mainbrightness,secColor[1]*mainbrightness,secColor[2]*mainbrightness);
  } else {
  	// none of the above, so we can turn it off
    rgb(0, 0, 0);
  }
}

So this lacks my above suggestion, still playing with it.
It has a fast second sweep hand.

1 Like

Ok, I’ve got a change I like…
this uses my idea of extra pixels to convey a second hand change every second

// better smooth clock by ScruffyNerf
// written for https://forum.electromage.com/t/how-to-force-a-value-to-be-an-integer/814

// built for a 24 pixel circle. Clocks are much easier with 30 pixels, or 12 even... 60 is ideal.

export var sec = 0;
export var min = 0;
export var hour = 0;
export var secpixel = 0; 
export var secpixel2 =  0;
export var minpixel =  0;
export var hourpixel =  0;

// pick your own colors if you want
var hrColor = array(3);
hrColor[0] = 1 // this is a cheat, array is all zeros otherwise, but let's default to Red, Green, Blue pointers
export function rgbPickerHoursColor(r, g, b){
  hrColor[0] = r
  hrColor[1] = g
  hrColor[2] = b
}

var minColor = array(3);
minColor[1] = 1
export function rgbPickerMinutesColor(r, g, b){
  minColor[0] = r
  minColor[1] = g
  minColor[2] = b
}

var secColor = array(3);
secColor[2] = 1
export function rgbPickerSecondsColor(r, g, b){
  secColor[0] = r
  secColor[1] = g
  secColor[2] = b
}

export function render(index) {
	// what time is it?
	sec = clockSecond(); // values from 0-59
	min = clockMinute(); // values from 0-59
	hour = clockHour();  // values from 0-23

	//let's convert these to fit 24 pixels nicely

	// hours would seem easy, except we don't want a 24 hour clock, we want a 12 hour clock	
	hourpixel = (hour%12) * 2
	//that will fold it in half, mod12 aka %12 turns 12 into 0, 13 into 1, etc...  
  // our pixels start at 0, but we need to light pixel 2 for 1 o'clock, pixel 4 for 2 o'clock, etc. so double it
	if (min > 29) {
		// if we are past 29 minutes, add one more, so the hour hand/pixel will move on the half-hour
		hourpixel++
		if (hourpixel>23) { hourpixel = 0} // catch the wrap around exception at 24/0
	}
	
	// seconds and minutes have to fit 60 into 24... or every 2.5 minutes
	minpixel = floor(min/2.5)  // floor rounds down
	if (min%5 == 2 && sec > 29) {
		// if we're in minute 2 out of every five, and more than 30 seconds, add one, to shift on time.
		minpixel++
		if (minpixel>23) { minpixel = 0} // catch the wrap around exception at 24/0
  }

  //seconds is the hard one... 
  //the eye can see the sweep 'stutter' irregularly
  // we don't have 60 pixels to get 1 per second
  // but can we fake smoothly 60 seconds with 24 pixels? 
  // not well with the existing clock functions it seems...
  

  // sec 0: X00
  // sec 1: xx0
  // sec 2: xX0
  // se2.5: 0X0 - never can do this
  // sec 3: 0Xx
  // sec 4: 0xx
  // sec 5: 00X
  
  secpixel = floor(sec/2.5) // floor rounds down, this is actual seconds
  secpixel2 = secpixel // same location, as default
  mainbrightness = 1;
  secondbrightness = .05;
  
  cycle = sec%5 // we get a cycle of 5 positions as above...
  if (cycle == 1 || cycle ==3) {
   secpixel2 = secpixel + 1 // add a pixel after...
   if (secpixel2 > 23) { secpixel2 = 0 }  //catch the overflow at 24/0
  }
  if (cycle == 2 || cycle == 4) {
   secpixel2 = secpixel //the earlier pixel is less bright
   secpixel++ // brighter pixel is added here
   if (secpixel > 23) { secpixel = 0 } // catch the overflow at 24/0
  }

  // Set the pixel for the second, then the minute, then the hour

  if (index == hourpixel) {
	  rgb(hrColor[0],hrColor[1],hrColor[2]);
  } else if (index == minpixel) {
    rgb(minColor[0],minColor[1],minColor[2]);
  } else if (index == secpixel2 && secpixel2 != secpixel) {
    rgb(secColor[0]*secondbrightness,secColor[1]*secondbrightness,secColor[2]*secondbrightness);
  } else if (index == secpixel) {
    rgb(secColor[0]*mainbrightness,secColor[1]*mainbrightness,secColor[2]*mainbrightness);
  } else {
  	// none of the above, so we can turn it off
    rgb(0, 0, 0);
  }
}

I’ll likely change this later to use HSV instead of RGB, and also add some color blending when pixels overlap… the second hand sweep could be improved by varying the brightness more… making it seem to move more fluidly… but it was a proof of concept.

And It’ll make it generic (so it’ll work on any size ring) and then I’ll post that into my github PB repo (and add it to the pattern repo…

1 Like

Hi @TechDoctor,
You’re asking for a round() function which gives the nearest integer value. Pixelblaze doesn’t have a round() function but it does have floor() and ceil() which round down and round up, respectively.

Something like this should do the trick:


function round(v) {
  return floor(v+.5)
}

Another way to do this would be to smoothly transition between sub-pixel values using the distance from the desired location (even if its not exactly a match).

I have a backburner clock pattern I’ve been working on I should post…

3 Likes

Are you thinking of the smooth transition work that “Dave’s Garage” did on youtube with fastLED? I thought that was a real interesting idea. https://www.youtube.com/watch?v=RF7GekbNmjU

Not specifically him, I hadn’t seen that before. Good stuff. Similar concepts.

Most of Pixelblazes animation apis encourage smooth sub pixel interpolation.

It’s a bit different in that we don’t usually paint into a buffer, but instead have a coordinate and need to figure out what to put there.

It is similar in that we have some fractional value, 2.5 in @TechDoctor case and need to draw some fractional brightness in some pixels to smooth it out.

Yeah, I hadn’t seen this either. But yes, it’s a basic concept, and used lots of places besides LEDs…

The key for this particular application is that if you are updating the clock every second (tick tick tick) but your display only updates every 3 out of 5 seconds, and the pattern is tick,quiet, quiet, tick, quiet, tick (60/24 yields 2.5 updates in 5 second span, at seconds 0,3,5) and your eye will absolutely notice that as irregular, which for a clock, is annoying.

Compare to my minute code, where we adjust the minute hand at 2 minutes and >29 seconds to put the minute hand one pixel ahead.

If we had a ClockTenthsofSecond (or smaller), we could solve this just like minutes: at 2 seconds and >=.5 of a second, push the second hand up a pixel. Then the clock second hand would go tick, quiet for 2.5 seconds, tick, quiet for 2.5 seconds, tick. Etc.

You might find that 2.5 second heartbeat annoying too… So doing something every second is likely to be more satisfying in some ways.

@TechDoctor and @Scruffynerf you both may be interested in the pattern I finally got around to, with inspiration from this post :slight_smile:

Implements a 2D clock with fractional seconds and a bunch of different ways to draw.

2 Likes

Many thanks for all your help, I will post what I come up with later. Just inwardly digesting all the posts and make sure I understand all the code that has been posted.

1 Like

Here is my code for now. Hope fully its self explanatory.
I have basically taken ideas from several other patterns, plus some of my own Arduino nano code for driving the ring.

/* Designed for a 24 neo pixel ring
The seconds are red, minutes green and hours blue.
The seconds are approximate seconds and sweep continually round the pixel ring.
Hours are displayed in 24 hour format.
*/
var min = 0;
var hour = 0;

export function render(index) {

var secColor = 1;
var minColor = 1;
var hrColor = 1;
var pixelSet = false;

min = clockMinute();
hour = clockHour();

// Set the pixel for the hour, minute, and second
red = green = blue = 0
leadPosition = time(0.4) * pixelCount // close approximation to move forward one pixel every second

red = abs(leadPosition - index ) < 0.5 // displays one moving pixel changing 0.5 to 1 will display 2 pixels etc
rgb(red, 0, 0)

if (index == floor(min / 2.5)){ // floor command rounds down to nearest integer and 24 * 2.5= 60
rgb(0, minColor, 0);
pixelSet = true;
} else if (index == (hour)){ // hours displayed in 24hr format
rgb(0, 0, hrColor);
pixelSet = true;
}

// Turn the pixel off if it is not supposed to be on
//if (!pixelSet)
//rgb(0, 0, 0); // have just left this in, but realised it was not needed
}