Help using millis, one LED continuously triggers while the other LED never triggers

This is the minimal program:

/*
    ESP32 https://www.mouser.com/ProductDetail/Espressif-Systems/ESP32-DevKitC-32D

    Could work with Arduino Uno or similar.

*/


#include <Adafruit_NeoPixel.h>

#define RXD2 16
#define TXD2 17

//Digital LED addressing control pins (one for each strand)
#define PIN4 27 // ckt down
#define PIN5 13 // ckt up

// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 13


Adafruit_NeoPixel pixels4(NUMPIXELS, PIN4, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels5(NUMPIXELS, PIN5, NEO_GRB + NEO_KHZ800);

unsigned long previousTime = millis();  // timestamp

unsigned long currentTime;


bool latch = false;

const unsigned long eventInterval = 9;

unsigned long startMillis4 = millis();
unsigned long startMillis5 = millis();


unsigned long now4;
unsigned long now5;


byte l = 0;
byte m = 0;


bool latch4 = false;
bool latch5 = false;

const int period = 200;

byte note = 0; //The MIDI note value to be played
byte resetMIDI = 4; //Reset line
int  instrument = 0;


int x4_a, y4_a;
int x4_b, y4_b;

int x5_a, y5_a;
int x5_b, y5_b;

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

  //Setup soft serial for MIDI control
  Serial2.begin(31250, SERIAL_8N1, RXD2, TXD2);

  pinMode(26, INPUT);
  pinMode(25, INPUT);
  pinMode(27, INPUT);
  pinMode(14, INPUT);

  pixels4.begin();
  pixels5.begin();
}

void loop()
{






  if (latch == false)
  {
    x4_a = analogRead(26);
    y4_a = analogRead(25);

    x5_a = analogRead(27);
    y5_a = analogRead(14);

    latch = true;
  }

  currentTime = millis();

  if (currentTime - previousTime >= eventInterval && latch == true)
  {

    x4_b = analogRead(26);  // accelerometer x
    y4_b = analogRead(25);  // accelerometer y

    x5_b = analogRead(27);
    y5_b = analogRead(14);


    x4_a = x4_b - x4_a;
    y4_a = y4_b - y4_a;

    x5_a = x5_b - x5_a;
    y5_a = y5_b - y5_a;



    Serial.print("x: ");
    Serial.print(x4_a);
    Serial.print("    y: ");
    Serial.println(y4_a);

    Serial.print("x: ");
    Serial.print(x5_a);
    Serial.print("    y: ");
    Serial.println(y5_a);


    //Update the timing for the next time around
    previousTime = currentTime;
    latch = false;
  }





  int xTolerance = 35;
  int yTolerance = 35;





  if (abs(x4_a) > xTolerance || abs(y4_a) > yTolerance)
  {
    latch4 = true;
  }

  if (abs(x5_a) > xTolerance || abs(y5_a) > yTolerance)
  {
    latch5 = true;

  }


  // 4th strand, activate                                             ---
  now4 = millis();

  if (latch4 == true)
  {
    if (now4 - startMillis4 >= period)
    {
      startMillis4 = now4;  // save timestamp

      if (l >= NUMPIXELS)
      {
        l = 0; // reset i at max value
        pixels4.clear(); // Set all pixel colors to 'off'
        latch4 = false;
      }

      pixels4.setPixelColor( l, pixels4.Color(150 - l * 20, l * 20, 0) );

      pixels4.show();   // Send the updated pixel colors to the hardware

      l++;  // go to next value
    }
  }


  // 5th strand, activate                                             ---

  now5 = millis();

  if (latch5 == true)
  {
    if (now5 - startMillis5 >= period)
    {
      startMillis5 = now5;  // save timestamp

      if (m >= NUMPIXELS)
      {
        m = 0; // reset i at max value
        pixels5.clear();
        latch5 = false;

      }

      pixels5.setPixelColor( m, pixels5.Color(150 - m * 20, m * 20, 0) );

      pixels5.show();

      m++;  // go to next value
    }
  }





}

I think there is something off with my placement of "latches." The LED should only go off or trigger if the accelerometers sense a large movement different (based on the tolerance).

What are these, "latches"? What are their function?

Placing time stamp checks inside any conditional block, is often the kiss of death. It's not an automatic failure, but it is a risky hazard that has to be carefully implemented (and it's rarely actually necessary).

This is where I am trying to do the equivalent of:

    x4_a = analogRead(26);
    y4_a = analogRead(25);

    x5_a = analogRead(27);
    y5_a = analogRead(14);

    delay(period);

    x4_b = analogRead(26);  // accelerometer x
    y4_b = analogRead(25);  // accelerometer y

    x5_b = analogRead(27);
    y5_b = analogRead(14);


    x4_a = x4_b - x4_a;
    y4_a = y4_b - y4_a;

    x5_a = x5_b - x5_a;
    y5_a = y5_b - y5_a;

Your program purpose and flow is not self explanatory. Can you please post a concise verbal description or better, pseudocode?

I suspect a procedural flow problem but your source code is too complex to grasp quickly.

There are two LED strands. An LED strand should only go off, light, if its respective accelerometer senses a large enough movement difference (based on a tolerance).

So if accelerometer4 is triggered, LED strand4 should light. If accelerometer5 is triggered, LED strand5 should light. If they are both triggered at the same time, they should both go off. If there is no or little movement, nothing should light.

In contrast to that desired action, what happens instead?

5th strand continually lights non-stop.
4th strand never lights.

Not sure which part you are referring to...

Which one? Please don't use non-specific language.

From the description in reply #6, there is no functional coupling between the two strips, each one can operate independently. So, you should make one work, and then simply add another one in loop(). To do that, you must ensure that nothing blocks. Instead of duplication, you could also factor the code and create strip objects using a C++ class, or at least use arrays.

Please do not go back and edit previous posts, when it makes subsequent replies seem incorrect. It's a forum no-no.

What do you think about my reply #11? If it is written the way I described, you could just comment out each strip and test, one at a time.

Do you see where I'm headed with this? Try to iron things out by design, not probing for some hidden issue...

You did not yet understand how effective communication about programming works
You have to be very precise. And the highest precisision is to post your actual and complete sketch with added comments where you changed something

What is "the first if-statement"???

What is "second if-statement"???

this is a unprecise description
an un-beatable precise description would be to post you actual and complete sketch.

Just doing a follow up, wasn't meant to be anything more. I'll delete since it's confusing others.

How about posting the actual and complete sketch?

Still has bugs, working on

the main purpose of the forum is to help based on detailed informations = actual and complete sketch. But of course you are free to work on it on your own for how long you ever want

/*
    ESP32 https://www.mouser.com/ProductDetail/Espressif-Systems/ESP32-DevKitC-32D

    Could work with Arduino Uno or similar.

*/


#include <Adafruit_NeoPixel.h>

#define RXD2 16
#define TXD2 17

//Digital LED addressing control pins (one for each strand)
#define PIN4 27 // ckt down
#define PIN5 13 // ckt up

// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 13


Adafruit_NeoPixel pixels4(NUMPIXELS, PIN4, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels5(NUMPIXELS, PIN5, NEO_GRB + NEO_KHZ800);

unsigned long previousTime = millis();  // timestamp

unsigned long currentTime;


bool latch = false;

const unsigned long eventInterval = 9;

unsigned long startMillis4 = millis();
unsigned long startMillis5 = millis();


unsigned long now4;
unsigned long now5;


byte l = 0;
byte m = 0;


bool latch4 = false;
bool latch5 = false;

const int period = 200;

byte note = 0; //The MIDI note value to be played
byte resetMIDI = 4; //Reset line
int  instrument = 0;


int x4_a, y4_a;
int x4_b, y4_b;

int x5_a, y5_a;
int x5_b, y5_b;

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

  //Setup soft serial for MIDI control
  Serial2.begin(31250, SERIAL_8N1, RXD2, TXD2);

  pinMode(26, INPUT);
  pinMode(25, INPUT);
  pinMode(27, INPUT);
  pinMode(14, INPUT);

  pixels4.begin();
  pixels5.begin();
}

void loop()
{






  if (latch == false)
  {
    x4_a = analogRead(26);
    y4_a = analogRead(25);

    x5_a = analogRead(27);
    y5_a = analogRead(14);

    latch = true;
  }

  currentTime = millis();

  if (currentTime - previousTime >= eventInterval && latch == true)
  {

    x4_b = analogRead(26);  // accelerometer x
    y4_b = analogRead(25);  // accelerometer y

    x5_b = analogRead(27);
    y5_b = analogRead(14);


    x4_a = x4_b - x4_a;
    y4_a = y4_b - y4_a;

    x5_a = x5_b - x5_a;
    y5_a = y5_b - y5_a;



    Serial.print("x: ");
    Serial.print(x4_a);
    Serial.print("    y: ");
    Serial.println(y4_a);

    Serial.print("x: ");
    Serial.print(x5_a);
    Serial.print("    y: ");
    Serial.println(y5_a);




 int xTolerance = 35;
  int yTolerance = 35;





  if (abs(x4_a) > xTolerance || abs(y4_a) > yTolerance)
  {
    latch4 = true;
//    delay(3000);
  }

//  if (abs(x5_a) > xTolerance || abs(y5_a) > yTolerance)
//  {
//    latch5 = true;
//
//  }


//   4th strand, activate                                             ---
  now4 = millis();

  if (latch4 == true)
  {
    if (now4 - startMillis4 >= period)
    {
      startMillis4 = now4;  // save timestamp

      if (l >= NUMPIXELS)
      {
        l = 0; // reset i at max value
        pixels4.clear(); // Set all pixel colors to 'off'
        latch4 = false;
      }

      pixels4.setPixelColor( l, pixels4.Color(150 - l * 20, l * 20, 0) );

      pixels4.show();   // Send the updated pixel colors to the hardware

      l++;  // go to next value
    }
  }


  // 5th strand, activate                                             ---

  now5 = millis();

  if (latch5 == true)
  {
    if (now5 - startMillis5 >= period)
    {
      startMillis5 = now5;  // save timestamp

      if (m >= NUMPIXELS)
      {
        m = 0; // reset i at max value
        pixels5.clear();
        latch5 = false;

      }

      pixels5.setPixelColor( m, pixels5.Color(150 - m * 20, m * 20, 0) );

      pixels5.show();

      m++;  // go to next value
    }
  }















    //Update the timing for the next time around
    previousTime = currentTime;
    latch = false;
  }





 




}

I re-formatted your code from 229 lines to 153 lines by deleting empty lines

Do yourself and your potential helpers a favor and delete too many empty lines and use auto-formatting for proper indentions of all lines of code

/*    ESP32 https://www.mouser.com/ProductDetail/Espressif-Systems/ESP32-DevKitC-32D
    Could work with Arduino Uno or similar.
*/

#include <Adafruit_NeoPixel.h>

#define RXD2 16
#define TXD2 17

//Digital LED addressing control pins (one for each strand)
#define PIN4 27 // ckt down
#define PIN5 13 // ckt up

// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 13

Adafruit_NeoPixel pixels4(NUMPIXELS, PIN4, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels5(NUMPIXELS, PIN5, NEO_GRB + NEO_KHZ800);

unsigned long previousTime = millis();  // timestamp

unsigned long currentTime;

bool latch = false;

const unsigned long eventInterval = 9;

unsigned long startMillis4 = millis();
unsigned long startMillis5 = millis();

unsigned long now4;
unsigned long now5;

byte l = 0;
byte m = 0;

bool latch4 = false;
bool latch5 = false;

const int period = 200;

byte note = 0; //The MIDI note value to be played
byte resetMIDI = 4; //Reset line
int  instrument = 0;


int x4_a, y4_a;
int x4_b, y4_b;

int x5_a, y5_a;
int x5_b, y5_b;

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");

  //Setup soft serial for MIDI control
  Serial2.begin(31250, SERIAL_8N1, RXD2, TXD2);

  pinMode(26, INPUT);
  pinMode(25, INPUT);
  pinMode(27, INPUT);
  pinMode(14, INPUT);

  pixels4.begin();
  pixels5.begin();
}

void loop() {

  if (latch == false) {
    x4_a = analogRead(26);
    y4_a = analogRead(25);

    x5_a = analogRead(27);
    y5_a = analogRead(14);

    latch = true;
  }

  currentTime = millis();

  if (currentTime - previousTime >= eventInterval && latch == true) {
    x4_b = analogRead(26);  // accelerometer x
    y4_b = analogRead(25);  // accelerometer y

    x5_b = analogRead(27);
    y5_b = analogRead(14);

    x4_a = x4_b - x4_a;
    y4_a = y4_b - y4_a;

    x5_a = x5_b - x5_a;
    y5_a = y5_b - y5_a;

    Serial.print("x: ");
    Serial.print(x4_a);
    Serial.print("    y: ");
    Serial.println(y4_a);

    Serial.print("x: ");
    Serial.print(x5_a);
    Serial.print("    y: ");
    Serial.println(y5_a);

    int xTolerance = 35;
    int yTolerance = 35;

    if (abs(x4_a) > xTolerance || abs(y4_a) > yTolerance){
      latch4 = true;
      //    delay(3000);
    }
    //  if (abs(x5_a) > xTolerance || abs(y5_a) > yTolerance) {
    //    latch5 = true;    //
    //  }
    //   4th strand, activate                                             ---
    now4 = millis();

    if (latch4 == true) {
      if (now4 - startMillis4 >= period) {
        startMillis4 = now4;  // save timestamp
        if (l >= NUMPIXELS) {
          l = 0; // reset i at max value
          pixels4.clear(); // Set all pixel colors to 'off'
          latch4 = false;
        }
        pixels4.setPixelColor( l, pixels4.Color(150 - l * 20, l * 20, 0) );
        pixels4.show();   // Send the updated pixel colors to the hardware
        l++;  // go to next value
      }
    }
    // 5th strand, activate                                             ---
    now5 = millis();

    if (latch5 == true) {
      if (now5 - startMillis5 >= period) {
        startMillis5 = now5;  // save timestamp

        if (m >= NUMPIXELS) {
          m = 0; // reset i at max value
          pixels5.clear();
          latch5 = false;
        }
        pixels5.setPixelColor( m, pixels5.Color(150 - m * 20, m * 20, 0) );
        pixels5.show();
        m++;  // go to next value
      }
    }
    //Update the timing for the next time around
    previousTime = currentTime;
    latch = false;
  }
}

best regards Stefan

Serial is a great debug assistant.
Send stuff like your latches and other variables through serial, and you might suddenly see what your sketch sees and what it misses.
It will help you pinpoint the problem.
To prevent a too fast scrolling output of serial, build in some delay()s.
Your serial communications and the delays can be commented out when you're done debugging, or in case you're 100% sure debugging is done these lines can be deleted.

not nescessary to use delay()
you can use non-blocking timing with macros like that

print name and value only once every timeinterval milliseconds

#define dbgi(myFixedText, variableName,timeInterval) \
  { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  }

print name and value only if value has changed

#define dbgc(myFixedText, variableName) \
  { \
    static long lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }

Demo-Code

// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *

// a detailed explanation how these macros work is given in this tutorial
// https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  }
// usage: dbgi("2:my fixed text",myVariable,1000);
// myVariable can be any variable or expression that is defined in scope
// third parameter is the time in milliseconds that must pass by until the next time a
// Serial.print is executed
// end of macros dbg and dbgi
// print only once when value has changed
#define dbgc(myFixedText, variableName) \
  { \
    static long lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }

#define dbgcf(myFixedText, variableName) \
  { \
    static float lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}

unsigned long MyTestTimer1 =  0;                   // Timer-variables MUST be of type unsigned long
unsigned long MyTestTimer2 =  0;                   // Timer-variables MUST be of type unsigned long

const byte    OnBoard_LED  = 13;

long myLong = 0;
float myFloat = -0.1;

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();

}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 250);

  // print value of variable myLong once every 500 milliseconds
  dbgi("dbgi1:", myLong, 500);

  // print value of variable myLong only if value has CHANGED
  // since last time it was printed
  dbgc("dbgc1:", myLong);


  // print value of variable myFloat only if value has CHANGED
  // since last time it was printed
  dbgcf("dbgcf:", myFloat);

  // check if 2000 milliseconds have passed by
  if ( TimePeriodIsOver(MyTestTimer1, 2000) ) {
    // when REALLY 2000 milliseconds have passed by
    myLong++; // increment variable myLong by 1
  }

  // check if 6000 milliseconds have passed by
  if ( TimePeriodIsOver(MyTestTimer2, 6000) ) {
    // when REALLY 6000 milliseconds have passed by
    myFloat += 0.5; // incrfement variable myFloat by 0.5
  }

}