Code processing at slow speed

My project is basically about displaying lightshows on a ws2812 led stick but the brightness is changing slower than expected.

Code itself is pretty simple, in brief:

  1. reads a string containing 4 diff data values
  2. assign them each to a variable (value1 to value4)
  3. perform basic calculations (multiply, subtraction)
  4. assign those variable as brightness value to each led (8 led in total)

Speed of reading data is fast, but displaying the brightness is where the slowness occurs

Anyway here's my code, any tips and guidance would be much appreciated!

For hardware specs, im using Arduino UNO R3 ATMega328P

#include <Adafruit_NeoPixel.h>

#define NYEO 4
#define NUMPIXELS 8

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, NYEO, NEO_GRB + NEO_KHZ800);

int r = 0;
int g = 255;
int b = 139;
int fr = 0;
int fg = 0;
int fb = 0;
uint32_t colors[NUMPIXELS];

int value1, value2, value3, value4;
int noko1, noko2, noko3, noko4;

void setup() {
  Serial.begin(9600);
  strip.begin();
  strip.show();
}

void loop() {
  if (Serial.available() > 0) {
    // Stage 1 Denial
    String input = Serial.readStringUntil('\n');  
    parseInput(input);
    // Stage 2 Anger
    if(value1 > 0) {noko1 = 39;}
    if(value2 > 0) {noko2 = 39;}
    if(value3 > 0) {noko3 = 39;}
    if(value4 > 0) {noko4 = 39;}
    // Stage 3 Bargaining
    if(noko1 > 0) {noko1--;} 
    if(noko2 > 0) {noko2--;} 
    if(noko3 > 0) {noko3--;} 
    if(noko4 > 0) {noko4--;} 
    // Stage 4 Depression
    int neko1 = noko1*6;
    int neko2 = noko2*6;
    int neko3 = noko3*6;
    int neko4 = noko4*6;
    int BrightNya[NUMPIXELS] = {neko1,neko1,neko2,neko2,neko3,neko3,neko4,neko4};
    for(int i = 0; i < NUMPIXELS; i++) {
      fr = (r*BrightNya[i])/255;
      fg = (g*BrightNya[i])/255;
      fb = (b*BrightNya[i])/255;
      colors[i] = strip.Color(fr,fg,fb);
    }
    // Stage 5 Acceptance
    for(int i = 0; i < NUMPIXELS; i++) {
      strip.setPixelColor(i, colors[i]);
    }
    delay(10);
    strip.show();
  }
}

void parseInput(String input) {
  int startIndex = 0;
  int commaIndex;
  int valueIndex = 0;

  while ((commaIndex = input.indexOf(',', startIndex)) != -1 && valueIndex < 3) {
    String valueString = input.substring(startIndex, commaIndex);
    int value = valueString.toInt();
    
    switch (valueIndex) {
      case 0: value1 = value; break;
      case 1: value2 = value; break;
      case 2: value3 = value; break;
    }
    startIndex = commaIndex + 1;
    valueIndex++;
  }
  
  value4 = input.substring(startIndex).toInt();
}

i have tried simplying and combining the calculations into one line and got rid of variable noko1 to noko4 but its still slow
i have also tried increasing baud rate from 9600 to 115200, no effects as well

Have you tried the FastLED library? I haven't but lots of folks seem to prefer it to the Adafruit option.

no not yet but i'll give it a shot

i just modified my code and used fastLED.h library and the speed is still relatively the same as using adafruit library

Seems to me that reading the Strings would be the slow part. What data are you reading into Serial and is there a way to shorten it to just chars? How long are these Strings you're

?

its actually just 4 integer data but separated with a comma. Here's the python code thats sending the data

    datanya = "{},{},{},{}".format(neko1,neko2,neko3,neko4)
    ser.write((datanya + "\n").encode())

so the serial data sent is "0,0,0,0" with a "\n" at the end
the values of each integer changes between 0 and 1

Yeah, I'm not really sure but I remembered something about the strip.show(); function and interaction with Serial.

Take a look at this discussion, hope it helps.
https://forums.adafruit.com/viewtopic.php?t=134771

1 Like

In loop(), you create 4 local ints with the same names as 4 global ints. I don't think you know what you're doing.

    int neko1 = noko1*6;
    int neko2 = noko2*6;
    int neko3 = noko3*6;
    int neko4 = noko4*6;

right before that

    if(value1 > 0) {noko1 = 39;}
    if(value2 > 0) {noko2 = 39;}
    if(value3 > 0) {noko3 = 39;}
    if(value4 > 0) {noko4 = 39;}
    // Stage 3 Bargaining
    if(noko1 > 0) {noko1--;} 
    if(noko2 > 0) {noko2--;} 
    if(noko3 > 0) {noko3--;} 
    if(noko4 > 0) {noko4--;} 

hello? same as only slower than

    if(value1 > 0) {noko1 = 38;}
    if(value2 > 0) {noko2 = 38;}
    if(value3 > 0) {noko3 = 38;}
    if(value4 > 0) {noko4 = 38;}

One advice; spend time getting away from C++ Strings and learn C char array strings. At least then you won't be wasting your time.

You are doing a lot of useless manipulations the hard way and it seems like tou barely know what arrays are. Are you using snippets of code examples or getting gelp frim chatGPT? Either way. you don't learn to think well.

I would nest these as chars in a switch/case structure that increments a byte every time you receive the next char and resets back to say, 0 once the fourth one arrives.

I mean, that's just how I would approach this code, I'm not saying to rewrite based on this, it's just how I would do it and telling Arduino to do stuff using just chars has always been plenty fast enough. I honestly don't have a better suggestion for you, just trying to tick a few things off before other helpers maybe offer a better suggestion.

I mean then you say that you don't think it's the Serial, but the pixels themselves so sorry I can't be more help than that.

In the off chance you do go for the Hail Mary and change your Serial input, the way to do single chars (or any Serial handling) is best illustrated to my knowledge in the immortal example of @Robin2. If you've never read this page, even if you don't use it for this project, it's well worth the time.

2 Likes

i used this approach because it worked for me in the past when there was lesser data to handle but i guess its not efficient for this kind of operation. I'll keep it in mind and read up on the page. Thanks for the inputs!

1 Like

the functionality is that i want a fading effect where the brightness slowly drops from (39x6) to (0x6) everytime the loop runs. And you're right I don't expose myself enough to using arrays

maybe figure out and fix the first thing I showed and see what that does?

1 Like

okay so I changed the noko1 to noko4 variables from global to local and modified the name to a different one, br1 to br4. The result is still the same with same speed as well.

As mentioned on the original post I also tried removing the variable noko1 to noko4 and simplified the calculation, also yield same result

That's funny. To me, not making local copies of global variables would be a thing to do! Local variables get lost at the end of a function and void loop() is a function. If you make them static, that's different but just keeping them global is fine. The PROBLEM is having different variables with the same name, the compiler will use the local vars and whatever happens to them gets lost when loop() ends, getting rid of those should change how the sketch works.

1 Like

Also what is the flow of the program?
As soon as it receives a 'command' from serial it writes the 8 leds ( once, without transitions)?
To see where is the 'timing bootleneck' try adding some debug print, checking the show timestamp option in the serial debug ( ar use millis() or a higher resolution timer if needed )

1 Like

I see no for-loop that accomplishes this.
Instead I see some code that basically just outputs light/color to a strip based on Serial inputs being fed to it.
If you're trying to feed new color data through Serial into this Arduino, then this bit surely won't help with the responsiveness of the system:

If all you really want is a fade effect, then what is the Serial input needed for?

Because void loop() should so as to not block execution.

added PS
I had not looked into gow often there would be serial input or saw rgw delay(). Honestly there's so much wrong it's like where to start?

1 Like

but the code in the loop is ececuted only if a 'command' is received from the serial... ( so once per command )

Ok, I made a Wokwi that I think simulates your project.

I don't understand your program flow and there seems to be unnecessary calls to strip.show(); (why at the end of void setup() ?

I tried changing the Serial if to a while, tried removing the if (Serial.available() > ) {} altogether (isn't that implicit in your subsequent call to String input = Serial.readStringUntil('\n');?) and I honestly can't help beyond this because I don't understand what this sketch is supposed to do.

For example, in the Wokwi, the pixels are always all green. Also, I can't seem to get them to turn off using "0,0,0,0" after they are all turned on with "1,1,1,1" input to Serial.

Also, this

  if (Serial.available() > 0) {
    // Stage 1 Denial
    String input = Serial.readStringUntil('\n');
    parseInput(input);
    // Stage 2 Anger
    if (value1 > 0) {
      noko1 = 39;
    }

You have // Stage 1 Denial but whatever that is supposed to do...just reads input from the incoming Python data and does nothing with it before going to
// Stage 2 Anger?

I must be missing something or maybe the Wokwi is not at all representative of where you're already at, I don't know but good luck.

1 Like

Sorry, I'll try to explain what it functionality is in detail

each set of data comes in format "0,0,0,0" and the arduino receives roughly 20 sets of such data per second. The incoming data value can change between 1 and 0.

Now for the arduino side, as you can see theres 2 if command (shown in stage 2 and 3) for each of the four data (so it calculates each variable individually).

In stage 2, whenever '1' is detected, it sets the variable value of 'noko' to 39. Else, the value of noko remains unchanged.

In stage 3, as long as the value of 'noko' is not zero, it will keep decreasing once per loop() cycle until it hits zero. This is what creates the fading effect.

In stage 4, 'neko' is just amplifying the value to map/scale brightness between 0 to 234 (39x6). Then it just sets each led brightness to value of 'neko'.