If-based on calculation return wrong boolean

Hi,
I am on project creating an 3-way Emergency Traffic Light that utilize ESP-NOW and HTTP POST functionality.
So the topology of my project is like this :


There are 3 feeds (traffic light) and 1 controller.
The general logic is like this :
Emergency will send an message containing targeted priority lane to controller, then the controller will relay that messages to all other feeds. But the cycle must not break. So, for example, the target is NORTH, then SOUTH and EAST will have to haste their green duration. The maximum haste duration is 6 seconds, and the interruption duration (green duration for prioritized lane) is 30 seconds.
Now, I originally wanted to make each feed independent of each other, including the controller. So If the controller or other feed dies / malfunction, the feed will still be able to run accordingly. That is what I had in mind when designing the flow of my program (over 250+ line of calculation). But please bear with me, I'll simplify my question, reason, and goal, I'll also include the log of my program so you can see why my calculation should work but didn't.

And because of what I had mind about making each feed dependent, I tried to create every possible scenario (as in calculation, so the timing of each feed is "synced" even though independent of each other). I do that by using HostFeed variable that contain waitTime and nextInLine duration, so I can predict at what time this feed will turn RED or GREEN and how long will they last. And the formula is the same for every feed, the difference only lays in HostFeed.nextInLine and HostFeed.waitTime value. And I've done numerous manual simulation of this formula, like for example, what happen if the interruption is North at 44 second, or South and 99 second, and many more. And I am confident that my formula should work. But it didn't.
For starter, here is the scenario for interruption target NORTH at 44second


So every feed receive the same message at 44 second.

  1. C will immediately turn RED because C has already passed 6 seconds hasteGreen duration
  2. A will immediately turn GREEN because it calculate that `cM - pM >= hasteGreen (0) + loading
  3. B will has its RED turn ON, until cM - pM >= hasteGreen (0) + loading (30) is true, so RED until 74 (please check switchTraffic for condition preparation).
    Now, that's what should happen, but when B receive the message, it immediately turn GREEN, even though the condition is not satisfied. Here is the log that explain the problem on B (east) feed
EAST STATUS : -> GREEN AT 25000

EAST STATUS : -> RED AT 37000

Message from controller: north
Received on : 
44936
44936-44936>=0+30000
EAST HASTE STATUS : -> GREEN AT 44936

Switch status : match = false, semiHaste = false, greenLight = 1, hasteGreen = 6000, pM = 44936, Loading = 0

There is 2 problem from this log :

  1. 44936 - 44936 >= 0 + 30000 is NOT TRUE, so EAST feed should still has its RED turn ON until the cM reach 74936 (+30s of its initial value).
  2. Notice how "Switch status" is printed AFTER cM - pM calculation? I believe the Switch status should be printed BEFORE them, because Switch status reside in switchTraffic() that run directly after OnDataRecv.

So, TL;DR,
The formula should be correct, but why does my ESP32 don't do as the program says?
Specifically in this part of code :

else {  // match == false
      if (greenLight == false) {
        if (semiHaste == false) {
          if ((cM - pM) >= (hasteGreen + loading)) {
            // at the time of interruption, it should translates to 44 - 44 >= 0 + 30
            ////////
            Serial.print(cM);
            Serial.print("-");
            Serial.print(pM);
            Serial.print(">=");
            Serial.print(hasteGreen);
            Serial.print("+");
            Serial.print(loading);
            Serial.println("");

            ///////
            pM = cM;
            Serial.print("EAST HASTE STATUS : -> GREEN AT ");
            Serial.println(pM);
            Serial.println("");
            hasteGreen = 6000;
            if (loading > 0) {
              loading = 0;
              useSemiHaste = false;
              haste = false;
            }
            greenLight = true;
          } else {
            red();
          }

Any insight and feedback is appreciated, and even if my way of creating this program is unnecessarily complex, I am still curious as to why this happen.

I'll attach the code below,
That is all, thank you

/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp-now-one-to-many-esp32-esp8266/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*********/

#include <esp_now.h>
#include <WiFi.h>

//Structure example to receive data
//Must match t

struct Direction {
  String direction;
  int time;
  String previous;
  String next;
  int nextInLine;
  int waitTime;
};
//                  direction  time  previous  next nextInLine waitTime
Direction hostFeed = { "east", 12000, "north", "south", 25000, 60000 };
// coba add direction 2 untuk siklus interupsi

// Direction east = {"east", 11000, "north", "south", 9000, 21000};
// Direction south = {"south", 12000, "east", "north", 11000, 20000};

// TRAFFIC LAMP SET UP for MAPPI32
#define RED 18     // The ESP32 pin GPIO25 connected to R pin of traffic light module
#define YELLOW 19  // The ESP32 pin GPIO26 connected to Y pin of traffic light module
#define GREEN 23   // The ESP32 pin GPIO27 connected to G pin of traffic light module

// VARIABLE SET UP
bool haste = false;
String from;
String instruction;
bool match;
bool running = false;
bool hold = false;
bool semiHaste = false;  // semiHaste true if it is located between target and initiator
bool useSemiHaste = false;
unsigned long pM = 0;
unsigned long cM;
unsigned long interruptTime;
unsigned long iTime;
unsigned long loading = 0;
unsigned long pMv2 = 0;
unsigned long hasteGreen = 6000;
unsigned long diff;  // used to find difference between cM / interruptTime and pM


bool greenLight = false;
bool nextInLine = true;  // EAST

int intDuration = 0;

void switchTraffic(String command) {
  // N23
  // E6
  // S27
  // E18
  // S19
  // N21
  // S8
  // N23
  // S15
  haste = true;
  interruptTime = cM;
  if (command == hostFeed.direction) {
    match = true;
    pMv2 = pM + (hostFeed.waitTime - hostFeed.nextInLine);  // used when interrupted is directly next to the host
    diff = interruptTime - pM;
    Serial.print("Switch status : match = true, pMv2 = ");
    Serial.print(pMv2);
    Serial.print(", pM = ");
    Serial.print(pM);
    Serial.print(", diff = ");
    Serial.println(diff);
    Serial.println("");
  } else {                           // match = false
    if (command == hostFeed.next) {  // semiHaste true
      semiHaste = true;
      match = false;
      if (greenLight == false) {
        pM = pM + (hostFeed.waitTime - hostFeed.nextInLine);
      }
      Serial.print("Switch status : match = false, semiHaste = true, greenLight = ");
      Serial.print(greenLight);
      Serial.print(", pM = ");
      Serial.println(pM);
    } else {  // semiHaste false
      semiHaste = false;
      match = false;
      if (greenLight == false) {
        if (interruptTime - pM >= hasteGreen) {  // check if this is false, then go for
          hasteGreen = 0;
          pM = cM;
        }
        loading = 30000;
      }
      Serial.print("Switch status : match = false, semiHaste = false, greenLight = ");
      Serial.print(greenLight);
      Serial.print(", hasteGreen = ");
      Serial.print(hasteGreen);
      Serial.print(", pM = ");
      Serial.print(pM);
      Serial.print(", Loading = ");
      Serial.print(loading);
      Serial.println("");
    }
  }
}

void red() {
  digitalWrite(RED, HIGH);
  digitalWrite(GREEN, LOW);
  digitalWrite(YELLOW, LOW);
}
void green() {
  digitalWrite(RED, LOW);
  digitalWrite(YELLOW, LOW);
  digitalWrite(GREEN, HIGH);
}

void handleTraffic() {

  // Example template for testing
  // N19s
  // N19s NORTH
  //// n.a... cM - pM > 4 bla bla at Xs trigger to greenLight ON, correct
  //// n.a condition : bla bla bla

  cM = millis();

  if (haste == true) {
    if (match == true) {
      // pMv2 = pM + (hostFeed.waitTime - hostFeed.nextInLine)
      // diff = interruptTime - pM
      if (greenLight == false) {
        if (diff <= hasteGreen) {  // MODE A
          if (cM - pM >= 12000) {  // if interrupt is not adjacent to the host
            pM = cM;
            Serial.print("EAST HASTE STATUS : MODE A -> GREEN AT ");
            Serial.println(pM);
            Serial.println("");
            greenLight = true;
          } else {
            red();
          }
        } else if (diff > hasteGreen && diff <= 12000) {  // MODE B
          if (cM - pM >= hasteGreen + diff) {
            pM = cM;
            Serial.print("EAST HASTE STATUS : MODE B -> GREEN AT ");
            Serial.println(pM);
            Serial.println("");
            greenLight = true;
          } else {
            red();
          }
        } else {  // MODE C
          if (interruptTime > pM + (hostFeed.waitTime - hostFeed.nextInLine)) {
            if (cM - pMv2 >= hasteGreen) {
              pM = cM;
              Serial.print("EAST HASTE STATUS : MODE C -> GREEN AT ");
              Serial.println(pM);
              greenLight = true;
            } else {
              red();
            }
          } else {  // MODE D
            if (cM >= interruptTime + hasteGreen) {
              pM = cM;
              Serial.print("EAST HASTE STATUS : MODE D -> GREEN AT ");
              Serial.println(pM);
              Serial.println("");
              greenLight = true;
            } else {
              red();
            }
          }
        }
      } else {  // greenLight == true
        if (cM - pM >= 30000) {
          pM = cM;
          Serial.print("EAST HASTE STATUS : -> RED AT ");
          Serial.println(pM);
          Serial.println("");
          greenLight = false;
          haste = false;
        } else {
          green();
        }
      }

    } else {  // match == false
      if (greenLight == false) {
        if (semiHaste == false) {
          if ((cM - pM) >= (hasteGreen + loading)) {
            ////////
            Serial.print(cM);
            Serial.print("-");
            Serial.print(pM);
            Serial.print(">=");
            Serial.print(hasteGreen);
            Serial.print("+");
            Serial.print(loading);
            Serial.println("");

            ///////
            pM = cM;
            Serial.print("EAST HASTE STATUS : -> GREEN AT ");
            Serial.println(pM);
            Serial.println("");
            hasteGreen = 6000;
            if (loading > 0) {
              loading = 0;
              useSemiHaste = false;
              haste = false;
            }
            greenLight = true;
          } else {
            red();
          }
        } else {  // semiHaste == true
          if (useSemiHaste == false) {
            if (cM - pM >= hasteGreen + loading) {
              pM = cM;
              Serial.print("EAST HASTE STATUS  (semiHaste) : -> GREEN AT ");
              Serial.println(pM);
              Serial.println("");
              if (loading > 1) {
                loading = 0;
                haste = false;
              }
              greenLight = true;
            } else {
              red();
            }
          } else {  // useSemiHaste == true
            if (cM - pM >= loading + hostFeed.nextInLine) {
              pM = cM;
              if (loading > 0) {
                loading = 0;
                useSemiHaste = false;
                haste = false;
              }
              greenLight = true;
            } else {
              red();
            }
          }
        }
      } else {  // greenLight == true
        if (cM - pM >= hasteGreen) {
          Serial.print("EAST HASTE STATUS : -> RED AT ");
          Serial.println(pM);
          Serial.println("");
          pM = cM;
          greenLight = false;
          loading = 30000;
          useSemiHaste = true;
        } else {
          green();
        }
      }
    }
    ////////////////////////////////////////////// NORMAL /////////////////////////////////////////////////
  } else {
    if (greenLight == true) {
      if (cM - pM >= hostFeed.time) {
        pM = cM;
        Serial.print("EAST STATUS : -> RED AT ");
        Serial.println(pM);
        Serial.println("");
        // if (hold == true) {
        //   pM = hostFeed.time + pM;
        // } else {
        //   pM = cM;
        // }
        // Serial.print("Switch to RED, p : ");
        // Serial.println(pM);
        hold = false;
        greenLight = false;
      } else {
        green();
      }
    } else {  // greenLight = false
      if (nextInLine == true) {
        if (cM - pM >= hostFeed.nextInLine) {
          pM = cM;
          Serial.print("EAST STATUS : -> GREEN AT ");
          Serial.println(pM);
          Serial.println("");
          greenLight = true;
          nextInLine = false;
        } else {
          red();
        }
      } else {
        if (cM - pM >= hostFeed.waitTime) {
          pM = cM;
          Serial.print("EAST STATUS : -> GREEN AT ");
          Serial.println(pM);
          Serial.println("");
          // Serial.print("Current report : p -> ");
          // Serial.println(pM);
          // if (hold == true) {
          //   pM = hostFeed.waitTime + pM;
          // } else {
          //   pM = cM;
          // }
          // Serial.print("Switch to GREEN, p : ");
          // Serial.println(pM);
          hold = false;
          greenLight = true;
        } else {
          red();
        }
      }
    }
  }
}







void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) {
  memcpy(&from, incomingData, sizeof(from));
  String direction = String((char *)incomingData);
  Serial.print("Message from controller: ");
  Serial.println(from);
  iTime = millis();
  Serial.println("Received on : ");
  Serial.print(iTime);
  Serial.println("");
  // if (from == "start") {
  //   running = true;
  //   pM = millis();
  // } else if (from == "stop") {
  //   running = false;
  // } else {
  switchTraffic(from);
  // }
}

void setup() {
  pinMode(RED, OUTPUT);
  pinMode(YELLOW, OUTPUT);
  pinMode(GREEN, OUTPUT);
  //Initialize Serial Monitor
  Serial.begin(115200);

  //Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  //Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);
  Serial.println("East Listening..");
}

void loop() {
  // if (running == true) {
  handleTraffic();
  // } else {
  //   digitalWrite(YELLOW, HIGH);
  // }
}

Well your code is doing exactly what you programmed it to do, that is how code works.

If you want to see the result of a calculation then calculate it and print it out before you applying it to your if statement.

From the log printed in serial monitor, I believe the program should wait for 30s before turning greenLight = true. But it immediately set greenLight = true after it receive the instruction (at 44s) .
I still don't understand the reason behind this error.

Your timing chart looks like the timing chart in this simulation... the simulation uses milliseconds for timing, just like your program.

That is because the formula is not correct.

It helps enormously to post all your code along with a schematic.

You can add comments in the code explaining where you think things start to go wrong. You could also not be using the correct type of variable, who knows until we see all the code?

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