Smoothing a status bar and interpolating values

Hey folks,

Here is the situation, PC is sending numbers between 0 to 100 to arduino ever 200ms. Arduino is taking these values and drawing a status bar.

So far so good. Problem is the number that comes to Arduino jumps around a lot and that caused very jittery status bar. What I need to to is something like this:

->Take the first value that arrives and store it. Wait for the second value
->When the second value arrives; run a loop that goes thru every integer between first and second. At every number draw to TFT screen. ie:

//Pseudo code
while (first_val < second val)
{
     first_var++;
     lcd.Text1.SetValue(first_val)//Text1 is the important part here. It's not static.

}
//Obviously there has to be another function for the cases where the first_val is bigger than the second

->When the third number arrives, overrides first_val with second_val and second_val with third_val
->Return to beginning

Doing this is no problem for a single value. I used a temporary value to store the last value and got it working. Problem is, there are around 10 values that needs to use this function. Creating an additional temporary value for each by hand is tedious. Also impacts performance pretty hard.

So the solution is obviously creating a Class. Problem is, I need to pass the TFT object to that Class too. The screen I’m using is Nextion, It has it’s own library and I have no idea how to pass an object created by some library to another class.

Not to mention, I’m pretty fuzzy about Arduino and classes. I’ve seen some examples of OOP in arduino, but I’m not even sure if they are native arduino codes or C++.

Can anyone give me a hand?

EDIT1:
Here is the video showing the problem.

The first one is the G15’s screen. If you look at the CPU load bars, they are updating very fluidly(Possibly with more than 30+ hz). The second one is mine, and it looks pretty bad.

EDIT2: Here is the github page if you want to see the entirety of Arduino code.

illusive: Problem is, I need to pass the TFT object to that Class too.

You can pass a pointer to an instance of a class.

aarg:
You can pass a pointer to an instance of a class.

How so? this is how I initialize an object:

NexProgressBar BAR1 = NexProgressBar(0, 3, “j0”);

I’m writing a library to do this. Passing the new integer value is easy.

#ifndef SmoothBar_h
#define SmoothBar_h

#include <Arduino.h>
#include <Nextion.h>

class SmoothBar{
public:
SmoothBar();
void attach(/* this is where the NexProgressBar object should be passed*/);
void new_val(int val)

private:


};

#endif

I’m not sure where to initialize an object inside a class or even if such a thing should be done(instantiating an object from another library inside a library- libraryception:))

What does new_val() do?

illusive: So the solution is obviously creating a Class. Problem is, I need to pass the TFT object to that Class too. The screen I'm using is Nextion, It has it's own library and I have no idea how to pass an object created by some library to another class.

Not to mention, I'm pretty fuzzy about Arduino and classes. I've seen some examples of OOP in arduino, but I'm not even sure if they are native arduino codes or C++.

Struggling with understanding why you need to develop a class, and why as part of that class you need to pass a pointer to your TFT object to that class to print a "status bar" Multiple TFT's?

->When the third number arrives, overrides first_val with second_val and second_val with third_val ->Return to beginning

sort of like a circular buffer? are you looking to smooth the values in an average to display them? Can you just slow down the feed?

BulldogLowell: Struggling with understanding why you need to develop a class, and why as part of that class you need to pass a pointer to your TFT object to that class to print a "status bar" Multiple TFT's?

sort of like a circular buffer? are you looking to smooth the values in an average to display them? Can you just slow down the feed?

OK. Let me explain this way. My computer is sending 10 values between 0 and 100 every 100ms. If I just update progressbar once every 100ms, there is a visible jitter in it(like playing a video game at 10FPS) so I need to "interpolate" some extra values and create a "transition" effect while we are waiting 100ms for a new value to arrive.

ie: If the first value is 10 and the second value is 100, I want a method to draw a progressbar for every number in between (10,11,12....100) and than wait for a new number. Say the next one is 90. So the progressbar goes from 100,99,98.....90.

I don't think circular buffer is the answer to my problem, but it'd play a role I believe.

illusive: OK. Let me explain this way. My computer is sending 10 values between 0 and 100 every 100ms. If I just update progressbar once every 100ms, there is a visible jitter in it(like playing a video game at 10FPS) so I need to "interpolate" some extra values and create a "transition" effect while we are waiting 100ms for a new value to arrive.

ie: If the first value is 10 and the second value is 100, I want a method to draw a progressbar for every number in between (10,11,12....100) and than wait for a new number. Say the next one is 90. So the progressbar goes from 100,99,98.....90.

I don't think circular buffer is the answer to my problem, but it'd play a role I believe.

so you want a smoothing effect by doing multiple display updates from LastValue to NewValue?

This is to occur in the 100millisecond interval between data updates?

BulldogLowell: so you want a smoothing effect by doing multiple display updates from LastValue to NewValue?

This is to occur in the 100millisecond interval between data updates?

Yeah. Nicely put :)

so create a non-blocking function that updates the display with the new values say 4 times between data updates…

you could do something like this:

void updateDisplay(int target, int increment)
{
  static int oldVal;
  static unsigned long lastUpdateMillis;
  if(millis() - lastUpdateMillis > 25UL && target != oldVal)
  {
    int updateVal = constrain(oldVal += increment, oldVal < target? oldVal : target, oldVal > target? oldVal : target);
    // call your function to update display using (updateVal)
    lastUpdateMillis += 25;
    oldVal = updateVal;
  }
}

calling a the function with two global vars in loop() like this:

updateDisplay(newValue, (newValue - oldValue) / 4);

where newValue and oldValue are global variables which are updated every 100ms.

kind-of-thing

you may run into refresh rate issues , depending on how frequently you want to update…

BulldogLowell:
so create a non-blocking function that updates the display with the new values say 4 times between data updates…

you could do something like this:

void updateDisplay(int target, int increment)

{
 static int oldVal;
 static unsigned long lastUpdateMillis;
 if(millis() - lastUpdateMillis > 25UL && target != oldVal)
 {
   int updateVal = constrain(oldVal += increment, oldVal < target? oldVal : target, oldVal > target? oldVal : target);
   // call your function to update display using (updateVal)
   lastUpdateMillis += 25;
   oldVal = updateVal;
 }
}




calling a the function with two global vars in loop() like this:



updateDisplay(newValue, (newValue - oldValue) / 4);




where newValue and oldValue are global variables which are updated every 100ms.

kind-of-thing

you may run into refresh rate issues , depending on how frequently you want to update...

I’ve already got it working the way you suggest. Admittedly mine wasn’t as elegant, but it was sure easier to read :slight_smile: I had to read this line 5 times to understand what it does.

 int updateVal = constrain(oldVal += increment, oldVal < target? oldVal : target, oldVal > target? oldVal : target);

Problem is I’ve got 10 different old-new value pairs. And 10 NextionProgressBar objects. Unless I use a class, I’d have to create them all by hand, maintainability would be sh*t, and it takes too many cycles(at least my version did).

I’ve deleted my old code since it didn’t work all that well. But I’ll rewrite it just to show what I’m trying to accomplish.

static int old_val;//This value is problematic. Every method has to have a different var to store pervious date....Hence the need for OOP
void SmoothBar(int val, NexProgressBar nextion) {
  if (old_val == val){}//If the value didn't change don't do anything.
    else {
      if (old_val < val)
      {
        while (old_val < val)
        {
          val--;
          nextion.setValue(val);//This is the problematic part. I don't know how to create an object indside the mothod.
        }
        old_val = val;

      }
      else
      {
        while (old_val > val)
        {
          val++;
          nextion.setValue(val);
        }
        old_val = val;

      }

    }

I know it’s ugly as sin. But if I had only one progressbar and if I were to hardcode the reference to the object into the method, this would work. Problem is to put it into an object.

BulldogLowell:
so create a non-blocking function that updates the display with the new values say 4 times between data updates…

you could do something like this:

void updateDisplay(int target, int increment)

{
  static int oldVal;
  static unsigned long lastUpdateMillis;
  if(millis() - lastUpdateMillis > 25UL && target != oldVal)
  {
    int updateVal = constrain(oldVal += increment, oldVal < target? oldVal : target, oldVal > target? oldVal : target);
    // call your function to update display using (updateVal)
    lastUpdateMillis += 25;
    oldVal = updateVal;
  }
}




calling a the function with two global vars in loop() like this:



updateDisplay(newValue, (newValue - oldValue) / 4);




where newValue and oldValue are global variables which are updated every 100ms.

kind-of-thing

you may run into refresh rate issues , depending on how frequently you want to update...

Also since I need to run this function for 10 different values, using static variables wouldn’t work. They’d get overwritten when the function gets called with a different variable.

yes, in that example you would have to have 10 different functions.

If you know how, you may be able to could extend the function by making the update function called in loop() handle an array of old and new values and pointers to NexProgressBar objects (also in an array) if you want. You could contain all of your values in a class/struct:

struct MyObject{
  NexProgressBar* progBar;
  int newVal;
  int oldVal;
};

MyObject myObject[10]; // an array of 10 MyObjects!

Function-wise whatever you do in a Class you'll have to accomplish in a function first.

maybe you should post all of your code.

BulldogLowell: yes, in that example you would have to have 10 different functions.

If you know how, you may be able to could extend the function by making the update function called in loop() handle an array of old and new values and pointers to NexProgressBar objects (also in an array) if you want. You could contain all of your values in a class/struct:

struct MyObject{
  NexProgressBar* progBar;
  int newVal;
  int oldVal;
};

MyObject myObject[10]; // an array of 10 MyObjects!




Function-wise whatever you do in a Class you'll have to accomplish in a function first.

maybe you should post all of your code.

I like the struct idea. While It wouldn't completely solve the problem, It should be able to reduce my workload and improve readability significantly.

White It's true that one should figure out the algorithm before putting it into an object, I can't think of any way to make this work without using instantiated variables.

I'm pushing the project to github now. I was gonna do it anyway(once the code was at least somewhat respectable :)) oh well...

Here is the github page