Arduino code takes long to "load" on the Arduino itself

So I have this (long) code:

#include <Servo.h>
#include <LiquidCrystal_I2C.h>


#include <ezButton.h>

ezButton toggleSwitch(1);  // create ezButton object that attach to pin 1;


enum Direction { left,
                 right,
                 front,
                 back };

int enA = 6;
int in1 = 7;
int in2 = 8;

// Motor B

int enB = 3;
int in3 = 4;
int in4 = 5;

int RightUltrasonicEcho = 16;
int RightUltrasonicTrigger = 17;
int LeftUltrasonicEcho = 12;
int LeftUltrasonicTrigger = 11;
int FrontUltrasonicEcho = 14;
int FrontUltrasonicTrigger = 15;
int BackUltrasonicEcho = 13;
int BackUltrasonicTrigger = 2;
int rotation = 0;

Servo FrontServo;
LiquidCrystal_I2C lcd(0x27, 16, 2);


bool CurrentlyMovingForward = false;
bool CurrentlySynchronous = false;
bool Parked = false;

String mode = "Driving";

void setup() {
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  pinMode(RightUltrasonicTrigger, OUTPUT);
  pinMode(RightUltrasonicEcho, INPUT);
  pinMode(LeftUltrasonicTrigger, OUTPUT);
  pinMode(LeftUltrasonicEcho, INPUT);
  pinMode(FrontUltrasonicTrigger, OUTPUT);
  pinMode(FrontUltrasonicEcho, INPUT);
  pinMode(BackUltrasonicTrigger, OUTPUT);
  pinMode(BackUltrasonicEcho, INPUT);
  FrontServo.attach(9);
  FrontServo.write(90);
  FrontServo.write(90);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.print("Welcome");
  delay(3000);
  lcd.clear();
  PrintBoilerplateToLCD();
  //ScoutForOpeningsToParkIn();
  toggleSwitch.setDebounceTime(50);  // set debounce time to 50 milliseconds
}
// Utils

void PrintBoilerplateToLCD() {
  lcd.setCursor(0, 0);
  lcd.print("Mode:");
  lcd.setCursor(6, 0);
  lcd.print(mode);
}

void FloatDelay(float ms) {
  unsigned long whole = ms;
  int part = (ms - static_cast<int>(ms)) * 1000;
  delay(whole);
  if (part > 4) delayMicroseconds(part);
}
void LcdDebug(String text) {
  lcd.setCursor(0, 1);
  lcd.print(text);
}
void Button() {
  toggleSwitch.loop();
  if (toggleSwitch.isPressed() && mode == "Driving") {
    mode = "Parking";
    lcd.clear();
    PrintBoilerplateToLCD();
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
    CurrentlySynchronous = false;
    return;
  }
  if (toggleSwitch.isPressed() && mode == "Parking") {
    mode = "Following";
    lcd.clear();
    PrintBoilerplateToLCD();
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
    CurrentlySynchronous = false;
    return;
    }
    if (toggleSwitch.isPressed() && mode == "Following") {
      mode = "Driving";
      lcd.clear();
      PrintBoilerplateToLCD();
      digitalWrite(in1, LOW);
      digitalWrite(in2, LOW);
      digitalWrite(in3, LOW);
      digitalWrite(in4, LOW);
      CurrentlySynchronous = false;
      return;
    }
  }
}
// Ultrasonic related
float ReadFromUltrasonicSensor(Direction direction) {
  int echo;
  int trigger;
  if (direction == right) {
    echo = RightUltrasonicEcho;
    trigger = RightUltrasonicTrigger;
  } else if (direction == left) {
    echo = LeftUltrasonicEcho;
    trigger = LeftUltrasonicTrigger;
  } else if (direction == front) {
    echo = FrontUltrasonicEcho;
    trigger = FrontUltrasonicTrigger;
  } else if (direction == back) {
    echo = BackUltrasonicEcho;
    trigger = BackUltrasonicTrigger;
  }
  digitalWrite(trigger, LOW);
  delay(2);
  digitalWrite(trigger, HIGH);
  delay(10);
  digitalWrite(trigger, LOW);
  float timing = pulseIn(echo, HIGH);
  float distance = (timing * 0.0343) / 2;
  return distance;
}

// Car related
void MoveForwardTillObjectDetection(int speed, int time, float distance, Direction direction) {
  unsigned long originalTime = millis();
  CurrentlySynchronous = true;
  // Stops proceeding if the speed is an invalid value
  if (speed >= 256 || speed <= 0) {
    CurrentlySynchronous = false;
    return;
  }
  if (ReadFromUltrasonicSensor(direction) <= distance && ReadFromUltrasonicSensor(direction) >= 3) {
    CurrentlySynchronous = false;
    return;
  }
  // This function will run the motors in both directions at a variable speed and for a variable time.
  // Turn on motor A.
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  // Set motor A speed.
  analogWrite(enA, speed - 30);
  // Turn on motor B.
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  // Set motor B speed.
  analogWrite(enB, speed);
  // Wait the specified time in miliseconds.
  for (unsigned long timer = 0; timer <= originalTime + time; timer = millis()) {
    Button();
    if (ReadFromUltrasonicSensor(direction) <= distance && ReadFromUltrasonicSensor(direction) >= 3) {
      digitalWrite(in1, LOW);
      digitalWrite(in2, LOW);
      digitalWrite(in3, LOW);
      digitalWrite(in4, LOW);
      CurrentlySynchronous = false;
      return;
    }
  }
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  CurrentlySynchronous = false;
}
void MoveBack() {
  // Turn on motor A
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  // Set speed to 200 out of possible range 0~255
  analogWrite(enA, 200);
  // Turn on motor B
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
  // Set speed to 200 out of possible range 0~255
  analogWrite(enB, 200);
}
void MoveRight() {
  // Turn on motor A
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  // Set speed to 200 out of possible range 0~255
  analogWrite(enA, 200);
  // Turn on motor B
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  // Set speed to 200 out of possible range 0~255
  analogWrite(enB, 200);
}
void MoveLeft() {
  // Turn on motor A
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  // Set speed to 200 out of possible range 0~255
  analogWrite(enA, 200);
  // Turn on motor B
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  // Set speed to 200 out of possible range 0~255
  analogWrite(enB, 200);
}
void MoveForward() {
  // Turn on motor
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  // Set speed to 200 out of possible range 0~255
  analogWrite(enA, 170);
  // Turn on motor B
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  // Set speed to 200 out of possible range 0~255
  analogWrite(enB, 200);
}
void Stop() {
  // Now turn off motors

  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
}

//Best accuracy is using this function in intervals of *under 90 degrees*.
void TurnCar(int degrees) {

  rotation += degrees;
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  analogWrite(enA, 170);
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  analogWrite(enB, 200);
  FloatDelay(degrees * 5);
  //FloatDelay(float(degrees) * 6);
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
}

//Servo-related
String ScoutForObjectsWithServo() {
  FrontServo.write(0);
  delay(1000);
  float DistanceToRight = ReadFromUltrasonicSensor(front);
  FrontServo.write(180);
  delay(1000);
  float DistanceToLeft = ReadFromUltrasonicSensor(front);
  FrontServo.write(90);
  delay(1000);
  if (DistanceToRight >= DistanceToLeft) {
    return "right";
  }
  return "left";
}

void ScoutForOpeningsToParkIn(Direction direction) {

  unsigned long originalTime = millis();
  int OriginalDistanceLeft = ReadFromUltrasonicSensor(left);
  int OriginalDistanceRight = ReadFromUltrasonicSensor(right);
  int DistanceLeft = ReadFromUltrasonicSensor(left);
  int DistanceRight = ReadFromUltrasonicSensor(right);
  MoveForward();
  for (unsigned long timer = 0; timer <= originalTime + 10000; timer = millis()) {
    DistanceLeft = ReadFromUltrasonicSensor(left);
    DistanceRight = ReadFromUltrasonicSensor(right);
    if (direction == right && DistanceRight <= 50) {
      OriginalDistanceRight = DistanceRight;
    }
    if (direction == left && DistanceLeft <= 50) {
      OriginalDistanceLeft = DistanceLeft;
    }
    if (direction == right && DistanceRight - OriginalDistanceRight >= 30 || direction == right && DistanceRight <= 3) {
      Stop();
      StartParking(left, true);
      return;
    }
    if (direction == left && DistanceLeft - OriginalDistanceLeft >= 30 || direction == left && DistanceLeft <= 3) {
      Stop();
      StartParking(right, true);
      return;
    }
    DistanceLeft = ReadFromUltrasonicSensor(left);
    DistanceRight = ReadFromUltrasonicSensor(right);
  }

  Stop();
}
void loop()

{
  Button();
  LcdDebug("drive");
  if (mode == "Driving") { MoveForwardSmartly(); }
  LcdDebug("park");
  if (mode == "Parking" && Parked == false) {Parked = true; ScoutForOpeningsToParkIn(left); }
  LcdDebug("follow");
  if (mode == "Following") { ActLikeADoggy(right); }
  
}

// Main Code
void MoveForwardSmartly() {
  LcdDebug("smartly");
  CurrentlyMovingForward = true;
  MoveForwardTillObjectDetection(200, 10000, 10.0, front);
  if (mode != "Driving") { return; }
  String DirectionResult = ScoutForObjectsWithServo();
  if (DirectionResult == "right") {
    TurnCar(90);
  } else {
    TurnCar(90);
    delay(300);
    TurnCar(90);
    delay(300);
    TurnCar(90);
    delay(300);
  }
  if (mode != "Driving") { return; }
  CurrentlyMovingForward = false;
}

void StartParking(Direction direction, bool vertical) {
  if (direction == right & !vertical) {
    // 2 iters
    MoveRight();
    delay(1000);
    Stop();
    MoveLeft();
    delay(1000);
    Stop();
    MoveRight();
    delay(1000);
    Stop();
    MoveLeft();
    delay(8000);
    Stop();
  } else if (direction == left && !vertical) {
    MoveLeft();
    delay(1000);
    Stop();
    MoveRight();
    delay(1000);
    Stop();
    MoveLeft();
    delay(1000);
    Stop();
    MoveRight();
    delay(1000);
    Stop();
  } else if (direction == right && vertical) {
    MoveRight();
    delay(1100);
    Stop();
    MoveForward();
    delay(300);
  } else if (direction == left && vertical) {
    MoveLeft();
    delay(1100);
    MoveForward();
    delay(300);
    Stop();
  }

  Parked = true;
  if (vertical = false) {
    for (int FrontDistance = 0; FrontDistance <= ReadFromUltrasonicSensor(back); FrontDistance = ReadFromUltrasonicSensor(front)) {
      MoveBack();
      delay(50);
      Stop();
    }
  }
}

void ActLikeADoggy(Direction direction) {
  while (mode = "Following") {
    Button();
    while (ReadFromUltrasonicSensor(direction) > 15) {
      switch (direction) {
        case left:
          MoveLeft();
          break;
        case right:
          MoveRight();
          break;
      }
    }
    Stop();
    while (ReadFromUltrasonicSensor(direction) < 10) {
      switch (direction) {
        case right:
          MoveLeft();
          break;
        case left:
          MoveRight();
          break;
      }
      Stop();
      while (ReadFromUltrasonicSensor(direction) > 10 && ReadFromUltrasonicSensor(direction) < 15) {
        MoveForward();
      }
      Stop();
    }
  }
}
// Unit tests
// All motors should spin
void Test() {

  // This function will run the motors in both directions at a fixed speed

  // Turn on motor A

  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);

  // Set speed to 200 out of possible range 0~255

  analogWrite(enA, 200);

  // Turn on motor B

  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);

  // Set speed to 200 out of possible range 0~255

  analogWrite(enB, 200);

  delay(2000);

  // Now change motor directions

  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);

  delay(2000);

  // Now turn off motors

  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
}

I have an lcd print line in loop, but the problem is, it seems the if condition before them are taking very long times to finish, despite simply being false.
While this doesn't affect the end result I do plan to showcase it to other people (this is for a school project), and having it take around 3 seconds to start up after pressing the button and switching it into another mode (via ezButton) would not be very ideal

To avoid the need to visit another site, please post your full sketch, using code tags when you do. This prevents parts of it being interpreted as HTML coding and makes it easier to copy for examination

In my experience the easiest way to tidy up the code and add the code tags is as follows
Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

1 Like

Alright, done

Thank you

You've written your program such that all the timing is handled by sitting and waiting in delay calls. When you are in delay then that is the line that is running. Nothing else is happening. You will have to wait for those delays to end before the code gets back to the line that reacts to the button.

There are thousands of tutorials online about how to handle timing without using delay. Sounds like that should be your next lesson.

While I do have a bunch of delays all the things that need to happen asynchronously are used without delays (for example, stopping when the ultrasonic sensor detects an object)
No delays should run in the loop as well because the if statement for mode == driving should return false
I don't mean to be rude, but, maybe you should read the entire code before commenting about any mistakes.

Looks like loop will call MoveForwardSmartly.

That function not only does in fact include delay calls, it also calls MoveForwardTillObjectDetection which includes this blocking for loop:

Which is blocking just like delay is. You just sit and go round and round that for loop for 10000 milliseconds.

Your problem is still the blocking code.

1 Like

That for loop is also not safe across millis rollover. Instead of predicting a future time point, use subtraction to figure how long it has been since some past time. See the various discussions around "Blink Without Delay" to understand why.

Your loop does call functions with delay. Prehaps you should read your own code before you decide to chide someone.

Thanks but this isnt my problem

It doesn't call MoveForwardSmartly, I used an LCD debug to check, which is still in the code

That's your loop function.

Looks like this line calls MoveForwardSmartly if mode is equal to "Driving"

The other methods that can be called from loop include ScoutForOpeningsToParkIn which also has the same sort of blocking for loop. Then there's also ActLikeADoggy which is also chock full of blocking code in the form of those while loops.

Code after a return statement is unreachable. The compiler should have given you a warning about this.

This is also blocking.

All blocking for loops are not in the start of the code, rather the middle or end
Placing a debug in the start yields no results, therefore the problem isn't the blocking
Please read my entire code before commenting

It didn't, nothing related to my problem, though

Ultrasonic sensor blocking is only a few milliseconds, which doesn't affect the flow of the program too much to matter

Forget you then. Rude ass. I'm trying to help you. You have lots of issues in this code. You say you have a ten second delay and i see the code producing a ten second delay right where you told it to.

I think you maybe dont understand what you've written. But given your rude attitude I'm not going to waste any more time trying to find it.

2 Likes

Thread is muted. You can reply with some other smart ass wrong remark but I won't see it.

Forget you.

2 Likes

Um, yeah. Well done. Come here for help, ignore what the help is telling you 'cause you know better. Chew on this:
Before setup(), you have:
String mode = "Driving";
And, mode is not modified in setup();
Then, in loop(), you have

  Button();
  LcdDebug("drive");
  if (mode == "Driving") { MoveForwardSmartly(); }

So unless Button(), or LcdDebug(), modify mode, you're pooched. Of course, Button() might, given the code in there, but you've a problem. Putting things on either Serial pin (you've got toggleswitch on TX, pin 1), is just asking for trouble - that's your transmit pin for Serial messages. So, what do you think? Is toggleSwitch(1) an input, or is it an output? Does the library continue to force it to input, right after you've sent a character(which may or may not force it to an output, but that's up to the Serial library; I suspect it does at Serial.begin(), other times YMMV).
Now, I'm not going to dig into either library for you, I'm just going to suggest you try a different pin, even if it's only temporary, and see if the behaviour is different. If it is, get back to us here, with, no doubt, a description of the next aberrant behaviour of your code.
Good luck. You've burnt one very big bridge, think about it before you burn another.