Arduino sketch function limits - script kills all lights?

I'm re-visiting Arduino after a long time, so I'm sort of new to it. I'm making a game using Unity keypresses to tell Arduino how to control 3 LED lights, and 1 LED strip. I'm using the library here to help with communications between Arduino and Unity.

The 3 LED lights get triggered to flash on/off indefinitely at diff points in the game, until told to turn off, but should still be able to be triggered to flash again later. The LED strip acts like a "health bar" and can either be emptied (turned off), filled to all green, raised or lowered by one light at a time, or filled to all red and then reset back to green again.

Everything, the flashing LEDS and the health bar strip, was working great - until I added in the last functions to turn the strip red and reset back to green. Then, any button that controlled the LAST LED button didn't trigger its flash - it turned off EVERY light on the setup! Then, after taking away the functions for the red - everything worked fine again - tho of course now I can't turn the LED strip red.

Hence, my fear is my code is getting bloated or messy or overloaded somewhere, i.e. my loop is running too fast or has too much stuff in it, but that's where my understanding stops. My output says the sketch uses 22% of program storage space, and global variables use 30% of dynamic memory.

So, my question is, what would I need to better optimize this code? I can send schematics of the circuit if needed too.

Apologies for the giant essay of code ... I'm guessing that's part of the problem!! Thanks in advance for any advice, this feels totally above my head.

#include <FastLED.h>
#include <SerialCommand.h>
#include <SoftwareSerial.h>

// LED strip variable ---------------------------------------------------------------------------
#define NUM_LEDS 11
CRGB leds[NUM_LEDS];
#define LED_PIN 9
static int currentAmt;

// Engine fix variables----------------------------------------------------------------------------
int LED1 = 3;
int LED2 = 4;
int LED3 = 5;

bool led1Trigger;
bool led2Trigger;
bool led3Trigger;

bool led1Flash;
bool led2Flash;
bool led3Flash;

int led1State = LOW;
int led2State = LOW;
int led3State = LOW;

unsigned long prevMillis = 0;
const long interval = 1000;

// communication between unity and arduino--------------------------------------------------
SerialCommand sCmd;

void setup() {
  Serial.begin(9600);

  // commands for fuel bar -----------------------------------------------------------------------
  sCmd.addCommand("FILL", fillHandler);
  sCmd.addCommand("RAISE", raiseHandler);
  sCmd.addCommand("LOWER", lowerHandler);
  sCmd.addCommand("EMPTY", emptyHandler);
  sCmd.addCommand("RED", redHandler);
  sCmd.addCommand("RESETGREEN", resetGreenHandler);

  // commands for engine leds--------------------------------------------------------------
  sCmd.addCommand("BLINK1", blink1);
  sCmd.addCommand("FIX1", fix1);
  sCmd.addCommand("BLINK2", blink2);
  sCmd.addCommand("FIX2", fix2);
  sCmd.addCommand("BLINK3", blink3);
  sCmd.addCommand("FIX3", fix3);

  // sets up the LED strip -------------------------------------------------------------------------
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS); // sets up our strip
  FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // limits it to only take 5 volts
  FastLED.clear();
  FastLED.show();

  // sets up the engine LEDS ---------------------------------------------------------------------
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);

}

void loop() {

  // for communicating between arduino and unity ----------------------------------------------------
  if (Serial.available() > 0) {
    sCmd.readSerial();
  }

  // engine light stuff ---------------------------------------------------------------------------------
  unsigned long currentMillis = millis();

  // these are all to say if the engine has been triggered, then the matching LED should begin flashing LED 1
  if (led1Trigger == true) {
    led1Flash = true;
  } else {
    led1Flash = false;
  }

  // LED 2
  if (led2Trigger == true) {
    led2Flash = true;
  } else {
    led2Flash = false;
  }

  //LED 3
  if (led3Trigger == true) {
    led3Flash = true;
  } else {
    led3Flash = false;
  }



  // this controls the on/off flashing, and also the ability the turn OFF the flashing
  if (currentMillis - prevMillis >= interval) {
    prevMillis = currentMillis;

    // LED 1
    if (led1State == LOW) {
      led1State = HIGH;
    } else {
      led1State = LOW;
    }

    if (led1Flash == true) {
      digitalWrite(LED1, led1State);
    } else {
      digitalWrite(LED1, LOW);
    }

    // LED 2
    if (led2State == LOW) {
      led2State = HIGH;
    } else {
      led2State = LOW;
    }

    if (led2Flash == true) {
      digitalWrite(LED2, led2State);
    } else {
      digitalWrite(LED2, LOW);
    }

    // LED 3
    if (led3State == LOW) {
      led3State = HIGH;
    } else {
      led3State = LOW;
    }

    if (led3Flash == true) {
      digitalWrite(LED3, led3State);
    } else {
      digitalWrite(LED3, LOW);
    }

  }
}

// engine LED commands -----------------------------------------------------------------------------------------
void blink1(const char *command) { led1Trigger = true; }

void fix1(const char *command) { led1Trigger = false; }

void blink2(const char *command) { led2Trigger = true; }

void fix2(const char *command) { led2Trigger = false; }

void blink3(const char *command) { led3Trigger = true; }

void fix3(const char *command) { led3Trigger = false; }

// fuel bar commands ----------------------------------------------------------------------------------------------
void fillHandler(const char *command) {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB(0, 255, 0);
    FastLED.show();
    delay(20);
  }
  currentAmt = NUM_LEDS - 1;
}

void raiseHandler(const char *command) {
  if (currentAmt < NUM_LEDS - 1) {
    leds[currentAmt] = CRGB(0, 255, 0);
    FastLED.show();
    currentAmt += 1;
  } else if (currentAmt == NUM_LEDS - 1) {
    leds[currentAmt] = CRGB(0, 255, 0);
    FastLED.show();
  }
}

void lowerHandler(const char *command) {
  if (currentAmt > 1) {
    leds[currentAmt] = CRGB::Black;
    FastLED.show();
    currentAmt -= 1;
  } else if (currentAmt == 1) {
    leds[currentAmt] = CRGB::Black;
    FastLED.show();
  }
}

void emptyHandler(const char *command) {
  for (int i = currentAmt; i >= 0; i--) {
    leds[i] = CRGB::Black;
    FastLED.show();
    delay(20);
  }
  currentAmt = 1;
}

// turns the whole LED strip red ----------------------------------------------------------
void redHandler (const char *command) {
    for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB(255, 0, 0);
    FastLED.show();
    delay(20);
  }
}

//turns the red off, and LED strip back to the amount of green it last had -----------------------------------------
void resetGreenHandler (const char *command) {
  for (int i = 0; i < NUM_LEDS; i++){
    leds[i] = CRGB::Black;
    FastLED.show();
  }
  for (int i = 0; i < currentAmt; i++) {
      leds[i] = CRGB(0, 255, 0);
      FastLED.show();
      delay(20);
  }
}

Don't wait.  Add a schematic as soon as you are able.

p.s. Fritzing diagrams are not considered schematics here.

2 Likes

Hi @meeeky,

here is (hopefully) some good news:

Think I got your sketch running on Wokwi:

You can input the Serial commands and see how the RGB leds and the three others act.

Feel also free to test this sketch that makes use of a structure for the three leds, an array to control them and a single function to fill the stripe from 0 to a given lastIndex.

It's also on Wokwi: https://wokwi.com/projects/386390922739579905

/*
  Forum: https://forum.arduino.cc/t/arduino-sketch-function-limits-script-kills-all-lights/1208706
  Wokwi: https://wokwi.com/projects/386390922739579905

*/

#include <FastLED.h>
#include <SerialCommand.h>
#include <SoftwareSerial.h>

// LED strip variable ---------------------------------------------------------------------------
#define NUM_LEDS 11
CRGB leds[NUM_LEDS];
#define LED_PIN 9
static int currentAmt;

// Engine fix variables----------------------------------------------------------------------------
struct engineLeds {
  byte pin = 0;
  boolean flash = false;
  byte state = LOW;
  void init(byte aPin) {
    pin = aPin;
    pinMode(pin, OUTPUT);
  }
  void set(byte aState) {
    if (state == aState) {
      return;
    }
    state = aState;
    digitalWrite(pin, state);
  }
  void toggle() {
    set(!state);
  }
  void handle() {
    if (flash) {
      toggle();
    } else {
      set(LOW);
    }
  }
};

const byte noOfLeds {3};
engineLeds led[noOfLeds];
const byte LEDPINs[noOfLeds] = {3, 4, 5};

unsigned long prevMillis = 0;
const long interval = 1000;

// communication between unity and arduino--------------------------------------------------
SerialCommand sCmd;

void setup() {
  Serial.begin(9600);
  Serial.println("Start");

  // commands for fuel bar -----------------------------------------------------------------------
  sCmd.addCommand("FILL", fillHandler);
  sCmd.addCommand("RAISE", raiseHandler);
  sCmd.addCommand("LOWER", lowerHandler);
  sCmd.addCommand("EMPTY", emptyHandler);
  sCmd.addCommand("RED", redHandler);
  sCmd.addCommand("RESETGREEN", resetGreenHandler);

  // commands for engine leds--------------------------------------------------------------
  sCmd.addCommand("BLINK1", blink1);
  sCmd.addCommand("FIX1", fix1);
  sCmd.addCommand("BLINK2", blink2);
  sCmd.addCommand("FIX2", fix2);
  sCmd.addCommand("BLINK3", blink3);
  sCmd.addCommand("FIX3", fix3);

  // sets up the LED strip -------------------------------------------------------------------------
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS); // sets up our strip
  FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // limits it to only take 5 volts
  FastLED.clear();
  FastLED.show();

  // sets up the engine LEDS ---------------------------------------------------------------------
  for (int i = 0; i < noOfLeds; i++) {
    led[i].init(LEDPINs[i]);
  }
}

void loop() {

  // for communicating between arduino and unity ----------------------------------------------------
  if (Serial.available() > 0) {
    sCmd.readSerial();
  }

  // engine light stuff ---------------------------------------------------------------------------------
  unsigned long currentMillis = millis();
  // this controls the on/off flashing, and also the ability to turn OFF the flashing
  if (currentMillis - prevMillis >= interval) {
    prevMillis = currentMillis;
    for (int i = 0; i < noOfLeds; i++) {
      led[i].handle();
    }
  }
}

// engine LED commands -----------------------------------------------------------------------------------------
void blink1(const char *command) {
  led[0].flash   = true;
}

void fix1(const char *command) {
  led[0].flash   = false;
}

void blink2(const char *command) {
  led[1].flash   = true;
}

void fix2(const char *command) {
  led[1].flash   = false;
}

void blink3(const char *command) {
  led[2].flash   = true;
}

void fix3(const char *command) {
  led[2].flash   = false;
}

// fuel bar commands ----------------------------------------------------------------------------------------------
void fillHandler(const char *command) {
  fill(CRGB(0, 255, 0), 20, NUM_LEDS);
  currentAmt = NUM_LEDS - 1;
}

void raiseHandler(const char *command) {
  if (currentAmt < NUM_LEDS - 1) {
    leds[currentAmt] = CRGB(0, 255, 0);
    FastLED.show();
    currentAmt += 1;
  } else if (currentAmt == NUM_LEDS - 1) {
    leds[currentAmt] = CRGB(0, 255, 0);
    FastLED.show();
  }
}

void lowerHandler(const char *command) {
  if (currentAmt > 1) {
    leds[currentAmt] = CRGB::Black;
    FastLED.show();
    currentAmt -= 1;
  } else if (currentAmt == 1) {
    leds[currentAmt] = CRGB::Black;
    FastLED.show();
  }
}

void emptyHandler(const char *command) {
  for (int i = currentAmt; i >= 0; i--) {
    leds[i] = CRGB::Black;
    FastLED.show();
    delay(20);
  }
  currentAmt = 1;
}

// turns the whole LED strip red ----------------------------------------------------------
void redHandler (const char *command) {
  fill(CRGB(255, 0, 0), 20, NUM_LEDS);
}

//turns the red off, and LED strip back to the amount of green it last had -----------------------------------------
void resetGreenHandler (const char *command) {
  fill(CRGB::Black, 0, NUM_LEDS);
  for (int i = 0; i < currentAmt; i++) {
    leds[i] = CRGB(0, 255, 0);
    FastLED.show();
    delay(20);
  }
}

void fill(CRGB color, int dely, int lastIndex) {
  for (int i = 0; i < lastIndex; i++) {
    leds[i] = color;
    FastLED.show();
    delay(dely);
  }
}

Good luck!

1 Like

@ec2021 Firstly, thank you for such a quick response?! I haven't even heard of Wokwi, so that's an immense help in and of itself. It's also very helpful to see how you've re-written this to have less happening in the loop, and combined the 2 repetitive led-strip fill functions into one function - simplifying redundant stuff is always something I've struggled with!

Unfortunately when it was hooked up to the hardware set-up, the 3rd LED button still shut everything off. Removing some of the LED strip functions from the code again let the LED buttons work normally.

I hesitated to think this was a hardware/power issue because everything works fine with this setup prior to adding in a couple more functions - but here's some images of the circuit setup. I did not mention in the previous post there are other buttons and joysticks, but they're being controlled separately with a zero delay encoder. My friend - who's currently on the other side of the country haha - is the one wiring things up, so if any clarity is needed I can ask for more.

Thanks again for the suggestions and advice!

Your picture shows more LEDs than mentioned in the sketch. Are each of them connected via a resistor?

It doesn't look like a software issue and therefore it's more likely that there is a hardware problem...

@ec2021 Yeah - so the other LED's (on pins 7 and 6, for example) are actually light-up arcade buttons which are controlled via a zero delay encoder as input for the Unity game, and do not have any interaction with the Arduino besides being plugged into it. Those 2 buttons have resistors built-in and are from Adafruit, but we've also tried connecting them with extra resistors anyways. I do agree at this point through both mine and your script that the software seems good, so it'd be back to the hardware.

We were initially worried that the Arduino and zero delay encoder would interfere with each other, but up until this point with earlier tests, they seemed to be fine and quite separate.

figured it out!!! Kicking myself for this, because this feels so.... I could have done this a million steps ago. The library I was using for communications between Arduino and Unity was the thing messing it up. The hardware and code was all fine, because when I switched methods of communication, everything was fixed. Thanks again everyone for your tips, it helped me narrow down where the issues stemmed from.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.